commit 5e4ed9d64a91d8c0bacf949ed97a6f2131154753 Author: saqib mir Date: Wed Aug 19 16:29:17 2026 +0530 first commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..92a8d0f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +node_modules +npm-debug.log +dist +.git +.gitignore +.github +.env +.env.* +!.env.example +Dockerfile* +docker-compose*.yml +coverage +.nyc_output +.idea +.vscode +*.log +.DS_Store \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4a7ea30 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.env.prod b/.env.prod new file mode 100644 index 0000000..3fafe6f --- /dev/null +++ b/.env.prod @@ -0,0 +1,16 @@ +NODE_ENV=production +PORT=3003 + +# Nest build +BUILD_COMMAND=npm run build:prod + +# Database +POSTGRES_HOST=postgres +POSTGRES_DB=myapp_prod +POSTGRES_USER=myapp_prod +POSTGRES_PASSWORD=CHANGE_ME +DATABASE_URL=postgresql://myapp_prod:CHANGE_ME@postgres:5432/myapp_prod + +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_PASSWORD=CHANGE_ME \ No newline at end of file diff --git a/.env.test.example b/.env.test.example new file mode 100644 index 0000000..8cf0c9b --- /dev/null +++ b/.env.test.example @@ -0,0 +1,26 @@ +# Server Environment - Test +NODE_ENV=test +PORT=3001 +HOST=127.0.0.1 +LOG_LEVEL=silent + +# Database (PostgreSQL Test Container/DB) +DATABASE_URL=postgresql://postgres:postgres@localhost:5432/supporthub_test_db?schema=public + +# Redis Test Container/DB +REDIS_HOST=localhost +REDIS_PORT=6379 +REDIS_PASSWORD= + +# Authentication Test Keys +JWT_SECRET=super-secret-test-jwt-key-min-32-characters + +# AWS S3 Test Storage +AWS_REGION=us-east-1 +AWS_S3_BUCKET=supporthub-test-bucket +AWS_ACCESS_KEY_ID=test-aws-access-key-id +AWS_SECRET_ACCESS_KEY=test-aws-secret-access-key +AWS_S3_ENDPOINT= + +# Security & CORS Test +CORS_ORIGINS=* diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f85a803 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +# Auto detect text files and perform LF normalization +* text=auto eol=lf + +# Explicit binary files +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.pdf binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db4c0a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# Dependencies +node_modules/ +.pnp +.pnp.js + +# Testing & Coverage +coverage/ +*.lcov +.vitest/ + +# Build Output +dist/ +build/ +*.tsbuildinfo + +# Environment Variables +.env +.env.local +.env.development +.env.production +.env.test + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pino-*.log + +# Editor & System Files +.vscode/* +!.vscode/extensions.json +!.vscode/settings.json +.idea/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.DS_Store +Thumbs.db + +# Docker Persistent Volumes Data (Local) +docker/postgres/data/ +docker/redis/data/ +docker/minio/data/ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..3758e37 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,2 @@ +npx lint-staged +npx tsx scripts/check-architecture.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e50066a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,65 @@ +# Contributing to SupportHub API + +Thank you for contributing to SupportHub API. Please review the following guidelines before submitting changes. + +--- + +## Branch Naming Convention + +- `feature/`: New domain feature or infrastructure addition +- `bugfix/`: Bug fix +- `refactor/`: Code restructuring without functional changes +- `chore/`: Tooling, dependency, or documentation updates + +--- + +## Commit Message Format + +Use Conventional Commits: + +```text +(): + +[optional body] +``` + +Examples: +- `feat(ticketing): add ticket priority calculator strategy` +- `fix(queue): resolve BullMQ connection leak on shutdown` +- `chore(deps): update fastify to 4.26.2` + +--- + +## Architecture Rules + +1. **Self-Contained Modules**: Every domain feature belongs in `src/modules//`. +2. **Public Boundary**: Expose public domain interfaces strictly via `index.ts`. Deep cross-module imports are prohibited. +3. **Layer Isolation**: + - `HTTP Route / Controller` -> Calls `Service` + - `Service` -> Calls `Repository` / `Engine` + - `Repository` -> Calls `PrismaClient` / `Database` + - Controllers **MUST NOT** directly query Prisma. +4. **Architecture Check**: Run `npm run architecture:check` before committing. + +--- + +## Code Quality & Verification Gates + +Before submitting a Pull Request, all of the following local commands must pass: + +```bash +npm run typecheck +npm run architecture:check +npm run lint +npm run format:check +npm run test +npm run build +``` + +--- + +## Pull Request Guidelines + +1. Create a PR against `main`. +2. Provide a clear description of changes and design decisions. +3. Ensure CI pipeline checks pass completely. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b97fae7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +FROM node:22-alpine AS base + +WORKDIR /app + +RUN apk add --no-cache libc6-compat + +FROM base AS dependencies + +COPY package*.json ./ + +RUN npm ci + +FROM dependencies AS builder + +COPY . . + +ARG BUILD_COMMAND="npm run build" + +RUN sh -c "$BUILD_COMMAND" + +FROM base AS production-dependencies + +COPY package*.json ./ + +RUN npm ci --omit=dev && npm cache clean --force + +FROM base AS runner + +WORKDIR /app + +USER node + +COPY --from=production-dependencies --chown=node:node /app/node_modules ./node_modules + +COPY --from=builder --chown=node:node /app/dist ./dist + +COPY --chown=node:node package*.json ./ + +CMD ["node", "dist/main.js"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a854df0 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Development +docker compose --env-file .env.development -f docker-compose.development.yml up -d --build + +# Test +docker compose --env-file .env.test -f docker-compose.test.yml up --build + +# Production +docker compose --env-file .env.prod -f docker-compose.prod.yml up --build -d + +# Stop +docker compose -f docker-compose.prod.yml down + diff --git a/docker-compose.development.yml b/docker-compose.development.yml new file mode 100644 index 0000000..e677369 --- /dev/null +++ b/docker-compose.development.yml @@ -0,0 +1,88 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + args: + BUILD_COMMAND: ${BUILD_COMMAND} + + container_name: support-development + + env_file: + - .env.development + + environment: + NODE_ENV: ${NODE_ENV} + PORT: ${PORT} + DATABASE_URL: ${DATABASE_URL} + REDIS_HOST: ${REDIS_HOST} + REDIS_PORT: ${REDIS_PORT} + REDIS_PASSWORD: ${REDIS_PASSWORD} + + ports: + - "${PORT}:${PORT}" + + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + + restart: unless-stopped + + postgres: + image: postgres:18-alpine + + container_name: postgres-development + + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + + volumes: + - postgres_development_data:/var/lib/postgresql + + healthcheck: + test: + [ + "CMD-SHELL", + "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" + ] + interval: 5s + timeout: 5s + retries: 10 + + restart: unless-stopped + + redis: + image: redis:7-alpine + + container_name: redis-development + + command: + - redis-server + - --requirepass + - ${REDIS_PASSWORD} + + volumes: + - redis_development_data:/data + + healthcheck: + test: + [ + "CMD", + "redis-cli", + "-a", + "${REDIS_PASSWORD}", + "ping" + ] + interval: 5s + timeout: 5s + retries: 10 + + restart: unless-stopped + +volumes: + postgres_development_data: + redis_development_data: \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..2775a34 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,88 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + args: + BUILD_COMMAND: ${BUILD_COMMAND} + + container_name: support-production + + env_file: + - .env.prod + + environment: + NODE_ENV: ${NODE_ENV} + PORT: ${PORT} + DATABASE_URL: ${DATABASE_URL} + REDIS_HOST: ${REDIS_HOST} + REDIS_PORT: ${REDIS_PORT} + REDIS_PASSWORD: ${REDIS_PASSWORD} + + ports: + - "${PORT}:${PORT}" + + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + + restart: unless-stopped + + postgres: + image: postgres:18-alpine + + container_name: postgres-production + + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + + volumes: + - postgres_production_data:/var/lib/postgresql + + healthcheck: + test: + [ + "CMD-SHELL", + "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" + ] + interval: 5s + timeout: 5s + retries: 10 + + restart: unless-stopped + + redis: + image: redis:7-alpine + + container_name: redis-production + + command: + - redis-server + - --requirepass + - ${REDIS_PASSWORD} + + volumes: + - redis_production_data:/data + + healthcheck: + test: + [ + "CMD", + "redis-cli", + "-a", + "${REDIS_PASSWORD}", + "ping" + ] + interval: 5s + timeout: 5s + retries: 10 + + restart: unless-stopped + +volumes: + postgres_production_data: + redis_production_data: \ No newline at end of file diff --git a/docker-compose.test.yml b/docker-compose.test.yml new file mode 100644 index 0000000..e30e1e4 --- /dev/null +++ b/docker-compose.test.yml @@ -0,0 +1,88 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + args: + BUILD_COMMAND: ${BUILD_COMMAND} + + container_name: support-test + + env_file: + - .env.test + + environment: + NODE_ENV: ${NODE_ENV} + PORT: ${PORT} + DATABASE_URL: ${DATABASE_URL} + REDIS_HOST: ${REDIS_HOST} + REDIS_PORT: ${REDIS_PORT} + REDIS_PASSWORD: ${REDIS_PASSWORD} + + ports: + - "${PORT}:${PORT}" + + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + + restart: unless-stopped + + postgres: + image: postgres:18-alpine + + container_name: postgres-test + + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + + volumes: + - postgres_test_data:/var/lib/postgresql + + healthcheck: + test: + [ + "CMD-SHELL", + "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" + ] + interval: 5s + timeout: 5s + retries: 10 + + restart: unless-stopped + + redis: + image: redis:7-alpine + + container_name: redis-test + + command: + - redis-server + - --requirepass + - ${REDIS_PASSWORD} + + volumes: + - redis_test_data:/data + + healthcheck: + test: + [ + "CMD", + "redis-cli", + "-a", + "${REDIS_PASSWORD}", + "ping" + ] + interval: 5s + timeout: 5s + retries: 10 + + restart: unless-stopped + +volumes: + postgres_test_data: + redis_test_data: \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..e066815 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,31 @@ +const typescriptEslintPlugin = require("@typescript-eslint/eslint-plugin"); +const typescriptEslintParser = require("@typescript-eslint/parser"); +const prettierConfig = require("eslint-config-prettier"); + +module.exports = [ + { + ignores: ["dist/**", "node_modules/**", "coverage/**", "prisma/migrations/**"], + }, + { + files: ["src/**/*.ts", "tests/**/*.ts", "scripts/**/*.ts", "prisma/**/*.ts"], + languageOptions: { + parser: typescriptEslintParser, + parserOptions: { + ecmaVersion: 2022, + sourceType: "module", + }, + }, + plugins: { + "@typescript-eslint": typescriptEslintPlugin, + }, + rules: { + ...typescriptEslintPlugin.configs.recommended.rules, + ...prettierConfig.rules, + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "@typescript-eslint/no-non-null-assertion": "error", + "no-console": "error", + }, + }, +]; diff --git a/lint-staged.config.js b/lint-staged.config.js new file mode 100644 index 0000000..e2d5d89 --- /dev/null +++ b/lint-staged.config.js @@ -0,0 +1,9 @@ +module.exports = { + "*.ts": [ + "eslint --fix", + "prettier --write" + ], + "*.{json,md,yml,yaml}": [ + "prettier --write" + ] +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8c6c0b8 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6948 @@ +{ + "name": "supporthub-api", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "supporthub-api", + "version": "1.0.0", + "dependencies": { + "@aws-sdk/client-s3": "^3.556.0", + "@aws-sdk/s3-request-presigner": "^3.556.0", + "@fastify/cors": "^9.0.1", + "@fastify/helmet": "^11.1.1", + "@fastify/rate-limit": "^9.1.0", + "@fastify/swagger": "^8.14.0", + "@fastify/swagger-ui": "^3.0.0", + "@opentelemetry/api": "^1.8.0", + "@opentelemetry/sdk-trace-base": "^1.22.0", + "@prisma/client": "^5.12.1", + "bullmq": "^5.7.1", + "dotenv": "^16.4.5", + "fastify": "^4.26.2", + "fastify-plugin": "^4.5.1", + "ioredis": "^5.3.2", + "pino": "^8.20.0", + "pino-pretty": "^11.0.0", + "prom-client": "^15.1.1", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/node": "^20.12.7", + "@typescript-eslint/eslint-plugin": "^7.6.0", + "@typescript-eslint/parser": "^7.6.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", + "prettier": "^3.2.5", + "prisma": "^5.12.1", + "tsx": "^4.7.2", + "typescript": "^5.4.5", + "vitest": "^1.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/checksums": { + "version": "3.1000.28", + "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.28.tgz", + "integrity": "sha512-VCpnmyHQ1IH49ni3LXnQj7DPr7rmcJmzYeiCkYdCcfgNtkvOj38cdcL9lapBWoItZWFACJPFJlymqC7/gem3Gw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.1112.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1112.0.tgz", + "integrity": "sha512-E+Z+rIkExcUQbnV9EYfT/fOnveV9B8vIZUzE+wYCVMKgcn/aJJy73FvRf46SGd1NqgT8ESqNlk3Wc/9wE/7/Og==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/checksums": "^3.1000.28", + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/credential-provider-node": "^3.972.80", + "@aws-sdk/middleware-sdk-s3": "^3.972.74", + "@aws-sdk/signature-v4-multi-region": "^3.996.45", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.977.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.977.8.tgz", + "integrity": "sha512-7+Kcrkvrk9lM/m7jRhHpT4jCdvzGHsuaSRbF8TdzzkY1mRzp/Ogwf9c7H29k4gGhey0BBWhCWr16+t0J61gwmg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@aws-sdk/xml-builder": "^3.972.39", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.31.1", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.69", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.69.tgz", + "integrity": "sha512-AreCFzcB4kH2HF9031Ot0jSJr3KXvRg6e8uDeub20JEVdZU3Bv0sTq1plc7VsT3KiqutlzH7l0j50UcCWHUioA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.71", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.71.tgz", + "integrity": "sha512-A8ObcqVmDMnk4F9NozZ7JwmUu9Q4xyBJkmyq1C5U+wNM9ht9J7+EuuyabsLWXZnOoTqFaJuYBYTKf5CTipkEjA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.14", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.14.tgz", + "integrity": "sha512-7c+Wti2LsERNWMfm7ySz3/6RPopFW3Nmn7s63Xpcq6R/tRuY5hpvkHA2xVgi5ukJbvok9l0IDtVEvqTtg+X7dw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/credential-provider-env": "^3.972.69", + "@aws-sdk/credential-provider-http": "^3.972.71", + "@aws-sdk/credential-provider-login": "^3.972.76", + "@aws-sdk/credential-provider-process": "^3.972.69", + "@aws-sdk/credential-provider-sso": "^3.973.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.75", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.76", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.76.tgz", + "integrity": "sha512-LVixwOnEJfrrfKHeZjBA8pIMTZjNDq8ak8VpcoWUuCJDrSnBNU8POJksULMgvN089P0MXtQYH2Zs627/MK1K0g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.80", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.80.tgz", + "integrity": "sha512-bE2qh8ww4iClO1jHsBXdOE8FUgzDbdxbyorNjSCoPSkQd51k3jODItuPZfuwcLHZqDXsH+bI4AMHhqtuyR7mSg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.69", + "@aws-sdk/credential-provider-http": "^3.972.71", + "@aws-sdk/credential-provider-ini": "^3.973.14", + "@aws-sdk/credential-provider-process": "^3.972.69", + "@aws-sdk/credential-provider-sso": "^3.973.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.75", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.69", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.69.tgz", + "integrity": "sha512-9kpTNdZTrcqXTfhxM7fgl9Z68ek3Fu5oe3Yf+A/pJGibEqpgZxz2tSY7SinmyCIU2PJ+ygY4FPoBBnLpocMtrQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.13.tgz", + "integrity": "sha512-Oc81qauMPzUoTnAS2YKpNwY6sY/LUyQTEeaf6yP197WMxkEBQfcKLR1MFpD7+pNTubXnfkH6gwpji+Gc7iyD2Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/token-providers": "3.1111.0", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.75", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.75.tgz", + "integrity": "sha512-YPN6uoGDgjjjeVFZrcOeCJqmB6zpXoeeNgIjqe+DexJaWqdjVfCCe+VAZwli9Z2h8KhFW8oxkO39emQ1tyz/Mw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.972.74", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.74.tgz", + "integrity": "sha512-2lzoV2z2QO5KJZYGOCnIZ1WVQgzMECvwuzr1xb034a++8QW4U4eGrmC2u4yg1xvNv4TLL/Uv5DLyuAiw0b9z7Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/signature-v4-multi-region": "^3.996.45", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.43.tgz", + "integrity": "sha512-bit+VpqWNyi3wHxFoTsTliNXimCSL2r2OeDTm7ZrG+YsTZ2D7ofDJ6r/t9PVBn80i6/v0X2h9Tgw6QP2MAKfPw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/signature-v4-multi-region": "^3.996.45", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner": { + "version": "3.1112.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.1112.0.tgz", + "integrity": "sha512-Qmnhl9jpjJrp3Jei6yfnMPdhX/wLxM2kFdUr2V/9PpDhosRUIMfVTNfuq6Mq6WVHfGyLyeksoHt16agzJ50auA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/signature-v4-multi-region": "^3.996.45", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.45", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.45.tgz", + "integrity": "sha512-bBuyztukzXq6plzFGHAWiQt0QXo+HL8b8lX5cFTzkez/74PtS1c0qPFCIVuHkyoT+miH2qOjAcm1/yoro2ESPA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1111.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1111.0.tgz", + "integrity": "sha512-JfljgoVtl+s3Qy21n9a7Z48uCQaOXcN74KJ3TEQfPoB293GrXFSt6HSQJF1sTZ8c/5QedEvd3NjJQMO4u9qa5A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.974.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.4.tgz", + "integrity": "sha512-dSFDNG00MEz0/xl5gxL62giLd1iYyJsTxZ1I1DOj6lC+bbgLB4TRsYClJg3b62dhXT1uATzsTNXPnC+33EJV3A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.39", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.39.tgz", + "integrity": "sha512-FTti8DS5MMWXNUWiRwXAJeYS+0GHHiMy0+7XOhcwk63ILHmfS2UFy2z/HNpZCSOJJ3P3dnWY6hfYNW3DF0nXUA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fastify/accept-negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz", + "integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@fastify/ajv-compiler": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.6.0.tgz", + "integrity": "sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv/node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/@fastify/cors": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-9.0.1.tgz", + "integrity": "sha512-YY9Ho3ovI+QHIL2hW+9X4XqQjXLjJqsU+sMV/xFsxZkE8p3GNnYVFpoOxF7SsP5ZL76gwvbo3V9L+FIekBGU4Q==", + "license": "MIT", + "dependencies": { + "fastify-plugin": "^4.0.0", + "mnemonist": "0.39.6" + } + }, + "node_modules/@fastify/error": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==", + "license": "MIT" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", + "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "license": "MIT", + "dependencies": { + "fast-json-stringify": "^5.7.0" + } + }, + "node_modules/@fastify/helmet": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@fastify/helmet/-/helmet-11.1.1.tgz", + "integrity": "sha512-pjJxjk6SLEimITWadtYIXt6wBMfFC1I6OQyH/jYVCqSAn36sgAIFjeNiibHtifjCd+e25442pObis3Rjtame6A==", + "license": "MIT", + "dependencies": { + "fastify-plugin": "^4.2.1", + "helmet": "^7.0.0" + } + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz", + "integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/@fastify/rate-limit": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@fastify/rate-limit/-/rate-limit-9.1.0.tgz", + "integrity": "sha512-h5dZWCkuZXN0PxwqaFQLxeln8/LNwQwH9popywmDCFdKfgpi4b/HoMH1lluy6P+30CG9yzzpSpwTCIPNB9T1JA==", + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "fastify-plugin": "^4.0.0", + "toad-cache": "^3.3.1" + } + }, + "node_modules/@fastify/send": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", + "integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==", + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "escape-html": "~1.0.3", + "fast-decode-uri-component": "^1.0.1", + "http-errors": "2.0.0", + "mime": "^3.0.0" + } + }, + "node_modules/@fastify/static": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-7.0.4.tgz", + "integrity": "sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==", + "license": "MIT", + "dependencies": { + "@fastify/accept-negotiator": "^1.0.0", + "@fastify/send": "^2.0.0", + "content-disposition": "^0.5.3", + "fastify-plugin": "^4.0.0", + "fastq": "^1.17.0", + "glob": "^10.3.4" + } + }, + "node_modules/@fastify/swagger": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@fastify/swagger/-/swagger-8.15.0.tgz", + "integrity": "sha512-zy+HEEKFqPMS2sFUsQU5X0MHplhKJvWeohBwTCkBAJA/GDYGLGUWQaETEhptiqxK7Hs0fQB9B4MDb3pbwIiCwA==", + "license": "MIT", + "dependencies": { + "fastify-plugin": "^4.0.0", + "json-schema-resolver": "^2.0.0", + "openapi-types": "^12.0.0", + "rfdc": "^1.3.0", + "yaml": "^2.2.2" + } + }, + "node_modules/@fastify/swagger-ui": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@fastify/swagger-ui/-/swagger-ui-3.1.0.tgz", + "integrity": "sha512-68jm6k8VzvHXkEBT4Dakm/kkzUlPO4POIi0agWJSWxsYichPBqzjo+IpfqPl4pSJR1zCToQhEOo+cv+yJL2qew==", + "license": "MIT", + "dependencies": { + "@fastify/static": "^7.0.0", + "fastify-plugin": "^4.0.0", + "openapi-types": "^12.0.2", + "rfdc": "^1.3.0", + "yaml": "^2.2.2" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@ioredis/commands": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.10.0.tgz", + "integrity": "sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lukeed/ms": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", + "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", + "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", + "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", + "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", + "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", + "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", + "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz", + "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz", + "integrity": "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/resources": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@prisma/client": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz", + "integrity": "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/debug": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz", + "integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.22.0.tgz", + "integrity": "sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.22.0", + "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", + "@prisma/fetch-engine": "5.22.0", + "@prisma/get-platform": "5.22.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz", + "integrity": "sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz", + "integrity": "sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.22.0", + "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", + "@prisma/get-platform": "5.22.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.22.0.tgz", + "integrity": "sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.22.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz", + "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz", + "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz", + "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz", + "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz", + "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz", + "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz", + "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz", + "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz", + "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz", + "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz", + "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz", + "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz", + "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz", + "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz", + "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz", + "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz", + "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", + "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz", + "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz", + "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz", + "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz", + "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz", + "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz", + "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz", + "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@smithy/core": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.33.2.tgz", + "integrity": "sha512-CUGXpnPkVdjUCbix+83sWLW9VFgQOm44MDOx/ihITJMAnOZKvL8YYIc7DR9pP/tZ8CIRvMiON/TucvygqbHO3w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", + "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.7.2.tgz", + "integrity": "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", + "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.2.tgz", + "integrity": "sha512-P7Ki6px6OOrxVtx8K7nLmyx4SlXUW/uTKDdMG44UHefmPGSRMBKe2v+TM59WdLcpUIrBrnuCsIqiM2MbsZjmhw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.17.2.tgz", + "integrity": "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitest/expect": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", + "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "1.6.1", + "@vitest/utils": "1.6.1", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", + "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "1.6.1", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", + "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", + "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz", + "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/avvio": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.4.0.tgz", + "integrity": "sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==", + "license": "MIT", + "dependencies": { + "@fastify/error": "^3.3.0", + "fastq": "^1.17.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bintrees": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", + "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", + "license": "MIT" + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bullmq": { + "version": "5.81.3", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.81.3.tgz", + "integrity": "sha512-Q7uEH2G92rVjX3Yl2qw3+6VEO15uxehC6DfeTHQBQTehddcRDSDuquD9zuvDjxiCffXsPUaBwrRlvlbVcgKs7g==", + "license": "MIT", + "dependencies": { + "cron-parser": "4.9.0", + "ioredis": "5.11.1", + "msgpackr": "2.0.5", + "node-abort-controller": "3.1.1", + "semver": "7.8.5", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=12.22.0" + }, + "peerDependencies": { + "redis": ">=5.0.0" + }, + "peerDependenciesMeta": { + "redis": { + "optional": true + } + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "deprecated": "v4 is no longer maintained, upgrade to v5", + "license": "MIT", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-content-type-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==", + "license": "MIT" + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "license": "MIT" + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stringify": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.1.tgz", + "integrity": "sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==", + "license": "MIT", + "dependencies": { + "@fastify/merge-json-schemas": "^0.1.0", + "ajv": "^8.10.0", + "ajv-formats": "^3.0.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "json-schema-ref-resolver": "^1.0.1", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/fast-json-stringify/node_modules/ajv/node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "license": "MIT", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.4.4.tgz", + "integrity": "sha512-GntYZbd2KSiFfoZI3Y02rXKihfsPwdWfiHrwKVLuU1i810D0SYw7fCarLxaRO2VvneTrbzCxSz3GnvEfUiApug==", + "license": "MIT" + }, + "node_modules/fastify": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.29.1.tgz", + "integrity": "sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/ajv-compiler": "^3.5.0", + "@fastify/error": "^3.4.0", + "@fastify/fast-json-stringify-compiler": "^4.3.0", + "abstract-logging": "^2.0.1", + "avvio": "^8.3.0", + "fast-content-type-parse": "^1.1.0", + "fast-json-stringify": "^5.8.0", + "find-my-way": "^8.0.0", + "light-my-request": "^5.11.0", + "pino": "^9.0.0", + "process-warning": "^3.0.0", + "proxy-addr": "^2.0.7", + "rfdc": "^1.3.0", + "secure-json-parse": "^2.7.0", + "semver": "^7.5.4", + "toad-cache": "^3.3.0" + } + }, + "node_modules/fastify-plugin": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz", + "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==", + "license": "MIT" + }, + "node_modules/fastify/node_modules/pino": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz", + "integrity": "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/fastify/node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/fastify/node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, + "node_modules/fastify/node_modules/pino/node_modules/process-warning": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.1.0.tgz", + "integrity": "sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/fastify/node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/fastify/node_modules/thread-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.2.0.tgz", + "integrity": "sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-my-way": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.2.tgz", + "integrity": "sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^3.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/helmet": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", + "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ioredis": { + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.11.1.tgz", + "integrity": "sha512-ehuGcf94bQXhfagULNXrJdfnWO38v070jxSx/qE87Kjzmu2fU7ro5EFAb+OPituLqgfyuQaym5DlrNydW2sJ9A==", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "1.10.0", + "cluster-key-slot": "1.1.1", + "debug": "4.4.3", + "denque": "2.1.0", + "redis-errors": "1.2.0", + "redis-parser": "3.0.0", + "standard-as-callback": "2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-ref-resolver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", + "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/json-schema-resolver": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json-schema-resolver/-/json-schema-resolver-2.0.0.tgz", + "integrity": "sha512-pJ4XLQP4Q9HTxl6RVDLJ8Cyh1uitSs0CzDBAz1uoJ4sRD/Bk7cFSXL1FUXDW3zJ7YnfliJx6eu8Jn283bpZ4Yg==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "rfdc": "^1.1.4", + "uri-js": "^4.2.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/Eomm/json-schema-resolver?sponsor=1" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/light-my-request": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.14.0.tgz", + "integrity": "sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==", + "license": "BSD-3-Clause", + "dependencies": { + "cookie": "^0.7.0", + "process-warning": "^3.0.0", + "set-cookie-parser": "^2.4.1" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/local-pkg": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mnemonist": { + "version": "0.39.6", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.6.tgz", + "integrity": "sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==", + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/msgpackr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-2.0.5.tgz", + "integrity": "sha512-cef05H/dSYpLpqp3sj/qyZh5vhUYCalnaLO7j1yOmpsR0y/XwLVtK7r5gn+U/F7CTEfMowcGhlUQJDLcLf7jcA==", + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.4" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", + "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" + } + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "license": "MIT" + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.1.tgz", + "integrity": "sha512-e0F9AOF1JMrCfBsyJOwU9lNvQ0WtXTq0j/4jk0BQ5JSI9VAybPXmDpPRw/2FQ3e5d3ZFN1mLh7jW99m/jjaptw==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pino": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.6.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "license": "MIT", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-abstract-transport/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.3.0.tgz", + "integrity": "sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-pretty/node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-pretty/node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", + "license": "MIT" + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prisma": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.22.0.tgz", + "integrity": "sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/engines": "5.22.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "license": "MIT" + }, + "node_modules/prom-client": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.3.tgz", + "integrity": "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.4.0", + "tdigest": "^0.1.1" + }, + "engines": { + "node": "^16 || ^18 || >=20" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ret": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", + "integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/rollup": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", + "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.62.4", + "@rollup/rollup-android-arm64": "4.62.4", + "@rollup/rollup-darwin-arm64": "4.62.4", + "@rollup/rollup-darwin-x64": "4.62.4", + "@rollup/rollup-freebsd-arm64": "4.62.4", + "@rollup/rollup-freebsd-x64": "4.62.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", + "@rollup/rollup-linux-arm-musleabihf": "4.62.4", + "@rollup/rollup-linux-arm64-gnu": "4.62.4", + "@rollup/rollup-linux-arm64-musl": "4.62.4", + "@rollup/rollup-linux-loong64-gnu": "4.62.4", + "@rollup/rollup-linux-loong64-musl": "4.62.4", + "@rollup/rollup-linux-ppc64-gnu": "4.62.4", + "@rollup/rollup-linux-ppc64-musl": "4.62.4", + "@rollup/rollup-linux-riscv64-gnu": "4.62.4", + "@rollup/rollup-linux-riscv64-musl": "4.62.4", + "@rollup/rollup-linux-s390x-gnu": "4.62.4", + "@rollup/rollup-linux-x64-gnu": "4.62.4", + "@rollup/rollup-linux-x64-musl": "4.62.4", + "@rollup/rollup-openbsd-x64": "4.62.4", + "@rollup/rollup-openharmony-arm64": "4.62.4", + "@rollup/rollup-win32-arm64-msvc": "4.62.4", + "@rollup/rollup-win32-ia32-msvc": "4.62.4", + "@rollup/rollup-win32-x64-gnu": "4.62.4", + "@rollup/rollup-win32-x64-msvc": "4.62.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz", + "integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==", + "license": "MIT", + "dependencies": { + "ret": "~0.4.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/sonic-boom": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", + "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tdigest": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", + "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", + "license": "MIT", + "dependencies": { + "bintrees": "1.0.2" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thread-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toad-cache": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.4.tgz", + "integrity": "sha512-m1TdR/rvT7kgGJZhspNtXdsdYk0fddFpJJFlG5s+UkPFo6lkLoZ3YLOaovPYjq1R75NP5JfeTlSHaOsE09peCg==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.23.12", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.12.tgz", + "integrity": "sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", + "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz", + "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "1.6.1", + "@vitest/runner": "1.6.1", + "@vitest/snapshot": "1.6.1", + "@vitest/spy": "1.6.1", + "@vitest/utils": "1.6.1", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.3", + "vite": "^5.0.0", + "vite-node": "1.6.1", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.6.1", + "@vitest/ui": "1.6.1", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0d6ded3 --- /dev/null +++ b/package.json @@ -0,0 +1,75 @@ +{ + "name": "supporthub-api", + "version": "1.0.0", + "description": "SupportHub API — Production Enterprise Modular Monolith API", + "main": "dist/server.js", + "scripts": { + "dev": "tsx watch src/server.ts", + "development": "tsx --env-file=.env.development watch src/server.ts", + "dev:env": "tsx --env-file=.env.development watch src/server.ts", + "build": "tsc -p tsconfig.build.json", + "start": "node dist/server.js", + "start:prod": "NODE_ENV=production node dist/server.js", + "start:dev": "NODE_ENV=development tsx src/server.ts", + "typecheck": "tsc --noEmit", + "architecture:check": "tsx scripts/check-architecture.ts", + "lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\"", + "lint:fix": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" --fix", + "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" \"prisma/**/*.ts\"", + "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" \"prisma/**/*.ts\"", + "test": "vitest run", + "test:env": "vitest run --env-file=.env.test", + "test:unit": "vitest run tests/unit", + "test:integration": "vitest run tests/integration", + "test:e2e": "vitest run tests/e2e", + "test:concurrency": "vitest run tests/concurrency", + "test:coverage": "vitest run --coverage", + "prisma:generate": "prisma generate", + "prisma:migrate": "prisma migrate dev", + "prisma:deploy": "prisma migrate deploy", + "prisma:seed": "tsx prisma/seed/index.ts", + "openapi:generate": "tsx scripts/generate-openapi.ts", + "docker:up": "docker compose -f docker-compose.dev.yml up -d", + "docker:down": "docker compose -f docker-compose.dev.yml down", + "docker:build:prod": "docker build -t supporthub-api:latest ." + }, + "dependencies": { + "@aws-sdk/client-s3": "^3.556.0", + "@aws-sdk/s3-request-presigner": "^3.556.0", + "@fastify/cors": "^9.0.1", + "@fastify/helmet": "^11.1.1", + "@fastify/rate-limit": "^9.1.0", + "@fastify/swagger": "^8.14.0", + "@fastify/swagger-ui": "^3.0.0", + "@opentelemetry/api": "^1.8.0", + "@opentelemetry/sdk-trace-base": "^1.22.0", + "@prisma/client": "^5.12.1", + "bullmq": "^5.7.1", + "dotenv": "^16.4.5", + "fastify": "^4.26.2", + "fastify-plugin": "^4.5.1", + "ioredis": "^5.3.2", + "pino": "^8.20.0", + "pino-pretty": "^11.0.0", + "prom-client": "^15.1.1", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/node": "^20.12.7", + "@typescript-eslint/eslint-plugin": "^7.6.0", + "@typescript-eslint/parser": "^7.6.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", + "prettier": "^3.2.5", + "prisma": "^5.12.1", + "tsx": "^4.7.2", + "typescript": "^5.4.5", + "vitest": "^1.5.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "private": true +} diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..41e8206 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,9 @@ +module.exports = { + semi: true, + trailingComma: "all", + singleQuote: true, + printWidth: 100, + tabWidth: 2, + useTabs: false, + endOfLine: "lf", +}; diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..db62feb --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,73 @@ +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +enum UserRole { + ADMIN + AGENT + CUSTOMER +} + +enum ProductStatus { + ACTIVE + DEPRECATED + INACTIVE +} + +model User { + id String @id @default(uuid()) + email String @unique + name String + role UserRole @default(CUSTOMER) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + auditLogs AuditLog[] + + @@map("users") +} + +model Product { + id String @id @default(uuid()) + code String @unique + name String + description String? + status ProductStatus @default(ACTIVE) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + categories Category[] + + @@map("products") +} + +model Category { + id String @id @default(uuid()) + productId String + name String + description String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + product Product @relation(fields: [productId], references: [id], onDelete: Cascade) + + @@map("categories") +} + +model AuditLog { + id String @id @default(uuid()) + userId String? + action String + resource String + payload Json? + createdAt DateTime @default(now()) + + user User? @relation(fields: [userId], references: [id], onDelete: SetNull) + + @@map("audit_logs") +} diff --git a/prisma/seed/categories.seed.ts b/prisma/seed/categories.seed.ts new file mode 100644 index 0000000..98797db --- /dev/null +++ b/prisma/seed/categories.seed.ts @@ -0,0 +1,26 @@ +import { PrismaClient } from '@prisma/client'; + +export async function seedCategories(prisma: PrismaClient): Promise { + // eslint-disable-next-line no-console + console.log(' -> Seeding baseline product categories...'); + + const product = await prisma.product.findUnique({ + where: { code: 'CORE_PLATFORM' }, + }); + + if (!product) return; + + const existingCategory = await prisma.category.findFirst({ + where: { productId: product.id, name: 'General Support' }, + }); + + if (!existingCategory) { + await prisma.category.create({ + data: { + productId: product.id, + name: 'General Support', + description: 'General support issues and inquiries', + }, + }); + } +} diff --git a/prisma/seed/demo.seed.ts b/prisma/seed/demo.seed.ts new file mode 100644 index 0000000..63360f7 --- /dev/null +++ b/prisma/seed/demo.seed.ts @@ -0,0 +1,16 @@ +import { PrismaClient, UserRole } from '@prisma/client'; + +export async function seedDemoData(prisma: PrismaClient): Promise { + // eslint-disable-next-line no-console + console.log(' -> Seeding demo environment data...'); + + await prisma.user.upsert({ + where: { email: 'john.doe@example.com' }, + update: {}, + create: { + email: 'john.doe@example.com', + name: 'John Doe (Demo Customer)', + role: UserRole.CUSTOMER, + }, + }); +} diff --git a/prisma/seed/hierarchy.seed.ts b/prisma/seed/hierarchy.seed.ts new file mode 100644 index 0000000..b2e0946 --- /dev/null +++ b/prisma/seed/hierarchy.seed.ts @@ -0,0 +1,7 @@ +import { PrismaClient } from '@prisma/client'; + +export async function seedHierarchy(_prisma: PrismaClient): Promise { + // eslint-disable-next-line no-console + console.log(' -> Hierarchy seed skipped (schema reserved for orchestration domain phase).'); + // Stub function - inactive until hierarchy schema models are introduced in domain phase. +} diff --git a/prisma/seed/index.ts b/prisma/seed/index.ts new file mode 100644 index 0000000..500e3d5 --- /dev/null +++ b/prisma/seed/index.ts @@ -0,0 +1,32 @@ +import { PrismaClient } from '@prisma/client'; +import { seedRoles } from './roles.seed'; +import { seedProducts } from './products.seed'; +import { seedCategories } from './categories.seed'; +import { seedHierarchy } from './hierarchy.seed'; +import { seedDemoData } from './demo.seed'; + +const prisma = new PrismaClient(); + +async function main(): Promise { + // eslint-disable-next-line no-console + console.log('🚀 Starting SupportHub API database seeding...'); + + await seedRoles(prisma); + await seedProducts(prisma); + await seedCategories(prisma); + await seedHierarchy(prisma); + await seedDemoData(prisma); + + // eslint-disable-next-line no-console + console.log('✅ Seeding completed successfully.'); +} + +main() + .catch((e) => { + // eslint-disable-next-line no-console + console.error('❌ Seeding failed with error:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/prisma/seed/products.seed.ts b/prisma/seed/products.seed.ts new file mode 100644 index 0000000..6dca6e4 --- /dev/null +++ b/prisma/seed/products.seed.ts @@ -0,0 +1,17 @@ +import { PrismaClient, ProductStatus } from '@prisma/client'; + +export async function seedProducts(prisma: PrismaClient): Promise { + // eslint-disable-next-line no-console + console.log(' -> Seeding baseline products...'); + + await prisma.product.upsert({ + where: { code: 'CORE_PLATFORM' }, + update: {}, + create: { + code: 'CORE_PLATFORM', + name: 'Core SupportHub Platform', + description: 'Main enterprise ticketing and support engine', + status: ProductStatus.ACTIVE, + }, + }); +} diff --git a/prisma/seed/roles.seed.ts b/prisma/seed/roles.seed.ts new file mode 100644 index 0000000..17afed0 --- /dev/null +++ b/prisma/seed/roles.seed.ts @@ -0,0 +1,26 @@ +import { PrismaClient, UserRole } from '@prisma/client'; + +export async function seedRoles(prisma: PrismaClient): Promise { + // eslint-disable-next-line no-console + console.log(' -> Seeding baseline users & roles...'); + + await prisma.user.upsert({ + where: { email: 'admin@supporthub.internal' }, + update: {}, + create: { + email: 'admin@supporthub.internal', + name: 'System Admin', + role: UserRole.ADMIN, + }, + }); + + await prisma.user.upsert({ + where: { email: 'agent@supporthub.internal' }, + update: {}, + create: { + email: 'agent@supporthub.internal', + name: 'Default Support Agent', + role: UserRole.AGENT, + }, + }); +} diff --git a/scripts/check-architecture.ts b/scripts/check-architecture.ts new file mode 100644 index 0000000..75e8118 --- /dev/null +++ b/scripts/check-architecture.ts @@ -0,0 +1,105 @@ +import fs from 'fs'; +import path from 'path'; + +const SRC_DIR = path.resolve(__dirname, '../src'); + +interface Violation { + file: string; + line: number; + rule: string; + detail: string; +} + +const violations: Violation[] = []; + +function getFilesRecursively(dir: string): string[] { + let results: string[] = []; + if (!fs.existsSync(dir)) return results; + const list = fs.readdirSync(dir); + for (const file of list) { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + if (stat && stat.isDirectory()) { + results = results.concat(getFilesRecursively(filePath)); + } else if (file.endsWith('.ts')) { + results.push(filePath); + } + } + return results; +} + +function checkControllerDatabaseImports(filePath: string, content: string): void { + const relativePath = path.relative(SRC_DIR, filePath); + if (!relativePath.includes('controller')) return; + + const lines = content.split('\n'); + lines.forEach((line, idx) => { + if ( + line.includes("from '@prisma/client'") || + line.includes('from "@prisma/client"') || + line.includes('prisma.client') || + line.includes('prisma.plugin') + ) { + violations.push({ + file: relativePath, + line: idx + 1, + rule: 'NO_CONTROLLER_DIRECT_DB_ACCESS', + detail: + 'Controllers must not directly import or access Prisma client. Use Services instead.', + }); + } + }); +} + +function checkCrossModuleInternalImports(filePath: string, content: string): void { + const relativePath = path.relative(SRC_DIR, filePath); + const lines = content.split('\n'); + + lines.forEach((line, idx) => { + // Check for deep import from @/modules/group/module/internal + const moduleImportMatch = line.match(/from\s+['"]@\/modules\/([^'"]+)['"]/); + if (moduleImportMatch && moduleImportMatch[1]) { + const targetPath = moduleImportMatch[1]; + const segments = targetPath.split('/'); + // Allow @/modules/group/module or @/modules/group/module/index + if (segments.length > 2 && segments[2] !== 'index') { + violations.push({ + file: relativePath, + line: idx + 1, + rule: 'NO_CROSS_MODULE_DEEP_IMPORTS', + detail: `Deep import '${targetPath}' bypasses module public API boundary (index.ts).`, + }); + } + } + }); +} + +function runArchitectureCheck(): void { + // eslint-disable-next-line no-console + console.log('🔍 Running Architecture & Boundary Checks...'); + + const allFiles = getFilesRecursively(SRC_DIR); + + for (const file of allFiles) { + const content = fs.readFileSync(file, 'utf-8'); + checkControllerDatabaseImports(file, content); + checkCrossModuleInternalImports(file, content); + } + + if (violations.length > 0) { + // eslint-disable-next-line no-console + console.error('\n❌ Architecture Violations Detected:\n'); + violations.forEach((v) => { + // eslint-disable-next-line no-console + console.error(` - [${v.rule}] ${v.file}:${v.line}`); + // eslint-disable-next-line no-console + console.error(` ${v.detail}\n`); + }); + process.exit(1); + } else { + // eslint-disable-next-line no-console + console.log('✅ All architecture rules and module boundaries passed successfully!'); + } +} + +runArchitectureCheck(); diff --git a/scripts/generate-openapi.ts b/scripts/generate-openapi.ts new file mode 100644 index 0000000..eeff93b --- /dev/null +++ b/scripts/generate-openapi.ts @@ -0,0 +1,30 @@ +import fs from 'fs'; +import path from 'path'; +import { buildApp } from '../src/app'; + +async function generateOpenApiSpec(): Promise { + // eslint-disable-next-line no-console + console.log('📝 Generating OpenAPI specification...'); + const app = await buildApp(); + + await app.ready(); + + const swaggerSpec = app.swagger(); + const outputPath = path.resolve(__dirname, '../docs/openapi.json'); + + const dir = path.dirname(outputPath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + + fs.writeFileSync(outputPath, JSON.stringify(swaggerSpec, null, 2)); + // eslint-disable-next-line no-console + console.log(`✅ OpenAPI specification exported to ${outputPath}`); + await app.close(); +} + +generateOpenApiSpec().catch((err: unknown) => { + // eslint-disable-next-line no-console + console.error('❌ Failed to generate OpenAPI spec:', err); + process.exit(1); +}); diff --git a/scripts/migrate.ts b/scripts/migrate.ts new file mode 100644 index 0000000..581d5e9 --- /dev/null +++ b/scripts/migrate.ts @@ -0,0 +1,17 @@ +import { execSync } from 'child_process'; + +function runMigrations(): void { + // eslint-disable-next-line no-console + console.log('🔄 Deploying Prisma database migrations...'); + try { + execSync('npx prisma migrate deploy', { stdio: 'inherit' }); + // eslint-disable-next-line no-console + console.log('✅ Migrations applied successfully.'); + } catch (error) { + // eslint-disable-next-line no-console + console.error('❌ Error executing database migrations:', error); + process.exit(1); + } +} + +runMigrations(); diff --git a/scripts/seed.ts b/scripts/seed.ts new file mode 100644 index 0000000..754da9d --- /dev/null +++ b/scripts/seed.ts @@ -0,0 +1,17 @@ +import { execSync } from 'child_process'; + +function runSeed(): void { + // eslint-disable-next-line no-console + console.log('🌱 Executing database seeds...'); + try { + execSync('npx tsx prisma/seed/index.ts', { stdio: 'inherit' }); + // eslint-disable-next-line no-console + console.log('✅ Seed completed successfully.'); + } catch (error) { + // eslint-disable-next-line no-console + console.error('❌ Error seeding database:', error); + process.exit(1); + } +} + +runSeed(); diff --git a/src/api/health.routes.ts b/src/api/health.routes.ts new file mode 100644 index 0000000..67ec371 --- /dev/null +++ b/src/api/health.routes.ts @@ -0,0 +1,21 @@ +import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import { healthService } from '@/infrastructure/observability'; + +export async function healthRoutes(fastify: FastifyInstance): Promise { + fastify.get('/health', async (_req: FastifyRequest, reply: FastifyReply) => { + const status = await healthService.getReadinessStatus(); + const statusCode = status.status === 'ok' ? 200 : status.status === 'degraded' ? 200 : 503; + return reply.status(statusCode).send(status); + }); + + fastify.get('/health/live', async (_req: FastifyRequest, reply: FastifyReply) => { + const status = await healthService.getLiveStatus(); + return reply.status(200).send(status); + }); + + fastify.get('/health/ready', async (_req: FastifyRequest, reply: FastifyReply) => { + const status = await healthService.getReadinessStatus(); + const statusCode = status.status === 'ok' ? 200 : 503; + return reply.status(statusCode).send(status); + }); +} diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..b5dc97a --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,3 @@ +export * from './health.routes'; +export * from './metrics.routes'; +export * from './routes'; diff --git a/src/api/metrics.routes.ts b/src/api/metrics.routes.ts new file mode 100644 index 0000000..d7c8656 --- /dev/null +++ b/src/api/metrics.routes.ts @@ -0,0 +1,9 @@ +import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import { metricsRegistry } from '@/infrastructure/observability'; + +export async function metricsRoutes(fastify: FastifyInstance): Promise { + fastify.get('/metrics', async (_req: FastifyRequest, reply: FastifyReply) => { + const metrics = await metricsRegistry.metrics(); + return reply.header('Content-Type', metricsRegistry.contentType).send(metrics); + }); +} diff --git a/src/api/routes.ts b/src/api/routes.ts new file mode 100644 index 0000000..ba6a957 --- /dev/null +++ b/src/api/routes.ts @@ -0,0 +1,9 @@ +import { FastifyInstance } from 'fastify'; +import { healthRoutes } from './health.routes'; +import { metricsRoutes } from './metrics.routes'; + +export async function registerGlobalRoutes(app: FastifyInstance): Promise { + await app.register(healthRoutes); + await app.register(metricsRoutes); + // Domain module routes will be registered here as feature modules are wired up +} diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 0000000..84a00d4 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,89 @@ +import Fastify, { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import { ZodError } from 'zod'; +import { env } from '@/config'; +import { logger } from '@/infrastructure/observability'; +import { AppError } from '@/common/errors'; +import { bootstrapPlugins, bootstrapRoutes } from '@/bootstrap'; + +export async function buildApp(): Promise { + const app = Fastify({ + logger: false, // Managed centrally via Pino logger instance + disableRequestLogging: false, + requestIdHeader: 'x-request-id', + }); + + // Register Bootstrapped Plugins + await bootstrapPlugins(app); + + // Register Bootstrapped Global Routes + await bootstrapRoutes(app); + + // Global Error Handler + app.setErrorHandler( + (error: Error | AppError | ZodError, request: FastifyRequest, reply: FastifyReply) => { + const requestId = request.reqContext?.requestId || (request.id as string) || 'unknown'; + + if (error instanceof AppError) { + logger.warn( + { code: error.code, statusCode: error.statusCode, requestId, details: error.details }, + error.message, + ); + return reply.status(error.statusCode).send({ + success: false, + error: { + code: error.code, + message: error.message, + details: error.details, + }, + requestId, + }); + } + + if (error instanceof ZodError) { + logger.warn({ requestId, issues: error.issues }, 'Request Validation Error'); + return reply.status(400).send({ + success: false, + error: { + code: 'VALIDATION_ERROR', + message: 'Invalid request payload or parameters', + details: error.issues, + }, + requestId, + }); + } + + logger.error({ error, requestId }, 'Unhandled Server Error'); + + const responseMessage = + env.NODE_ENV === 'production' + ? 'Internal server error occurred' + : error.message || 'Internal server error'; + + return reply.status(500).send({ + success: false, + error: { + code: 'INTERNAL_SERVER_ERROR', + message: responseMessage, + details: null, + }, + requestId, + }); + }, + ); + + // 404 Not Found Handler + app.setNotFoundHandler((request: FastifyRequest, reply: FastifyReply) => { + const requestId = request.reqContext?.requestId || (request.id as string) || 'unknown'; + return reply.status(404).send({ + success: false, + error: { + code: 'NOT_FOUND', + message: `Route ${request.method} ${request.url} not found`, + details: null, + }, + requestId, + }); + }); + + return app; +} diff --git a/src/bootstrap/database.bootstrap.ts b/src/bootstrap/database.bootstrap.ts new file mode 100644 index 0000000..e7b9498 --- /dev/null +++ b/src/bootstrap/database.bootstrap.ts @@ -0,0 +1,12 @@ +import { prismaClient } from '@/infrastructure/database'; +import { logger } from '@/infrastructure/observability'; + +export async function bootstrapDatabase(): Promise { + try { + await prismaClient.$connect(); + logger.info('Database (Prisma) initialized successfully.'); + } catch (error) { + logger.error({ error }, 'Failed to initialize Database connection.'); + throw error; + } +} diff --git a/src/bootstrap/index.ts b/src/bootstrap/index.ts new file mode 100644 index 0000000..02f533c --- /dev/null +++ b/src/bootstrap/index.ts @@ -0,0 +1,7 @@ +export * from './database.bootstrap'; +export * from './redis.bootstrap'; +export * from './queue.bootstrap'; +export * from './storage.bootstrap'; +export * from './plugins.bootstrap'; +export * from './routes.bootstrap'; +export * from './shutdown.bootstrap'; diff --git a/src/bootstrap/plugins.bootstrap.ts b/src/bootstrap/plugins.bootstrap.ts new file mode 100644 index 0000000..60db9b3 --- /dev/null +++ b/src/bootstrap/plugins.bootstrap.ts @@ -0,0 +1,20 @@ +import { FastifyInstance } from 'fastify'; +import { + prismaPlugin, + authPlugin, + swaggerPlugin, + corsPlugin, + helmetPlugin, + rateLimitPlugin, + requestContextPlugin, +} from '@/plugins'; + +export async function bootstrapPlugins(app: FastifyInstance): Promise { + await app.register(requestContextPlugin); + await app.register(corsPlugin); + await app.register(helmetPlugin); + await app.register(rateLimitPlugin); + await app.register(prismaPlugin); + await app.register(authPlugin); + await app.register(swaggerPlugin); +} diff --git a/src/bootstrap/queue.bootstrap.ts b/src/bootstrap/queue.bootstrap.ts new file mode 100644 index 0000000..0885c36 --- /dev/null +++ b/src/bootstrap/queue.bootstrap.ts @@ -0,0 +1,6 @@ +import { logger } from '@/infrastructure/observability'; + +export async function bootstrapQueue(): Promise { + logger.info('Queue Manager initialized.'); + // Ready to register workers as domain features are introduced +} diff --git a/src/bootstrap/redis.bootstrap.ts b/src/bootstrap/redis.bootstrap.ts new file mode 100644 index 0000000..b58c710 --- /dev/null +++ b/src/bootstrap/redis.bootstrap.ts @@ -0,0 +1,12 @@ +import { redisClient } from '@/infrastructure/cache'; +import { logger } from '@/infrastructure/observability'; + +export async function bootstrapRedis(): Promise { + try { + await redisClient.connect(); + logger.info('Redis cache client initialized successfully.'); + } catch (error) { + logger.error({ error }, 'Failed to initialize Redis connection.'); + // Lazy connect fallback: log warning if already connected or deferred + } +} diff --git a/src/bootstrap/routes.bootstrap.ts b/src/bootstrap/routes.bootstrap.ts new file mode 100644 index 0000000..d3ca86e --- /dev/null +++ b/src/bootstrap/routes.bootstrap.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { registerGlobalRoutes } from '@/api/routes'; + +export async function bootstrapRoutes(app: FastifyInstance): Promise { + await registerGlobalRoutes(app); +} diff --git a/src/bootstrap/shutdown.bootstrap.ts b/src/bootstrap/shutdown.bootstrap.ts new file mode 100644 index 0000000..d4e274e --- /dev/null +++ b/src/bootstrap/shutdown.bootstrap.ts @@ -0,0 +1,34 @@ +import { FastifyInstance } from 'fastify'; +import { prismaClient } from '@/infrastructure/database'; +import { redisClient } from '@/infrastructure/cache'; +import { queueManager } from '@/infrastructure/queue'; +import { logger } from '@/infrastructure/observability'; + +export function setupGracefulShutdown(app: FastifyInstance): void { + const handleShutdown = async (signal: string): Promise => { + logger.info({ signal }, 'Received termination signal. Starting graceful shutdown...'); + + try { + await app.close(); + logger.info('Fastify server closed.'); + + await queueManager.shutdown(); + logger.info('Queue workers closed.'); + + await redisClient.quit(); + logger.info('Redis client disconnected.'); + + await prismaClient.$disconnect(); + logger.info('Prisma database client disconnected.'); + + logger.info('Graceful shutdown completed. Exiting process.'); + process.exit(0); + } catch (error) { + logger.error({ error }, 'Error occurred during graceful shutdown.'); + process.exit(1); + } + }; + + process.on('SIGTERM', () => handleShutdown('SIGTERM')); + process.on('SIGINT', () => handleShutdown('SIGINT')); +} diff --git a/src/bootstrap/storage.bootstrap.ts b/src/bootstrap/storage.bootstrap.ts new file mode 100644 index 0000000..3293d91 --- /dev/null +++ b/src/bootstrap/storage.bootstrap.ts @@ -0,0 +1,11 @@ +import { storageService } from '@/infrastructure/storage'; +import { logger } from '@/infrastructure/observability'; + +export async function bootstrapStorage(): Promise { + try { + await storageService.ensureBucketExists(); + logger.info('AWS S3 Object Storage initialized.'); + } catch (error) { + logger.warn({ error }, 'AWS S3 initialization deferred or bucket check bypassed.'); + } +} diff --git a/src/common/constants/app.constants.ts b/src/common/constants/app.constants.ts new file mode 100644 index 0000000..b0a50bf --- /dev/null +++ b/src/common/constants/app.constants.ts @@ -0,0 +1,7 @@ +export const APP_CONSTANTS = { + DEFAULT_PAGE: 1, + DEFAULT_LIMIT: 20, + MAX_LIMIT: 100, + CORRELATION_HEADER: 'x-correlation-id', + REQUEST_ID_HEADER: 'x-request-id', +} as const; diff --git a/src/common/constants/index.ts b/src/common/constants/index.ts new file mode 100644 index 0000000..cd95e50 --- /dev/null +++ b/src/common/constants/index.ts @@ -0,0 +1 @@ +export * from './app.constants'; diff --git a/src/common/enums/index.ts b/src/common/enums/index.ts new file mode 100644 index 0000000..d980cfa --- /dev/null +++ b/src/common/enums/index.ts @@ -0,0 +1,13 @@ +export enum Environment { + DEVELOPMENT = 'development', + TEST = 'test', + STAGING = 'staging', + PRODUCTION = 'production', +} + +export enum ActorType { + USER = 'USER', + AGENT = 'AGENT', + CUSTOMER = 'CUSTOMER', + SYSTEM = 'SYSTEM', +} diff --git a/src/common/errors/app.error.ts b/src/common/errors/app.error.ts new file mode 100644 index 0000000..f907e4a --- /dev/null +++ b/src/common/errors/app.error.ts @@ -0,0 +1,23 @@ +export class AppError extends Error { + public readonly code: string; + public readonly statusCode: number; + public readonly details: unknown | null; + public readonly metadata: Record | null; + + constructor( + message: string, + code = 'INTERNAL_SERVER_ERROR', + statusCode = 500, + details: unknown | null = null, + metadata: Record | null = null, + ) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + this.name = this.constructor.name; + this.code = code; + this.statusCode = statusCode; + this.details = details; + this.metadata = metadata; + Error.captureStackTrace(this, this.constructor); + } +} diff --git a/src/common/errors/authorization.error.ts b/src/common/errors/authorization.error.ts new file mode 100644 index 0000000..91d95f3 --- /dev/null +++ b/src/common/errors/authorization.error.ts @@ -0,0 +1,13 @@ +import { AppError } from './app.error'; + +export class AuthorizationError extends AppError { + constructor(message = 'Forbidden access', details: unknown | null = null) { + super(message, 'FORBIDDEN', 403, details); + } +} + +export class AuthenticationError extends AppError { + constructor(message = 'Unauthorized access', details: unknown | null = null) { + super(message, 'UNAUTHORIZED', 401, details); + } +} diff --git a/src/common/errors/index.ts b/src/common/errors/index.ts new file mode 100644 index 0000000..bc23914 --- /dev/null +++ b/src/common/errors/index.ts @@ -0,0 +1,4 @@ +export * from './app.error'; +export * from './validation.error'; +export * from './authorization.error'; +export * from './not-found.error'; diff --git a/src/common/errors/not-found.error.ts b/src/common/errors/not-found.error.ts new file mode 100644 index 0000000..bee4acc --- /dev/null +++ b/src/common/errors/not-found.error.ts @@ -0,0 +1,19 @@ +import { AppError } from './app.error'; + +export class NotFoundError extends AppError { + constructor(message = 'Resource not found', details: unknown | null = null) { + super(message, 'NOT_FOUND', 404, details); + } +} + +export class ConflictError extends AppError { + constructor(message = 'Resource conflict', details: unknown | null = null) { + super(message, 'CONFLICT', 409, details); + } +} + +export class RateLimitError extends AppError { + constructor(message = 'Too many requests', details: unknown | null = null) { + super(message, 'RATE_LIMIT_EXCEEDED', 429, details); + } +} diff --git a/src/common/errors/validation.error.ts b/src/common/errors/validation.error.ts new file mode 100644 index 0000000..7c35e12 --- /dev/null +++ b/src/common/errors/validation.error.ts @@ -0,0 +1,7 @@ +import { AppError } from './app.error'; + +export class ValidationError extends AppError { + constructor(message = 'Validation Error', details: unknown | null = null) { + super(message, 'VALIDATION_ERROR', 400, details); + } +} diff --git a/src/common/types/auth.types.ts b/src/common/types/auth.types.ts new file mode 100644 index 0000000..d87018a --- /dev/null +++ b/src/common/types/auth.types.ts @@ -0,0 +1,17 @@ +import { ActorType } from '../enums'; + +export interface AuthUser { + id: string; + email: string; + role: string; + actorType: ActorType; +} + +export interface JwtPayload { + sub: string; + email: string; + role: string; + actorType: ActorType; + iat?: number; + exp?: number; +} diff --git a/src/common/types/index.ts b/src/common/types/index.ts new file mode 100644 index 0000000..eef9aae --- /dev/null +++ b/src/common/types/index.ts @@ -0,0 +1,3 @@ +export * from './request-context.types'; +export * from './pagination.types'; +export * from './auth.types'; diff --git a/src/common/types/pagination.types.ts b/src/common/types/pagination.types.ts new file mode 100644 index 0000000..1318ec6 --- /dev/null +++ b/src/common/types/pagination.types.ts @@ -0,0 +1,18 @@ +export interface PaginationParams { + page?: number; + limit?: number; +} + +export interface PaginationMeta { + page: number; + limit: number; + totalItems: number; + totalPages: number; + hasNextPage: boolean; + hasPrevPage: boolean; +} + +export interface PaginatedResult { + data: T[]; + meta: PaginationMeta; +} diff --git a/src/common/types/request-context.types.ts b/src/common/types/request-context.types.ts new file mode 100644 index 0000000..b3f06cc --- /dev/null +++ b/src/common/types/request-context.types.ts @@ -0,0 +1,11 @@ +import { ActorType } from '../enums'; + +export interface RequestContext { + requestId: string; + correlationId: string; + actorId?: string; + actorType?: ActorType; + productId?: string; + customerId?: string; + tenantId?: string; +} diff --git a/src/common/utils/date.utils.ts b/src/common/utils/date.utils.ts new file mode 100644 index 0000000..23eb7b9 --- /dev/null +++ b/src/common/utils/date.utils.ts @@ -0,0 +1,11 @@ +export function formatDateToIso(date: Date = new Date()): string { + return date.toISOString(); +} + +export function addMinutes(date: Date, minutes: number): Date { + return new Date(date.getTime() + minutes * 60 * 1000); +} + +export function addHours(date: Date, hours: number): Date { + return new Date(date.getTime() + hours * 60 * 60 * 1000); +} diff --git a/src/common/utils/id.utils.ts b/src/common/utils/id.utils.ts new file mode 100644 index 0000000..c97a243 --- /dev/null +++ b/src/common/utils/id.utils.ts @@ -0,0 +1,11 @@ +import { randomUUID } from 'crypto'; + +export function generateUuid(): string { + return randomUUID(); +} + +export function generateUlidLikeId(prefix = 'id'): string { + const timestamp = Date.now().toString(36); + const randomStr = Math.random().toString(36).substring(2, 8); + return `${prefix}_${timestamp}${randomStr}`; +} diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts new file mode 100644 index 0000000..569733e --- /dev/null +++ b/src/common/utils/index.ts @@ -0,0 +1,3 @@ +export * from './date.utils'; +export * from './id.utils'; +export * from './pagination.utils'; diff --git a/src/common/utils/pagination.utils.ts b/src/common/utils/pagination.utils.ts new file mode 100644 index 0000000..f9530da --- /dev/null +++ b/src/common/utils/pagination.utils.ts @@ -0,0 +1,33 @@ +import { APP_CONSTANTS } from '../constants'; +import { PaginationMeta, PaginationParams } from '../types'; + +export function normalizePagination(params: PaginationParams = {}): { + page: number; + limit: number; + skip: number; +} { + const page = Math.max(1, params.page || APP_CONSTANTS.DEFAULT_PAGE); + const limit = Math.min( + APP_CONSTANTS.MAX_LIMIT, + Math.max(1, params.limit || APP_CONSTANTS.DEFAULT_LIMIT), + ); + const skip = (page - 1) * limit; + + return { page, limit, skip }; +} + +export function buildPaginationMeta( + totalItems: number, + page: number, + limit: number, +): PaginationMeta { + const totalPages = Math.ceil(totalItems / limit) || 1; + return { + page, + limit, + totalItems, + totalPages, + hasNextPage: page < totalPages, + hasPrevPage: page > 1, + }; +} diff --git a/src/config/database.ts b/src/config/database.ts new file mode 100644 index 0000000..a02b8db --- /dev/null +++ b/src/config/database.ts @@ -0,0 +1,6 @@ +import { env } from './env'; + +export const databaseConfig = { + url: env.DATABASE_URL, + maxConnections: env.NODE_ENV === 'production' ? 50 : 10, +}; diff --git a/src/config/env.ts b/src/config/env.ts new file mode 100644 index 0000000..8b7c2d3 --- /dev/null +++ b/src/config/env.ts @@ -0,0 +1,50 @@ +import dotenv from 'dotenv'; +import { z } from 'zod'; + +dotenv.config(); + +const envSchema = z.object({ + NODE_ENV: z.enum(['development', 'test', 'staging', 'production']).default('development'), + PORT: z.coerce.number().default(3000), + HOST: z.string().default('0.0.0.0'), + LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent']).default('info'), + + DATABASE_URL: z.string().url(), + + REDIS_HOST: z.string().default('localhost'), + REDIS_PORT: z.coerce.number().default(6379), + REDIS_PASSWORD: z.string().optional(), + + JWT_SECRET: z.string().min(16), + JWT_ACCESS_EXPIRES: z.string().default('15m'), + JWT_REFRESH_EXPIRES: z.string().default('7d'), + + // AWS S3 Configuration + AWS_REGION: z.string().default('us-east-1'), + AWS_S3_BUCKET: z.string().default('supporthub-attachments'), + AWS_ACCESS_KEY_ID: z.string().default('mock-aws-access-key-id'), + AWS_SECRET_ACCESS_KEY: z.string().default('mock-aws-secret-access-key'), + AWS_S3_ENDPOINT: z.string().optional(), + + CORS_ORIGINS: z + .string() + .transform((val) => val.split(',').map((origin) => origin.trim())) + .default('http://localhost:3000'), +}); + +export type EnvConfig = z.infer; + +function parseEnv(): EnvConfig { + const result = envSchema.safeParse(process.env); + if (!result.success) { + // eslint-disable-next-line no-console + console.error( + '❌ Invalid environment variables:', + JSON.stringify(result.error.format(), null, 2), + ); + throw new Error('Environment configuration validation failed.'); + } + return result.data; +} + +export const env = parseEnv(); diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 0000000..fb9a0c9 --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1,5 @@ +export * from './env'; +export * from './database'; +export * from './redis'; +export * from './queue'; +export * from './storage'; diff --git a/src/config/queue.ts b/src/config/queue.ts new file mode 100644 index 0000000..66a54d7 --- /dev/null +++ b/src/config/queue.ts @@ -0,0 +1,14 @@ +import { redisConfig } from './redis'; + +export const queueConfig = { + connection: redisConfig, + defaultJobOptions: { + attempts: 3, + backoff: { + type: 'exponential', + delay: 1000, + }, + removeOnComplete: 100, + removeOnFail: 500, + }, +}; diff --git a/src/config/redis.ts b/src/config/redis.ts new file mode 100644 index 0000000..fe5b6bf --- /dev/null +++ b/src/config/redis.ts @@ -0,0 +1,8 @@ +import { env } from './env'; + +export const redisConfig = { + host: env.REDIS_HOST, + port: env.REDIS_PORT, + password: env.REDIS_PASSWORD || undefined, + maxRetriesPerRequest: null, +}; diff --git a/src/config/storage.ts b/src/config/storage.ts new file mode 100644 index 0000000..19df1ba --- /dev/null +++ b/src/config/storage.ts @@ -0,0 +1,11 @@ +import { env } from './env'; + +export const storageConfig = { + region: env.AWS_REGION, + bucketName: env.AWS_S3_BUCKET, + credentials: { + accessKeyId: env.AWS_ACCESS_KEY_ID, + secretAccessKey: env.AWS_SECRET_ACCESS_KEY, + }, + endpoint: env.AWS_S3_ENDPOINT || undefined, +}; diff --git a/src/events/domain-events.ts b/src/events/domain-events.ts new file mode 100644 index 0000000..fe7d763 --- /dev/null +++ b/src/events/domain-events.ts @@ -0,0 +1,9 @@ +export enum DomainEventName { + TICKET_CREATED = 'ticket.created', + TICKET_UPDATED = 'ticket.updated', + TICKET_ASSIGNED = 'ticket.assigned', + TICKET_RESOLVED = 'ticket.resolved', + PROBLEM_IDENTIFIED = 'problem.identified', + SLA_BREACHED = 'sla.breached', + ESCALATION_TRIGGERED = 'escalation.triggered', +} diff --git a/src/events/event-bus.ts b/src/events/event-bus.ts new file mode 100644 index 0000000..fd92572 --- /dev/null +++ b/src/events/event-bus.ts @@ -0,0 +1,33 @@ +import EventEmitter from 'events'; +import { BaseDomainEvent } from './event-types'; +import { logger } from '@/infrastructure/observability'; + +export class EventBus { + private emitter: EventEmitter; + + constructor() { + this.emitter = new EventEmitter(); + this.emitter.setMaxListeners(50); + } + + publish(event: BaseDomainEvent): void { + logger.info({ eventName: event.eventName, eventId: event.eventId }, 'Publishing domain event'); + this.emitter.emit(event.eventName, event); + this.emitter.emit('*', event); + } + + subscribe( + eventName: string, + handler: (event: BaseDomainEvent) => Promise | void, + ): void { + this.emitter.on(eventName, async (event: BaseDomainEvent) => { + try { + await handler(event); + } catch (error) { + logger.error({ error, eventName, eventId: event.eventId }, 'Error executing event handler'); + } + }); + } +} + +export const eventBus = new EventBus(); diff --git a/src/events/event-types.ts b/src/events/event-types.ts new file mode 100644 index 0000000..d7612b1 --- /dev/null +++ b/src/events/event-types.ts @@ -0,0 +1,8 @@ +export interface BaseDomainEvent { + eventId: string; + eventName: string; + aggregateId: string; + aggregateType: string; + timestamp: string; + payload: T; +} diff --git a/src/events/handlers/index.ts b/src/events/handlers/index.ts new file mode 100644 index 0000000..f1984cc --- /dev/null +++ b/src/events/handlers/index.ts @@ -0,0 +1,3 @@ +export function registerDomainEventHandlers(): void { + // Skeleton for registering domain event listeners during feature module implementation +} diff --git a/src/events/index.ts b/src/events/index.ts new file mode 100644 index 0000000..a557394 --- /dev/null +++ b/src/events/index.ts @@ -0,0 +1,4 @@ +export * from './event-types'; +export * from './domain-events'; +export * from './event-bus'; +export * from './handlers'; diff --git a/src/infrastructure/cache/cache.service.ts b/src/infrastructure/cache/cache.service.ts new file mode 100644 index 0000000..c7de9ef --- /dev/null +++ b/src/infrastructure/cache/cache.service.ts @@ -0,0 +1,36 @@ +import Redis from 'ioredis'; +import { redisClient } from './redis.client'; + +export class CacheService { + constructor(private readonly redis: Redis = redisClient) {} + + async get(key: string): Promise { + const data = await this.redis.get(key); + if (!data) return null; + try { + return JSON.parse(data) as T; + } catch { + return data as unknown as T; + } + } + + async set(key: string, value: T, ttlSeconds?: number): Promise { + const serialized = typeof value === 'string' ? value : JSON.stringify(value); + if (ttlSeconds && ttlSeconds > 0) { + await this.redis.set(key, serialized, 'EX', ttlSeconds); + } else { + await this.redis.set(key, serialized); + } + } + + async del(key: string): Promise { + await this.redis.del(key); + } + + async exists(key: string): Promise { + const count = await this.redis.exists(key); + return count > 0; + } +} + +export const cacheService = new CacheService(); diff --git a/src/infrastructure/cache/index.ts b/src/infrastructure/cache/index.ts new file mode 100644 index 0000000..2754ad1 --- /dev/null +++ b/src/infrastructure/cache/index.ts @@ -0,0 +1,2 @@ +export * from './redis.client'; +export * from './cache.service'; diff --git a/src/infrastructure/cache/redis.client.ts b/src/infrastructure/cache/redis.client.ts new file mode 100644 index 0000000..a34344d --- /dev/null +++ b/src/infrastructure/cache/redis.client.ts @@ -0,0 +1,22 @@ +import Redis from 'ioredis'; +import { redisConfig } from '@/config'; + +declare global { + // eslint-disable-next-line no-var + var __redisClient: Redis | undefined; +} + +export function createRedisClient(): Redis { + if (!global.__redisClient) { + global.__redisClient = new Redis({ + host: redisConfig.host, + port: redisConfig.port, + password: redisConfig.password, + maxRetriesPerRequest: redisConfig.maxRetriesPerRequest, + lazyConnect: true, + }); + } + return global.__redisClient; +} + +export const redisClient = createRedisClient(); diff --git a/src/infrastructure/database/index.ts b/src/infrastructure/database/index.ts new file mode 100644 index 0000000..a3eb26e --- /dev/null +++ b/src/infrastructure/database/index.ts @@ -0,0 +1,2 @@ +export * from './prisma.client'; +export * from './transaction.service'; diff --git a/src/infrastructure/database/prisma.client.ts b/src/infrastructure/database/prisma.client.ts new file mode 100644 index 0000000..24e9cdc --- /dev/null +++ b/src/infrastructure/database/prisma.client.ts @@ -0,0 +1,23 @@ +import { PrismaClient } from '@prisma/client'; +import { env } from '@/config'; + +declare global { + // eslint-disable-next-line no-var + var __prismaClient: PrismaClient | undefined; +} + +export function createPrismaClient(): PrismaClient { + if (env.NODE_ENV === 'production') { + return new PrismaClient(); + } + + if (!global.__prismaClient) { + global.__prismaClient = new PrismaClient({ + log: ['error', 'warn'], + }); + } + + return global.__prismaClient; +} + +export const prismaClient = createPrismaClient(); diff --git a/src/infrastructure/database/transaction.service.ts b/src/infrastructure/database/transaction.service.ts new file mode 100644 index 0000000..82604cf --- /dev/null +++ b/src/infrastructure/database/transaction.service.ts @@ -0,0 +1,15 @@ +import { Prisma, PrismaClient } from '@prisma/client'; +import { prismaClient } from './prisma.client'; + +export class TransactionService { + constructor(private readonly prisma: PrismaClient = prismaClient) {} + + async runInTransaction( + fn: (tx: Prisma.TransactionClient) => Promise, + options?: { maxWait?: number; timeout?: number }, + ): Promise { + return this.prisma.$transaction(fn, options); + } +} + +export const transactionService = new TransactionService(); diff --git a/src/infrastructure/observability/health.service.ts b/src/infrastructure/observability/health.service.ts new file mode 100644 index 0000000..00377a6 --- /dev/null +++ b/src/infrastructure/observability/health.service.ts @@ -0,0 +1,75 @@ +import { prismaClient } from '../database/prisma.client'; +import { redisClient } from '../cache/redis.client'; + +export interface ComponentHealth { + status: 'up' | 'down'; + latencyMs?: number; + error?: string; +} + +export interface HealthStatus { + status: 'ok' | 'degraded' | 'error'; + timestamp: string; + uptime: number; + components: Record; +} + +export class HealthService { + async getLiveStatus(): Promise<{ status: 'ok'; timestamp: string }> { + return { + status: 'ok', + timestamp: new Date().toISOString(), + }; + } + + async getReadinessStatus(): Promise { + const components: Record = {}; + + // Check PostgreSQL DB + try { + const dbStart = Date.now(); + await prismaClient.$queryRaw`SELECT 1`; + components['database'] = { + status: 'up', + latencyMs: Date.now() - dbStart, + }; + } catch (err: unknown) { + components['database'] = { + status: 'down', + error: err instanceof Error ? err.message : 'Database connection failed', + }; + } + + // Check Redis Cache + try { + const redisStart = Date.now(); + await redisClient.ping(); + components['redis'] = { + status: 'up', + latencyMs: Date.now() - redisStart, + }; + } catch (err: unknown) { + components['redis'] = { + status: 'down', + error: err instanceof Error ? err.message : 'Redis connection failed', + }; + } + + const isAllUp = Object.values(components).every((c) => c.status === 'up'); + const isAnyUp = Object.values(components).some((c) => c.status === 'up'); + + let overallStatus: 'ok' | 'degraded' | 'error' = 'ok'; + if (!isAllUp) { + overallStatus = isAnyUp ? 'degraded' : 'error'; + } + + return { + status: overallStatus, + timestamp: new Date().toISOString(), + uptime: process.uptime(), + components, + }; + } +} + +export const healthService = new HealthService(); diff --git a/src/infrastructure/observability/index.ts b/src/infrastructure/observability/index.ts new file mode 100644 index 0000000..ab92453 --- /dev/null +++ b/src/infrastructure/observability/index.ts @@ -0,0 +1,4 @@ +export * from './logger'; +export * from './metrics'; +export * from './tracing'; +export * from './health.service'; diff --git a/src/infrastructure/observability/logger.ts b/src/infrastructure/observability/logger.ts new file mode 100644 index 0000000..aea312b --- /dev/null +++ b/src/infrastructure/observability/logger.ts @@ -0,0 +1,22 @@ +import pino from 'pino'; +import { env } from '@/config'; + +const pinoOptions: pino.LoggerOptions = { + level: env.LOG_LEVEL, + base: { + env: env.NODE_ENV, + }, +}; + +if (env.NODE_ENV === 'development') { + pinoOptions.transport = { + target: 'pino-pretty', + options: { + colorize: true, + translateTime: 'SYS:standard', + ignore: 'pid,hostname', + }, + }; +} + +export const logger = pino(pinoOptions); diff --git a/src/infrastructure/observability/metrics.ts b/src/infrastructure/observability/metrics.ts new file mode 100644 index 0000000..7cbd5e9 --- /dev/null +++ b/src/infrastructure/observability/metrics.ts @@ -0,0 +1,12 @@ +import client from 'prom-client'; + +client.collectDefaultMetrics({ prefix: 'supporthub_' }); + +export const httpRequestDurationHistogram = new client.Histogram({ + name: 'supporthub_http_request_duration_seconds', + help: 'Duration of HTTP requests in seconds', + labelNames: ['method', 'route', 'status_code'], + buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5], +}); + +export const metricsRegistry = client.register; diff --git a/src/infrastructure/observability/tracing.ts b/src/infrastructure/observability/tracing.ts new file mode 100644 index 0000000..70b08e1 --- /dev/null +++ b/src/infrastructure/observability/tracing.ts @@ -0,0 +1,5 @@ +import { trace, Tracer } from '@opentelemetry/api'; + +export function getTracer(name = 'supporthub-api'): Tracer { + return trace.getTracer(name); +} diff --git a/src/infrastructure/queue/index.ts b/src/infrastructure/queue/index.ts new file mode 100644 index 0000000..f385baf --- /dev/null +++ b/src/infrastructure/queue/index.ts @@ -0,0 +1,2 @@ +export * from './queue.types'; +export * from './queue.manager'; diff --git a/src/infrastructure/queue/queue.manager.ts b/src/infrastructure/queue/queue.manager.ts new file mode 100644 index 0000000..0b72142 --- /dev/null +++ b/src/infrastructure/queue/queue.manager.ts @@ -0,0 +1,63 @@ +import { Queue, Worker, Processor, Job } from 'bullmq'; +import { queueConfig } from '@/config'; +import { QueueName, QueueJobPayload } from './queue.types'; + +export class QueueManager { + private queues: Map = new Map(); + private workers: Map = new Map(); + + getQueue(name: QueueName): Queue> { + if (!this.queues.has(name)) { + const queue = new Queue>(name, { + connection: queueConfig.connection, + defaultJobOptions: queueConfig.defaultJobOptions, + }); + this.queues.set(name, queue as Queue); + } + return this.queues.get(name) as Queue>; + } + + registerWorker( + name: QueueName, + processor: Processor>, + ): Worker> { + if (this.workers.has(name)) { + return this.workers.get(name) as Worker>; + } + + const worker = new Worker>(name, processor, { + connection: queueConfig.connection, + }); + + this.workers.set(name, worker as Worker); + return worker; + } + + async addJob( + queueName: QueueName, + jobName: string, + data: T, + ): Promise>> { + const queue = this.getQueue(queueName); + const payload: QueueJobPayload = { + jobId: `${jobName}_${Date.now()}`, + type: jobName, + payload: data, + createdAt: new Date().toISOString(), + }; + return queue.add(jobName, payload); + } + + async shutdown(): Promise { + for (const worker of this.workers.values()) { + await worker.close(); + } + for (const queue of this.queues.values()) { + await queue.close(); + } + this.workers.clear(); + this.queues.clear(); + } +} + +export const queueManager = new QueueManager(); diff --git a/src/infrastructure/queue/queue.types.ts b/src/infrastructure/queue/queue.types.ts new file mode 100644 index 0000000..0588dcb --- /dev/null +++ b/src/infrastructure/queue/queue.types.ts @@ -0,0 +1,15 @@ +export enum QueueName { + SLA = 'sla-queue', + ESCALATION = 'escalation-queue', + NOTIFICATIONS = 'notifications-queue', + ATTACHMENTS = 'attachments-queue', + ANALYTICS = 'analytics-queue', + CLEANUP = 'cleanup-queue', +} + +export interface QueueJobPayload { + jobId: string; + type: string; + payload: T; + createdAt: string; +} diff --git a/src/infrastructure/storage/index.ts b/src/infrastructure/storage/index.ts new file mode 100644 index 0000000..30d8d4d --- /dev/null +++ b/src/infrastructure/storage/index.ts @@ -0,0 +1,2 @@ +export * from './storage.client'; +export * from './storage.service'; diff --git a/src/infrastructure/storage/storage.client.ts b/src/infrastructure/storage/storage.client.ts new file mode 100644 index 0000000..9378bad --- /dev/null +++ b/src/infrastructure/storage/storage.client.ts @@ -0,0 +1,26 @@ +import { S3Client, S3ClientConfig } from '@aws-sdk/client-s3'; +import { storageConfig } from '@/config'; + +declare global { + // eslint-disable-next-line no-var + var __storageClient: S3Client | undefined; +} + +export function createStorageClient(): S3Client { + if (!global.__storageClient) { + const config: S3ClientConfig = { + region: storageConfig.region, + credentials: storageConfig.credentials, + }; + + if (storageConfig.endpoint) { + config.endpoint = storageConfig.endpoint; + config.forcePathStyle = true; + } + + global.__storageClient = new S3Client(config); + } + return global.__storageClient; +} + +export const storageClient = createStorageClient(); diff --git a/src/infrastructure/storage/storage.service.ts b/src/infrastructure/storage/storage.service.ts new file mode 100644 index 0000000..43fdeb1 --- /dev/null +++ b/src/infrastructure/storage/storage.service.ts @@ -0,0 +1,69 @@ +import { + S3Client, + PutObjectCommand, + GetObjectCommand, + DeleteObjectCommand, + HeadBucketCommand, + CreateBucketCommand, +} from '@aws-sdk/client-s3'; +import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; +import { storageConfig } from '@/config'; +import { storageClient } from './storage.client'; + +export class StorageService { + constructor( + private readonly client: S3Client = storageClient, + private readonly defaultBucket: string = storageConfig.bucketName, + ) {} + + async ensureBucketExists(bucketName: string = this.defaultBucket): Promise { + try { + await this.client.send(new HeadBucketCommand({ Bucket: bucketName })); + } catch { + try { + await this.client.send(new CreateBucketCommand({ Bucket: bucketName })); + } catch { + // Ignore if bucket creation isn't permitted or already exists in AWS environment + } + } + } + + async uploadFile( + objectName: string, + body: Buffer | Uint8Array | Blob | string, + contentType?: string, + bucketName: string = this.defaultBucket, + ): Promise { + await this.ensureBucketExists(bucketName); + const command = new PutObjectCommand({ + Bucket: bucketName, + Key: objectName, + Body: body, + ContentType: contentType, + }); + await this.client.send(command); + return objectName; + } + + async getPresignedUrl( + objectName: string, + expirySeconds = 3600, + bucketName: string = this.defaultBucket, + ): Promise { + const command = new GetObjectCommand({ + Bucket: bucketName, + Key: objectName, + }); + return getSignedUrl(this.client, command, { expiresIn: expirySeconds }); + } + + async deleteFile(objectName: string, bucketName: string = this.defaultBucket): Promise { + const command = new DeleteObjectCommand({ + Bucket: bucketName, + Key: objectName, + }); + await this.client.send(command); + } +} + +export const storageService = new StorageService(); diff --git a/src/jobs/analytics/index.ts b/src/jobs/analytics/index.ts new file mode 100644 index 0000000..2f62837 --- /dev/null +++ b/src/jobs/analytics/index.ts @@ -0,0 +1,8 @@ +import { queueManager, QueueName } from '@/infrastructure/queue'; +import { logger } from '@/infrastructure/observability'; + +export function registerAnalyticsWorker(): void { + queueManager.registerWorker(QueueName.ANALYTICS, async (job) => { + logger.info({ jobId: job.id, data: job.data }, 'Processing Analytics Job'); + }); +} diff --git a/src/jobs/attachments/index.ts b/src/jobs/attachments/index.ts new file mode 100644 index 0000000..d91bbab --- /dev/null +++ b/src/jobs/attachments/index.ts @@ -0,0 +1,8 @@ +import { queueManager, QueueName } from '@/infrastructure/queue'; +import { logger } from '@/infrastructure/observability'; + +export function registerAttachmentWorker(): void { + queueManager.registerWorker(QueueName.ATTACHMENTS, async (job) => { + logger.info({ jobId: job.id, data: job.data }, 'Processing Attachment Job'); + }); +} diff --git a/src/jobs/cleanup/index.ts b/src/jobs/cleanup/index.ts new file mode 100644 index 0000000..4c226ec --- /dev/null +++ b/src/jobs/cleanup/index.ts @@ -0,0 +1,8 @@ +import { queueManager, QueueName } from '@/infrastructure/queue'; +import { logger } from '@/infrastructure/observability'; + +export function registerCleanupWorker(): void { + queueManager.registerWorker(QueueName.CLEANUP, async (job) => { + logger.info({ jobId: job.id, data: job.data }, 'Processing Cleanup Job'); + }); +} diff --git a/src/jobs/escalation/index.ts b/src/jobs/escalation/index.ts new file mode 100644 index 0000000..ebce297 --- /dev/null +++ b/src/jobs/escalation/index.ts @@ -0,0 +1,8 @@ +import { queueManager, QueueName } from '@/infrastructure/queue'; +import { logger } from '@/infrastructure/observability'; + +export function registerEscalationWorker(): void { + queueManager.registerWorker(QueueName.ESCALATION, async (job) => { + logger.info({ jobId: job.id, data: job.data }, 'Processing Escalation Job'); + }); +} diff --git a/src/jobs/index.ts b/src/jobs/index.ts new file mode 100644 index 0000000..01a1e59 --- /dev/null +++ b/src/jobs/index.ts @@ -0,0 +1,6 @@ +export * from './sla'; +export * from './escalation'; +export * from './notifications'; +export * from './attachments'; +export * from './analytics'; +export * from './cleanup'; diff --git a/src/jobs/notifications/index.ts b/src/jobs/notifications/index.ts new file mode 100644 index 0000000..cd92e55 --- /dev/null +++ b/src/jobs/notifications/index.ts @@ -0,0 +1,8 @@ +import { queueManager, QueueName } from '@/infrastructure/queue'; +import { logger } from '@/infrastructure/observability'; + +export function registerNotificationWorker(): void { + queueManager.registerWorker(QueueName.NOTIFICATIONS, async (job) => { + logger.info({ jobId: job.id, data: job.data }, 'Processing Notification Job'); + }); +} diff --git a/src/jobs/sla/index.ts b/src/jobs/sla/index.ts new file mode 100644 index 0000000..64a9d2b --- /dev/null +++ b/src/jobs/sla/index.ts @@ -0,0 +1,8 @@ +import { queueManager, QueueName } from '@/infrastructure/queue'; +import { logger } from '@/infrastructure/observability'; + +export function registerSlaWorker(): void { + queueManager.registerWorker(QueueName.SLA, async (job) => { + logger.info({ jobId: job.id, data: job.data }, 'Processing SLA Job'); + }); +} diff --git a/src/modules/catalog/categories/constants/index.ts b/src/modules/catalog/categories/constants/index.ts new file mode 100644 index 0000000..f93221e --- /dev/null +++ b/src/modules/catalog/categories/constants/index.ts @@ -0,0 +1,3 @@ +export const CATEGORIES_CONSTANTS = { + MODULE_NAME: 'CATALOG_CATEGORIES', +} as const; diff --git a/src/modules/catalog/categories/controller/categories.controller.ts b/src/modules/catalog/categories/controller/categories.controller.ts new file mode 100644 index 0000000..434424f --- /dev/null +++ b/src/modules/catalog/categories/controller/categories.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { categoriesService, CategoriesService } from '../service'; + +export class CategoriesController { + constructor(private readonly service: CategoriesService = categoriesService) {} + + async getCategories(_request: FastifyRequest, reply: FastifyReply) { + const categories = await this.service.listCategories(); + return reply.status(200).send({ + success: true, + data: categories, + meta: null, + }); + } +} + +export const categoriesController = new CategoriesController(); diff --git a/src/modules/catalog/categories/controller/index.ts b/src/modules/catalog/categories/controller/index.ts new file mode 100644 index 0000000..1f5e2ad --- /dev/null +++ b/src/modules/catalog/categories/controller/index.ts @@ -0,0 +1 @@ +export * from './categories.controller'; diff --git a/src/modules/catalog/categories/index.ts b/src/modules/catalog/categories/index.ts new file mode 100644 index 0000000..3f15c2c --- /dev/null +++ b/src/modules/catalog/categories/index.ts @@ -0,0 +1,3 @@ +export { categoriesRoutes } from './routes'; +export { CategoriesService, categoriesService } from './service'; +export type { CategoryDTO } from './types'; diff --git a/src/modules/catalog/categories/mapper/index.ts b/src/modules/catalog/categories/mapper/index.ts new file mode 100644 index 0000000..ce0046d --- /dev/null +++ b/src/modules/catalog/categories/mapper/index.ts @@ -0,0 +1,5 @@ +export class CategoryMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/catalog/categories/repository/categories.repository.ts b/src/modules/catalog/categories/repository/categories.repository.ts new file mode 100644 index 0000000..dcd53fc --- /dev/null +++ b/src/modules/catalog/categories/repository/categories.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class CategoriesRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAllCategories(): Promise { + return this.prisma.category.findMany(); + } +} + +export const categoriesRepository = new CategoriesRepository(); diff --git a/src/modules/catalog/categories/repository/index.ts b/src/modules/catalog/categories/repository/index.ts new file mode 100644 index 0000000..b6fa1d3 --- /dev/null +++ b/src/modules/catalog/categories/repository/index.ts @@ -0,0 +1 @@ +export * from './categories.repository'; diff --git a/src/modules/catalog/categories/routes/categories.routes.ts b/src/modules/catalog/categories/routes/categories.routes.ts new file mode 100644 index 0000000..b764ce9 --- /dev/null +++ b/src/modules/catalog/categories/routes/categories.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { categoriesController } from '../controller'; + +export async function categoriesRoutes(fastify: FastifyInstance): Promise { + fastify.get('/categories', (req, reply) => categoriesController.getCategories(req, reply)); +} diff --git a/src/modules/catalog/categories/routes/index.ts b/src/modules/catalog/categories/routes/index.ts new file mode 100644 index 0000000..31c1799 --- /dev/null +++ b/src/modules/catalog/categories/routes/index.ts @@ -0,0 +1 @@ +export * from './categories.routes'; diff --git a/src/modules/catalog/categories/schema/categories.schema.ts b/src/modules/catalog/categories/schema/categories.schema.ts new file mode 100644 index 0000000..1b79785 --- /dev/null +++ b/src/modules/catalog/categories/schema/categories.schema.ts @@ -0,0 +1,5 @@ +import { z } from 'zod'; + +export const categoryQuerySchema = z.object({ + productId: z.string().optional(), +}); diff --git a/src/modules/catalog/categories/schema/index.ts b/src/modules/catalog/categories/schema/index.ts new file mode 100644 index 0000000..a581803 --- /dev/null +++ b/src/modules/catalog/categories/schema/index.ts @@ -0,0 +1 @@ +export * from './categories.schema'; diff --git a/src/modules/catalog/categories/service/categories.service.ts b/src/modules/catalog/categories/service/categories.service.ts new file mode 100644 index 0000000..d97c778 --- /dev/null +++ b/src/modules/catalog/categories/service/categories.service.ts @@ -0,0 +1,11 @@ +import { categoriesRepository, CategoriesRepository } from '../repository'; + +export class CategoriesService { + constructor(private readonly repo: CategoriesRepository = categoriesRepository) {} + + async listCategories(): Promise { + return this.repo.findAllCategories(); + } +} + +export const categoriesService = new CategoriesService(); diff --git a/src/modules/catalog/categories/service/index.ts b/src/modules/catalog/categories/service/index.ts new file mode 100644 index 0000000..8f23a25 --- /dev/null +++ b/src/modules/catalog/categories/service/index.ts @@ -0,0 +1 @@ +export * from './categories.service'; diff --git a/src/modules/catalog/categories/types/categories.types.ts b/src/modules/catalog/categories/types/categories.types.ts new file mode 100644 index 0000000..55f6698 --- /dev/null +++ b/src/modules/catalog/categories/types/categories.types.ts @@ -0,0 +1,6 @@ +export interface CategoryDTO { + id: string; + productId: string; + name: string; + description?: string | null; +} diff --git a/src/modules/catalog/categories/types/index.ts b/src/modules/catalog/categories/types/index.ts new file mode 100644 index 0000000..6d64fa5 --- /dev/null +++ b/src/modules/catalog/categories/types/index.ts @@ -0,0 +1 @@ +export * from './categories.types'; diff --git a/src/modules/catalog/priorities/constants/index.ts b/src/modules/catalog/priorities/constants/index.ts new file mode 100644 index 0000000..1bb6424 --- /dev/null +++ b/src/modules/catalog/priorities/constants/index.ts @@ -0,0 +1,3 @@ +export const PRIORITIES_CONSTANTS = { + MODULE_NAME: 'CATALOG_PRIORITIES', +} as const; diff --git a/src/modules/catalog/priorities/controller/index.ts b/src/modules/catalog/priorities/controller/index.ts new file mode 100644 index 0000000..8bfe3c3 --- /dev/null +++ b/src/modules/catalog/priorities/controller/index.ts @@ -0,0 +1 @@ +export * from './priorities.controller'; diff --git a/src/modules/catalog/priorities/controller/priorities.controller.ts b/src/modules/catalog/priorities/controller/priorities.controller.ts new file mode 100644 index 0000000..c693e93 --- /dev/null +++ b/src/modules/catalog/priorities/controller/priorities.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { prioritiesService, PrioritiesService } from '../service'; + +export class PrioritiesController { + constructor(private readonly service: PrioritiesService = prioritiesService) {} + + async getPriorities(_request: FastifyRequest, reply: FastifyReply) { + const priorities = await this.service.listPriorities(); + return reply.status(200).send({ + success: true, + data: priorities, + meta: null, + }); + } +} + +export const prioritiesController = new PrioritiesController(); diff --git a/src/modules/catalog/priorities/index.ts b/src/modules/catalog/priorities/index.ts new file mode 100644 index 0000000..78031fc --- /dev/null +++ b/src/modules/catalog/priorities/index.ts @@ -0,0 +1,3 @@ +export { prioritiesRoutes } from './routes'; +export { PrioritiesService, prioritiesService } from './service'; +export type { PriorityDTO } from './types'; diff --git a/src/modules/catalog/priorities/mapper/index.ts b/src/modules/catalog/priorities/mapper/index.ts new file mode 100644 index 0000000..603f473 --- /dev/null +++ b/src/modules/catalog/priorities/mapper/index.ts @@ -0,0 +1,5 @@ +export class PriorityMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/catalog/priorities/repository/index.ts b/src/modules/catalog/priorities/repository/index.ts new file mode 100644 index 0000000..dc5090a --- /dev/null +++ b/src/modules/catalog/priorities/repository/index.ts @@ -0,0 +1 @@ +export * from './priorities.repository'; diff --git a/src/modules/catalog/priorities/repository/priorities.repository.ts b/src/modules/catalog/priorities/repository/priorities.repository.ts new file mode 100644 index 0000000..f1a9a7c --- /dev/null +++ b/src/modules/catalog/priorities/repository/priorities.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class PrioritiesRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAllPriorities(): Promise { + return []; + } +} + +export const prioritiesRepository = new PrioritiesRepository(); diff --git a/src/modules/catalog/priorities/routes/index.ts b/src/modules/catalog/priorities/routes/index.ts new file mode 100644 index 0000000..8032ed7 --- /dev/null +++ b/src/modules/catalog/priorities/routes/index.ts @@ -0,0 +1 @@ +export * from './priorities.routes'; diff --git a/src/modules/catalog/priorities/routes/priorities.routes.ts b/src/modules/catalog/priorities/routes/priorities.routes.ts new file mode 100644 index 0000000..ecdbe3e --- /dev/null +++ b/src/modules/catalog/priorities/routes/priorities.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { prioritiesController } from '../controller'; + +export async function prioritiesRoutes(fastify: FastifyInstance): Promise { + fastify.get('/priorities', (req, reply) => prioritiesController.getPriorities(req, reply)); +} diff --git a/src/modules/catalog/priorities/schema/index.ts b/src/modules/catalog/priorities/schema/index.ts new file mode 100644 index 0000000..64564fb --- /dev/null +++ b/src/modules/catalog/priorities/schema/index.ts @@ -0,0 +1 @@ +export * from './priorities.schema'; diff --git a/src/modules/catalog/priorities/schema/priorities.schema.ts b/src/modules/catalog/priorities/schema/priorities.schema.ts new file mode 100644 index 0000000..97ca9ae --- /dev/null +++ b/src/modules/catalog/priorities/schema/priorities.schema.ts @@ -0,0 +1,5 @@ +import { z } from 'zod'; + +export const priorityQuerySchema = z.object({ + code: z.string().optional(), +}); diff --git a/src/modules/catalog/priorities/service/index.ts b/src/modules/catalog/priorities/service/index.ts new file mode 100644 index 0000000..0da9cbf --- /dev/null +++ b/src/modules/catalog/priorities/service/index.ts @@ -0,0 +1 @@ +export * from './priorities.service'; diff --git a/src/modules/catalog/priorities/service/priorities.service.ts b/src/modules/catalog/priorities/service/priorities.service.ts new file mode 100644 index 0000000..a835216 --- /dev/null +++ b/src/modules/catalog/priorities/service/priorities.service.ts @@ -0,0 +1,11 @@ +import { prioritiesRepository, PrioritiesRepository } from '../repository'; + +export class PrioritiesService { + constructor(private readonly repo: PrioritiesRepository = prioritiesRepository) {} + + async listPriorities(): Promise { + return this.repo.findAllPriorities(); + } +} + +export const prioritiesService = new PrioritiesService(); diff --git a/src/modules/catalog/priorities/types/index.ts b/src/modules/catalog/priorities/types/index.ts new file mode 100644 index 0000000..37bb031 --- /dev/null +++ b/src/modules/catalog/priorities/types/index.ts @@ -0,0 +1 @@ +export * from './priorities.types'; diff --git a/src/modules/catalog/priorities/types/priorities.types.ts b/src/modules/catalog/priorities/types/priorities.types.ts new file mode 100644 index 0000000..86482d2 --- /dev/null +++ b/src/modules/catalog/priorities/types/priorities.types.ts @@ -0,0 +1,6 @@ +export interface PriorityDTO { + id: string; + code: string; + name: string; + level: number; +} diff --git a/src/modules/catalog/problem-types/constants/index.ts b/src/modules/catalog/problem-types/constants/index.ts new file mode 100644 index 0000000..fe5ef5a --- /dev/null +++ b/src/modules/catalog/problem-types/constants/index.ts @@ -0,0 +1,3 @@ +export const PROBLEM_TYPES_CONSTANTS = { + MODULE_NAME: 'CATALOG_PROBLEM_TYPES', +} as const; diff --git a/src/modules/catalog/problem-types/controller/index.ts b/src/modules/catalog/problem-types/controller/index.ts new file mode 100644 index 0000000..447ef2a --- /dev/null +++ b/src/modules/catalog/problem-types/controller/index.ts @@ -0,0 +1 @@ +export * from './problem-types.controller'; diff --git a/src/modules/catalog/problem-types/controller/problem-types.controller.ts b/src/modules/catalog/problem-types/controller/problem-types.controller.ts new file mode 100644 index 0000000..4cb3622 --- /dev/null +++ b/src/modules/catalog/problem-types/controller/problem-types.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { problemTypesService, ProblemTypesService } from '../service'; + +export class ProblemTypesController { + constructor(private readonly service: ProblemTypesService = problemTypesService) {} + + async getProblemTypes(_request: FastifyRequest, reply: FastifyReply) { + const types = await this.service.listProblemTypes(); + return reply.status(200).send({ + success: true, + data: types, + meta: null, + }); + } +} + +export const problemTypesController = new ProblemTypesController(); diff --git a/src/modules/catalog/problem-types/index.ts b/src/modules/catalog/problem-types/index.ts new file mode 100644 index 0000000..5c01107 --- /dev/null +++ b/src/modules/catalog/problem-types/index.ts @@ -0,0 +1,3 @@ +export { problemTypesRoutes } from './routes'; +export { ProblemTypesService, problemTypesService } from './service'; +export type { ProblemTypeDTO } from './types'; diff --git a/src/modules/catalog/problem-types/mapper/index.ts b/src/modules/catalog/problem-types/mapper/index.ts new file mode 100644 index 0000000..8240e0c --- /dev/null +++ b/src/modules/catalog/problem-types/mapper/index.ts @@ -0,0 +1,5 @@ +export class ProblemTypeMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/catalog/problem-types/repository/index.ts b/src/modules/catalog/problem-types/repository/index.ts new file mode 100644 index 0000000..48ef0bc --- /dev/null +++ b/src/modules/catalog/problem-types/repository/index.ts @@ -0,0 +1 @@ +export * from './problem-types.repository'; diff --git a/src/modules/catalog/problem-types/repository/problem-types.repository.ts b/src/modules/catalog/problem-types/repository/problem-types.repository.ts new file mode 100644 index 0000000..0e10445 --- /dev/null +++ b/src/modules/catalog/problem-types/repository/problem-types.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class ProblemTypesRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAllProblemTypes(): Promise { + return []; + } +} + +export const problemTypesRepository = new ProblemTypesRepository(); diff --git a/src/modules/catalog/problem-types/routes/index.ts b/src/modules/catalog/problem-types/routes/index.ts new file mode 100644 index 0000000..a3357d5 --- /dev/null +++ b/src/modules/catalog/problem-types/routes/index.ts @@ -0,0 +1 @@ +export * from './problem-types.routes'; diff --git a/src/modules/catalog/problem-types/routes/problem-types.routes.ts b/src/modules/catalog/problem-types/routes/problem-types.routes.ts new file mode 100644 index 0000000..a266473 --- /dev/null +++ b/src/modules/catalog/problem-types/routes/problem-types.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { problemTypesController } from '../controller'; + +export async function problemTypesRoutes(fastify: FastifyInstance): Promise { + fastify.get('/problem-types', (req, reply) => problemTypesController.getProblemTypes(req, reply)); +} diff --git a/src/modules/catalog/problem-types/schema/index.ts b/src/modules/catalog/problem-types/schema/index.ts new file mode 100644 index 0000000..3fca7ca --- /dev/null +++ b/src/modules/catalog/problem-types/schema/index.ts @@ -0,0 +1 @@ +export * from './problem-types.schema'; diff --git a/src/modules/catalog/problem-types/schema/problem-types.schema.ts b/src/modules/catalog/problem-types/schema/problem-types.schema.ts new file mode 100644 index 0000000..f1dd144 --- /dev/null +++ b/src/modules/catalog/problem-types/schema/problem-types.schema.ts @@ -0,0 +1,5 @@ +import { z } from 'zod'; + +export const problemTypeQuerySchema = z.object({ + code: z.string().optional(), +}); diff --git a/src/modules/catalog/problem-types/service/index.ts b/src/modules/catalog/problem-types/service/index.ts new file mode 100644 index 0000000..77e9d27 --- /dev/null +++ b/src/modules/catalog/problem-types/service/index.ts @@ -0,0 +1 @@ +export * from './problem-types.service'; diff --git a/src/modules/catalog/problem-types/service/problem-types.service.ts b/src/modules/catalog/problem-types/service/problem-types.service.ts new file mode 100644 index 0000000..f8b8b34 --- /dev/null +++ b/src/modules/catalog/problem-types/service/problem-types.service.ts @@ -0,0 +1,11 @@ +import { problemTypesRepository, ProblemTypesRepository } from '../repository'; + +export class ProblemTypesService { + constructor(private readonly repo: ProblemTypesRepository = problemTypesRepository) {} + + async listProblemTypes(): Promise { + return this.repo.findAllProblemTypes(); + } +} + +export const problemTypesService = new ProblemTypesService(); diff --git a/src/modules/catalog/problem-types/types/index.ts b/src/modules/catalog/problem-types/types/index.ts new file mode 100644 index 0000000..be5720d --- /dev/null +++ b/src/modules/catalog/problem-types/types/index.ts @@ -0,0 +1 @@ +export * from './problem-types.types'; diff --git a/src/modules/catalog/problem-types/types/problem-types.types.ts b/src/modules/catalog/problem-types/types/problem-types.types.ts new file mode 100644 index 0000000..eb9a115 --- /dev/null +++ b/src/modules/catalog/problem-types/types/problem-types.types.ts @@ -0,0 +1,5 @@ +export interface ProblemTypeDTO { + id: string; + code: string; + name: string; +} diff --git a/src/modules/catalog/products/constants/index.ts b/src/modules/catalog/products/constants/index.ts new file mode 100644 index 0000000..7a0b7c4 --- /dev/null +++ b/src/modules/catalog/products/constants/index.ts @@ -0,0 +1,3 @@ +export const PRODUCTS_CONSTANTS = { + MODULE_NAME: 'CATALOG_PRODUCTS', +} as const; diff --git a/src/modules/catalog/products/controller/index.ts b/src/modules/catalog/products/controller/index.ts new file mode 100644 index 0000000..575ded0 --- /dev/null +++ b/src/modules/catalog/products/controller/index.ts @@ -0,0 +1 @@ +export * from './products.controller'; diff --git a/src/modules/catalog/products/controller/products.controller.ts b/src/modules/catalog/products/controller/products.controller.ts new file mode 100644 index 0000000..f5ba167 --- /dev/null +++ b/src/modules/catalog/products/controller/products.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { productsService, ProductsService } from '../service'; + +export class ProductsController { + constructor(private readonly service: ProductsService = productsService) {} + + async getProducts(_request: FastifyRequest, reply: FastifyReply) { + const products = await this.service.listProducts(); + return reply.status(200).send({ + success: true, + data: products, + meta: null, + }); + } +} + +export const productsController = new ProductsController(); diff --git a/src/modules/catalog/products/index.ts b/src/modules/catalog/products/index.ts new file mode 100644 index 0000000..23113df --- /dev/null +++ b/src/modules/catalog/products/index.ts @@ -0,0 +1,3 @@ +export { productsRoutes } from './routes'; +export { ProductsService, productsService } from './service'; +export type { ProductDTO } from './types'; diff --git a/src/modules/catalog/products/mapper/index.ts b/src/modules/catalog/products/mapper/index.ts new file mode 100644 index 0000000..0d140a5 --- /dev/null +++ b/src/modules/catalog/products/mapper/index.ts @@ -0,0 +1,5 @@ +export class ProductMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/catalog/products/repository/index.ts b/src/modules/catalog/products/repository/index.ts new file mode 100644 index 0000000..a876253 --- /dev/null +++ b/src/modules/catalog/products/repository/index.ts @@ -0,0 +1 @@ +export * from './products.repository'; diff --git a/src/modules/catalog/products/repository/products.repository.ts b/src/modules/catalog/products/repository/products.repository.ts new file mode 100644 index 0000000..4b88042 --- /dev/null +++ b/src/modules/catalog/products/repository/products.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class ProductsRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAllProducts(): Promise { + return this.prisma.product.findMany(); + } +} + +export const productsRepository = new ProductsRepository(); diff --git a/src/modules/catalog/products/routes/index.ts b/src/modules/catalog/products/routes/index.ts new file mode 100644 index 0000000..916dc0b --- /dev/null +++ b/src/modules/catalog/products/routes/index.ts @@ -0,0 +1 @@ +export * from './products.routes'; diff --git a/src/modules/catalog/products/routes/products.routes.ts b/src/modules/catalog/products/routes/products.routes.ts new file mode 100644 index 0000000..278a9bd --- /dev/null +++ b/src/modules/catalog/products/routes/products.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { productsController } from '../controller'; + +export async function productsRoutes(fastify: FastifyInstance): Promise { + fastify.get('/products', (req, reply) => productsController.getProducts(req, reply)); +} diff --git a/src/modules/catalog/products/schema/index.ts b/src/modules/catalog/products/schema/index.ts new file mode 100644 index 0000000..7f705a2 --- /dev/null +++ b/src/modules/catalog/products/schema/index.ts @@ -0,0 +1 @@ +export * from './products.schema'; diff --git a/src/modules/catalog/products/schema/products.schema.ts b/src/modules/catalog/products/schema/products.schema.ts new file mode 100644 index 0000000..c30443c --- /dev/null +++ b/src/modules/catalog/products/schema/products.schema.ts @@ -0,0 +1,5 @@ +import { z } from 'zod'; + +export const productQuerySchema = z.object({ + code: z.string().optional(), +}); diff --git a/src/modules/catalog/products/service/index.ts b/src/modules/catalog/products/service/index.ts new file mode 100644 index 0000000..2859ce3 --- /dev/null +++ b/src/modules/catalog/products/service/index.ts @@ -0,0 +1 @@ +export * from './products.service'; diff --git a/src/modules/catalog/products/service/products.service.ts b/src/modules/catalog/products/service/products.service.ts new file mode 100644 index 0000000..d1ae1bd --- /dev/null +++ b/src/modules/catalog/products/service/products.service.ts @@ -0,0 +1,11 @@ +import { productsRepository, ProductsRepository } from '../repository'; + +export class ProductsService { + constructor(private readonly repo: ProductsRepository = productsRepository) {} + + async listProducts(): Promise { + return this.repo.findAllProducts(); + } +} + +export const productsService = new ProductsService(); diff --git a/src/modules/catalog/products/types/index.ts b/src/modules/catalog/products/types/index.ts new file mode 100644 index 0000000..7d9cfa7 --- /dev/null +++ b/src/modules/catalog/products/types/index.ts @@ -0,0 +1 @@ +export * from './products.types'; diff --git a/src/modules/catalog/products/types/products.types.ts b/src/modules/catalog/products/types/products.types.ts new file mode 100644 index 0000000..55239eb --- /dev/null +++ b/src/modules/catalog/products/types/products.types.ts @@ -0,0 +1,6 @@ +export interface ProductDTO { + id: string; + code: string; + name: string; + description?: string | null; +} diff --git a/src/modules/identity/agents/constants/index.ts b/src/modules/identity/agents/constants/index.ts new file mode 100644 index 0000000..b409c4e --- /dev/null +++ b/src/modules/identity/agents/constants/index.ts @@ -0,0 +1,3 @@ +export const AGENTS_CONSTANTS = { + MODULE_NAME: 'IDENTITY_AGENTS', +} as const; diff --git a/src/modules/identity/agents/controller/agents.controller.ts b/src/modules/identity/agents/controller/agents.controller.ts new file mode 100644 index 0000000..ebc09ab --- /dev/null +++ b/src/modules/identity/agents/controller/agents.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { agentsService, AgentsService } from '../service'; + +export class AgentsController { + constructor(private readonly service: AgentsService = agentsService) {} + + async getAgents(_request: FastifyRequest, reply: FastifyReply) { + const agents = await this.service.listAgents(); + return reply.status(200).send({ + success: true, + data: agents, + meta: null, + }); + } +} + +export const agentsController = new AgentsController(); diff --git a/src/modules/identity/agents/controller/index.ts b/src/modules/identity/agents/controller/index.ts new file mode 100644 index 0000000..80d40ab --- /dev/null +++ b/src/modules/identity/agents/controller/index.ts @@ -0,0 +1 @@ +export * from './agents.controller'; diff --git a/src/modules/identity/agents/index.ts b/src/modules/identity/agents/index.ts new file mode 100644 index 0000000..a3d7bd9 --- /dev/null +++ b/src/modules/identity/agents/index.ts @@ -0,0 +1,3 @@ +export { agentsRoutes } from './routes'; +export { AgentsService, agentsService } from './service'; +export type { AgentProfile } from './types'; diff --git a/src/modules/identity/agents/mapper/index.ts b/src/modules/identity/agents/mapper/index.ts new file mode 100644 index 0000000..4a1b9ea --- /dev/null +++ b/src/modules/identity/agents/mapper/index.ts @@ -0,0 +1,5 @@ +export class AgentMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/identity/agents/repository/agents.repository.ts b/src/modules/identity/agents/repository/agents.repository.ts new file mode 100644 index 0000000..40aaefa --- /dev/null +++ b/src/modules/identity/agents/repository/agents.repository.ts @@ -0,0 +1,14 @@ +import { prismaClient } from '@/infrastructure/database'; +import { UserRole } from '@prisma/client'; + +export class AgentsRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAllAgents(): Promise { + return this.prisma.user.findMany({ + where: { role: UserRole.AGENT }, + }); + } +} + +export const agentsRepository = new AgentsRepository(); diff --git a/src/modules/identity/agents/repository/index.ts b/src/modules/identity/agents/repository/index.ts new file mode 100644 index 0000000..6fff761 --- /dev/null +++ b/src/modules/identity/agents/repository/index.ts @@ -0,0 +1 @@ +export * from './agents.repository'; diff --git a/src/modules/identity/agents/routes/agents.routes.ts b/src/modules/identity/agents/routes/agents.routes.ts new file mode 100644 index 0000000..e23e521 --- /dev/null +++ b/src/modules/identity/agents/routes/agents.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { agentsController } from '../controller'; + +export async function agentsRoutes(fastify: FastifyInstance): Promise { + fastify.get('/agents', (req, reply) => agentsController.getAgents(req, reply)); +} diff --git a/src/modules/identity/agents/routes/index.ts b/src/modules/identity/agents/routes/index.ts new file mode 100644 index 0000000..16f4cbb --- /dev/null +++ b/src/modules/identity/agents/routes/index.ts @@ -0,0 +1 @@ +export * from './agents.routes'; diff --git a/src/modules/identity/agents/schema/agents.schema.ts b/src/modules/identity/agents/schema/agents.schema.ts new file mode 100644 index 0000000..033f2d9 --- /dev/null +++ b/src/modules/identity/agents/schema/agents.schema.ts @@ -0,0 +1,6 @@ +import { z } from 'zod'; + +export const agentQuerySchema = z.object({ + page: z.coerce.number().optional(), + limit: z.coerce.number().optional(), +}); diff --git a/src/modules/identity/agents/schema/index.ts b/src/modules/identity/agents/schema/index.ts new file mode 100644 index 0000000..f20467f --- /dev/null +++ b/src/modules/identity/agents/schema/index.ts @@ -0,0 +1 @@ +export * from './agents.schema'; diff --git a/src/modules/identity/agents/service/agents.service.ts b/src/modules/identity/agents/service/agents.service.ts new file mode 100644 index 0000000..3f410e7 --- /dev/null +++ b/src/modules/identity/agents/service/agents.service.ts @@ -0,0 +1,11 @@ +import { agentsRepository, AgentsRepository } from '../repository'; + +export class AgentsService { + constructor(private readonly repo: AgentsRepository = agentsRepository) {} + + async listAgents(): Promise { + return this.repo.findAllAgents(); + } +} + +export const agentsService = new AgentsService(); diff --git a/src/modules/identity/agents/service/index.ts b/src/modules/identity/agents/service/index.ts new file mode 100644 index 0000000..77fba1f --- /dev/null +++ b/src/modules/identity/agents/service/index.ts @@ -0,0 +1 @@ +export * from './agents.service'; diff --git a/src/modules/identity/agents/types/agents.types.ts b/src/modules/identity/agents/types/agents.types.ts new file mode 100644 index 0000000..0c328fc --- /dev/null +++ b/src/modules/identity/agents/types/agents.types.ts @@ -0,0 +1,5 @@ +export interface AgentProfile { + id: string; + email: string; + name: string; +} diff --git a/src/modules/identity/agents/types/index.ts b/src/modules/identity/agents/types/index.ts new file mode 100644 index 0000000..6307333 --- /dev/null +++ b/src/modules/identity/agents/types/index.ts @@ -0,0 +1 @@ +export * from './agents.types'; diff --git a/src/modules/identity/auth/constants/auth.constants.ts b/src/modules/identity/auth/constants/auth.constants.ts new file mode 100644 index 0000000..d46d698 --- /dev/null +++ b/src/modules/identity/auth/constants/auth.constants.ts @@ -0,0 +1,3 @@ +export const AUTH_CONSTANTS = { + MODULE_NAME: 'IDENTITY_AUTH', +} as const; diff --git a/src/modules/identity/auth/constants/index.ts b/src/modules/identity/auth/constants/index.ts new file mode 100644 index 0000000..f64c41d --- /dev/null +++ b/src/modules/identity/auth/constants/index.ts @@ -0,0 +1 @@ +export * from './auth.constants'; diff --git a/src/modules/identity/auth/controller/auth.controller.ts b/src/modules/identity/auth/controller/auth.controller.ts new file mode 100644 index 0000000..b0469e1 --- /dev/null +++ b/src/modules/identity/auth/controller/auth.controller.ts @@ -0,0 +1,18 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { authService, AuthService } from '../service'; +import { AuthCredentialsInput } from '../types'; + +export class AuthController { + constructor(private readonly service: AuthService = authService) {} + + async handleLogin(request: FastifyRequest<{ Body: AuthCredentialsInput }>, reply: FastifyReply) { + const user = await this.service.validateCredentials(request.body); + return reply.status(200).send({ + success: true, + data: user, + meta: null, + }); + } +} + +export const authController = new AuthController(); diff --git a/src/modules/identity/auth/controller/index.ts b/src/modules/identity/auth/controller/index.ts new file mode 100644 index 0000000..04d02fa --- /dev/null +++ b/src/modules/identity/auth/controller/index.ts @@ -0,0 +1 @@ +export * from './auth.controller'; diff --git a/src/modules/identity/auth/index.ts b/src/modules/identity/auth/index.ts new file mode 100644 index 0000000..fef740a --- /dev/null +++ b/src/modules/identity/auth/index.ts @@ -0,0 +1,3 @@ +export { authRoutes } from './routes'; +export { AuthService, authService } from './service'; +export type { AuthCredentialsInput } from './types'; diff --git a/src/modules/identity/auth/mapper/auth.mapper.ts b/src/modules/identity/auth/mapper/auth.mapper.ts new file mode 100644 index 0000000..05c4df1 --- /dev/null +++ b/src/modules/identity/auth/mapper/auth.mapper.ts @@ -0,0 +1,5 @@ +export class AuthMapper { + static toResponse(user: Record): Record { + return { ...user }; + } +} diff --git a/src/modules/identity/auth/mapper/index.ts b/src/modules/identity/auth/mapper/index.ts new file mode 100644 index 0000000..0a117f4 --- /dev/null +++ b/src/modules/identity/auth/mapper/index.ts @@ -0,0 +1 @@ +export * from './auth.mapper'; diff --git a/src/modules/identity/auth/repository/auth.repository.ts b/src/modules/identity/auth/repository/auth.repository.ts new file mode 100644 index 0000000..8020c84 --- /dev/null +++ b/src/modules/identity/auth/repository/auth.repository.ts @@ -0,0 +1,13 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class AuthRepository { + constructor(private readonly prisma = prismaClient) {} + + async findByEmail(email: string): Promise { + return this.prisma.user.findUnique({ + where: { email }, + }); + } +} + +export const authRepository = new AuthRepository(); diff --git a/src/modules/identity/auth/repository/index.ts b/src/modules/identity/auth/repository/index.ts new file mode 100644 index 0000000..cda518a --- /dev/null +++ b/src/modules/identity/auth/repository/index.ts @@ -0,0 +1 @@ +export * from './auth.repository'; diff --git a/src/modules/identity/auth/routes/auth.routes.ts b/src/modules/identity/auth/routes/auth.routes.ts new file mode 100644 index 0000000..f8c0c30 --- /dev/null +++ b/src/modules/identity/auth/routes/auth.routes.ts @@ -0,0 +1,9 @@ +import { FastifyInstance, FastifyRequest } from 'fastify'; +import { authController } from '../controller'; +import { AuthCredentialsInput } from '../types'; + +export async function authRoutes(fastify: FastifyInstance): Promise { + fastify.post('/auth/login', (req: FastifyRequest<{ Body: AuthCredentialsInput }>, reply) => + authController.handleLogin(req, reply), + ); +} diff --git a/src/modules/identity/auth/routes/index.ts b/src/modules/identity/auth/routes/index.ts new file mode 100644 index 0000000..358e0c5 --- /dev/null +++ b/src/modules/identity/auth/routes/index.ts @@ -0,0 +1 @@ +export * from './auth.routes'; diff --git a/src/modules/identity/auth/schema/auth.schema.ts b/src/modules/identity/auth/schema/auth.schema.ts new file mode 100644 index 0000000..66f6442 --- /dev/null +++ b/src/modules/identity/auth/schema/auth.schema.ts @@ -0,0 +1,5 @@ +import { z } from 'zod'; + +export const authCredentialsSchema = z.object({ + email: z.string().email(), +}); diff --git a/src/modules/identity/auth/schema/index.ts b/src/modules/identity/auth/schema/index.ts new file mode 100644 index 0000000..f3aafc7 --- /dev/null +++ b/src/modules/identity/auth/schema/index.ts @@ -0,0 +1 @@ +export * from './auth.schema'; diff --git a/src/modules/identity/auth/service/auth.service.ts b/src/modules/identity/auth/service/auth.service.ts new file mode 100644 index 0000000..6044f24 --- /dev/null +++ b/src/modules/identity/auth/service/auth.service.ts @@ -0,0 +1,12 @@ +import { authRepository, AuthRepository } from '../repository'; +import { AuthCredentialsInput } from '../types'; + +export class AuthService { + constructor(private readonly repo: AuthRepository = authRepository) {} + + async validateCredentials(input: AuthCredentialsInput): Promise { + return this.repo.findByEmail(input.email); + } +} + +export const authService = new AuthService(); diff --git a/src/modules/identity/auth/service/index.ts b/src/modules/identity/auth/service/index.ts new file mode 100644 index 0000000..2a719d1 --- /dev/null +++ b/src/modules/identity/auth/service/index.ts @@ -0,0 +1 @@ +export * from './auth.service'; diff --git a/src/modules/identity/auth/types/auth.types.ts b/src/modules/identity/auth/types/auth.types.ts new file mode 100644 index 0000000..7689f73 --- /dev/null +++ b/src/modules/identity/auth/types/auth.types.ts @@ -0,0 +1,3 @@ +export interface AuthCredentialsInput { + email: string; +} diff --git a/src/modules/identity/auth/types/index.ts b/src/modules/identity/auth/types/index.ts new file mode 100644 index 0000000..5999493 --- /dev/null +++ b/src/modules/identity/auth/types/index.ts @@ -0,0 +1 @@ +export * from './auth.types'; diff --git a/src/modules/identity/customers/constants/index.ts b/src/modules/identity/customers/constants/index.ts new file mode 100644 index 0000000..306ae19 --- /dev/null +++ b/src/modules/identity/customers/constants/index.ts @@ -0,0 +1,3 @@ +export const CUSTOMERS_CONSTANTS = { + MODULE_NAME: 'IDENTITY_CUSTOMERS', +} as const; diff --git a/src/modules/identity/customers/controller/customers.controller.ts b/src/modules/identity/customers/controller/customers.controller.ts new file mode 100644 index 0000000..e64c1b7 --- /dev/null +++ b/src/modules/identity/customers/controller/customers.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { customersService, CustomersService } from '../service'; + +export class CustomersController { + constructor(private readonly service: CustomersService = customersService) {} + + async getCustomers(_request: FastifyRequest, reply: FastifyReply) { + const customers = await this.service.listCustomers(); + return reply.status(200).send({ + success: true, + data: customers, + meta: null, + }); + } +} + +export const customersController = new CustomersController(); diff --git a/src/modules/identity/customers/controller/index.ts b/src/modules/identity/customers/controller/index.ts new file mode 100644 index 0000000..ea53646 --- /dev/null +++ b/src/modules/identity/customers/controller/index.ts @@ -0,0 +1 @@ +export * from './customers.controller'; diff --git a/src/modules/identity/customers/index.ts b/src/modules/identity/customers/index.ts new file mode 100644 index 0000000..4fe6693 --- /dev/null +++ b/src/modules/identity/customers/index.ts @@ -0,0 +1,3 @@ +export { customersRoutes } from './routes'; +export { CustomersService, customersService } from './service'; +export type { CustomerProfile } from './types'; diff --git a/src/modules/identity/customers/mapper/index.ts b/src/modules/identity/customers/mapper/index.ts new file mode 100644 index 0000000..baa0a68 --- /dev/null +++ b/src/modules/identity/customers/mapper/index.ts @@ -0,0 +1,5 @@ +export class CustomerMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/identity/customers/repository/customers.repository.ts b/src/modules/identity/customers/repository/customers.repository.ts new file mode 100644 index 0000000..6e2a3a3 --- /dev/null +++ b/src/modules/identity/customers/repository/customers.repository.ts @@ -0,0 +1,14 @@ +import { prismaClient } from '@/infrastructure/database'; +import { UserRole } from '@prisma/client'; + +export class CustomersRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAllCustomers(): Promise { + return this.prisma.user.findMany({ + where: { role: UserRole.CUSTOMER }, + }); + } +} + +export const customersRepository = new CustomersRepository(); diff --git a/src/modules/identity/customers/repository/index.ts b/src/modules/identity/customers/repository/index.ts new file mode 100644 index 0000000..60b316f --- /dev/null +++ b/src/modules/identity/customers/repository/index.ts @@ -0,0 +1 @@ +export * from './customers.repository'; diff --git a/src/modules/identity/customers/routes/customers.routes.ts b/src/modules/identity/customers/routes/customers.routes.ts new file mode 100644 index 0000000..a7968ff --- /dev/null +++ b/src/modules/identity/customers/routes/customers.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { customersController } from '../controller'; + +export async function customersRoutes(fastify: FastifyInstance): Promise { + fastify.get('/customers', (req, reply) => customersController.getCustomers(req, reply)); +} diff --git a/src/modules/identity/customers/routes/index.ts b/src/modules/identity/customers/routes/index.ts new file mode 100644 index 0000000..02c7d7a --- /dev/null +++ b/src/modules/identity/customers/routes/index.ts @@ -0,0 +1 @@ +export * from './customers.routes'; diff --git a/src/modules/identity/customers/schema/customers.schema.ts b/src/modules/identity/customers/schema/customers.schema.ts new file mode 100644 index 0000000..4724417 --- /dev/null +++ b/src/modules/identity/customers/schema/customers.schema.ts @@ -0,0 +1,6 @@ +import { z } from 'zod'; + +export const customerQuerySchema = z.object({ + page: z.coerce.number().optional(), + limit: z.coerce.number().optional(), +}); diff --git a/src/modules/identity/customers/schema/index.ts b/src/modules/identity/customers/schema/index.ts new file mode 100644 index 0000000..a821b46 --- /dev/null +++ b/src/modules/identity/customers/schema/index.ts @@ -0,0 +1 @@ +export * from './customers.schema'; diff --git a/src/modules/identity/customers/service/customers.service.ts b/src/modules/identity/customers/service/customers.service.ts new file mode 100644 index 0000000..ea21123 --- /dev/null +++ b/src/modules/identity/customers/service/customers.service.ts @@ -0,0 +1,11 @@ +import { customersRepository, CustomersRepository } from '../repository'; + +export class CustomersService { + constructor(private readonly repo: CustomersRepository = customersRepository) {} + + async listCustomers(): Promise { + return this.repo.findAllCustomers(); + } +} + +export const customersService = new CustomersService(); diff --git a/src/modules/identity/customers/service/index.ts b/src/modules/identity/customers/service/index.ts new file mode 100644 index 0000000..8932a85 --- /dev/null +++ b/src/modules/identity/customers/service/index.ts @@ -0,0 +1 @@ +export * from './customers.service'; diff --git a/src/modules/identity/customers/types/customers.types.ts b/src/modules/identity/customers/types/customers.types.ts new file mode 100644 index 0000000..0ea364c --- /dev/null +++ b/src/modules/identity/customers/types/customers.types.ts @@ -0,0 +1,5 @@ +export interface CustomerProfile { + id: string; + email: string; + name: string; +} diff --git a/src/modules/identity/customers/types/index.ts b/src/modules/identity/customers/types/index.ts new file mode 100644 index 0000000..f3af2e7 --- /dev/null +++ b/src/modules/identity/customers/types/index.ts @@ -0,0 +1 @@ +export * from './customers.types'; diff --git a/src/modules/identity/teams/constants/index.ts b/src/modules/identity/teams/constants/index.ts new file mode 100644 index 0000000..d817c15 --- /dev/null +++ b/src/modules/identity/teams/constants/index.ts @@ -0,0 +1,3 @@ +export const TEAMS_CONSTANTS = { + MODULE_NAME: 'IDENTITY_TEAMS', +} as const; diff --git a/src/modules/identity/teams/controller/index.ts b/src/modules/identity/teams/controller/index.ts new file mode 100644 index 0000000..bd9072e --- /dev/null +++ b/src/modules/identity/teams/controller/index.ts @@ -0,0 +1 @@ +export * from './teams.controller'; diff --git a/src/modules/identity/teams/controller/teams.controller.ts b/src/modules/identity/teams/controller/teams.controller.ts new file mode 100644 index 0000000..646e17b --- /dev/null +++ b/src/modules/identity/teams/controller/teams.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { teamsService, TeamsService } from '../service'; + +export class TeamsController { + constructor(private readonly service: TeamsService = teamsService) {} + + async getTeams(_request: FastifyRequest, reply: FastifyReply) { + const teams = await this.service.listTeams(); + return reply.status(200).send({ + success: true, + data: teams, + meta: null, + }); + } +} + +export const teamsController = new TeamsController(); diff --git a/src/modules/identity/teams/index.ts b/src/modules/identity/teams/index.ts new file mode 100644 index 0000000..d0fa9d5 --- /dev/null +++ b/src/modules/identity/teams/index.ts @@ -0,0 +1,3 @@ +export { teamsRoutes } from './routes'; +export { TeamsService, teamsService } from './service'; +export type { TeamProfile } from './types'; diff --git a/src/modules/identity/teams/mapper/index.ts b/src/modules/identity/teams/mapper/index.ts new file mode 100644 index 0000000..74d16c4 --- /dev/null +++ b/src/modules/identity/teams/mapper/index.ts @@ -0,0 +1,5 @@ +export class TeamMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/identity/teams/repository/index.ts b/src/modules/identity/teams/repository/index.ts new file mode 100644 index 0000000..b42324f --- /dev/null +++ b/src/modules/identity/teams/repository/index.ts @@ -0,0 +1 @@ +export * from './teams.repository'; diff --git a/src/modules/identity/teams/repository/teams.repository.ts b/src/modules/identity/teams/repository/teams.repository.ts new file mode 100644 index 0000000..728cf65 --- /dev/null +++ b/src/modules/identity/teams/repository/teams.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class TeamsRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAllTeams(): Promise { + return []; + } +} + +export const teamsRepository = new TeamsRepository(); diff --git a/src/modules/identity/teams/routes/index.ts b/src/modules/identity/teams/routes/index.ts new file mode 100644 index 0000000..44df8f8 --- /dev/null +++ b/src/modules/identity/teams/routes/index.ts @@ -0,0 +1 @@ +export * from './teams.routes'; diff --git a/src/modules/identity/teams/routes/teams.routes.ts b/src/modules/identity/teams/routes/teams.routes.ts new file mode 100644 index 0000000..deb6495 --- /dev/null +++ b/src/modules/identity/teams/routes/teams.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { teamsController } from '../controller'; + +export async function teamsRoutes(fastify: FastifyInstance): Promise { + fastify.get('/teams', (req, reply) => teamsController.getTeams(req, reply)); +} diff --git a/src/modules/identity/teams/schema/index.ts b/src/modules/identity/teams/schema/index.ts new file mode 100644 index 0000000..a9e58cd --- /dev/null +++ b/src/modules/identity/teams/schema/index.ts @@ -0,0 +1 @@ +export * from './teams.schema'; diff --git a/src/modules/identity/teams/schema/teams.schema.ts b/src/modules/identity/teams/schema/teams.schema.ts new file mode 100644 index 0000000..d2036f1 --- /dev/null +++ b/src/modules/identity/teams/schema/teams.schema.ts @@ -0,0 +1,6 @@ +import { z } from 'zod'; + +export const teamQuerySchema = z.object({ + page: z.coerce.number().optional(), + limit: z.coerce.number().optional(), +}); diff --git a/src/modules/identity/teams/service/index.ts b/src/modules/identity/teams/service/index.ts new file mode 100644 index 0000000..8849608 --- /dev/null +++ b/src/modules/identity/teams/service/index.ts @@ -0,0 +1 @@ +export * from './teams.service'; diff --git a/src/modules/identity/teams/service/teams.service.ts b/src/modules/identity/teams/service/teams.service.ts new file mode 100644 index 0000000..689b51b --- /dev/null +++ b/src/modules/identity/teams/service/teams.service.ts @@ -0,0 +1,11 @@ +import { teamsRepository, TeamsRepository } from '../repository'; + +export class TeamsService { + constructor(private readonly repo: TeamsRepository = teamsRepository) {} + + async listTeams(): Promise { + return this.repo.findAllTeams(); + } +} + +export const teamsService = new TeamsService(); diff --git a/src/modules/identity/teams/types/index.ts b/src/modules/identity/teams/types/index.ts new file mode 100644 index 0000000..bcc1cc8 --- /dev/null +++ b/src/modules/identity/teams/types/index.ts @@ -0,0 +1 @@ +export * from './teams.types'; diff --git a/src/modules/identity/teams/types/teams.types.ts b/src/modules/identity/teams/types/teams.types.ts new file mode 100644 index 0000000..c848dce --- /dev/null +++ b/src/modules/identity/teams/types/teams.types.ts @@ -0,0 +1,4 @@ +export interface TeamProfile { + id: string; + name: string; +} diff --git a/src/modules/orchestration/assignments/calculators/workload.calculator.ts b/src/modules/orchestration/assignments/calculators/workload.calculator.ts new file mode 100644 index 0000000..fa77969 --- /dev/null +++ b/src/modules/orchestration/assignments/calculators/workload.calculator.ts @@ -0,0 +1,7 @@ +export class WorkloadCalculator { + async calculateAgentLoad(_agentId: string): Promise { + return 0; + } +} + +export const workloadCalculator = new WorkloadCalculator(); diff --git a/src/modules/orchestration/assignments/engine/assignment.engine.ts b/src/modules/orchestration/assignments/engine/assignment.engine.ts new file mode 100644 index 0000000..3f5de07 --- /dev/null +++ b/src/modules/orchestration/assignments/engine/assignment.engine.ts @@ -0,0 +1,7 @@ +export class AssignmentEngine { + async evaluateAndAssign(_ticketId: string): Promise<{ assignedAgentId: string | null }> { + return { assignedAgentId: null }; + } +} + +export const assignmentEngine = new AssignmentEngine(); diff --git a/src/modules/orchestration/assignments/index.ts b/src/modules/orchestration/assignments/index.ts new file mode 100644 index 0000000..7f6ebcf --- /dev/null +++ b/src/modules/orchestration/assignments/index.ts @@ -0,0 +1,3 @@ +export * from './engine/assignment.engine'; +export * from './strategies/round-robin.strategy'; +export * from './calculators/workload.calculator'; diff --git a/src/modules/orchestration/assignments/rules/assignment.rules.ts b/src/modules/orchestration/assignments/rules/assignment.rules.ts new file mode 100644 index 0000000..248df1e --- /dev/null +++ b/src/modules/orchestration/assignments/rules/assignment.rules.ts @@ -0,0 +1,5 @@ +export interface AssignmentRule { + id: string; + name: string; + enabled: boolean; +} diff --git a/src/modules/orchestration/assignments/strategies/round-robin.strategy.ts b/src/modules/orchestration/assignments/strategies/round-robin.strategy.ts new file mode 100644 index 0000000..57f1b80 --- /dev/null +++ b/src/modules/orchestration/assignments/strategies/round-robin.strategy.ts @@ -0,0 +1,7 @@ +export class RoundRobinAssignmentStrategy { + async selectNextAgent(_candidateIds: string[]): Promise { + return _candidateIds[0] || null; + } +} + +export const roundRobinAssignmentStrategy = new RoundRobinAssignmentStrategy(); diff --git a/src/modules/orchestration/escalation/engine/escalation.engine.ts b/src/modules/orchestration/escalation/engine/escalation.engine.ts new file mode 100644 index 0000000..91e2268 --- /dev/null +++ b/src/modules/orchestration/escalation/engine/escalation.engine.ts @@ -0,0 +1,7 @@ +export class EscalationEngine { + async triggerEscalation(_ticketId: string): Promise<{ escalated: boolean }> { + return { escalated: false }; + } +} + +export const escalationEngine = new EscalationEngine(); diff --git a/src/modules/orchestration/escalation/index.ts b/src/modules/orchestration/escalation/index.ts new file mode 100644 index 0000000..2ab5eb9 --- /dev/null +++ b/src/modules/orchestration/escalation/index.ts @@ -0,0 +1 @@ +export * from './engine/escalation.engine'; diff --git a/src/modules/orchestration/hierarchy/index.ts b/src/modules/orchestration/hierarchy/index.ts new file mode 100644 index 0000000..1db6d65 --- /dev/null +++ b/src/modules/orchestration/hierarchy/index.ts @@ -0,0 +1,11 @@ +export const HIERARCHY_CONSTANTS = { + MODULE_NAME: 'ORCHESTRATION_HIERARCHY', +} as const; + +export class HierarchyService { + async getHierarchyTree() { + return []; + } +} + +export const hierarchyService = new HierarchyService(); diff --git a/src/modules/orchestration/orchestration/index.ts b/src/modules/orchestration/orchestration/index.ts new file mode 100644 index 0000000..153116f --- /dev/null +++ b/src/modules/orchestration/orchestration/index.ts @@ -0,0 +1,11 @@ +export const ORCHESTRATION_CONSTANTS = { + MODULE_NAME: 'ORCHESTRATION_ENGINE', +} as const; + +export class OrchestrationService { + async orchestrateWorkflow(_event: string) { + return { status: 'HANDLED' }; + } +} + +export const orchestrationService = new OrchestrationService(); diff --git a/src/modules/orchestration/routing/index.ts b/src/modules/orchestration/routing/index.ts new file mode 100644 index 0000000..5000f5a --- /dev/null +++ b/src/modules/orchestration/routing/index.ts @@ -0,0 +1,11 @@ +export const ROUTING_CONSTANTS = { + MODULE_NAME: 'ORCHESTRATION_ROUTING', +} as const; + +export class RoutingService { + async routeTicket(_ticketId: string) { + return { targetTeamId: null }; + } +} + +export const routingService = new RoutingService(); diff --git a/src/modules/orchestration/sla/calculators/sla-due-date.calculator.ts b/src/modules/orchestration/sla/calculators/sla-due-date.calculator.ts new file mode 100644 index 0000000..9f803c0 --- /dev/null +++ b/src/modules/orchestration/sla/calculators/sla-due-date.calculator.ts @@ -0,0 +1,7 @@ +export class SlaDueDateCalculator { + calculateDueTime(createdDate: Date, targetHours: number): Date { + return new Date(createdDate.getTime() + targetHours * 3600 * 1000); + } +} + +export const slaDueDateCalculator = new SlaDueDateCalculator(); diff --git a/src/modules/orchestration/sla/engine/sla.engine.ts b/src/modules/orchestration/sla/engine/sla.engine.ts new file mode 100644 index 0000000..00ad950 --- /dev/null +++ b/src/modules/orchestration/sla/engine/sla.engine.ts @@ -0,0 +1,7 @@ +export class SlaEngine { + async evaluateSlaTargets(_ticketId: string): Promise> { + return { status: 'NORMAL' }; + } +} + +export const slaEngine = new SlaEngine(); diff --git a/src/modules/orchestration/sla/index.ts b/src/modules/orchestration/sla/index.ts new file mode 100644 index 0000000..1d83c5b --- /dev/null +++ b/src/modules/orchestration/sla/index.ts @@ -0,0 +1,2 @@ +export * from './engine/sla.engine'; +export * from './calculators/sla-due-date.calculator'; diff --git a/src/modules/platform/admin/index.ts b/src/modules/platform/admin/index.ts new file mode 100644 index 0000000..6882c55 --- /dev/null +++ b/src/modules/platform/admin/index.ts @@ -0,0 +1,11 @@ +export const ADMIN_CONSTANTS = { + MODULE_NAME: 'PLATFORM_ADMIN', +} as const; + +export class AdminService { + async getSystemSettings(): Promise> { + return {}; + } +} + +export const adminService = new AdminService(); diff --git a/src/modules/platform/audit/index.ts b/src/modules/platform/audit/index.ts new file mode 100644 index 0000000..084f82f --- /dev/null +++ b/src/modules/platform/audit/index.ts @@ -0,0 +1,11 @@ +export const AUDIT_CONSTANTS = { + MODULE_NAME: 'PLATFORM_AUDIT', +} as const; + +export class AuditService { + async recordLog(_action: string, _resource: string, _payload?: unknown): Promise { + // Audit logging service skeleton + } +} + +export const auditService = new AuditService(); diff --git a/src/modules/platform/business-calendars/index.ts b/src/modules/platform/business-calendars/index.ts new file mode 100644 index 0000000..16084e6 --- /dev/null +++ b/src/modules/platform/business-calendars/index.ts @@ -0,0 +1,11 @@ +export const BUSINESS_CALENDARS_CONSTANTS = { + MODULE_NAME: 'PLATFORM_BUSINESS_CALENDARS', +} as const; + +export class BusinessCalendarsService { + async isWorkingHour(_date: Date): Promise { + return true; + } +} + +export const businessCalendarsService = new BusinessCalendarsService(); diff --git a/src/modules/platform/integrations/index.ts b/src/modules/platform/integrations/index.ts new file mode 100644 index 0000000..227912a --- /dev/null +++ b/src/modules/platform/integrations/index.ts @@ -0,0 +1,9 @@ +export const INTEGRATIONS_CONSTANTS = { + MODULE_NAME: 'PLATFORM_INTEGRATIONS', +} as const; + +export class IntegrationsService { + async triggerWebhook(_event: string, _data: unknown): Promise {} +} + +export const integrationsService = new IntegrationsService(); diff --git a/src/modules/platform/notifications/index.ts b/src/modules/platform/notifications/index.ts new file mode 100644 index 0000000..e7897fa --- /dev/null +++ b/src/modules/platform/notifications/index.ts @@ -0,0 +1,11 @@ +export const NOTIFICATIONS_CONSTANTS = { + MODULE_NAME: 'PLATFORM_NOTIFICATIONS', +} as const; + +export class NotificationsService { + async sendNotification(_userId: string, _message: string): Promise { + return true; + } +} + +export const notificationsService = new NotificationsService(); diff --git a/src/modules/platform/reports/index.ts b/src/modules/platform/reports/index.ts new file mode 100644 index 0000000..c0e435d --- /dev/null +++ b/src/modules/platform/reports/index.ts @@ -0,0 +1,11 @@ +export const REPORTS_CONSTANTS = { + MODULE_NAME: 'PLATFORM_REPORTS', +} as const; + +export class ReportsService { + async generateSummaryReport(): Promise> { + return {}; + } +} + +export const reportsService = new ReportsService(); diff --git a/src/modules/problem-management/investigation/index.ts b/src/modules/problem-management/investigation/index.ts new file mode 100644 index 0000000..fba3b7b --- /dev/null +++ b/src/modules/problem-management/investigation/index.ts @@ -0,0 +1,11 @@ +export const INVESTIGATION_CONSTANTS = { + MODULE_NAME: 'PROBLEM_INVESTIGATION', +} as const; + +export class InvestigationService { + async getInvestigationStatus(_problemId: string) { + return { status: 'PENDING' }; + } +} + +export const investigationService = new InvestigationService(); diff --git a/src/modules/problem-management/problems/constants/index.ts b/src/modules/problem-management/problems/constants/index.ts new file mode 100644 index 0000000..b6c52b0 --- /dev/null +++ b/src/modules/problem-management/problems/constants/index.ts @@ -0,0 +1,3 @@ +export const PROBLEMS_CONSTANTS = { + MODULE_NAME: 'PROBLEM_MANAGEMENT_PROBLEMS', +} as const; diff --git a/src/modules/problem-management/problems/controller/index.ts b/src/modules/problem-management/problems/controller/index.ts new file mode 100644 index 0000000..aaec09f --- /dev/null +++ b/src/modules/problem-management/problems/controller/index.ts @@ -0,0 +1 @@ +export * from './problems.controller'; diff --git a/src/modules/problem-management/problems/controller/problems.controller.ts b/src/modules/problem-management/problems/controller/problems.controller.ts new file mode 100644 index 0000000..10587f9 --- /dev/null +++ b/src/modules/problem-management/problems/controller/problems.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { problemsService, ProblemsService } from '../service'; + +export class ProblemsController { + constructor(private readonly service: ProblemsService = problemsService) {} + + async getProblems(_request: FastifyRequest, reply: FastifyReply) { + const problems = await this.service.listProblems(); + return reply.status(200).send({ + success: true, + data: problems, + meta: null, + }); + } +} + +export const problemsController = new ProblemsController(); diff --git a/src/modules/problem-management/problems/index.ts b/src/modules/problem-management/problems/index.ts new file mode 100644 index 0000000..e350693 --- /dev/null +++ b/src/modules/problem-management/problems/index.ts @@ -0,0 +1,3 @@ +export { problemsRoutes } from './routes'; +export { ProblemsService, problemsService } from './service'; +export type { ProblemDTO } from './types'; diff --git a/src/modules/problem-management/problems/mapper/index.ts b/src/modules/problem-management/problems/mapper/index.ts new file mode 100644 index 0000000..8bd54ff --- /dev/null +++ b/src/modules/problem-management/problems/mapper/index.ts @@ -0,0 +1,5 @@ +export class ProblemMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/problem-management/problems/repository/index.ts b/src/modules/problem-management/problems/repository/index.ts new file mode 100644 index 0000000..24692c1 --- /dev/null +++ b/src/modules/problem-management/problems/repository/index.ts @@ -0,0 +1 @@ +export * from './problems.repository'; diff --git a/src/modules/problem-management/problems/repository/problems.repository.ts b/src/modules/problem-management/problems/repository/problems.repository.ts new file mode 100644 index 0000000..e28957b --- /dev/null +++ b/src/modules/problem-management/problems/repository/problems.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class ProblemsRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAll(): Promise { + return []; + } +} + +export const problemsRepository = new ProblemsRepository(); diff --git a/src/modules/problem-management/problems/routes/index.ts b/src/modules/problem-management/problems/routes/index.ts new file mode 100644 index 0000000..b52819c --- /dev/null +++ b/src/modules/problem-management/problems/routes/index.ts @@ -0,0 +1 @@ +export * from './problems.routes'; diff --git a/src/modules/problem-management/problems/routes/problems.routes.ts b/src/modules/problem-management/problems/routes/problems.routes.ts new file mode 100644 index 0000000..f496977 --- /dev/null +++ b/src/modules/problem-management/problems/routes/problems.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { problemsController } from '../controller'; + +export async function problemsRoutes(fastify: FastifyInstance): Promise { + fastify.get('/problems', (req, reply) => problemsController.getProblems(req, reply)); +} diff --git a/src/modules/problem-management/problems/schema/index.ts b/src/modules/problem-management/problems/schema/index.ts new file mode 100644 index 0000000..a2ec7fb --- /dev/null +++ b/src/modules/problem-management/problems/schema/index.ts @@ -0,0 +1 @@ +export * from './problems.schema'; diff --git a/src/modules/problem-management/problems/schema/problems.schema.ts b/src/modules/problem-management/problems/schema/problems.schema.ts new file mode 100644 index 0000000..05e8e4c --- /dev/null +++ b/src/modules/problem-management/problems/schema/problems.schema.ts @@ -0,0 +1,5 @@ +import { z } from 'zod'; + +export const problemQuerySchema = z.object({ + status: z.string().optional(), +}); diff --git a/src/modules/problem-management/problems/service/index.ts b/src/modules/problem-management/problems/service/index.ts new file mode 100644 index 0000000..9b6f5f2 --- /dev/null +++ b/src/modules/problem-management/problems/service/index.ts @@ -0,0 +1 @@ +export * from './problems.service'; diff --git a/src/modules/problem-management/problems/service/problems.service.ts b/src/modules/problem-management/problems/service/problems.service.ts new file mode 100644 index 0000000..b4a90eb --- /dev/null +++ b/src/modules/problem-management/problems/service/problems.service.ts @@ -0,0 +1,11 @@ +import { problemsRepository, ProblemsRepository } from '../repository'; + +export class ProblemsService { + constructor(private readonly repo: ProblemsRepository = problemsRepository) {} + + async listProblems(): Promise { + return this.repo.findAll(); + } +} + +export const problemsService = new ProblemsService(); diff --git a/src/modules/problem-management/problems/types/index.ts b/src/modules/problem-management/problems/types/index.ts new file mode 100644 index 0000000..6ff8655 --- /dev/null +++ b/src/modules/problem-management/problems/types/index.ts @@ -0,0 +1 @@ +export * from './problems.types'; diff --git a/src/modules/problem-management/problems/types/problems.types.ts b/src/modules/problem-management/problems/types/problems.types.ts new file mode 100644 index 0000000..bae4298 --- /dev/null +++ b/src/modules/problem-management/problems/types/problems.types.ts @@ -0,0 +1,6 @@ +export interface ProblemDTO { + id: string; + title: string; + description: string; + status: string; +} diff --git a/src/modules/problem-management/resolutions/index.ts b/src/modules/problem-management/resolutions/index.ts new file mode 100644 index 0000000..a69c170 --- /dev/null +++ b/src/modules/problem-management/resolutions/index.ts @@ -0,0 +1,11 @@ +export const RESOLUTIONS_CONSTANTS = { + MODULE_NAME: 'PROBLEM_RESOLUTIONS', +} as const; + +export class ResolutionsService { + async getResolutions(_problemId: string) { + return []; + } +} + +export const resolutionsService = new ResolutionsService(); diff --git a/src/modules/problem-management/root-causes/index.ts b/src/modules/problem-management/root-causes/index.ts new file mode 100644 index 0000000..1937634 --- /dev/null +++ b/src/modules/problem-management/root-causes/index.ts @@ -0,0 +1,11 @@ +export const ROOT_CAUSES_CONSTANTS = { + MODULE_NAME: 'PROBLEM_ROOT_CAUSES', +} as const; + +export class RootCausesService { + async getRootCause(_problemId: string) { + return null; + } +} + +export const rootCausesService = new RootCausesService(); diff --git a/src/modules/problem-management/solutions/index.ts b/src/modules/problem-management/solutions/index.ts new file mode 100644 index 0000000..a700550 --- /dev/null +++ b/src/modules/problem-management/solutions/index.ts @@ -0,0 +1,11 @@ +export const SOLUTIONS_CONSTANTS = { + MODULE_NAME: 'PROBLEM_SOLUTIONS', +} as const; + +export class SolutionsService { + async getSolutions(_problemId: string) { + return []; + } +} + +export const solutionsService = new SolutionsService(); diff --git a/src/modules/problem-management/verification/index.ts b/src/modules/problem-management/verification/index.ts new file mode 100644 index 0000000..12e843e --- /dev/null +++ b/src/modules/problem-management/verification/index.ts @@ -0,0 +1,11 @@ +export const VERIFICATION_CONSTANTS = { + MODULE_NAME: 'PROBLEM_VERIFICATION', +} as const; + +export class VerificationService { + async verifySolution(_solutionId: string) { + return { verified: false }; + } +} + +export const verificationService = new VerificationService(); diff --git a/src/modules/ticketing/attachments/constants/index.ts b/src/modules/ticketing/attachments/constants/index.ts new file mode 100644 index 0000000..1dc6e0a --- /dev/null +++ b/src/modules/ticketing/attachments/constants/index.ts @@ -0,0 +1,3 @@ +export const ATTACHMENTS_CONSTANTS = { + MODULE_NAME: 'TICKETING_ATTACHMENTS', +} as const; diff --git a/src/modules/ticketing/attachments/controller/attachments.controller.ts b/src/modules/ticketing/attachments/controller/attachments.controller.ts new file mode 100644 index 0000000..49592cf --- /dev/null +++ b/src/modules/ticketing/attachments/controller/attachments.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { attachmentsService, AttachmentsService } from '../service'; + +export class AttachmentsController { + constructor(private readonly service: AttachmentsService = attachmentsService) {} + + async getAttachments(_request: FastifyRequest, reply: FastifyReply) { + const attachments = await this.service.listAttachments(); + return reply.status(200).send({ + success: true, + data: attachments, + meta: null, + }); + } +} + +export const attachmentsController = new AttachmentsController(); diff --git a/src/modules/ticketing/attachments/controller/index.ts b/src/modules/ticketing/attachments/controller/index.ts new file mode 100644 index 0000000..49cdb01 --- /dev/null +++ b/src/modules/ticketing/attachments/controller/index.ts @@ -0,0 +1 @@ +export * from './attachments.controller'; diff --git a/src/modules/ticketing/attachments/index.ts b/src/modules/ticketing/attachments/index.ts new file mode 100644 index 0000000..294617b --- /dev/null +++ b/src/modules/ticketing/attachments/index.ts @@ -0,0 +1,3 @@ +export { attachmentsRoutes } from './routes'; +export { AttachmentsService, attachmentsService } from './service'; +export type { AttachmentDTO } from './types'; diff --git a/src/modules/ticketing/attachments/mapper/index.ts b/src/modules/ticketing/attachments/mapper/index.ts new file mode 100644 index 0000000..786e92c --- /dev/null +++ b/src/modules/ticketing/attachments/mapper/index.ts @@ -0,0 +1,5 @@ +export class AttachmentMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/ticketing/attachments/repository/attachments.repository.ts b/src/modules/ticketing/attachments/repository/attachments.repository.ts new file mode 100644 index 0000000..3b55117 --- /dev/null +++ b/src/modules/ticketing/attachments/repository/attachments.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class AttachmentsRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAll(): Promise { + return []; + } +} + +export const attachmentsRepository = new AttachmentsRepository(); diff --git a/src/modules/ticketing/attachments/repository/index.ts b/src/modules/ticketing/attachments/repository/index.ts new file mode 100644 index 0000000..ab33aec --- /dev/null +++ b/src/modules/ticketing/attachments/repository/index.ts @@ -0,0 +1 @@ +export * from './attachments.repository'; diff --git a/src/modules/ticketing/attachments/routes/attachments.routes.ts b/src/modules/ticketing/attachments/routes/attachments.routes.ts new file mode 100644 index 0000000..8433f33 --- /dev/null +++ b/src/modules/ticketing/attachments/routes/attachments.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { attachmentsController } from '../controller'; + +export async function attachmentsRoutes(fastify: FastifyInstance): Promise { + fastify.get('/attachments', (req, reply) => attachmentsController.getAttachments(req, reply)); +} diff --git a/src/modules/ticketing/attachments/routes/index.ts b/src/modules/ticketing/attachments/routes/index.ts new file mode 100644 index 0000000..a4d84c3 --- /dev/null +++ b/src/modules/ticketing/attachments/routes/index.ts @@ -0,0 +1 @@ +export * from './attachments.routes'; diff --git a/src/modules/ticketing/attachments/schema/attachments.schema.ts b/src/modules/ticketing/attachments/schema/attachments.schema.ts new file mode 100644 index 0000000..92db91c --- /dev/null +++ b/src/modules/ticketing/attachments/schema/attachments.schema.ts @@ -0,0 +1,5 @@ +import { z } from 'zod'; + +export const attachmentQuerySchema = z.object({ + ticketId: z.string().uuid().optional(), +}); diff --git a/src/modules/ticketing/attachments/schema/index.ts b/src/modules/ticketing/attachments/schema/index.ts new file mode 100644 index 0000000..41101ae --- /dev/null +++ b/src/modules/ticketing/attachments/schema/index.ts @@ -0,0 +1 @@ +export * from './attachments.schema'; diff --git a/src/modules/ticketing/attachments/service/attachments.service.ts b/src/modules/ticketing/attachments/service/attachments.service.ts new file mode 100644 index 0000000..d26f765 --- /dev/null +++ b/src/modules/ticketing/attachments/service/attachments.service.ts @@ -0,0 +1,11 @@ +import { attachmentsRepository, AttachmentsRepository } from '../repository'; + +export class AttachmentsService { + constructor(private readonly repo: AttachmentsRepository = attachmentsRepository) {} + + async listAttachments(): Promise { + return this.repo.findAll(); + } +} + +export const attachmentsService = new AttachmentsService(); diff --git a/src/modules/ticketing/attachments/service/index.ts b/src/modules/ticketing/attachments/service/index.ts new file mode 100644 index 0000000..50786c3 --- /dev/null +++ b/src/modules/ticketing/attachments/service/index.ts @@ -0,0 +1 @@ +export * from './attachments.service'; diff --git a/src/modules/ticketing/attachments/types/attachments.types.ts b/src/modules/ticketing/attachments/types/attachments.types.ts new file mode 100644 index 0000000..43fe289 --- /dev/null +++ b/src/modules/ticketing/attachments/types/attachments.types.ts @@ -0,0 +1,6 @@ +export interface AttachmentDTO { + id: string; + filename: string; + size: number; + mimeType: string; +} diff --git a/src/modules/ticketing/attachments/types/index.ts b/src/modules/ticketing/attachments/types/index.ts new file mode 100644 index 0000000..c2994fd --- /dev/null +++ b/src/modules/ticketing/attachments/types/index.ts @@ -0,0 +1 @@ +export * from './attachments.types'; diff --git a/src/modules/ticketing/messages/constants/index.ts b/src/modules/ticketing/messages/constants/index.ts new file mode 100644 index 0000000..c805460 --- /dev/null +++ b/src/modules/ticketing/messages/constants/index.ts @@ -0,0 +1,3 @@ +export const MESSAGES_CONSTANTS = { + MODULE_NAME: 'TICKETING_MESSAGES', +} as const; diff --git a/src/modules/ticketing/messages/controller/index.ts b/src/modules/ticketing/messages/controller/index.ts new file mode 100644 index 0000000..abc3b46 --- /dev/null +++ b/src/modules/ticketing/messages/controller/index.ts @@ -0,0 +1 @@ +export * from './messages.controller'; diff --git a/src/modules/ticketing/messages/controller/messages.controller.ts b/src/modules/ticketing/messages/controller/messages.controller.ts new file mode 100644 index 0000000..3eb1863 --- /dev/null +++ b/src/modules/ticketing/messages/controller/messages.controller.ts @@ -0,0 +1,20 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { messagesService, MessagesService } from '../service'; + +export class MessagesController { + constructor(private readonly service: MessagesService = messagesService) {} + + async getMessages( + request: FastifyRequest<{ Params: { ticketId: string } }>, + reply: FastifyReply, + ) { + const messages = await this.service.getMessages(request.params.ticketId); + return reply.status(200).send({ + success: true, + data: messages, + meta: null, + }); + } +} + +export const messagesController = new MessagesController(); diff --git a/src/modules/ticketing/messages/index.ts b/src/modules/ticketing/messages/index.ts new file mode 100644 index 0000000..e5a78af --- /dev/null +++ b/src/modules/ticketing/messages/index.ts @@ -0,0 +1,3 @@ +export { messagesRoutes } from './routes'; +export { MessagesService, messagesService } from './service'; +export type { MessageDTO } from './types'; diff --git a/src/modules/ticketing/messages/mapper/index.ts b/src/modules/ticketing/messages/mapper/index.ts new file mode 100644 index 0000000..d97084e --- /dev/null +++ b/src/modules/ticketing/messages/mapper/index.ts @@ -0,0 +1,5 @@ +export class MessageMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/ticketing/messages/repository/index.ts b/src/modules/ticketing/messages/repository/index.ts new file mode 100644 index 0000000..5d2e136 --- /dev/null +++ b/src/modules/ticketing/messages/repository/index.ts @@ -0,0 +1 @@ +export * from './messages.repository'; diff --git a/src/modules/ticketing/messages/repository/messages.repository.ts b/src/modules/ticketing/messages/repository/messages.repository.ts new file mode 100644 index 0000000..7eeba6d --- /dev/null +++ b/src/modules/ticketing/messages/repository/messages.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class MessagesRepository { + constructor(private readonly prisma = prismaClient) {} + + async findByTicketId(_ticketId: string): Promise { + return []; + } +} + +export const messagesRepository = new MessagesRepository(); diff --git a/src/modules/ticketing/messages/routes/index.ts b/src/modules/ticketing/messages/routes/index.ts new file mode 100644 index 0000000..7bef5d9 --- /dev/null +++ b/src/modules/ticketing/messages/routes/index.ts @@ -0,0 +1 @@ +export * from './messages.routes'; diff --git a/src/modules/ticketing/messages/routes/messages.routes.ts b/src/modules/ticketing/messages/routes/messages.routes.ts new file mode 100644 index 0000000..9ef2459 --- /dev/null +++ b/src/modules/ticketing/messages/routes/messages.routes.ts @@ -0,0 +1,10 @@ +import { FastifyInstance, FastifyRequest } from 'fastify'; +import { messagesController } from '../controller'; + +export async function messagesRoutes(fastify: FastifyInstance): Promise { + fastify.get( + '/tickets/:ticketId/messages', + (req: FastifyRequest<{ Params: { ticketId: string } }>, reply) => + messagesController.getMessages(req, reply), + ); +} diff --git a/src/modules/ticketing/messages/schema/index.ts b/src/modules/ticketing/messages/schema/index.ts new file mode 100644 index 0000000..9e34c13 --- /dev/null +++ b/src/modules/ticketing/messages/schema/index.ts @@ -0,0 +1 @@ +export * from './messages.schema'; diff --git a/src/modules/ticketing/messages/schema/messages.schema.ts b/src/modules/ticketing/messages/schema/messages.schema.ts new file mode 100644 index 0000000..6be816b --- /dev/null +++ b/src/modules/ticketing/messages/schema/messages.schema.ts @@ -0,0 +1,6 @@ +import { z } from 'zod'; + +export const createMessageSchema = z.object({ + ticketId: z.string().uuid(), + content: z.string().min(1), +}); diff --git a/src/modules/ticketing/messages/service/index.ts b/src/modules/ticketing/messages/service/index.ts new file mode 100644 index 0000000..e86e2e5 --- /dev/null +++ b/src/modules/ticketing/messages/service/index.ts @@ -0,0 +1 @@ +export * from './messages.service'; diff --git a/src/modules/ticketing/messages/service/messages.service.ts b/src/modules/ticketing/messages/service/messages.service.ts new file mode 100644 index 0000000..3d93e84 --- /dev/null +++ b/src/modules/ticketing/messages/service/messages.service.ts @@ -0,0 +1,11 @@ +import { messagesRepository, MessagesRepository } from '../repository'; + +export class MessagesService { + constructor(private readonly repo: MessagesRepository = messagesRepository) {} + + async getMessages(ticketId: string): Promise { + return this.repo.findByTicketId(ticketId); + } +} + +export const messagesService = new MessagesService(); diff --git a/src/modules/ticketing/messages/types/index.ts b/src/modules/ticketing/messages/types/index.ts new file mode 100644 index 0000000..764de36 --- /dev/null +++ b/src/modules/ticketing/messages/types/index.ts @@ -0,0 +1 @@ +export * from './messages.types'; diff --git a/src/modules/ticketing/messages/types/messages.types.ts b/src/modules/ticketing/messages/types/messages.types.ts new file mode 100644 index 0000000..5d3d706 --- /dev/null +++ b/src/modules/ticketing/messages/types/messages.types.ts @@ -0,0 +1,6 @@ +export interface MessageDTO { + id: string; + ticketId: string; + content: string; + senderId: string; +} diff --git a/src/modules/ticketing/tickets/constants/index.ts b/src/modules/ticketing/tickets/constants/index.ts new file mode 100644 index 0000000..6246568 --- /dev/null +++ b/src/modules/ticketing/tickets/constants/index.ts @@ -0,0 +1,3 @@ +export const TICKETS_CONSTANTS = { + MODULE_NAME: 'TICKETING_TICKETS', +} as const; diff --git a/src/modules/ticketing/tickets/controller/index.ts b/src/modules/ticketing/tickets/controller/index.ts new file mode 100644 index 0000000..6bbd779 --- /dev/null +++ b/src/modules/ticketing/tickets/controller/index.ts @@ -0,0 +1 @@ +export * from './tickets.controller'; diff --git a/src/modules/ticketing/tickets/controller/tickets.controller.ts b/src/modules/ticketing/tickets/controller/tickets.controller.ts new file mode 100644 index 0000000..620aa86 --- /dev/null +++ b/src/modules/ticketing/tickets/controller/tickets.controller.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { ticketsService, TicketsService } from '../service'; + +export class TicketsController { + constructor(private readonly service: TicketsService = ticketsService) {} + + async getTickets(_request: FastifyRequest, reply: FastifyReply) { + const tickets = await this.service.listTickets(); + return reply.status(200).send({ + success: true, + data: tickets, + meta: null, + }); + } +} + +export const ticketsController = new TicketsController(); diff --git a/src/modules/ticketing/tickets/index.ts b/src/modules/ticketing/tickets/index.ts new file mode 100644 index 0000000..62f2c9d --- /dev/null +++ b/src/modules/ticketing/tickets/index.ts @@ -0,0 +1,3 @@ +export { ticketsRoutes } from './routes'; +export { TicketsService, ticketsService } from './service'; +export type { CreateTicketInput, TicketFilters } from './types'; diff --git a/src/modules/ticketing/tickets/mapper/index.ts b/src/modules/ticketing/tickets/mapper/index.ts new file mode 100644 index 0000000..bd709e2 --- /dev/null +++ b/src/modules/ticketing/tickets/mapper/index.ts @@ -0,0 +1,5 @@ +export class TicketMapper { + static toDTO(data: T): T { + return data; + } +} diff --git a/src/modules/ticketing/tickets/repository/index.ts b/src/modules/ticketing/tickets/repository/index.ts new file mode 100644 index 0000000..3dc2f14 --- /dev/null +++ b/src/modules/ticketing/tickets/repository/index.ts @@ -0,0 +1 @@ +export * from './tickets.repository'; diff --git a/src/modules/ticketing/tickets/repository/tickets.repository.ts b/src/modules/ticketing/tickets/repository/tickets.repository.ts new file mode 100644 index 0000000..f67c7e7 --- /dev/null +++ b/src/modules/ticketing/tickets/repository/tickets.repository.ts @@ -0,0 +1,11 @@ +import { prismaClient } from '@/infrastructure/database'; + +export class TicketsRepository { + constructor(private readonly prisma = prismaClient) {} + + async findAll(): Promise { + return []; + } +} + +export const ticketsRepository = new TicketsRepository(); diff --git a/src/modules/ticketing/tickets/routes/index.ts b/src/modules/ticketing/tickets/routes/index.ts new file mode 100644 index 0000000..834f278 --- /dev/null +++ b/src/modules/ticketing/tickets/routes/index.ts @@ -0,0 +1 @@ +export * from './tickets.routes'; diff --git a/src/modules/ticketing/tickets/routes/tickets.routes.ts b/src/modules/ticketing/tickets/routes/tickets.routes.ts new file mode 100644 index 0000000..35a7514 --- /dev/null +++ b/src/modules/ticketing/tickets/routes/tickets.routes.ts @@ -0,0 +1,6 @@ +import { FastifyInstance } from 'fastify'; +import { ticketsController } from '../controller'; + +export async function ticketsRoutes(fastify: FastifyInstance): Promise { + fastify.get('/tickets', (req, reply) => ticketsController.getTickets(req, reply)); +} diff --git a/src/modules/ticketing/tickets/schema/index.ts b/src/modules/ticketing/tickets/schema/index.ts new file mode 100644 index 0000000..a6eb4f8 --- /dev/null +++ b/src/modules/ticketing/tickets/schema/index.ts @@ -0,0 +1 @@ +export * from './tickets.schema'; diff --git a/src/modules/ticketing/tickets/schema/tickets.schema.ts b/src/modules/ticketing/tickets/schema/tickets.schema.ts new file mode 100644 index 0000000..c35183d --- /dev/null +++ b/src/modules/ticketing/tickets/schema/tickets.schema.ts @@ -0,0 +1,8 @@ +import { z } from 'zod'; + +export const createTicketSchema = z.object({ + title: z.string().min(3), + description: z.string().min(5), + productId: z.string().uuid(), + categoryId: z.string().uuid().optional(), +}); diff --git a/src/modules/ticketing/tickets/service/index.ts b/src/modules/ticketing/tickets/service/index.ts new file mode 100644 index 0000000..50b48d9 --- /dev/null +++ b/src/modules/ticketing/tickets/service/index.ts @@ -0,0 +1 @@ +export * from './tickets.service'; diff --git a/src/modules/ticketing/tickets/service/tickets.service.ts b/src/modules/ticketing/tickets/service/tickets.service.ts new file mode 100644 index 0000000..9670d59 --- /dev/null +++ b/src/modules/ticketing/tickets/service/tickets.service.ts @@ -0,0 +1,11 @@ +import { ticketsRepository, TicketsRepository } from '../repository'; + +export class TicketsService { + constructor(private readonly repo: TicketsRepository = ticketsRepository) {} + + async listTickets(): Promise { + return this.repo.findAll(); + } +} + +export const ticketsService = new TicketsService(); diff --git a/src/modules/ticketing/tickets/types/index.ts b/src/modules/ticketing/tickets/types/index.ts new file mode 100644 index 0000000..9b0d2a0 --- /dev/null +++ b/src/modules/ticketing/tickets/types/index.ts @@ -0,0 +1 @@ +export * from './tickets.types'; diff --git a/src/modules/ticketing/tickets/types/tickets.types.ts b/src/modules/ticketing/tickets/types/tickets.types.ts new file mode 100644 index 0000000..d9f39fc --- /dev/null +++ b/src/modules/ticketing/tickets/types/tickets.types.ts @@ -0,0 +1,11 @@ +export interface CreateTicketInput { + title: string; + description: string; + productId: string; + categoryId?: string; +} + +export interface TicketFilters { + status?: string; + priority?: string; +} diff --git a/src/plugins/auth.plugin.ts b/src/plugins/auth.plugin.ts new file mode 100644 index 0000000..c1699df --- /dev/null +++ b/src/plugins/auth.plugin.ts @@ -0,0 +1,30 @@ +import { FastifyPluginAsync, FastifyRequest, FastifyReply } from 'fastify'; +import fp from 'fastify-plugin'; +import { AuthUser } from '@/common/types'; + +declare module 'fastify' { + interface FastifyRequest { + user?: AuthUser; + } + interface FastifyInstance { + authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise; + } +} + +const authPluginCallback: FastifyPluginAsync = async (fastify) => { + fastify.decorate( + 'authenticate', + async (request: FastifyRequest, _reply: FastifyReply): Promise => { + const authHeader = request.headers.authorization; + if (!authHeader) { + // Foundation auth: default context or optional pass + return; + } + // Stub for JWT verification foundation + }, + ); +}; + +export const authPlugin = fp(authPluginCallback, { + name: 'auth-plugin', +}); diff --git a/src/plugins/cors.plugin.ts b/src/plugins/cors.plugin.ts new file mode 100644 index 0000000..5cbec03 --- /dev/null +++ b/src/plugins/cors.plugin.ts @@ -0,0 +1,17 @@ +import { FastifyPluginAsync } from 'fastify'; +import fp from 'fastify-plugin'; +import fastifyCors from '@fastify/cors'; +import { env } from '@/config'; + +const corsPluginCallback: FastifyPluginAsync = async (fastify) => { + await fastify.register(fastifyCors, { + origin: env.CORS_ORIGINS, + methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization', 'x-request-id', 'x-correlation-id'], + credentials: true, + }); +}; + +export const corsPlugin = fp(corsPluginCallback, { + name: 'cors-plugin', +}); diff --git a/src/plugins/helmet.plugin.ts b/src/plugins/helmet.plugin.ts new file mode 100644 index 0000000..4f79859 --- /dev/null +++ b/src/plugins/helmet.plugin.ts @@ -0,0 +1,13 @@ +import { FastifyPluginAsync } from 'fastify'; +import fp from 'fastify-plugin'; +import fastifyHelmet from '@fastify/helmet'; + +const helmetPluginCallback: FastifyPluginAsync = async (fastify) => { + await fastify.register(fastifyHelmet, { + contentSecurityPolicy: false, // Turned off for Swagger UI compatibility + }); +}; + +export const helmetPlugin = fp(helmetPluginCallback, { + name: 'helmet-plugin', +}); diff --git a/src/plugins/index.ts b/src/plugins/index.ts new file mode 100644 index 0000000..f137e2f --- /dev/null +++ b/src/plugins/index.ts @@ -0,0 +1,7 @@ +export * from './prisma.plugin'; +export * from './auth.plugin'; +export * from './swagger.plugin'; +export * from './cors.plugin'; +export * from './helmet.plugin'; +export * from './rate-limit.plugin'; +export * from './request-context.plugin'; diff --git a/src/plugins/prisma.plugin.ts b/src/plugins/prisma.plugin.ts new file mode 100644 index 0000000..a7c67b5 --- /dev/null +++ b/src/plugins/prisma.plugin.ts @@ -0,0 +1,21 @@ +import { FastifyPluginAsync } from 'fastify'; +import fp from 'fastify-plugin'; +import { prismaClient } from '@/infrastructure/database'; + +declare module 'fastify' { + interface FastifyInstance { + prisma: typeof prismaClient; + } +} + +const prismaPluginCallback: FastifyPluginAsync = async (fastify) => { + fastify.decorate('prisma', prismaClient); + + fastify.addHook('onClose', async (instance) => { + await instance.prisma.$disconnect(); + }); +}; + +export const prismaPlugin = fp(prismaPluginCallback, { + name: 'prisma-plugin', +}); diff --git a/src/plugins/rate-limit.plugin.ts b/src/plugins/rate-limit.plugin.ts new file mode 100644 index 0000000..e6abd30 --- /dev/null +++ b/src/plugins/rate-limit.plugin.ts @@ -0,0 +1,14 @@ +import { FastifyPluginAsync } from 'fastify'; +import fp from 'fastify-plugin'; +import fastifyRateLimit from '@fastify/rate-limit'; + +const rateLimitPluginCallback: FastifyPluginAsync = async (fastify) => { + await fastify.register(fastifyRateLimit, { + max: 1000, + timeWindow: '1 minute', + }); +}; + +export const rateLimitPlugin = fp(rateLimitPluginCallback, { + name: 'rate-limit-plugin', +}); diff --git a/src/plugins/request-context.plugin.ts b/src/plugins/request-context.plugin.ts new file mode 100644 index 0000000..31e9e24 --- /dev/null +++ b/src/plugins/request-context.plugin.ts @@ -0,0 +1,33 @@ +import { FastifyPluginAsync, FastifyRequest } from 'fastify'; +import fp from 'fastify-plugin'; +import { generateUuid } from '@/common/utils'; +import { RequestContext } from '@/common/types'; +import { APP_CONSTANTS } from '@/common/constants'; + +declare module 'fastify' { + interface FastifyRequest { + reqContext: RequestContext; + } +} + +const requestContextPluginCallback: FastifyPluginAsync = async (fastify) => { + fastify.addHook('onRequest', async (request: FastifyRequest, reply) => { + const rawReqId = request.headers[APP_CONSTANTS.REQUEST_ID_HEADER]; + const rawCorrId = request.headers[APP_CONSTANTS.CORRELATION_HEADER]; + + const requestId = typeof rawReqId === 'string' ? rawReqId : generateUuid(); + const correlationId = typeof rawCorrId === 'string' ? rawCorrId : requestId; + + request.reqContext = { + requestId, + correlationId, + }; + + reply.header(APP_CONSTANTS.REQUEST_ID_HEADER, requestId); + reply.header(APP_CONSTANTS.CORRELATION_HEADER, correlationId); + }); +}; + +export const requestContextPlugin = fp(requestContextPluginCallback, { + name: 'request-context-plugin', +}); diff --git a/src/plugins/swagger.plugin.ts b/src/plugins/swagger.plugin.ts new file mode 100644 index 0000000..8b49550 --- /dev/null +++ b/src/plugins/swagger.plugin.ts @@ -0,0 +1,43 @@ +import { FastifyPluginAsync } from 'fastify'; +import fp from 'fastify-plugin'; +import fastifySwagger from '@fastify/swagger'; +import fastifySwaggerUi from '@fastify/swagger-ui'; + +const swaggerPluginCallback: FastifyPluginAsync = async (fastify) => { + await fastify.register(fastifySwagger, { + openapi: { + info: { + title: 'SupportHub Enterprise API', + description: 'Production Enterprise Modular Monolith OpenAPI Specification', + version: '1.0.0', + }, + servers: [ + { + url: 'http://localhost:3000', + description: 'Development Server', + }, + ], + components: { + securitySchemes: { + bearerAuth: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + }, + }, + }, + }, + }); + + await fastify.register(fastifySwaggerUi, { + routePrefix: '/docs', + uiConfig: { + docExpansion: 'list', + deepLinking: false, + }, + }); +}; + +export const swaggerPlugin = fp(swaggerPluginCallback, { + name: 'swagger-plugin', +}); diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..eba5109 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,45 @@ +import { buildApp } from './app'; +import { env } from '@/config'; +import { logger } from '@/infrastructure/observability'; +import { + bootstrapDatabase, + bootstrapRedis, + bootstrapQueue, + bootstrapStorage, + setupGracefulShutdown, +} from '@/bootstrap'; + +async function startServer(): Promise { + try { + logger.info('🚀 Bootstrapping SupportHub API Enterprise Modular Monolith...'); + + // Initialize Infrastructure Connections + await bootstrapDatabase(); + await bootstrapRedis(); + await bootstrapQueue(); + await bootstrapStorage(); + + // Create Fastify Instance + const app = await buildApp(); + + // Register Graceful Shutdown Processors + setupGracefulShutdown(app); + + // Listen on Configured Host and Port + const address = await app.listen({ + port: env.PORT, + host: env.HOST, + }); + + logger.info( + { port: env.PORT, host: env.HOST, env: env.NODE_ENV }, + `🟢 SupportHub API running at ${address}`, + ); + logger.info(`📚 Swagger OpenAPI documentation available at ${address}/docs`); + } catch (error) { + logger.error({ error }, '❌ Fatal error during server startup.'); + process.exit(1); + } +} + +startServer(); diff --git a/tests/concurrency/queue.test.ts b/tests/concurrency/queue.test.ts new file mode 100644 index 0000000..e9ee9cd --- /dev/null +++ b/tests/concurrency/queue.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from 'vitest'; +import { queueManager } from '@/infrastructure/queue'; + +describe('Queue Concurrency Baseline Test', () => { + it('should instantiate queue manager cleanly', () => { + expect(queueManager).toBeDefined(); + }); +}); diff --git a/tests/e2e/api.test.ts b/tests/e2e/api.test.ts new file mode 100644 index 0000000..fad1312 --- /dev/null +++ b/tests/e2e/api.test.ts @@ -0,0 +1,28 @@ +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { FastifyInstance } from 'fastify'; +import { buildApp } from '@/app'; + +describe('API End-to-End Baseline Test', () => { + let app: FastifyInstance; + + beforeAll(async () => { + app = await buildApp(); + }); + + afterAll(async () => { + await app.close(); + }); + + it('should return 404 formatted error on invalid route', async () => { + const response = await app.inject({ + method: 'GET', + url: '/invalid-unregistered-route-xyz', + }); + + expect(response.statusCode).toBe(404); + const body = JSON.parse(response.payload); + expect(body.success).toBe(false); + expect(body.error.code).toBe('NOT_FOUND'); + expect(body.requestId).toBeDefined(); + }); +}); diff --git a/tests/fixtures/sample-payloads.ts b/tests/fixtures/sample-payloads.ts new file mode 100644 index 0000000..d641b3e --- /dev/null +++ b/tests/fixtures/sample-payloads.ts @@ -0,0 +1,5 @@ +export const sampleTicketPayload = { + title: 'Sample Ticket for Unit Test', + description: 'Test description content', + productId: '11111111-1111-1111-1111-111111111111', +}; diff --git a/tests/integration/health.test.ts b/tests/integration/health.test.ts new file mode 100644 index 0000000..d005fee --- /dev/null +++ b/tests/integration/health.test.ts @@ -0,0 +1,36 @@ +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { FastifyInstance } from 'fastify'; +import { buildApp } from '@/app'; + +describe('Health Routes Integration Test', () => { + let app: FastifyInstance; + + beforeAll(async () => { + app = await buildApp(); + }); + + afterAll(async () => { + await app.close(); + }); + + it('GET /health/live should return 200 OK', async () => { + const response = await app.inject({ + method: 'GET', + url: '/health/live', + }); + + expect(response.statusCode).toBe(200); + const body = JSON.parse(response.payload); + expect(body.status).toBe('ok'); + }); + + it('GET /metrics should return Prometheus metrics format', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + expect(response.statusCode).toBe(200); + expect(response.payload).toContain('supporthub_'); + }); +}); diff --git a/tests/integration/prisma.test.ts b/tests/integration/prisma.test.ts new file mode 100644 index 0000000..1b8cd00 --- /dev/null +++ b/tests/integration/prisma.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from 'vitest'; +import { prismaClient } from '@/infrastructure/database'; + +describe('Prisma Connectivity Test', () => { + it('should instantiate Prisma client instance', () => { + expect(prismaClient).toBeDefined(); + }); +}); diff --git a/tests/integration/redis.test.ts b/tests/integration/redis.test.ts new file mode 100644 index 0000000..848b6c9 --- /dev/null +++ b/tests/integration/redis.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from 'vitest'; +import { cacheService } from '@/infrastructure/cache'; + +describe('Redis Cache Service Baseline Test', () => { + it('should instantiate cache service abstraction', () => { + expect(cacheService).toBeDefined(); + }); +}); diff --git a/tests/unit/app.test.ts b/tests/unit/app.test.ts new file mode 100644 index 0000000..d1d12f2 --- /dev/null +++ b/tests/unit/app.test.ts @@ -0,0 +1,10 @@ +import { describe, it, expect } from 'vitest'; +import { buildApp } from '@/app'; + +describe('App Factory Unit Test', () => { + it('should build Fastify application instance successfully', async () => { + const app = await buildApp(); + expect(app).toBeDefined(); + await app.close(); + }); +}); diff --git a/tests/unit/env.test.ts b/tests/unit/env.test.ts new file mode 100644 index 0000000..a39b176 --- /dev/null +++ b/tests/unit/env.test.ts @@ -0,0 +1,10 @@ +import { describe, it, expect } from 'vitest'; +import { env } from '@/config'; + +describe('Environment Configuration Unit Test', () => { + it('should load default environment variables cleanly', () => { + expect(env).toBeDefined(); + expect(env.PORT).toBeGreaterThan(0); + expect(env.DATABASE_URL).toBeDefined(); + }); +}); diff --git a/tests/unit/error.test.ts b/tests/unit/error.test.ts new file mode 100644 index 0000000..57e7d2c --- /dev/null +++ b/tests/unit/error.test.ts @@ -0,0 +1,23 @@ +import { describe, it, expect } from 'vitest'; +import { AppError, NotFoundError, ValidationError } from '@/common/errors'; + +describe('Error Model Unit Test', () => { + it('should instantiate AppError with correct properties', () => { + const err = new AppError('Test error message', 'TEST_CODE', 400); + expect(err.message).toBe('Test error message'); + expect(err.code).toBe('TEST_CODE'); + expect(err.statusCode).toBe(400); + }); + + it('should instantiate NotFoundError correctly', () => { + const err = new NotFoundError('Ticket not found'); + expect(err.statusCode).toBe(404); + expect(err.code).toBe('NOT_FOUND'); + }); + + it('should instantiate ValidationError correctly', () => { + const err = new ValidationError('Invalid input'); + expect(err.statusCode).toBe(400); + expect(err.code).toBe('VALIDATION_ERROR'); + }); +}); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..2e74633 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "coverage", "tests/**/*", "scripts/**/*", "prisma/**/*.ts"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..177f1cb --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,37 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022"], + "outDir": "./dist", + "rootDir": "./", + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "noImplicitOverride": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "skipLibCheck": true, + "sourceMap": true, + "declaration": true, + "declarationMap": true, + "resolveJsonModule": true, + "allowJs": false, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "@/config/*": ["src/config/*"], + "@/common/*": ["src/common/*"], + "@/infrastructure/*": ["src/infrastructure/*"], + "@/modules/*": ["src/modules/*"], + "@/events/*": ["src/events/*"], + "@/jobs/*": ["src/jobs/*"] + } + }, + "include": ["src/**/*", "tests/**/*", "scripts/**/*", "prisma/**/*.ts"], + "exclude": ["node_modules", "dist", "coverage"] +} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..6b75f80 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,31 @@ +import { defineConfig } from 'vitest/config'; +import path from 'path'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['tests/**/*.test.ts'], + env: { + NODE_ENV: 'test', + DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/supporthub_test_db?schema=public', + JWT_SECRET: 'super-secret-test-jwt-key-min-32-characters', + }, + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + exclude: ['node_modules/', 'dist/', 'scripts/'], + }, + }, + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + '@/config': path.resolve(__dirname, './src/config'), + '@/common': path.resolve(__dirname, './src/common'), + '@/infrastructure': path.resolve(__dirname, './src/infrastructure'), + '@/modules': path.resolve(__dirname, './src/modules'), + '@/events': path.resolve(__dirname, './src/events'), + '@/jobs': path.resolve(__dirname, './src/jobs'), + }, + }, +});