commit 11bb86854cf9a4f17dc8552a8748b3b7aef78c97 Author: yuzhiran-dev Date: Mon May 18 09:48:51 2026 +0800 feat: Phase 1-3 全部完成 — 沙盒增强、学情分析、学习路径 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2e4b345 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,97 @@ +name: CI + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +jobs: + backend-lint-and-test: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./backend + + services: + mysql: + image: mysql:8.0 + env: + MYSQL_ROOT_PASSWORD: root123 + MYSQL_DATABASE: yuzhiran + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5 + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + cache-dependency-path: backend/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Generate Prisma client + run: npx prisma generate + env: + DATABASE_URL: mysql://root:root123@localhost:3306/yuzhiran + + - name: Type check + run: npx tsc --noEmit + + - name: Run tests + run: npm test + + frontend-lint-and-test: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./frontend + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + - name: Build + run: npm run build + + docker-build: + runs-on: ubuntu-latest + needs: [backend-lint-and-test, frontend-lint-and-test] + if: github.ref == 'refs/heads/main' + + steps: + - uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build backend + uses: docker/build-push-action@v5 + with: + context: ./backend + push: false + tags: yuzhiran/backend:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build frontend + uses: docker/build-push-action@v5 + with: + context: ./frontend + push: false + tags: yuzhiran/frontend:latest + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb0929c --- /dev/null +++ b/.gitignore @@ -0,0 +1,62 @@ +# Dependencies +node_modules/ +*/node_modules/ + +# Build outputs +dist/ +*/dist/ +out/ +*/out/ +.next/ +*/.next/ + +# Environment files +.env +.env.local +.env.*.local +backend/.env +frontend/.env.local + +# Database +*.db +*.db-journal + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids/ +*.pid +*.seed + +# Coverage +coverage/ +*.lcov + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Certificates (keep template, ignore actual certs) +backend/cert/key/*.pem +backend/cert/key/*.p12 +backend/cert/key/*.txt + +# Temp files +*.tmp +*.temp + +# Playwright E2E test output +test-results/ +playwright-report/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8687583 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,112 @@ +# AGENTS.md — 项目知识库(AI 专用) + +> 每次任务前先读此文件。维护项目关键上下文,避免重复探索。 + +## 项目概览 + +宇之然 AI 学习与实践平台。前端 Next.js + shadcn/ui,后端 NestJS + PostgreSQL。 + +| 项目 | 值 | +|------|-----| +| 品牌 | 宇之然(北京宇之然科技中心) | +| 域名 | yuzhiran.com | +| 前端 | `frontend/`, port 3000, Next.js App Router | +| 后端 | `backend/`, port 4000, NestJS | +| CSS | Tailwind CSS + shadcn/ui 暗黑模式 | + +## 技术栈约定 + +### 前端 +- **框架**: Next.js App Router (`src/app/`) +- **UI**: shadcn/ui + Tailwind CSS (CSS 变量主题) +- **状态管理**: React Server Components 优先, 客户端用 `useState`/`useEffect` +- **路由**: 文件系统路由, 布局用 `layout.tsx`, 加载用 `loading.tsx`, 错误用 `error.tsx` +- **暗黑模式**: `next-themes` + Tailwind 暗类策略 (`darkMode: 'class'`) + +### 后端 +- **框架**: NestJS 模块化架构 +- **ORM**: TypeORM + PostgreSQL(schema 在 `database/migrations/`) +- **认证**: JWT + Passport +- **API 前缀**: `/api/v1` +- **CORS**: `origin: true`, `maxAge: 0`(避免浏览器预检缓存) + +### UI/UX 统一规则 +- **容器**: 内容页 `max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12`;法律/文本页用 `max-w-3xl` +- **标题**: `text-3xl font-bold text-foreground` +- **副标题**: `

...

` +- **颜色**: 全站禁用 `text-gray-*` / `bg-gray-*` / `border-gray-*` 硬编码 —— 使用 CSS 变量: + - 前景色 → `text-foreground` / `text-muted-foreground` + - 背景 → `bg-card` / `bg-muted/50` / `bg-accent` + - 边框 → `border-border` + - hover → `hover:text-foreground` / `hover:bg-accent` + +## 关键架构决策 + +| 决策 | 方案 | 原因 | +|------|------|------| +| CORS | `origin: true` + `maxAge: 0` | 避免预检缓存, 开发灵活 | +| Favicon | `public/favicon.png` + `app/icon.svg` | `.ico` 与 `output: 'export'` 不兼容 | +| 静态导出 | `output: 'export'` | 部署到静态托管 | +| Sandbox 布局 | `h-[calc(100vh-4rem)] flex flex-col` | 固定头尾, 消息区滚动 | +| 流式聊天 | `ReadableStream` fetch API | 实时 AI 响应 | +| 法律页面 | `max-w-3xl` 窄容器 | 长文本可读性 | +| 模型列表 | `frontend/src/lib/models.ts` | 全站唯一数据源,3 个页面统一导入 | +| 颜色约定 | 全站禁用 `text-gray-*` / `bg-gray-*` / `border-gray-*` | 必须使用 CSS 变量 | +| 学情分析 | `GET /api/v1/learning/analytics` + `GET /api/v1/learning/path` | 基于对话知识度分析 | + +## 后端关键 API + +| 端点 | 说明 | +|------|------| +| `POST /api/v1/auth/register` | 注册 | +| `POST /api/v1/auth/login` | 登录 | +| `GET /api/v1/search?q=xxx` | 搜索(返回 `{ results: [...] }`,**不是** `items`) | +| `GET /api/v1/users/:id` | 用户信息 | +| `POST /api/v1/chat/completions` | AI 流式对话 | +| `GET /api/v1/enterprise/...` | 企业版管理 | +| `GET /api/v1/notifications` | 通知列表(需 JWT) | +| `GET /api/v1/notifications/unread` | 未读数(需 JWT) | +| `PATCH /api/v1/notifications/:id/read` | 标记已读(需 JWT) | +| `PATCH /api/v1/notifications/read-all` | 全部已读(需 JWT) | +| `GET /api/v1/learning/analytics` | 学情分析(需 JWT,返回知识领域掌握度) | +| `GET /api/v1/learning/path` | 学习路径进度(需 JWT,返回阶段任务完成情况) | + +## 关键上下文(Critical Context) + +- `search.service.ts` 返回 `results` 而非 `items` —— 写测试时注意 +- `users.service.ts` 的 `if (status)` 曾误写为 `if (params.status)`(已修复) +- 静态构建 (`next build`) 已修复 —— 所有动态路由都通过 server wrapper 模式导出 `generateStaticParams()`(60 页面全部生成) +- `public/favicon.ico` 和 `app/favicon.ico` 不能共存,会触发 500 +- 数据库 schema 通过 TypeORM migration 管理, 位于 `backend/src/database/migrations/` + +## 项目管理流程 + +每次任务遵循以下流程: + +1. **任务开始前** — 读 AGENTS.md + docs/progress.md,了解当前进度和上下文 +2. **规划阶段** — 分析需求,拆解为 TODO 列表,按优先级排序 +3. **执行阶段** — 按 TODO 依次实施,每次完成后验证(lint/test/build) +4. **任务完成后** — 更新 docs/progress.md(更新阶段状态、补充完成项) +5. **归档** — 旧版 progress.md 移到 `docs/archive/progress-YYYY-MM-DD.md` +6. **提交** — 只有在用户明确要求时才创建 git commit + +## 常用命令 + +```bash +# 前端开发 +cd frontend && npm run dev + +# 后端开发 +cd backend && npm run start:dev + +# 前端构建 +cd frontend && npm run build + +# 后端测试 +cd backend && npm test +npm run test:e2e +``` + +--- + +> 此文件仅在架构/约定变更时更新。进度追踪见 `docs/progress.md`。 diff --git a/README.md b/README.md new file mode 100644 index 0000000..a023d31 --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ +# 宇之然 AI (YuZhiRan AI) + +AI 学习与实践平台 — 让每个人都能用好 AI + +| 信息 | 内容 | +|------|------| +| 品牌 | 宇之然(北京宇之然科技中心) | +| 官网 | https://yuzhiran.com | +| 备域名 | https://yuzhiran.com.cn | +| ICP 备案 | ✅ 已完成 | + +## 项目结构 + +``` +ai-learning-platform/ +├── README.md # 项目说明 +├── docs/ # 项目文档 +│ ├── 产品规划书.md # 完整产品规划(含商业模式、可行性分析) +│ ├── 技术架构设计.md # 技术选型与系统架构 +│ └── 合规与运营方案.md # ICP合规、数据合规、运营策略 +├── frontend/ # 官网前端(Next.js + Tailwind) +├── mobile/ # 移动端 App/小程序 +├── backend/ # 后端 API(NestJS + Prisma + MySQL) +│ ├── src/modules/payment/ # 微信支付模块(已完善) +│ ├── src/modules/ai/ # AI模型接入(支持OpenAI兼容接口) +│ └── prisma/ # 数据模型定义 +└── scripts/ # 工具脚本 + └── setup.sh # 项目初始化脚本 +``` + +## 技术栈 + +### 后端 +- **框架**: NestJS (Node.js) +- **ORM**: Prisma +- **数据库**: MySQL +- **支付**: 微信支付 V3 SDK +- **AI接口**: OpenAI兼容接口、DeepSeek、通义千问 + +### 前端 +- **框架**: Next.js 14 +- **样式**: Tailwind CSS +- **状态管理**: React Hooks + +## 快速开始 + +### 1. 初始化项目 + +```bash +cd ai-learning-platform +./scripts/setup.sh +``` + +### 2. 手动配置 + +#### 后端配置 +编辑 `backend/.env` 文件,配置: +- 微信支付参数(已从 `/www/wwwroot/sharefile/note.txt` 获取) +- AI模型API密钥 +- 数据库密码 + +#### 前端配置 +编辑 `frontend/.env.local` 文件,配置API地址。 + +### 3. 启动开发环境 + +```bash +# 启动后端(默认端口3000) +cd backend && npm run dev + +# 启动前端(默认端口3001) +cd frontend && npm run dev +``` + +### 4. 访问 + +- 前端: http://localhost:3001 +- 后端API文档: http://localhost:3000/api + +## 核心功能 + +- ✅ 用户系统(注册、登录、会员管理) +- ✅ 微信支付集成(JSAPI/NATIVE/MWEB) +- ✅ 会员订阅管理(月卡/年卡自动续期) +- ✅ AI模型接入(支持美团longcat等OpenAI兼容接口) +- ✅ 课程系统 +- ✅ 提示词库 +- ✅ AI实操沙箱 +- ✅ 社区功能 + +## 产品定位 + +面向大众化分领域用户的 AI 学习与实践平台,涵盖: +- AI 基础知识与通识教育 +- 提示词工程教学与模板库 +- 智能体(Agent)使用教程 +- 大模型介绍与选型指南 +- AI 实操沙箱体验 diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..b60b791 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,10 @@ +node_modules +dist +.next +.env +.env.local +*.log +.git +.gitignore +.DS_Store +coverage diff --git a/backend/.env.example b/backend/.env.example new file mode 100644 index 0000000..1e1ded3 --- /dev/null +++ b/backend/.env.example @@ -0,0 +1,32 @@ +# Database +DATABASE_URL="mysql://yuzhiran:yuzhiran123@localhost:3306/yuzhiran" + +# JWT +JWT_SECRET=yuzhiran-jwt-secret-2024 +JWT_EXPIRES_IN=2h + +# Server +PORT=4000 + +# AI Models (OpenAI-compatible) +OPENAI_API_KEY= +OPENAI_BASE_URL=https://api.openai.com/v1 +AI_DEFAULT_MODEL=gpt-3.5-turbo + +# DeepSeek +DEEPSEEK_API_KEY= +DEEPSEEK_BASE_URL=https://api.deepseek.com + +# DashScope (通义千问) +DASHSCOPE_API_KEY= +DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 + +# WeChat Pay +WX_APPID= +WX_MCHID= +WX_KEY= +WX_CERT_PATH= +WX_CERT_KEY_PATH= + +# WeChat Mini Program +WX_SECRET= diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..205eab9 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,36 @@ +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci --only=production && cp -R node_modules /prod_modules +RUN npm ci + +COPY tsconfig*.json ./ +COPY src/ ./src/ + +RUN npm run build && \ + rm -rf node_modules && \ + mv /prod_modules node_modules + +# Production stage +FROM node:20-alpine + +WORKDIR /app + +RUN apk add --no-cache tini + +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package*.json ./ +COPY prisma/ ./prisma/ + +RUN npx prisma generate + +EXPOSE 4000 + +USER node + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["node", "dist/main.js"] diff --git a/backend/admin/index.html b/backend/admin/index.html new file mode 100644 index 0000000..82af87e --- /dev/null +++ b/backend/admin/index.html @@ -0,0 +1,798 @@ + + + + + + 宇之然 AI - 管理后台 + + + + + +
+
+
+

宇之然 AI

+

管理后台

+
+
+ + + + +
+
+
+ + + + + + diff --git a/backend/jest-e2e.json b/backend/jest-e2e.json new file mode 100644 index 0000000..aed47ed --- /dev/null +++ b/backend/jest-e2e.json @@ -0,0 +1,12 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testRegex": ".e2e-spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "testEnvironment": "node", + "moduleNameMapper": { + "^@/(.*)$": "/src/$1" + } +} diff --git a/backend/jest.config.json b/backend/jest.config.json new file mode 100644 index 0000000..67033cc --- /dev/null +++ b/backend/jest.config.json @@ -0,0 +1,14 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testRegex": ".*\\.spec\\.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "collectCoverageFrom": ["**/*.(t|j)s"], + "coverageDirectory": "../coverage", + "testEnvironment": "node", + "moduleNameMapper": { + "^@/(.*)$": "/src/$1" + } +} diff --git a/backend/nest-cli.json b/backend/nest-cli.json new file mode 100644 index 0000000..f9aa683 --- /dev/null +++ b/backend/nest-cli.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "deleteOutDir": true + } +} diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000..acf8bd6 --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,10441 @@ +{ + "name": "@yuzhiran/backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@yuzhiran/backend", + "version": "1.0.0", + "license": "UNLICENSED", + "dependencies": { + "@nestjs/common": "^11.1.19", + "@nestjs/config": "^4.0.4", + "@nestjs/core": "^11.1.19", + "@nestjs/jwt": "^11.0.2", + "@nestjs/passport": "^11.0.5", + "@nestjs/platform-express": "^11.1.19", + "@nestjs/serve-static": "^5.0.5", + "@nestjs/swagger": "^11.4.2", + "@prisma/client": "^5.22.0", + "bcryptjs": "^3.0.3", + "class-transformer": "^0.5.1", + "class-validator": "^0.15.1", + "compression": "^1.8.1", + "helmet": "^8.1.0", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "prisma": "^5.22.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2", + "wechat-pay-nodejs": "^0.2.3" + }, + "devDependencies": { + "@nestjs/cli": "^11.0.21", + "@nestjs/schematics": "^11.1.0", + "@nestjs/testing": "^11.1.19", + "@types/bcryptjs": "^2.4.6", + "@types/compression": "^1.8.1", + "@types/express": "^5.0.6", + "@types/jest": "^30.0.0", + "@types/multer": "^2.1.0", + "@types/node": "^20.19.40", + "@types/passport-jwt": "^4.0.1", + "@types/supertest": "^7.2.0", + "jest": "^30.4.0", + "supertest": "^7.2.2", + "ts-jest": "^29.4.9", + "ts-loader": "^9.5.7", + "ts-node": "^10.9.2", + "tsx": "^4.21.0", + "typescript": "5.3" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "19.2.24", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.24.tgz", + "integrity": "sha512-lnw+ZM1Io+cJAkReC0NPDjqObL8NtKzKIkdgEEKC8CUmkhurYhedbicN8Y8NYHgG1uLd2GozW3+/QqPRZaN+Lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.24", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.17", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli": { + "version": "19.2.24", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-19.2.24.tgz", + "integrity": "sha512-bsStZQG67J1HBqTmWxtIcobvgrn32L4UOdL7hGyOru5VxDWPNA8pRnDYavT3hnJeBkJYPoQIw8u7Dm0ecoQprw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.24", + "@angular-devkit/schematics": "19.2.24", + "@inquirer/prompts": "7.3.2", + "ansi-colors": "4.1.3", + "symbol-observable": "4.0.0", + "yargs-parser": "21.1.1" + }, + "bin": { + "schematics": "bin/schematics.js" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/core": { + "version": "19.2.24", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.24.tgz", + "integrity": "sha512-Kd49warf6U/EyWe5BszF/eebN3zQ3bk7tgfEljAw8q/rX95UUtriJubWvp6pgzHfzBA4jwq8f+QiNZB8eBEXPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/@inquirer/prompts": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.3.2.tgz", + "integrity": "sha512-G1ytyOoHh5BphmEBxSwALin3n1KGNYB6yImbICcRQdzXfOGbuJ9Jske/Of5Sebk339NSGGNfUshnzK8YWkTPsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.1.2", + "@inquirer/confirm": "^5.1.6", + "@inquirer/editor": "^4.2.7", + "@inquirer/expand": "^4.0.9", + "@inquirer/input": "^4.1.6", + "@inquirer/number": "^3.0.9", + "@inquirer/password": "^4.0.9", + "@inquirer/rawlist": "^4.0.9", + "@inquirer/search": "^3.0.9", + "@inquirer/select": "^4.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "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/@angular-devkit/schematics-cli/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { + "version": "19.2.24", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.24.tgz", + "integrity": "sha512-Kd49warf6U/EyWe5BszF/eebN3zQ3bk7tgfEljAw8q/rX95UUtriJubWvp6pgzHfzBA4jwq8f+QiNZB8eBEXPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "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/@angular-devkit/schematics/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fidm/asn1": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", + "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@fidm/x509": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", + "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", + "license": "MIT", + "dependencies": { + "@fidm/asn1": "^1.0.4", + "tweetnacl": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "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==", + "dev": true, + "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.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/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/@isaacs/cliui/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/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==", + "dev": true, + "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/@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==", + "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/@isaacs/cliui/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==", + "dev": true, + "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/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.4.0.tgz", + "integrity": "sha512-116ay6wMT9l0QRIhmvDtcw77Ql35S0CMePCn5FGIvuqUZv+Twx+hiIacSPH1pONdG7JhiWqOiqX7s2eQ7Wko2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.4.0", + "jest-util": "30.4.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.4.0.tgz", + "integrity": "sha512-447tRaMsRo65u4ByBxHk4XnuNYX7M0vfazqMdPgJTUTttmC4/7A8yzBE6mSKkj2Md+dR3DWF9mVNfF/Bo+cJJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.4.0", + "@jest/pattern": "30.4.0", + "@jest/reporters": "30.4.0", + "@jest/test-result": "30.4.0", + "@jest/transform": "30.4.0", + "@jest/types": "30.4.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.4.0", + "jest-config": "30.4.0", + "jest-haste-map": "30.4.0", + "jest-message-util": "30.4.0", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.0", + "jest-resolve-dependencies": "30.4.0", + "jest-runner": "30.4.0", + "jest-runtime": "30.4.0", + "jest-snapshot": "30.4.0", + "jest-util": "30.4.0", + "jest-validate": "30.4.0", + "jest-watcher": "30.4.0", + "pretty-format": "30.4.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", + "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.4.0.tgz", + "integrity": "sha512-X9ba/XraafanjsAXRnbRLydhgH10o0RaQIW1evmT0JJ0ShP2DI0khkt0HVNuPnadxUnl1Y6ihCksuA0btmeh6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "30.4.0", + "@jest/types": "30.4.0", + "@types/node": "*", + "jest-mock": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.4.0.tgz", + "integrity": "sha512-eJeAOjHMAD1R/vwGQ8DJkD7z7QBj4Fb8T3/tId1srXAx9UJ9zxWVd875WP1dfGmiznMDoalJGZutzi6UR3R6dA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "30.4.0", + "jest-snapshot": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.0.tgz", + "integrity": "sha512-+7IjdIwKEvViPvFizspuFeFAJhQGYkbOWBBWq+XVLsSl4t3H6lOk9QlxYC3et6GRgJ+jJvnVOAv2CpN4kJowzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.4.0.tgz", + "integrity": "sha512-J+uX5pz4SYiiMP2gR6wqjygxCBhwYXhdPn07XPmZUFTMvm9TQpIGEt4TLbKCMQszslSe3ElEV6GvX3K1CPtzrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.0", + "@sinonjs/fake-timers": "^15.4.0", + "@types/node": "*", + "jest-message-util": "30.4.0", + "jest-mock": "30.4.0", + "jest-util": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.4.0.tgz", + "integrity": "sha512-xf3neOb0PXqNgT7bLpNAcQmrDOQ1rv6zsfSYSQsEXnpFIqkJvJ2Qyp+4P8Bl5XXnL3pMmrjtNHRgl34Ou7TGKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.0", + "@jest/expect": "30.4.0", + "@jest/types": "30.4.0", + "jest-mock": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", + "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.4.0.tgz", + "integrity": "sha512-GMpW1XRCVWKfaGOthupxLTM0Dk/lvDDu6Bb5CgoSkFhbQ+4OT5BcurzInZ99OLeEM7X71i0zv7JmNYHKkcQhFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.4.0", + "@jest/test-result": "30.4.0", + "@jest/transform": "30.4.0", + "@jest/types": "30.4.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.4.0", + "jest-util": "30.4.0", + "jest-worker": "30.4.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@jest/reporters/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", + "dev": true, + "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/@jest/reporters/node_modules/jest-worker": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.0.tgz", + "integrity": "sha512-0ZghqNv1P/M0nBysxrkGpLnorjM1ulhZ76QijLcwyBm+kIj/DPKyHcpHDVh0LD05JDZzVxi8z9RStF22B4gikQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.4.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters/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==", + "dev": true, + "license": "ISC" + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/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==", + "dev": true, + "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/@jest/reporters/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/schemas": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.0.tgz", + "integrity": "sha512-tJLUhzktAsL7VKYJzdkNKxYTKGnkQvd6bMZQtxWnaE4V1VJyzzwt5WrCG5hwC+mB55uZbNSsxQUXLKjla08XPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.4.0.tgz", + "integrity": "sha512-oPrzffukMros86mvKXzDMiAV5qId0U3dTGV/nLnhsKsUKjma7pwmoOvNA5mprG7hVUJ6raRBqkVZVk+kyyjbpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jest/test-result": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.4.0.tgz", + "integrity": "sha512-brA2woQJEP0TyaZ7UEe/8aNvXTYYJ3iuCD3Rm78zNKF2CLqY7ShM+mdJ0f3dvy7ruWE5gKsFvd2bODmeTC8z2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.4.0", + "@jest/types": "30.4.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.4.0.tgz", + "integrity": "sha512-6xWCB+Ix4dMqoc987QxF4piGeC1Mzv71NeWlHo8Wa3z3z8Yookz68gYwFJAKQO+SPhduIs2csX71syItuvrg/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.4.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.4.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.4.0.tgz", + "integrity": "sha512-2X7FL+yezRtfthTZdUgtWnbixqkmGnDfkXE1vimu2Y1Wi7g0WxY2AAPctVrU7J9xmw5dWOBprBjx1hJIamJPbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.4.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.4.0", + "jest-regex-util": "30.4.0", + "jest-util": "30.4.0", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jest/types": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.0.tgz", + "integrity": "sha512-C951KSoEicxFUsUIO4T8lqWEemuMgMb3vlI8FO4OP369GSf6SOJd681nOcv7XR0TV5vCO4Jypvq3rBGEqfy9KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.4.0", + "@jest/schemas": "30.4.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "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/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz", + "integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==", + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@nestjs/cli": { + "version": "11.0.21", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.21.tgz", + "integrity": "sha512-F8mV0Sj/zVEouzR3NxBuJy08YHTUOmC5Xdcx3qIIaJWzrm8Vw86CHkhkaPBJ5ewRMHPDCShPmhsfwhpCcjts3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.24", + "@angular-devkit/schematics": "19.2.24", + "@angular-devkit/schematics-cli": "19.2.24", + "@inquirer/prompts": "7.10.1", + "@nestjs/schematics": "^11.0.1", + "ansis": "4.2.0", + "chokidar": "4.0.3", + "cli-table3": "0.6.5", + "commander": "4.1.1", + "fork-ts-checker-webpack-plugin": "9.1.0", + "glob": "13.0.6", + "node-emoji": "1.11.0", + "ora": "5.4.1", + "tsconfig-paths": "4.2.0", + "tsconfig-paths-webpack-plugin": "4.2.0", + "typescript": "5.9.3", + "webpack": "5.106.0", + "webpack-node-externals": "3.0.0" + }, + "bin": { + "nest": "bin/nest.js" + }, + "engines": { + "node": ">= 20.11" + }, + "peerDependencies": { + "@swc/cli": "^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0", + "@swc/core": "^1.3.62" + }, + "peerDependenciesMeta": { + "@swc/cli": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/@nestjs/cli/node_modules/@angular-devkit/core": { + "version": "19.2.24", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.24.tgz", + "integrity": "sha512-Kd49warf6U/EyWe5BszF/eebN3zQ3bk7tgfEljAw8q/rX95UUtriJubWvp6pgzHfzBA4jwq8f+QiNZB8eBEXPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@nestjs/cli/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "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/@nestjs/cli/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nestjs/cli/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@nestjs/cli/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@nestjs/cli/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@nestjs/cli/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nestjs/cli/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@nestjs/cli/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@nestjs/cli/node_modules/schema-utils/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@nestjs/cli/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nestjs/cli/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/@nestjs/cli/node_modules/webpack": { + "version": "5.106.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.0.tgz", + "integrity": "sha512-Pkx5joZ9RrdgO5LBkyX1L2ZAJeK/Taz3vqZ9CbcP0wS5LEMx5QkKsEwLl29QJfihZ+DKRBFldzy1O30pJ1MDpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.20.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.17", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.4" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/@nestjs/common": { + "version": "11.1.19", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.19.tgz", + "integrity": "sha512-qeiTt2tv+e5QyDKqG8HlVZb2wx64FEaSGFJouqTSRs+kG44iTfl3xlz1XqVped+rihx4hmjWgL5gkhtdK3E6+Q==", + "license": "MIT", + "dependencies": { + "file-type": "21.3.4", + "iterare": "1.2.1", + "load-esm": "1.0.3", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": ">=0.4.1", + "class-validator": ">=0.13.2", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/config": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.4.tgz", + "integrity": "sha512-CJPjNitr0bAufSEnRe2N+JbnVmMmDoo6hvKCPzXgZoGwJSmp/dZPk9f/RMbuD/+Q1ZJPjwsRpq0vxna++Knwow==", + "license": "MIT", + "dependencies": { + "dotenv": "17.4.1", + "dotenv-expand": "12.0.3", + "lodash": "4.18.1" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "rxjs": "^7.1.0" + } + }, + "node_modules/@nestjs/core": { + "version": "11.1.19", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.19.tgz", + "integrity": "sha512-6nJkWa2efrYi+XlU686J9y5L7OvxpLVjT0T/sxRKE7Jvpffiihelup4WSvLvRhdHDjj/5SuoWEwqReXAaaeHmw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@nuxt/opencollective": "0.4.1", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "8.4.2", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "engines": { + "node": ">= 20" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^11.0.0", + "@nestjs/microservices": "^11.0.0", + "@nestjs/platform-express": "^11.0.0", + "@nestjs/websockets": "^11.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + } + } + }, + "node_modules/@nestjs/jwt": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.2.tgz", + "integrity": "sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "9.0.10", + "jsonwebtoken": "9.0.3" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" + } + }, + "node_modules/@nestjs/mapped-types": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.1.tgz", + "integrity": "sha512-SCCoMEJ6jdeI5h/N+KCVF1+pmg/hmEkNA5nHTS8Gvww7T/LCl4o1gFLinw2iQ60w7slFkszHcGLKGdazVI4F8A==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0 || ^0.15.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/passport": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-11.0.5.tgz", + "integrity": "sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "passport": "^0.5.0 || ^0.6.0 || ^0.7.0" + } + }, + "node_modules/@nestjs/platform-express": { + "version": "11.1.19", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.19.tgz", + "integrity": "sha512-Vpdv8jyCQdThfoTx+UTn+DRYr6H6X02YUqcpZ3qP6G3ZUwtVp7eS+hoQPGd4UuCnlnFG8Wqr2J9bGEzQdi1rIg==", + "license": "MIT", + "dependencies": { + "cors": "2.8.6", + "express": "5.2.1", + "multer": "2.1.1", + "path-to-regexp": "8.4.2", + "tslib": "2.8.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^11.0.0", + "@nestjs/core": "^11.0.0" + } + }, + "node_modules/@nestjs/schematics": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-11.1.0.tgz", + "integrity": "sha512-lVxGZ46tcdItFMoXr6vyKWlnOsm1SZm/GUqAEDvy2RL4Q4O+3bkziAhrO7Y8JLssFUUvNFEGqAizI52WAxhjDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.24", + "@angular-devkit/schematics": "19.2.24", + "comment-json": "5.0.0", + "jsonc-parser": "3.3.1", + "pluralize": "8.0.0" + }, + "peerDependencies": { + "prettier": "^3.0.0", + "typescript": ">=4.8.2" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@nestjs/schematics/node_modules/@angular-devkit/core": { + "version": "19.2.24", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.24.tgz", + "integrity": "sha512-Kd49warf6U/EyWe5BszF/eebN3zQ3bk7tgfEljAw8q/rX95UUtriJubWvp6pgzHfzBA4jwq8f+QiNZB8eBEXPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@nestjs/schematics/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "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/@nestjs/schematics/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nestjs/schematics/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@nestjs/schematics/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nestjs/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@nestjs/schematics/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nestjs/serve-static": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@nestjs/serve-static/-/serve-static-5.0.5.tgz", + "integrity": "sha512-AhYx3N9aMwR2cb0w5Nlb5nHNYiAcF74ea/D/xna+PxlXwjmwGN/PpC/5fuMtOwmPBMgOTxNPOnB8C9LDZBSgyw==", + "license": "MIT", + "dependencies": { + "path-to-regexp": "8.4.2" + }, + "peerDependencies": { + "@fastify/static": "^8.0.4 || ^9.0.0", + "@nestjs/common": "^11.0.2", + "@nestjs/core": "^11.0.2", + "express": "^5.0.1", + "fastify": "^5.2.1" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "express": { + "optional": true + }, + "fastify": { + "optional": true + } + } + }, + "node_modules/@nestjs/swagger": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.4.2.tgz", + "integrity": "sha512-aBihEogDMj/bLEcaqhkvyX/ZVWUw/bmnhKzR0zwUoyGJikvZyaq7rOPYl/H7Lxkkr3c90SJxyuv1AX2UT1WKlw==", + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.16.0", + "@nestjs/mapped-types": "2.1.1", + "js-yaml": "4.1.1", + "lodash": "4.18.1", + "path-to-regexp": "8.4.2", + "swagger-ui-dist": "5.32.4" + }, + "peerDependencies": { + "@fastify/static": "^8.0.0 || ^9.0.0", + "@nestjs/common": "^11.0.1", + "@nestjs/core": "^11.0.1", + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/testing": { + "version": "11.1.19", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.19.tgz", + "integrity": "sha512-/UFNWXvPEdu4v4DlC5oWLbGKmD27LehLK06b8oLzs6D6lf4vAQTdST8LRAXBadyMUQnVEQWMuBo3CtAVtlfXtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^11.0.0", + "@nestjs/core": "^11.0.0", + "@nestjs/microservices": "^11.0.0", + "@nestjs/platform-express": "^11.0.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + } + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nuxt/opencollective": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.4.1.tgz", + "integrity": "sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + }, + "bin": { + "opencollective": "bin/opencollective.js" + }, + "engines": { + "node": "^14.18.0 || >=16.10.0", + "npm": ">=5.10.0" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "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==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "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==", + "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==", + "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==", + "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==", + "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==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.22.0" + } + }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true, + "license": "Apache-2.0" + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/bcryptjs": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", + "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "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/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.1.0.tgz", + "integrity": "sha512-zYZb0+nJhOHtPpGDb3vqPjwpdeGlGC157VpkqNQL+UU2qwoacoQ7MpsAmUptI/0Oa127X32JzWDqQVEXp2RcIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.40", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.40.tgz", + "integrity": "sha512-xxx6M2IpSTnnKcR0cMvIiohkiCx20/oRPtWGbenFygKCGl3zqUzdNjQ/1V4solq1LU+dgv0nQzeGOuqkqZGg0Q==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/passport": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.17.tgz", + "integrity": "sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" + } + }, + "node_modules/@types/passport-strategy": { + "version": "0.2.38", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", + "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/passport": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-7.2.0.tgz", + "integrity": "sha512-uh2Lv57xvggst6lCqNdFAmDSvoMG7M/HDtX4iUCquxQ5EGPtaPM5PL5Hmi7LCvOG8db7YaCPNJEeoI8s/WzIQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, + "node_modules/@types/validator": { + "version": "13.15.10", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", + "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.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": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "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": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "Python-2.0" + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz", + "integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/babel-jest": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.4.0.tgz", + "integrity": "sha512-GQ4CKCr1XQ1dettGyiDCPg2u4kP/nav2z9PugOM3Da5l3zpNzY9PRuxmN1dV714Ghm2fdkQLhNxlUopDcoKc6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.4.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.4.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.4.0.tgz", + "integrity": "sha512-9EdtWM/sSfXLOGLwSn+GS6pIXyBnL07/8gyJlwFXjWy4DxMOyItqyUT29d4lQiS380EZwYlX7/At4PgBS+m2aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.4.0.tgz", + "integrity": "sha512-lBY4jxsNmCnSiu7kquw8ZC9F4+XLMOKypT3RnNHPvU2Kpd4W0xaPuLr5ZkRyOsvLYAY4yaW1ZwTW4xB7NIiZzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.4.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.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==", + "dev": true, + "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==", + "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/baseline-browser-mapping": { + "version": "2.10.27", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.27.tgz", + "integrity": "sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bcryptjs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", + "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "license": "MIT" + }, + "node_modules/class-validator": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.15.1.tgz", + "integrity": "sha512-LqoS80HBBSCVhz/3KloUly0ovokxpdOLR++Al3J3+dHXWt9sTKlKd4eYtoxhxyUjoe5+UcIM+5k9MIxyBWnRTw==", + "license": "MIT", + "dependencies": { + "@types/validator": "^13.15.3", + "libphonenumber-js": "^1.11.1", + "validator": "^13.15.22" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/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==", + "dev": true, + "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/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/comment-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-5.0.0.tgz", + "integrity": "sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "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/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "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-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz", + "integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", + "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand/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/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.352", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.352.tgz", + "integrity": "sha512-9wHk8x6dyuimoe18EdiDPWKExNdxYqo4fn4FwOVVper6RxT3cmpBwBkWWfSOCYJjQdIco/nPhJhNLmn4Ufg1Yg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.1.tgz", + "integrity": "sha512-8p7DUVq6XJnZEz9W4oSwiwycxBIjHjRzYb3Je3zVN+geKTRQKzAkR/K4PBExlS0090d9nshak6phMUxr3PDjmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "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/esrecurse/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/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.0.tgz", + "integrity": "sha512-wwj3yHn8F2Uj4fyL+2n1M1cjfYFGtYq7cF00OjMHBxX5eTeX/EcVdHHIMkhxO6nFfopwHtaQEasP1WfxzQaZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.4.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.4.0", + "jest-message-util": "30.4.0", + "jest-mock": "30.4.0", + "jest-util": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "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-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": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-type": { + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "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/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "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==", + "dev": true, + "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/fork-ts-checker-webpack-plugin": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^4.0.1", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "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/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", + "dev": true, + "license": "Unlicense" + }, + "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==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz", + "integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/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/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "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/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/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "license": "ISC", + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "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/jest": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.4.0.tgz", + "integrity": "sha512-4+7GP22nzoACtoFiKP9rptEF49oQJs0C/hCk7oW8oEIeSH9j43EiQmJCCPVGWQ1noI98CgKl2TeLwaIJzO2Bvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.4.0", + "@jest/types": "30.4.0", + "import-local": "^3.2.0", + "jest-cli": "30.4.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.4.0.tgz", + "integrity": "sha512-L6TnosD7ftCv+r6ENOSoqeKdPA+IG4L+3ayXmmmlzPyEK4aU34KTUJC+Y/ep755LyQfV6DOdhnxXVRTrGJNX5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.4.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.4.0.tgz", + "integrity": "sha512-RtgndWX8qprDn2wvx6hGJhYiokwSJc6vEwEzqUXERMB/MqQb7b8V/yIwe9IUZo91JOb61uA526LWQaFUjgbaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.0", + "@jest/expect": "30.4.0", + "@jest/test-result": "30.4.0", + "@jest/types": "30.4.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.4.0", + "jest-matcher-utils": "30.4.0", + "jest-message-util": "30.4.0", + "jest-runtime": "30.4.0", + "jest-snapshot": "30.4.0", + "jest-util": "30.4.0", + "p-limit": "^3.1.0", + "pretty-format": "30.4.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.4.0.tgz", + "integrity": "sha512-N/Hd8MPTzh8EivGpgMqEzd1pTS1P9tnVKiSgztXrnGkxUr+wqpD3u+huqvxMB4KXtHuBfpVSnNJrU3y9mbOOww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.4.0", + "@jest/test-result": "30.4.0", + "@jest/types": "30.4.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.4.0", + "jest-util": "30.4.0", + "jest-validate": "30.4.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.4.0.tgz", + "integrity": "sha512-7JoLxH5DNk5lSpCw+AH1wTqui9crCPVezHUoro5y9Ay9Snw///woP+J2UFR5mpNFuavlOyd8endtCIHlPHSdUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.4.0", + "@jest/test-sequencer": "30.4.0", + "@jest/types": "30.4.0", + "babel-jest": "30.4.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-circus": "30.4.0", + "jest-docblock": "30.4.0", + "jest-environment-node": "30.4.0", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.0", + "jest-runner": "30.4.0", + "jest-util": "30.4.0", + "jest-validate": "30.4.0", + "parse-json": "^5.2.0", + "pretty-format": "30.4.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-config/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", + "dev": true, + "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/jest-config/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==", + "dev": true, + "license": "ISC" + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/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==", + "dev": true, + "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/jest-diff": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.0.tgz", + "integrity": "sha512-8SHpYWUtt2LyH5tw5Oa+larOuy5WHDH7vklFxbxf4LJfYkepoA2eu/loHmvYDlrHrdB3JZ89197oG2A1V982yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.4.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.4.0.tgz", + "integrity": "sha512-ZPMabUZCx5MpbZ2eBYSvZ0J8fvo3dR9oM+eeUpb3aKNQFuS2tu3Duw1TNlMoP8k3WQgKGJuhcMFvwcVuq6T7oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-each": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.4.0.tgz", + "integrity": "sha512-AusMWaBQags04/SptcZu/Ex1juOebeSozkC9Pjx+teA2zoNd0drNsZe6PseKrHWsgimatgicXJNXHr9yCvnXaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.4.0", + "chalk": "^4.1.2", + "jest-util": "30.4.0", + "pretty-format": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.4.0.tgz", + "integrity": "sha512-pmMYkiufguU6bqe+XP3DM24e7sCG7aYjPnCJdKiXjRh1H2SCBJgY1KC1JlIxqQjNr9dWLNpw5TLuHbXbq0CDqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.0", + "@jest/fake-timers": "30.4.0", + "@jest/types": "30.4.0", + "@types/node": "*", + "jest-mock": "30.4.0", + "jest-util": "30.4.0", + "jest-validate": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.4.0.tgz", + "integrity": "sha512-01+o3CS8t35Va0Ed6w/HyeK9VaejRlBnZ1hGoOlTYlruFzycn3RfIdG1Szu1DVoACTs07ALirRjECq1FqNuAFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.4.0", + "jest-util": "30.4.0", + "jest-worker": "30.4.0", + "picomatch": "^4.0.3", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/jest-haste-map/node_modules/jest-worker": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.0.tgz", + "integrity": "sha512-0ZghqNv1P/M0nBysxrkGpLnorjM1ulhZ76QijLcwyBm+kIj/DPKyHcpHDVh0LD05JDZzVxi8z9RStF22B4gikQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.4.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-haste-map/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.4.0.tgz", + "integrity": "sha512-n9beq0bFyt2m17RSjo6n8RsZiE1w+sOfr+p1J0aYTBXoxd/4hZeK2M7GQENKtslIsGVu2xOrNEe10CTmQfO8Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.0.tgz", + "integrity": "sha512-m28k6fJ1hsHxYRBMbQvIfHz8FQA1e8U/I3o/Z+id0etJJL7Af6mJqMKvH11lTFX6rRKANi/8iVwdche9E+wz8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.4.0", + "pretty-format": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.0.tgz", + "integrity": "sha512-XjJEhPYwvJezXMYuPKX52xIE7CPNNVocuUzEJcMts82HhmXii7zC3KZVjlFDXdp8khX4lwWj9Rva9bs+8oucLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.4.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-util": "30.4.0", + "picomatch": "^4.0.3", + "pretty-format": "30.4.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-mock": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.0.tgz", + "integrity": "sha512-Xy8aJikWCFMLFdAvmBTWgFzik3+qnYVEqDz1n/NQQqJX14e48J31XGx+km/0INV7YPzfl6SXmjsaVidUs3zQ5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.0", + "@types/node": "*", + "jest-util": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", + "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.4.0.tgz", + "integrity": "sha512-N8Nmytv/LMGsIQXZ2kWHXC3UhzTFC696cTx3ER0jtdrIBmmNjYK6RSJPllGf6iCdj3qimKizc+nczj3kdflDOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.4.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.4.0", + "jest-validate": "30.4.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.4.0.tgz", + "integrity": "sha512-2iooc09EwOjWpyIe03NQ4V7kgKZgs6TtO3vSydMUjTXjQhmj/0wWX/n4qbWw/K3LEMUkBhEuk3QHVWEC7k79nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "30.4.0", + "jest-snapshot": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.4.0.tgz", + "integrity": "sha512-9LKu3gQKGvOIbzVh/xkoEYW2+/xDRjZ5/TU2Kqb1aC9TNYd3egENB0+0MXoTfaLNH1TlrIISTl6lABNHOuo3Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.4.0", + "@jest/environment": "30.4.0", + "@jest/test-result": "30.4.0", + "@jest/transform": "30.4.0", + "@jest/types": "30.4.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.4.0", + "jest-environment-node": "30.4.0", + "jest-haste-map": "30.4.0", + "jest-leak-detector": "30.4.0", + "jest-message-util": "30.4.0", + "jest-resolve": "30.4.0", + "jest-runtime": "30.4.0", + "jest-util": "30.4.0", + "jest-watcher": "30.4.0", + "jest-worker": "30.4.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-worker": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.0.tgz", + "integrity": "sha512-0ZghqNv1P/M0nBysxrkGpLnorjM1ulhZ76QijLcwyBm+kIj/DPKyHcpHDVh0LD05JDZzVxi8z9RStF22B4gikQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.4.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-runtime": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.4.0.tgz", + "integrity": "sha512-xPjd7AStvPrnP/lZr+Urp7GPS9MFQDrWBtjXZYMuYZnQeFvkw5xM0jpjpGUxhsYYf4q3JY80SPlld7U2Sy9hyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.0", + "@jest/fake-timers": "30.4.0", + "@jest/globals": "30.4.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.4.0", + "@jest/transform": "30.4.0", + "@jest/types": "30.4.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.4.0", + "jest-message-util": "30.4.0", + "jest-mock": "30.4.0", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.0", + "jest-snapshot": "30.4.0", + "jest-util": "30.4.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-runtime/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", + "dev": true, + "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/jest-runtime/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==", + "dev": true, + "license": "ISC" + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/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==", + "dev": true, + "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/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.4.0.tgz", + "integrity": "sha512-2OdJoU/ogYJOAnbTG6FCelziKiyDZA1FocmO1xnKLfOb4J2gpHXsJC5nAP7wfG/VgwJxtM06ZUYz7rJmAhOsLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.4.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.4.0", + "@jest/transform": "30.4.0", + "@jest/types": "30.4.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.4.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.4.0", + "jest-matcher-utils": "30.4.0", + "jest-message-util": "30.4.0", + "jest-util": "30.4.0", + "pretty-format": "30.4.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.0.tgz", + "integrity": "sha512-nae+Oh7CEdSTC5+uL4HCVDCLusj5IcypnVXWBSRjCUDkh7dX/FwreTsgvLROwHnEWW5dcdvLkW9RvmmMzKw+aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.4.0.tgz", + "integrity": "sha512-tIzxS3lajj3BAELRD1bde4GdsZFU9gwUYlyGoKq23XNR7oaeYQRt7KKA38VxGNoLJpkJ5jQBs9Q0fhefXnol0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.4.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.4.0.tgz", + "integrity": "sha512-VPLgD4ZydEWWY8B/edBUwLsTANwaLM8R1NA1M0szFKkgjWmP6F6w7T+c6rtUYuE5r/5SsFLGwGkvmrlS4JHiwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.4.0", + "@jest/types": "30.4.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.4.0", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/libphonenumber-js": { + "version": "1.12.43", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.43.tgz", + "integrity": "sha512-5n+HnmkNpgZCfaNVxrTGZHr6Lhv3gd0UtbD5lrzun3T2YNyVvCuJz9vkap2E0YWZWU1XF+0XljYAkrAJBbwbrg==", + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-esm": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.3.tgz", + "integrity": "sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + }, + { + "type": "buymeacoffee", + "url": "https://buymeacoffee.com/borewit" + } + ], + "license": "MIT", + "engines": { + "node": ">=13.2.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "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==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "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/multer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz", + "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "type-is": "^1.6.18" + }, + "engines": { + "node": ">= 10.16.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "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/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", + "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "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/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "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/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pretty-format": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.0.tgz", + "integrity": "sha512-PzJLEF72RqCj01UTBWqBi2ar3U2iJ0oG0+HzcdHPW+rzfpzDCuiVeiy6lns8L3Nbpp4Ajw+nBsW2KuKPPyPlCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.4.0", + "ansi-styles": "^5.2.0", + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.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==", + "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/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-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/react-is-18": { + "name": "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/react-is-19": { + "name": "react-is", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", + "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/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/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/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/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "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/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "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-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "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": { + "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==", + "dev": true, + "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/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strtok3": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/superagent": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.3.0.tgz", + "integrity": "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.5", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.14.1" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.2.2.tgz", + "integrity": "sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cookie-signature": "^1.2.2", + "methods": "^1.1.2", + "superagent": "^10.3.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "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/swagger-ui-dist": { + "version": "5.32.4", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.32.4.tgz", + "integrity": "sha512-0AADFFQNJzExEN49SrD/34Nn9cxNxVLiydYl2MBwSZFPVXNkVwC/EFAjoezGGqE8oDegiDC+p47t8lKObCinMQ==", + "license": "Apache-2.0", + "dependencies": { + "@scarf/scarf": "=1.4.0" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.47.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz", + "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-UYhptBwhWvfIjKd/UuFo6D8uq9xpGLDK+z8EDsj/zWhrTaH34cKEbrkMKfV5YWqGBvAYA3tlzZbs2R+qYrbQJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/terser-webpack-plugin/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/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/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "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/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/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/ts-jest": { + "version": "29.4.9", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.9.tgz", + "integrity": "sha512-LTb9496gYPMCqjeDLdPrKuXtncudeV1yRZnF4Wo5l3SFi0RYEnYRNgMrFIdg+FHvfzjCyQk1cLncWVqiSX+EvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.4", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-loader": { + "version": "9.5.7", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.7.tgz", + "integrity": "sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz", + "integrity": "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tapable": "^2.2.1", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.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.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "license": "Unlicense" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/validator": { + "version": "13.15.35", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webpack": { + "version": "5.106.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz", + "integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.20.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "loader-runner": "^4.3.1", + "mime-db": "^1.54.0", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.17", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.4" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-node-externals": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", + "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-sources": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz", + "integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/wechat-pay-nodejs": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/wechat-pay-nodejs/-/wechat-pay-nodejs-0.2.3.tgz", + "integrity": "sha512-ZmECl4sbG7uGeUDYbCrPQcTnBzkI0aKkf0X1uNhymcmObzhPZ6m6B8Go8FRjI2b0+m1VB3llw/RRXv8vnWXklw==", + "license": "MIT", + "dependencies": { + "@fidm/x509": "^1.2.1", + "axios": "^1.4.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "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/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/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..db972c4 --- /dev/null +++ b/backend/package.json @@ -0,0 +1,73 @@ +{ + "name": "@yuzhiran/backend", + "version": "1.0.0", + "description": "宇之然 AI - 后端 API 服务", + "main": "dist/main.js", + "scripts": { + "build": "nest build", + "start": "nest start", + "dev": "nest start --watch", + "start:prod": "node dist/main", + "prisma:generate": "prisma generate", + "prisma:push": "prisma db push", + "prisma:migrate": "prisma migrate dev", + "prisma:seed": "ts-node prisma/seed.ts", + "lint": "nest lint", + "test": "jest --no-cache --verbose", + "test:watch": "jest --watch" + }, + "keywords": [ + "yuzhiran", + "ai", + "learning", + "platform" + ], + "author": "北京宇之然科技中心", + "license": "UNLICENSED", + "private": true, + "prisma": { + "seed": "node prisma/seed.js" + }, + "dependencies": { + "@nestjs/common": "^11.1.19", + "@nestjs/config": "^4.0.4", + "@nestjs/core": "^11.1.19", + "@nestjs/jwt": "^11.0.2", + "@nestjs/passport": "^11.0.5", + "@nestjs/platform-express": "^11.1.19", + "@nestjs/serve-static": "^5.0.5", + "@nestjs/swagger": "^11.4.2", + "@prisma/client": "^5.22.0", + "bcryptjs": "^3.0.3", + "class-transformer": "^0.5.1", + "class-validator": "^0.15.1", + "compression": "^1.8.1", + "helmet": "^8.1.0", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "prisma": "^5.22.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2", + "wechat-pay-nodejs": "^0.2.3" + }, + "devDependencies": { + "@nestjs/cli": "^11.0.21", + "@nestjs/schematics": "^11.1.0", + "@nestjs/testing": "^11.1.19", + "@types/bcryptjs": "^2.4.6", + "@types/compression": "^1.8.1", + "@types/express": "^5.0.6", + "@types/jest": "^30.0.0", + "@types/multer": "^2.1.0", + "@types/node": "^20.19.40", + "@types/passport-jwt": "^4.0.1", + "@types/supertest": "^7.2.0", + "jest": "^30.4.0", + "supertest": "^7.2.2", + "ts-jest": "^29.4.9", + "ts-loader": "^9.5.7", + "ts-node": "^10.9.2", + "tsx": "^4.21.0", + "typescript": "5.3" + } +} diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma new file mode 100644 index 0000000..b98d289 --- /dev/null +++ b/backend/prisma/schema.prisma @@ -0,0 +1,511 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "mysql" + url = env("DATABASE_URL") +} + +enum UserStatus { + ACTIVE + INACTIVE + BANNED +} + +enum ContentStatus { + DRAFT + PUBLISHED + ARCHIVED +} + +enum OrderStatus { + PENDING + PAID + CANCELLED + REFUNDED +} + +enum MemberPlan { + FREE + MONTHLY + YEARLY +} + +model User { + id Int @id @default(autoincrement()) + phone String? @unique + email String? @unique + passwordHash String? + nickname String? + avatar String? + bio String? + status UserStatus @default(ACTIVE) + memberPlan MemberPlan @default(FREE) + memberExpire DateTime? + sandboxDaily Int @default(10) + followerCount Int @default(0) + followingCount Int @default(0) + postCount Int @default(0) + lastLoginAt DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime? + + learnRecords LearnRecord[] + promptFavorites PromptFavorite[] + prompts Prompt[] + sandboxSessions SandboxSession[] + orders Order[] + subscriptions Subscription[] + posts Post[] + comments Comment[] + postLikes PostLike[] + followers Follow[] @relation("Following") + following Follow[] @relation("Follower") + createdCircles Circle[] @relation("CircleCreator") + circleMemberships CircleMember[] + organizationMemberships OrganizationMember[] + notifications Notification[] + + @@map("users") +} + +model Category { + id Int @id @default(autoincrement()) + name String + slug String @unique + description String? + sortOrder Int @default(0) + parentId Int? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + parent Category? @relation("CategoryTree", fields: [parentId], references: [id]) + children Category[] @relation("CategoryTree") + + courses Course[] + prompts Prompt[] + contents Content[] + tools Tool[] + + @@map("categories") +} + +model Course { + id Int @id @default(autoincrement()) + title String + description String? + cover String? + categoryId Int? + price Float @default(0) + isFree Boolean @default(true) + status ContentStatus @default(DRAFT) + sortOrder Int @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime? + + category Category? @relation(fields: [categoryId], references: [id]) + chapters Chapter[] + progress LearnRecord[] + assignments CourseAssignment[] + + @@map("courses") +} + +model Chapter { + id Int @id @default(autoincrement()) + courseId Int + title String + sortOrder Int @default(0) + createdAt DateTime @default(now()) + + course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) + lessons Lesson[] + + @@map("chapters") +} + +model Lesson { + id Int @id @default(autoincrement()) + chapterId Int + title String + content String? + videoUrl String? + duration Int? + sortOrder Int @default(0) + status ContentStatus @default(DRAFT) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + chapter Chapter @relation(fields: [chapterId], references: [id], onDelete: Cascade) + progress LearnRecord[] + + @@map("lessons") +} + +model LearnRecord { + id Int @id @default(autoincrement()) + userId Int + courseId Int + lessonId Int + completed Boolean @default(false) + progress Float @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) + lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade) + + @@unique([userId, lessonId]) + @@map("learn_records") +} + +model Prompt { + id Int @id @default(autoincrement()) + title String + content String + description String? + categoryId Int? + tags String? + authorId Int? + model String? + isPublic Boolean @default(true) + status ContentStatus @default(PUBLISHED) + viewCount Int @default(0) + likeCount Int @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime? + + category Category? @relation(fields: [categoryId], references: [id]) + author User? @relation(fields: [authorId], references: [id]) + favorites PromptFavorite[] + + @@map("prompts") +} + +model PromptFavorite { + id Int @id @default(autoincrement()) + userId Int + promptId Int + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) + + @@unique([userId, promptId]) + @@map("prompt_favorites") +} + +model Tool { + id Int @id @default(autoincrement()) + name String + description String? + url String + icon String? + categoryId Int? + tags String? + isFeatured Boolean @default(false) + status ContentStatus @default(PUBLISHED) + viewCount Int @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime? + + category Category? @relation(fields: [categoryId], references: [id]) + + @@map("tools") +} + +model Content { + id Int @id @default(autoincrement()) + title String + summary String? + content String? + cover String? + categoryId Int? + tags String? + authorName String? + contentType String @default("article") + status ContentStatus @default(DRAFT) + viewCount Int @default(0) + isAiGenerated Boolean @default(false) + publishedAt DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime? + + category Category? @relation(fields: [categoryId], references: [id]) + + @@map("contents") +} + +model AiModel { + id Int @id @default(autoincrement()) + name String + provider String + description String? + capabilities String? + contextWindow Int? + maxTokens Int? + pricing String? + isFree Boolean @default(false) + isFeatured Boolean @default(false) + icon String? + sortOrder Int @default(0) + status String @default("ACTIVE") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@map("ai_models") +} + +model SandboxSession { + id Int @id @default(autoincrement()) + userId Int + conversationId String @default("") + model String + title String @default("AI 对话") + messages String @db.Text + feedback String? + tokens Int @default(0) + duration Int @default(0) + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([userId, conversationId]) + @@index([userId, createdAt]) + @@map("sandbox_sessions") +} + +model Order { + id Int @id @default(autoincrement()) + orderNo String @unique + userId Int + amount Float + planType String + status OrderStatus @default(PENDING) + payChannel String? + paidAt DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id]) + + @@index([userId, status]) + @@index([status, createdAt]) + @@map("orders") +} + +model Subscription { + id Int @id @default(autoincrement()) + userId Int + plan MemberPlan + startDate DateTime + endDate DateTime + status String @default("ACTIVE") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id]) + + @@index([userId, status]) + @@map("subscriptions") +} + +model AdminUser { + id Int @id @default(autoincrement()) + username String @unique + passwordHash String + nickname String? + role String @default("editor") + status String @default("ACTIVE") + lastLoginAt DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@map("admin_users") +} + +model AdminLog { + id Int @id @default(autoincrement()) + adminId Int + action String + target String? + detail String? + ip String? + createdAt DateTime @default(now()) + + @@map("admin_logs") +} + +model Post { + id Int @id @default(autoincrement()) + userId Int + title String + content String + tags String? + circleId Int? + status String @default("PUBLISHED") + viewCount Int @default(0) + likeCount Int @default(0) + commentCount Int @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + comments Comment[] + likes PostLike[] + circle Circle? @relation(fields: [circleId], references: [id]) + + @@index([userId]) + @@index([status, createdAt]) + @@index([circleId]) + @@map("posts") +} + +model Comment { + id Int @id @default(autoincrement()) + postId Int + userId Int + content String + parentId Int? + status String @default("PUBLISHED") + reviewNote String? + reviewedAt DateTime? + createdAt DateTime @default(now()) + + post Post @relation(fields: [postId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + parent Comment? @relation("CommentReply", fields: [parentId], references: [id]) + replies Comment[] @relation("CommentReply") + + @@index([postId]) + @@index([status]) + @@map("comments") +} + +model PostLike { + id Int @id @default(autoincrement()) + postId Int + userId Int + createdAt DateTime @default(now()) + + post Post @relation(fields: [postId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([postId, userId]) + @@map("post_likes") +} + +model Circle { + id Int @id @default(autoincrement()) + name String + description String? + tags String? + creatorId Int + isPublic Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + creator User @relation("CircleCreator", fields: [creatorId], references: [id]) + members CircleMember[] + posts Post[] + + @@map("circles") +} + +model CircleMember { + id Int @id @default(autoincrement()) + circleId Int + userId Int + role String @default("member") + joinedAt DateTime @default(now()) + + circle Circle @relation(fields: [circleId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([circleId, userId]) + @@map("circle_members") +} + +model Follow { + id Int @id @default(autoincrement()) + followerId Int + followingId Int + createdAt DateTime @default(now()) + + follower User @relation("Follower", fields: [followerId], references: [id], onDelete: Cascade) + following User @relation("Following", fields: [followingId], references: [id], onDelete: Cascade) + + @@unique([followerId, followingId]) + @@map("follows") +} + +model Organization { + id Int @id @default(autoincrement()) + name String + description String? + contactName String? + contactPhone String? + logo String? + memberCount Int @default(0) + status String @default("ACTIVE") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + members OrganizationMember[] + assignments CourseAssignment[] + + @@map("organizations") +} + +model OrganizationMember { + id Int @id @default(autoincrement()) + organizationId Int + userId Int + role String @default("MEMBER") + status String @default("ACTIVE") + joinedAt DateTime @default(now()) + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([organizationId, userId]) + @@map("organization_members") +} + +model CourseAssignment { + id Int @id @default(autoincrement()) + organizationId Int + courseId Int + assignedBy Int + deadline DateTime? + createdAt DateTime @default(now()) + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) + course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) + + @@map("course_assignments") +} + +model Notification { + id Int @id @default(autoincrement()) + userId Int + type String // 'like', 'comment', 'follow', 'system' + title String + content String? + link String? + relatedId Int? + isRead Boolean @default(false) + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@index([userId, isRead]) + @@map("notifications") +} diff --git a/backend/prisma/seed.d.ts b/backend/prisma/seed.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/backend/prisma/seed.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/backend/prisma/seed.js b/backend/prisma/seed.js new file mode 100644 index 0000000..5085a51 --- /dev/null +++ b/backend/prisma/seed.js @@ -0,0 +1,156 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +const client_1 = require("@prisma/client"); +const bcrypt = __importStar(require("bcryptjs")); +const prisma = new client_1.PrismaClient(); +async function main() { + const adminPassword = await bcrypt.hash('admin123456', 10); + await prisma.adminUser.upsert({ + where: { username: 'admin' }, + update: {}, + create: { + username: 'admin', + passwordHash: adminPassword, + nickname: '超级管理员', + role: 'superadmin', + }, + }); + const categories = [ + { name: 'AI 入门', slug: 'ai-basics', description: 'AI 基础知识与入门指南' }, + { name: '办公效率', slug: 'office-productivity', description: '用 AI 提升办公效率' }, + { name: '创意设计', slug: 'creative-design', description: 'AI 辅助创意与设计' }, + { name: '编程开发', slug: 'programming', description: 'AI 辅助编程开发' }, + { name: '教育学习', slug: 'education', description: 'AI 在教育中的应用' }, + { name: '提示词技巧', slug: 'prompt-engineering', description: '提示词工程与技巧' }, + { name: 'AI 工具', slug: 'ai-tools', description: 'AI 工具收录与评测' }, + { name: '模型百科', slug: 'model-encyclopedia', description: '大模型介绍与对比' }, + ]; + for (const cat of categories) { + await prisma.category.upsert({ + where: { slug: cat.slug }, + update: {}, + create: cat, + }); + } + const basicsCategory = await prisma.category.findUnique({ where: { slug: 'ai-basics' } }); + const promptCategory = await prisma.category.findUnique({ where: { slug: 'prompt-engineering' } }); + if (basicsCategory) { + const course = await prisma.course.upsert({ + where: { id: 1 }, + update: {}, + create: { + title: 'AI 通识课:零基础入门人工智能', + description: '面向零基础用户的 AI 入门课程,带你了解 AI 的基本概念、发展历程和实际应用。', + categoryId: basicsCategory.id, + isFree: true, + status: 'PUBLISHED', + sortOrder: 1, + chapters: { + create: [ + { + title: '第一章:什么是人工智能', + sortOrder: 1, + lessons: { + create: [ + { title: 'AI 的定义与发展简史', content: '# AI 的定义\n\n人工智能...', sortOrder: 1, status: 'PUBLISHED' }, + { title: '机器学习 vs 深度学习', content: '# 机器学习\n\n...', sortOrder: 2, status: 'PUBLISHED' }, + { title: '大语言模型(LLM)是什么', content: '# 大语言模型\n\n...', sortOrder: 3, status: 'PUBLISHED' }, + ], + }, + }, + { + title: '第二章:主流 AI 工具介绍', + sortOrder: 2, + lessons: { + create: [ + { title: 'ChatGPT 与 GPT 系列', content: '# ChatGPT\n\n...', sortOrder: 1, status: 'PUBLISHED' }, + { title: 'Claude 系列模型', content: '# Claude\n\n...', sortOrder: 2, status: 'PUBLISHED' }, + { title: '国内大模型:通义千问、文心一言、GLM', content: '# 国内大模型\n\n...', sortOrder: 3, status: 'PUBLISHED' }, + ], + }, + }, + ], + }, + }, + }); + } + if (promptCategory) { + const prompts = [ + { title: '写周报助手', content: '请帮我写一份本周工作总结,我的工作是:[描述你的工作内容]。\n\n要求:\n1. 按重点项目分类\n2. 包含数据成果\n3. 列出下周计划\n4. 语言简洁专业', description: '帮你快速生成高质量周报', categoryId: promptCategory.id, tags: '办公,周报', model: '通用', status: 'PUBLISHED' }, + { title: '会议纪要生成', content: '请根据以下会议内容生成会议纪要:\n[粘贴会议内容]\n\n格式要求:\n- 时间\n- 参会人\n- 会议议题\n- 讨论要点\n- 待办事项及负责人', description: '快速整理会议内容为结构化纪要', categoryId: promptCategory.id, tags: '办公,会议', model: '通用', status: 'PUBLISHED' }, + ]; + for (const prompt of prompts) { + await prisma.prompt.create({ data: prompt }); + } + } + const toolsCategory = await prisma.category.findUnique({ where: { slug: 'ai-tools' } }); + if (toolsCategory) { + const tools = [ + { name: 'ChatGPT', description: 'OpenAI 开发的对话式 AI 助手,支持文本生成、代码编写、分析等', url: 'https://chat.openai.com', categoryId: toolsCategory.id, tags: '对话,文本生成,代码', isFeatured: true, status: 'PUBLISHED' }, + { name: 'Claude', description: 'Anthropic 开发的 AI 助手,擅长深度分析、长文本处理', url: 'https://claude.ai', categoryId: toolsCategory.id, tags: '对话,分析,长文本', isFeatured: true, status: 'PUBLISHED' }, + { name: '通义千问', description: '阿里云开发的 AI 大模型,支持文本、图像、代码等多种任务', url: 'https://tongyi.aliyun.com', categoryId: toolsCategory.id, tags: '对话,文本,国内', isFeatured: true, status: 'PUBLISHED' }, + { name: '文心一言', description: '百度开发的 AI 对话产品,基于文心大模型', url: 'https://yiyan.baidu.com', categoryId: toolsCategory.id, tags: '对话,文本,国内', isFeatured: true, status: 'PUBLISHED' }, + ]; + for (const tool of tools) { + await prisma.tool.create({ data: tool }); + } + } + const models = [ + { name: 'GPT-4o', provider: 'OpenAI', description: 'OpenAI 的多模态旗舰模型,支持文本、图像、音频输入,性能全面领先', capabilities: '文本生成,图像理解,代码,分析,多语言', contextWindow: 128000, maxTokens: 4096, pricing: '付费 API', isFeatured: true, sortOrder: 1 }, + { name: 'GPT-4o-mini', provider: 'OpenAI', description: 'GPT-4o 的轻量版,速度快、成本低,适合日常对话和简单任务', capabilities: '文本生成,代码,分析', contextWindow: 128000, maxTokens: 16384, pricing: '付费 API', isFeatured: false, sortOrder: 2 }, + { name: 'Claude 3.5 Sonnet', provider: 'Anthropic', description: 'Anthropic 的旗舰模型,在编程、深度分析、长文本处理方面表现优异', capabilities: '文本生成,代码,分析,长文本,多语言', contextWindow: 200000, maxTokens: 8192, pricing: '付费 API', isFeatured: true, sortOrder: 3 }, + { name: 'DeepSeek-V3', provider: '深度求索', description: '国产开源大模型,推理能力强,数学和编程能力突出,性价比极高', capabilities: '文本生成,代码,数学推理,分析', contextWindow: 128000, maxTokens: 8192, pricing: '免费/付费 API', isFeatured: true, sortOrder: 4 }, + { name: 'DeepSeek-R1', provider: '深度求索', description: '专注推理的模型,擅长复杂逻辑推理、数学问题,思维链能力强大', capabilities: '推理,数学,逻辑,代码', contextWindow: 128000, maxTokens: 8192, pricing: '免费/付费 API', isFeatured: true, sortOrder: 5 }, + { name: '通义千问 2.5', provider: '阿里云', description: '阿里云推出的最新版 Qwen 模型,中英文能力优秀,支持图像理解', capabilities: '文本生成,图像理解,代码,多语言', contextWindow: 131072, maxTokens: 8192, pricing: '免费/付费 API', isFeatured: true, sortOrder: 6 }, + { name: 'GLM-4', provider: '智谱 AI', description: '智谱 AI 的第四代 GLM 模型,中文理解能力强,支持多模态和工具调用', capabilities: '文本生成,代码,工具调用,多模态', contextWindow: 128000, maxTokens: 4096, pricing: '免费/付费 API', isFeatured: false, sortOrder: 7 }, + { name: '文心一言 4.0', provider: '百度', description: '百度文心大模型 4.0,知识问答和中文理解能力强,支持多种格式', capabilities: '文本生成,知识问答,图像生成,代码', contextWindow: 8000, maxTokens: 4096, pricing: '付费 API', isFeatured: false, sortOrder: 8 }, + { name: 'Moonshot', provider: '月之暗面', description: 'Kimi 背后的模型,超长上下文窗口(200 万字),擅长长文档处理', capabilities: '长文本,文档分析,文本生成', contextWindow: 128000, maxTokens: 4096, pricing: '免费/付费 API', isFeatured: false, sortOrder: 9 }, + { name: 'Gemini 2.0 Flash', provider: 'Google', description: 'Google 的轻量高速模型,多模态能力强,支持图片/视频/音频理解', capabilities: '多模态,图像理解,音频,视频,代码', contextWindow: 1000000, maxTokens: 8192, pricing: '免费 API', isFree: true, isFeatured: false, sortOrder: 10 }, + ]; + for (const model of models) { + await prisma.aiModel.create({ data: model }); + } + console.log('Seed data created successfully!'); +} +main() + .catch((e) => { + console.error(e); + process.exit(1); +}) + .finally(async () => { + await prisma.$disconnect(); +}); +//# sourceMappingURL=seed.js.map \ No newline at end of file diff --git a/backend/prisma/seed.js.map b/backend/prisma/seed.js.map new file mode 100644 index 0000000..6ec53f1 --- /dev/null +++ b/backend/prisma/seed.js.map @@ -0,0 +1 @@ +{"version":3,"file":"seed.js","sourceRoot":"","sources":["seed.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA8C;AAC9C,iDAAmC;AAEnC,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAElC,KAAK,UAAU,IAAI;IAEjB,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAC3D,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;QAC5B,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE;QAC5B,MAAM,EAAE,EAAE;QACV,MAAM,EAAE;YACN,QAAQ,EAAE,OAAO;YACjB,YAAY,EAAE,aAAa;YAC3B,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,YAAY;SACnB;KACF,CAAC,CAAC;IAGH,MAAM,UAAU,GAAG;QACjB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE;QACjE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,EAAE,WAAW,EAAE,aAAa,EAAE;QACzE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,YAAY,EAAE;QACpE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE;QAC/D,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE;QAC9D,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,WAAW,EAAE,UAAU,EAAE;QACtE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE;QAC9D,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,WAAW,EAAE,UAAU,EAAE;KACtE,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;YACzB,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,GAAG;SACZ,CAAC,CAAC;IACL,CAAC;IAGD,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;IAC1F,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,EAAE,CAAC,CAAC;IAEnG,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;YACxC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;YAChB,MAAM,EAAE,EAAE;YACV,MAAM,EAAE;gBACN,KAAK,EAAE,kBAAkB;gBACzB,WAAW,EAAE,2CAA2C;gBACxD,UAAU,EAAE,cAAc,CAAC,EAAE;gBAC7B,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,WAAW;gBACnB,SAAS,EAAE,CAAC;gBACZ,QAAQ,EAAE;oBACR,MAAM,EAAE;wBACN;4BACE,KAAK,EAAE,aAAa;4BACpB,SAAS,EAAE,CAAC;4BACZ,OAAO,EAAE;gCACP,MAAM,EAAE;oCACN,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE;oCAC3F,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE;oCACtF,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE;iCACzF;6BACF;yBACF;wBACD;4BACE,KAAK,EAAE,gBAAgB;4BACvB,SAAS,EAAE,CAAC;4BACZ,OAAO,EAAE;gCACP,MAAM,EAAE;oCACN,EAAE,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE;oCAC7F,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE;oCACvF,EAAE,KAAK,EAAE,qBAAqB,EAAE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE;iCAC/F;6BACF;yBACF;qBACF;iBACF;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAGD,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG;YACd,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,oFAAoF,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAoB,EAAE;YACtO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,8EAA8E,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAoB,EAAE;SACrO,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAGD,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;IACxF,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG;YACZ,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,qCAAqC,EAAE,GAAG,EAAE,yBAAyB,EAAE,UAAU,EAAE,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,WAAoB,EAAE;YACzM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kCAAkC,EAAE,GAAG,EAAE,mBAAmB,EAAE,UAAU,EAAE,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,WAAoB,EAAE;YAC9L,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,+BAA+B,EAAE,GAAG,EAAE,2BAA2B,EAAE,UAAU,EAAE,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,WAAoB,EAAE;YAChM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,uBAAuB,EAAE,GAAG,EAAE,yBAAyB,EAAE,UAAU,EAAE,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,WAAoB,EAAE;SACvL,CAAC;QAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AACjD,CAAC;AAED,IAAI,EAAE;KACH,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACX,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;KACD,OAAO,CAAC,KAAK,IAAI,EAAE;IAClB,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/backend/prisma/seed.ts b/backend/prisma/seed.ts new file mode 100644 index 0000000..b9acda8 --- /dev/null +++ b/backend/prisma/seed.ts @@ -0,0 +1,122 @@ +import { PrismaClient } from '@prisma/client'; +import * as bcrypt from 'bcryptjs'; + +const prisma = new PrismaClient(); + +async function main() { + // 创建管理员 + const adminPassword = await bcrypt.hash('admin123456', 10); + await prisma.adminUser.upsert({ + where: { username: 'admin' }, + update: {}, + create: { + username: 'admin', + passwordHash: adminPassword, + nickname: '超级管理员', + role: 'superadmin', + }, + }); + + // 创建分类 + const categories = [ + { name: 'AI 入门', slug: 'ai-basics', description: 'AI 基础知识与入门指南' }, + { name: '办公效率', slug: 'office-productivity', description: '用 AI 提升办公效率' }, + { name: '创意设计', slug: 'creative-design', description: 'AI 辅助创意与设计' }, + { name: '编程开发', slug: 'programming', description: 'AI 辅助编程开发' }, + { name: '教育学习', slug: 'education', description: 'AI 在教育中的应用' }, + { name: '提示词技巧', slug: 'prompt-engineering', description: '提示词工程与技巧' }, + { name: 'AI 工具', slug: 'ai-tools', description: 'AI 工具收录与评测' }, + { name: '模型百科', slug: 'model-encyclopedia', description: '大模型介绍与对比' }, + ]; + + for (const cat of categories) { + await prisma.category.upsert({ + where: { slug: cat.slug }, + update: {}, + create: cat, + }); + } + + // 创建示例课程 + const basicsCategory = await prisma.category.findUnique({ where: { slug: 'ai-basics' } }); + const promptCategory = await prisma.category.findUnique({ where: { slug: 'prompt-engineering' } }); + + if (basicsCategory) { + const course = await prisma.course.upsert({ + where: { id: 1 }, + update: {}, + create: { + title: 'AI 通识课:零基础入门人工智能', + description: '面向零基础用户的 AI 入门课程,带你了解 AI 的基本概念、发展历程和实际应用。', + categoryId: basicsCategory.id, + isFree: true, + status: 'PUBLISHED', + sortOrder: 1, + chapters: { + create: [ + { + title: '第一章:什么是人工智能', + sortOrder: 1, + lessons: { + create: [ + { title: 'AI 的定义与发展简史', content: '# AI 的定义\n\n人工智能...', sortOrder: 1, status: 'PUBLISHED' }, + { title: '机器学习 vs 深度学习', content: '# 机器学习\n\n...', sortOrder: 2, status: 'PUBLISHED' }, + { title: '大语言模型(LLM)是什么', content: '# 大语言模型\n\n...', sortOrder: 3, status: 'PUBLISHED' }, + ], + }, + }, + { + title: '第二章:主流 AI 工具介绍', + sortOrder: 2, + lessons: { + create: [ + { title: 'ChatGPT 与 GPT 系列', content: '# ChatGPT\n\n...', sortOrder: 1, status: 'PUBLISHED' }, + { title: 'Claude 系列模型', content: '# Claude\n\n...', sortOrder: 2, status: 'PUBLISHED' }, + { title: '国内大模型:通义千问、文心一言、GLM', content: '# 国内大模型\n\n...', sortOrder: 3, status: 'PUBLISHED' }, + ], + }, + }, + ], + }, + }, + }); + } + + // 创建示例提示词 + if (promptCategory) { + const prompts = [ + { title: '写周报助手', content: '请帮我写一份本周工作总结,我的工作是:[描述你的工作内容]。\n\n要求:\n1. 按重点项目分类\n2. 包含数据成果\n3. 列出下周计划\n4. 语言简洁专业', description: '帮你快速生成高质量周报', categoryId: promptCategory.id, tags: '办公,周报', model: '通用', status: 'PUBLISHED' as const }, + { title: '会议纪要生成', content: '请根据以下会议内容生成会议纪要:\n[粘贴会议内容]\n\n格式要求:\n- 时间\n- 参会人\n- 会议议题\n- 讨论要点\n- 待办事项及负责人', description: '快速整理会议内容为结构化纪要', categoryId: promptCategory.id, tags: '办公,会议', model: '通用', status: 'PUBLISHED' as const }, + ]; + + for (const prompt of prompts) { + await prisma.prompt.create({ data: prompt }); + } + } + + // 创建示例 AI 工具 + const toolsCategory = await prisma.category.findUnique({ where: { slug: 'ai-tools' } }); + if (toolsCategory) { + const tools = [ + { name: 'ChatGPT', description: 'OpenAI 开发的对话式 AI 助手,支持文本生成、代码编写、分析等', url: 'https://chat.openai.com', categoryId: toolsCategory.id, tags: '对话,文本生成,代码', isFeatured: true, status: 'PUBLISHED' as const }, + { name: 'Claude', description: 'Anthropic 开发的 AI 助手,擅长深度分析、长文本处理', url: 'https://claude.ai', categoryId: toolsCategory.id, tags: '对话,分析,长文本', isFeatured: true, status: 'PUBLISHED' as const }, + { name: '通义千问', description: '阿里云开发的 AI 大模型,支持文本、图像、代码等多种任务', url: 'https://tongyi.aliyun.com', categoryId: toolsCategory.id, tags: '对话,文本,国内', isFeatured: true, status: 'PUBLISHED' as const }, + { name: '文心一言', description: '百度开发的 AI 对话产品,基于文心大模型', url: 'https://yiyan.baidu.com', categoryId: toolsCategory.id, tags: '对话,文本,国内', isFeatured: true, status: 'PUBLISHED' as const }, + ]; + + for (const tool of tools) { + await prisma.tool.create({ data: tool }); + } + } + + console.log('Seed data created successfully!'); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/backend/prisma/tsconfig.json b/backend/prisma/tsconfig.json new file mode 100644 index 0000000..b3e0cf8 --- /dev/null +++ b/backend/prisma/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "./dist-prisma", + "types": ["node"] + }, + "include": ["prisma/**/*.ts"] +} diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts new file mode 100644 index 0000000..feae196 --- /dev/null +++ b/backend/src/app.module.ts @@ -0,0 +1,49 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { PrismaModule } from './prisma/prisma.module'; +import { AuthModule } from './modules/auth/auth.module'; +import { UsersModule } from './modules/users/users.module'; +import { CoursesModule } from './modules/courses/courses.module'; +import { ContentsModule } from './modules/contents/contents.module'; +import { PromptsModule } from './modules/prompts/prompts.module'; +import { ToolsModule } from './modules/tools/tools.module'; +import { SandboxModule } from './modules/sandbox/sandbox.module'; +import { OrdersModule } from './modules/orders/orders.module'; +import { AdminModule } from './modules/admin/admin.module'; +import { PaymentModule } from './modules/payment/payment.module'; +import { CategoriesModule } from './modules/categories/categories.module'; +import { DashboardModule } from './modules/dashboard/dashboard.module'; +import { SearchModule } from './modules/search/search.module'; +import { ModelsModule } from './modules/models/models.module'; +import { UploadModule } from './modules/upload/upload.module'; +import { CommunityModule } from './modules/community/community.module'; +import { EnterpriseModule } from './modules/enterprise/enterprise.module'; +import { NotificationModule } from './modules/notifications/notification.module'; +import { LearningModule } from './modules/learning/learning.module'; + +@Module({ + imports: [ + ConfigModule.forRoot({ isGlobal: true }), + PrismaModule, + AuthModule, + UsersModule, + CoursesModule, + ContentsModule, + PromptsModule, + ToolsModule, + SandboxModule, + OrdersModule, + AdminModule, + PaymentModule, + CategoriesModule, + DashboardModule, + SearchModule, + ModelsModule, + UploadModule, + CommunityModule, + EnterpriseModule, + NotificationModule, + LearningModule, + ], +}) +export class AppModule {} diff --git a/backend/src/common/filters/global-exception.filter.ts b/backend/src/common/filters/global-exception.filter.ts new file mode 100644 index 0000000..f7e7624 --- /dev/null +++ b/backend/src/common/filters/global-exception.filter.ts @@ -0,0 +1,31 @@ +import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus, Logger } from '@nestjs/common'; +import { Response } from 'express'; + +@Catch() +export class GlobalExceptionFilter implements ExceptionFilter { + private readonly logger = new Logger(GlobalExceptionFilter.name); + + catch(exception: unknown, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + + let status = HttpStatus.INTERNAL_SERVER_ERROR; + let message = '服务器内部错误'; + + if (exception instanceof HttpException) { + status = exception.getStatus(); + const res = exception.getResponse(); + message = typeof res === 'string' ? res : (res as any).message || message; + if (Array.isArray(message)) message = message[0]; + } + + this.logger.error(`[${status}] ${message}`, exception instanceof Error ? exception.stack : ''); + + response.status(status).json({ + code: status, + message, + data: null, + timestamp: new Date().toISOString(), + }); + } +} diff --git a/backend/src/common/index.ts b/backend/src/common/index.ts new file mode 100644 index 0000000..5cecf5f --- /dev/null +++ b/backend/src/common/index.ts @@ -0,0 +1,2 @@ +export { GlobalExceptionFilter } from './filters/global-exception.filter'; +export { LoggingInterceptor } from './interceptors/logging.interceptor'; diff --git a/backend/src/common/interceptors/logging.interceptor.ts b/backend/src/common/interceptors/logging.interceptor.ts new file mode 100644 index 0000000..cb4b87e --- /dev/null +++ b/backend/src/common/interceptors/logging.interceptor.ts @@ -0,0 +1,22 @@ +import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +@Injectable() +export class LoggingInterceptor implements NestInterceptor { + private readonly logger = new Logger('HTTP'); + + intercept(context: ExecutionContext, next: CallHandler): Observable { + const request = context.switchToHttp().getRequest(); + const { method, url } = request; + const now = Date.now(); + + return next.handle().pipe( + tap(() => { + const response = context.switchToHttp().getResponse(); + const ms = Date.now() - now; + this.logger.log(`${method} ${url} ${response.statusCode} ${ms}ms`); + }), + ); + } +} diff --git a/backend/src/main.ts b/backend/src/main.ts new file mode 100644 index 0000000..4a733a7 --- /dev/null +++ b/backend/src/main.ts @@ -0,0 +1,52 @@ +import { NestFactory } from '@nestjs/core'; +import { ValidationPipe } from '@nestjs/common'; +import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; +import { NestExpressApplication } from '@nestjs/platform-express'; +import { join } from 'path'; +import helmet from 'helmet'; +import * as compression from 'compression'; +import { AppModule } from './app.module'; +import { GlobalExceptionFilter, LoggingInterceptor } from './common'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule, { + logger: ['log', 'error', 'warn', 'debug', 'verbose'], + }); + + app.use(helmet({ + crossOriginResourcePolicy: { policy: 'cross-origin' }, + contentSecurityPolicy: false, + })); + app.use(compression()); + + app.useStaticAssets(join(process.cwd(), 'uploads'), { prefix: '/uploads' }); + app.setGlobalPrefix('api/v1'); + app.enableCors({ + origin: true, + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], + allowedHeaders: ['Content-Type', 'Authorization'], + maxAge: 0, + }); + + app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true })); + app.useGlobalFilters(new GlobalExceptionFilter()); + app.useGlobalInterceptors(new LoggingInterceptor()); + + const config = new DocumentBuilder() + .setTitle('宇之然 AI API') + .setDescription('宇之然 AI 学习与实践平台 API 文档') + .setVersion('1.0') + .addBearerAuth() + .build(); + + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api/docs', app, document); + + const port = process.env.PORT || 4000; + await app.listen(port); + console.log(`宇之然 AI API 服务已启动: http://localhost:${port}`); + console.log(`API 文档: http://localhost:${port}/api/docs`); +} + +bootstrap(); diff --git a/backend/src/modules/admin/admin.controller.ts b/backend/src/modules/admin/admin.controller.ts new file mode 100644 index 0000000..e236b18 --- /dev/null +++ b/backend/src/modules/admin/admin.controller.ts @@ -0,0 +1,86 @@ +import { Controller, Post, Get, Put, Body, UseGuards, Req, Param } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { AdminService } from './admin.service'; +import { AdminGuard } from './admin.guard'; +import { CoursesService } from '../courses/courses.service'; +import { PrismaService } from '../../prisma/prisma.service'; + +@ApiTags('管理后台') +@Controller('admin') +export class AdminController { + constructor( + private adminService: AdminService, + private coursesService: CoursesService, + private prisma: PrismaService, + ) {} + + @Post('login') + async login(@Body() body: { username: string; password: string }) { + return this.adminService.login(body.username, body.password); + } + + @Get('dashboard') + @UseGuards(AuthGuard('jwt'), AdminGuard) + @ApiBearerAuth() + async dashboard() { + return this.adminService.getDashboard(); + } + + @Get('orders') + @UseGuards(AuthGuard('jwt'), AdminGuard) + @ApiBearerAuth() + async orders(@Req() req: any) { + const items = await this.prisma.order.findMany({ + orderBy: { createdAt: 'desc' }, + take: 100, + include: { user: { select: { id: true, nickname: true, phone: true } } }, + }); + return { items }; + } + + @Put('courses/:id/chapters') + @UseGuards(AuthGuard('jwt'), AdminGuard) + @ApiBearerAuth() + async updateCourseChapters(@Param('id') id: string, @Body() body: any) { + return this.coursesService.updateWithChapters(+id, body); + } + + @Get('comments/pending') + @UseGuards(AuthGuard('jwt'), AdminGuard) + @ApiBearerAuth() + async pendingComments() { + const items = await this.prisma.comment.findMany({ + where: { status: 'PENDING_REVIEW' }, + include: { + user: { select: { id: true, nickname: true, avatar: true } }, + post: { select: { id: true, title: true } }, + }, + orderBy: { createdAt: 'desc' }, + take: 50, + }); + return { items }; + } + + @Put('comments/:id/approve') + @UseGuards(AuthGuard('jwt'), AdminGuard) + @ApiBearerAuth() + async approveComment(@Param('id') id: string) { + await this.prisma.comment.update({ + where: { id: parseInt(id) }, + data: { status: 'PUBLISHED', reviewedAt: new Date() }, + }); + return { ok: true }; + } + + @Put('comments/:id/reject') + @UseGuards(AuthGuard('jwt'), AdminGuard) + @ApiBearerAuth() + async rejectComment(@Param('id') id: string, @Body() body: { reason?: string }) { + await this.prisma.comment.update({ + where: { id: parseInt(id) }, + data: { status: 'REJECTED', reviewNote: body.reason || '违规内容', reviewedAt: new Date() }, + }); + return { ok: true }; + } +} diff --git a/backend/src/modules/admin/admin.guard.ts b/backend/src/modules/admin/admin.guard.ts new file mode 100644 index 0000000..d17fb7e --- /dev/null +++ b/backend/src/modules/admin/admin.guard.ts @@ -0,0 +1,12 @@ +import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common'; + +@Injectable() +export class AdminGuard implements CanActivate { + canActivate(context: ExecutionContext): boolean { + const request = context.switchToHttp().getRequest(); + if (!request.user?.isAdmin) { + throw new ForbiddenException('无管理员权限'); + } + return true; + } +} diff --git a/backend/src/modules/admin/admin.module.ts b/backend/src/modules/admin/admin.module.ts new file mode 100644 index 0000000..82e344d --- /dev/null +++ b/backend/src/modules/admin/admin.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { JwtModule } from '@nestjs/jwt'; +import { AdminController } from './admin.controller'; +import { AdminService } from './admin.service'; +import { AdminGuard } from './admin.guard'; +import { CoursesModule } from '../courses/courses.module'; +import { AuthModule } from '../auth/auth.module'; + +@Module({ + imports: [CoursesModule, AuthModule], + controllers: [AdminController], + providers: [AdminService, AdminGuard], + exports: [AdminService], +}) +export class AdminModule {} diff --git a/backend/src/modules/admin/admin.service.ts b/backend/src/modules/admin/admin.service.ts new file mode 100644 index 0000000..65ff19c --- /dev/null +++ b/backend/src/modules/admin/admin.service.ts @@ -0,0 +1,56 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import * as bcrypt from 'bcryptjs'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class AdminService { + constructor( + private prisma: PrismaService, + private jwtService: JwtService, + ) {} + + async login(username: string, password: string) { + const admin = await this.prisma.adminUser.findUnique({ where: { username } }); + if (!admin || admin.status !== 'ACTIVE') { + throw new UnauthorizedException('管理员账号不可用'); + } + + const isValid = await bcrypt.compare(password, admin.passwordHash); + if (!isValid) { + throw new UnauthorizedException('密码错误'); + } + + await this.prisma.adminUser.update({ + where: { id: admin.id }, + data: { lastLoginAt: new Date() }, + }); + + const token = this.jwtService.sign( + { sub: admin.id, type: 'admin' }, + { expiresIn: '8h' }, + ); + + return { token, id: admin.id, username: admin.username, role: admin.role }; + } + + async getDashboard() { + const [userCount, courseCount, contentCount, promptCount, orderCount] = await Promise.all([ + this.prisma.user.count({ where: { deletedAt: null } }), + this.prisma.course.count({ where: { deletedAt: null } }), + this.prisma.content.count({ where: { deletedAt: null, status: 'PUBLISHED' } }), + this.prisma.prompt.count({ where: { deletedAt: null, status: 'PUBLISHED' } }), + this.prisma.order.count(), + ]); + + return { + stats: { userCount, courseCount, contentCount, promptCount, orderCount }, + }; + } + + async logAction(adminId: number, action: string, target?: string, detail?: string, ip?: string) { + return this.prisma.adminLog.create({ + data: { adminId, action, target, detail, ip }, + }); + } +} diff --git a/backend/src/modules/admin/tests/admin.service.spec.ts b/backend/src/modules/admin/tests/admin.service.spec.ts new file mode 100644 index 0000000..898a00b --- /dev/null +++ b/backend/src/modules/admin/tests/admin.service.spec.ts @@ -0,0 +1,172 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UnauthorizedException } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import * as bcrypt from 'bcryptjs'; +import { AdminService } from '../admin.service'; +import { PrismaService } from '../../../prisma/prisma.service'; + +// Mock bcrypt +jest.mock('bcryptjs', () => ({ + compare: jest.fn(), + hash: jest.fn(), +})); + +describe('AdminService', () => { + let service: AdminService; + let prisma: PrismaService; + + const mockPrisma = { + adminUser: { + findUnique: jest.fn(), + update: jest.fn(), + }, + user: { count: jest.fn() }, + course: { count: jest.fn() }, + content: { count: jest.fn() }, + prompt: { count: jest.fn() }, + order: { count: jest.fn() }, + adminLog: { create: jest.fn() }, + }; + + const mockJwtService = { + sign: jest.fn().mockReturnValue('mock-jwt-token'), + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + AdminService, + { provide: PrismaService, useValue: mockPrisma }, + { provide: JwtService, useValue: mockJwtService }, + ], + }).compile(); + + service = module.get(AdminService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('login', () => { + const mockAdmin = { + id: 1, + username: 'admin', + passwordHash: '$2a$10$hashed', + role: 'superadmin', + status: 'ACTIVE', + }; + + it('should login successfully', async () => { + mockPrisma.adminUser.findUnique.mockResolvedValue(mockAdmin); + jest.spyOn(bcrypt, 'compare').mockResolvedValue(true as never); + mockPrisma.adminUser.update.mockResolvedValue(mockAdmin); + + const result = await service.login('admin', 'admin123456'); + + expect(result).toEqual(expect.objectContaining({ id: 1, username: 'admin', role: 'superadmin' })); + expect(mockPrisma.adminUser.update).toHaveBeenCalledWith( + expect.objectContaining({ + where: { id: 1 }, + data: { lastLoginAt: expect.any(Date) }, + }) + ); + }); + + it('should throw on wrong password', async () => { + mockPrisma.adminUser.findUnique.mockResolvedValue(mockAdmin); + jest.spyOn(bcrypt, 'compare').mockResolvedValue(false as never); + + await expect(service.login('admin', 'wrongpass')).rejects.toThrow(UnauthorizedException); + }); + + it('should throw when admin not found', async () => { + mockPrisma.adminUser.findUnique.mockResolvedValue(null); + + await expect(service.login('unknown', 'pass')).rejects.toThrow(UnauthorizedException); + }); + + it('should throw when admin is inactive', async () => { + mockPrisma.adminUser.findUnique.mockResolvedValue({ ...mockAdmin, status: 'INACTIVE' }); + + await expect(service.login('admin', 'pass')).rejects.toThrow(UnauthorizedException); + }); + }); + + describe('getDashboard', () => { + it('should return all stats', async () => { + mockPrisma.user.count.mockResolvedValue(100); + mockPrisma.course.count.mockResolvedValue(20); + mockPrisma.content.count.mockResolvedValue(45); + mockPrisma.prompt.count.mockResolvedValue(30); + mockPrisma.order.count.mockResolvedValue(15); + + const result = await service.getDashboard(); + + expect(result).toEqual({ + stats: { + userCount: 100, + courseCount: 20, + contentCount: 45, + promptCount: 30, + orderCount: 15, + }, + }); + }); + + it('should return zeroes when no data', async () => { + mockPrisma.user.count.mockResolvedValue(0); + mockPrisma.course.count.mockResolvedValue(0); + mockPrisma.content.count.mockResolvedValue(0); + mockPrisma.prompt.count.mockResolvedValue(0); + mockPrisma.order.count.mockResolvedValue(0); + + const result = await service.getDashboard(); + + expect(result).toEqual({ + stats: { + userCount: 0, courseCount: 0, contentCount: 0, + promptCount: 0, orderCount: 0, + }, + }); + }); + + it('should filter deleted users and courses', async () => { + mockPrisma.user.count.mockResolvedValue(50); + mockPrisma.course.count.mockResolvedValue(10); + mockPrisma.content.count.mockResolvedValue(5); + mockPrisma.prompt.count.mockResolvedValue(3); + mockPrisma.order.count.mockResolvedValue(2); + + await service.getDashboard(); + + expect(mockPrisma.user.count).toHaveBeenCalledWith({ where: { deletedAt: null } }); + expect(mockPrisma.course.count).toHaveBeenCalledWith({ where: { deletedAt: null } }); + expect(mockPrisma.content.count).toHaveBeenCalledWith({ + where: { deletedAt: null, status: 'PUBLISHED' }, + }); + }); + }); + + describe('logAction', () => { + it('should create an admin log entry', async () => { + const mockLog = { id: 1, adminId: 1, action: 'login', target: null, detail: null, ip: null }; + mockPrisma.adminLog.create.mockResolvedValue(mockLog); + + const result = await service.logAction(1, 'login'); + + expect(result).toEqual(mockLog); + expect(mockPrisma.adminLog.create).toHaveBeenCalledWith({ + data: { adminId: 1, action: 'login', target: undefined, detail: undefined, ip: undefined }, + }); + }); + + it('should create log with full details', async () => { + mockPrisma.adminLog.create.mockResolvedValue({ id: 2 }); + + await service.logAction(1, 'update', 'courses/1', '修改课程标题', '127.0.0.1'); + + expect(mockPrisma.adminLog.create).toHaveBeenCalledWith({ + data: { adminId: 1, action: 'update', target: 'courses/1', detail: '修改课程标题', ip: '127.0.0.1' }, + }); + }); + }); +}); diff --git a/backend/src/modules/ai/ai-gateway.service.ts b/backend/src/modules/ai/ai-gateway.service.ts new file mode 100644 index 0000000..3cdf4a6 --- /dev/null +++ b/backend/src/modules/ai/ai-gateway.service.ts @@ -0,0 +1,158 @@ +import { Injectable, Logger } from '@nestjs/common'; + +interface ChatMessage { + role: 'user' | 'assistant' | 'system'; + content: string; +} + +export interface ChatOptions { + temperature?: number; + top_p?: number; + max_tokens?: number; +} + +interface AIProvider { + name: string; + chat(messages: ChatMessage[], options?: ChatOptions): Promise; +} + +@Injectable() +export class AIGatewayService { + private readonly logger = new Logger(AIGatewayService.name); + private providers: Map = new Map(); + + constructor() { + this.registerProviders(); + } + + private registerProviders() { + if (process.env.OPENAI_API_KEY) { + let apiUrl = process.env.OPENAI_API_URL || 'https://api.openai.com/v1/chat/completions'; + if (!apiUrl.endsWith('/chat/completions')) { + apiUrl = apiUrl.replace(/\/+$/, '') + '/chat/completions'; + } + const defaultModel = process.env.OPENAI_MODEL || 'gpt-3.5-turbo'; + this.providers.set('openai', new OpenAICompatibleProvider( + process.env.OPENAI_API_KEY!, + apiUrl, + defaultModel, + 'OpenAI 兼容接口', + )); + this.logger.log(`OpenAI 兼容接口已注册: ${defaultModel}`); + } + + if (process.env.OPENCODE_API_KEY) { + let apiUrl = process.env.OPENCODE_API_URL || 'https://opencode.ai/zen/go/v1'; + if (!apiUrl.endsWith('/chat/completions')) { + apiUrl = apiUrl.replace(/\/+$/, '') + '/chat/completions'; + } + const defaultModel = process.env.OPENCODE_MODEL || 'deepseek-v4-flash'; + this.providers.set('opencode', new OpenAICompatibleProvider( + process.env.OPENCODE_API_KEY!, + apiUrl, + defaultModel, + 'OpenCode Go', + )); + this.logger.log(`OpenCode Go 已注册: ${defaultModel}`); + } + } + + async chat(model: string, messages: ChatMessage[], options?: ChatOptions): Promise { + const modelMap: Record = { + 'general': 'openai', + 'openai': 'openai', + 'gpt-3.5': 'openai', + 'gpt-4': 'openai', + 'longcat': 'openai', + 'meituan/longcat-flash-lite': 'openai', + 'opencode-go': 'opencode', + 'opencode': 'opencode', + 'deepseek-v4-flash': 'opencode', + }; + + const providerKey = modelMap[model.toLowerCase()] || (model.includes('/') ? 'openai' : model); + const provider = this.providers.get(providerKey); + + if (provider) { + try { + const reply = await provider.chat(messages, options); + if (typeof reply !== 'string' || reply.length === 0) { + throw new Error(`AI 返回内容为空: ${JSON.stringify(reply)}`); + } + return reply; + } catch (err: any) { + this.logger.error(`${provider.name} 调用失败: ${err.message}`); + return this.fallback(messages); + } + } + + return this.fallback(messages); + } + + private fallback(messages: ChatMessage[]): string { + const lastMsg = messages[messages.length - 1]?.content || ''; + const mockReplies: Record = { + '你好': '你好!我是宇之然 AI 助手,很高兴为你服务!', + 'hello': 'Hello! I am YuZhiRan AI assistant, nice to meet you!', + }; + + for (const [key, reply] of Object.entries(mockReplies)) { + if (lastMsg.toLowerCase().includes(key)) { + return reply; + } + } + + if (lastMsg.includes('提示词') || lastMsg.includes('prompt')) { + return '好的提示词需要明确角色、任务、输出格式和约束条件。例如:"你是一名专业的文案编辑,请帮我优化以下产品描述,要求语言简洁有力,突出产品核心卖点,控制在200字以内。"'; + } + + if (lastMsg.includes('模型') || lastMsg.includes('大模型')) { + return '目前主流的 AI 大模型包括:OpenAI 的 GPT 系列、Anthropic 的 Claude 系列、Google 的 Gemini 系列,以及国内的 DeepSeek、通义千问、文心一言、GLM 等。各模型在语言理解、代码生成、逻辑推理等方面各有优势。'; + } + + const names = Array.from(this.providers.values()).map(p => p.name).join('、'); + return `我是宇之然 AI 助手。关于"${lastMsg.slice(0, 50)}..."的问题,我已收到。当前 AI 沙箱处于模拟模式,请配置 API Key 以获取真实回复。已配置的 API:${names}。`; + } + + getRegisteredProviders(): string[] { + return Array.from(this.providers.keys()); + } +} + +class OpenAICompatibleProvider implements AIProvider { + name: string; + private apiKey: string; + private apiUrl: string; + private defaultModel: string; + + constructor(apiKey: string, apiUrl: string, defaultModel: string, name?: string) { + this.apiKey = apiKey; + this.apiUrl = apiUrl; + this.defaultModel = defaultModel; + this.name = name || 'OpenAI 兼容接口'; + } + + async chat(messages: ChatMessage[], options?: ChatOptions): Promise { + const res = await fetch(this.apiUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${this.apiKey}`, + }, + body: JSON.stringify({ + model: this.defaultModel, + messages, + temperature: options?.temperature ?? 0.7, + top_p: options?.top_p ?? 1, + max_tokens: options?.max_tokens ?? 2000, + }), + }); + + if (!res.ok) { + throw new Error(`${this.name} API error: ${res.status} ${await res.text()}`); + } + + const data = await res.json() as any; + return data.choices[0].message.content; + } +} diff --git a/backend/src/modules/ai/ai.module.ts b/backend/src/modules/ai/ai.module.ts new file mode 100644 index 0000000..483efed --- /dev/null +++ b/backend/src/modules/ai/ai.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { AIGatewayService } from './ai-gateway.service'; + +@Module({ + providers: [AIGatewayService], + exports: [AIGatewayService], +}) +export class AIModule {} diff --git a/backend/src/modules/ai/tests/ai-gateway.service.spec.ts b/backend/src/modules/ai/tests/ai-gateway.service.spec.ts new file mode 100644 index 0000000..b3b8e3f --- /dev/null +++ b/backend/src/modules/ai/tests/ai-gateway.service.spec.ts @@ -0,0 +1,131 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AIGatewayService } from '../ai-gateway.service'; + +describe('AIGatewayService', () => { + let service: AIGatewayService; + + beforeEach(async () => { + // Clear env before each test + delete process.env.DEEPSEEK_API_KEY; + delete process.env.DASHSCOPE_API_KEY; + + const module: TestingModule = await Test.createTestingModule({ + providers: [AIGatewayService], + }).compile(); + + service = module.get(AIGatewayService); + }); + + describe('initialization', () => { + it('should have no providers when no API keys set', () => { + const providers = service.getRegisteredProviders(); + expect(providers).toEqual([]); + }); + }); + + describe('fallback mock responses', () => { + it('should greet when asked "你好"', async () => { + const result = await service.chat('any-model', [ + { role: 'user', content: '你好' }, + ]); + + expect(result).toContain('你好!我是宇之然 AI 助手'); + }); + + it('should greet in English for "hello"', async () => { + const result = await service.chat('any-model', [ + { role: 'user', content: 'hello' }, + ]); + + expect(result).toContain('Hello! I am YuZhiRan AI assistant'); + }); + + it('should provide prompt tips when asked about 提示词', async () => { + const result = await service.chat('any-model', [ + { role: 'user', content: '如何写好提示词?' }, + ]); + + expect(result).toContain('明确角色'); + expect(result).toContain('输出格式'); + }); + + it('should provide model info when asked about 大模型', async () => { + const result = await service.chat('any-model', [ + { role: 'user', content: '有哪些大模型?' }, + ]); + + expect(result).toContain('GPT'); + expect(result).toContain('Claude'); + expect(result).toContain('DeepSeek'); + }); + + it('should return generic fallback for unknown queries', async () => { + const result = await service.chat('any-model', [ + { role: 'user', content: '今天的天气怎么样?' }, + ]); + + expect(result).toContain('模拟模式'); + expect(result).toContain('API Key'); + }); + }); + + describe('model routing', () => { + it('should route deepseek models to deepseek provider (but fallback to mock)', async () => { + const result = await service.chat('deepseek-chat', [ + { role: 'user', content: '你好' }, + ]); + + // Falls back to mock since no API key + expect(result).toContain('宇之然 AI 助手'); + }); + + it('should route qwen models to dashscope provider (but fallback to mock)', async () => { + const result = await service.chat('qwen-max', [ + { role: 'user', content: '你好' }, + ]); + + expect(result).toContain('宇之然 AI 助手'); + }); + + it('should handle unknown model names by falling back', async () => { + const result = await service.chat('unknown-model-xyz', [ + { role: 'user', content: '测试' }, + ]); + + expect(result).toContain('模拟模式'); + }); + }); + + describe('contextual fallback', () => { + it('should include user message in fallback response', async () => { + const result = await service.chat('any', [ + { role: 'user', content: '如何学习 Python 编程?' }, + ]); + + expect(result).toContain('Python'); + }); + + it('should handle multi-turn conversations', async () => { + const messages = [ + { role: 'user' as const, content: '你是谁?' }, + { role: 'assistant' as const, content: '我是 AI 助手。' }, + { role: 'user' as const, content: '提示词有什么技巧?' }, + ]; + + const result = await service.chat('any', messages); + + expect(result).toContain('提示词'); + }); + + it('should truncate long user messages', async () => { + const longMsg = 'a'.repeat(200); + const result = await service.chat('any', [ + { role: 'user', content: longMsg }, + ]); + + expect(result).toContain('...'); + }); + }); +}); + + diff --git a/backend/src/modules/auth/auth.controller.ts b/backend/src/modules/auth/auth.controller.ts new file mode 100644 index 0000000..cc4c298 --- /dev/null +++ b/backend/src/modules/auth/auth.controller.ts @@ -0,0 +1,33 @@ +import { Controller, Post, Get, Body, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { AuthService } from './auth.service'; +import { RegisterDto } from './dto/register.dto'; + +@ApiTags('认证') +@Controller('auth') +export class AuthController { + constructor(private authService: AuthService) {} + + @Post('register') + async register(@Body() body: RegisterDto) { + return this.authService.register(body); + } + + @Post('login') + async login(@Body() body: { account: string; password: string }) { + return this.authService.login(body.account, body.password); + } + + @Post('refresh') + async refresh(@Body() body: { accessToken: string }) { + return this.authService.refreshAccessToken(body.accessToken); + } + + @Get('profile') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async profile(@Req() req: any) { + return this.authService.getProfile(req.user.userId); + } +} diff --git a/backend/src/modules/auth/auth.module.ts b/backend/src/modules/auth/auth.module.ts new file mode 100644 index 0000000..fcdcb82 --- /dev/null +++ b/backend/src/modules/auth/auth.module.ts @@ -0,0 +1,24 @@ +import { Module } from '@nestjs/common'; +import { JwtModule } from '@nestjs/jwt'; +import { PassportModule } from '@nestjs/passport'; +import { ConfigService } from '@nestjs/config'; +import { AuthController } from './auth.controller'; +import { AuthService } from './auth.service'; +import { JwtStrategy } from './jwt.strategy'; + +@Module({ + imports: [ + PassportModule.register({ defaultStrategy: 'jwt' }), + JwtModule.registerAsync({ + useFactory: (config: ConfigService) => ({ + secret: config.get('JWT_SECRET'), + signOptions: { expiresIn: config.get('JWT_EXPIRES_IN') || '2h' }, + }), + inject: [ConfigService], + }), + ], + controllers: [AuthController], + providers: [AuthService, JwtStrategy], + exports: [AuthService, JwtModule], +}) +export class AuthModule {} diff --git a/backend/src/modules/auth/auth.service.ts b/backend/src/modules/auth/auth.service.ts new file mode 100644 index 0000000..00e8300 --- /dev/null +++ b/backend/src/modules/auth/auth.service.ts @@ -0,0 +1,91 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import * as bcrypt from 'bcryptjs'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class AuthService { + constructor( + private prisma: PrismaService, + private jwtService: JwtService, + ) {} + + async register(data: { phone?: string; email?: string; password: string; nickname?: string }) { + const passwordHash = await bcrypt.hash(data.password, 10); + const user = await this.prisma.user.create({ + data: { + phone: data.phone, + email: data.email, + passwordHash, + nickname: data.nickname || data.phone || data.email?.split('@')[0], + }, + }); + return this.generateTokens(user.id); + } + + async login(account: string, password: string) { + const user = await this.prisma.user.findFirst({ + where: { + OR: [{ phone: account }, { email: account }], + deletedAt: null, + }, + }); + + if (!user || !user.passwordHash) { + throw new UnauthorizedException('账号或密码错误'); + } + + const isValid = await bcrypt.compare(password, user.passwordHash); + if (!isValid) { + throw new UnauthorizedException('账号或密码错误'); + } + + await this.prisma.user.update({ + where: { id: user.id }, + data: { lastLoginAt: new Date() }, + }); + + return this.generateTokens(user.id); + } + + async refreshAccessToken(accessToken: string) { + try { + const payload = this.jwtService.verify(accessToken, { ignoreExpiration: true }); + const user = await this.prisma.user.findUnique({ + where: { id: payload.sub, deletedAt: null }, + }); + if (!user || user.status !== 'ACTIVE') { + throw new UnauthorizedException('用户不可用'); + } + return this.generateTokens(user.id); + } catch { + throw new UnauthorizedException('Token 无效'); + } + } + + async getProfile(userId: number) { + return this.prisma.user.findUnique({ + where: { id: userId }, + select: { + id: true, + phone: true, + email: true, + nickname: true, + avatar: true, + status: true, + memberPlan: true, + memberExpire: true, + sandboxDaily: true, + createdAt: true, + }, + }); + } + + private generateTokens(userId: number) { + const payload = { sub: userId }; + return { + accessToken: this.jwtService.sign(payload, { expiresIn: '2h' }), + refreshToken: this.jwtService.sign(payload, { expiresIn: '7d' }), + }; + } +} diff --git a/backend/src/modules/auth/dto/register.dto.ts b/backend/src/modules/auth/dto/register.dto.ts new file mode 100644 index 0000000..d5231a7 --- /dev/null +++ b/backend/src/modules/auth/dto/register.dto.ts @@ -0,0 +1,20 @@ +import { IsNotEmpty, IsOptional, IsString, MinLength } from 'class-validator'; + +export class RegisterDto { + @IsOptional() + @IsString() + phone?: string; + + @IsOptional() + @IsString() + email?: string; + + @IsNotEmpty({ message: '密码不能为空' }) + @IsString() + @MinLength(6, { message: '密码至少6位' }) + password: string; + + @IsOptional() + @IsString() + nickname?: string; +} diff --git a/backend/src/modules/auth/jwt.strategy.ts b/backend/src/modules/auth/jwt.strategy.ts new file mode 100644 index 0000000..57b8fd3 --- /dev/null +++ b/backend/src/modules/auth/jwt.strategy.ts @@ -0,0 +1,36 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { PassportStrategy } from '@nestjs/passport'; +import { ExtractJwt, Strategy } from 'passport-jwt'; +import { ConfigService } from '@nestjs/config'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor( + private config: ConfigService, + private prisma: PrismaService, + ) { + const secret = config.get('JWT_SECRET') || 'yuzhiran-ai-default-secret'; + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: secret, + }); + } + + async validate(payload: { sub: number; type?: string }) { + if (payload.type === 'admin') { + const admin = await this.prisma.adminUser.findUnique({ where: { id: payload.sub } }); + if (!admin || admin.status !== 'ACTIVE') { + throw new UnauthorizedException(); + } + return { userId: payload.sub, isAdmin: true }; + } + + const user = await this.prisma.user.findUnique({ where: { id: payload.sub } }); + if (!user || user.deletedAt) { + throw new UnauthorizedException(); + } + return { userId: payload.sub, isAdmin: false }; + } +} diff --git a/backend/src/modules/auth/tests/auth.service.spec.ts b/backend/src/modules/auth/tests/auth.service.spec.ts new file mode 100644 index 0000000..1b69cb6 --- /dev/null +++ b/backend/src/modules/auth/tests/auth.service.spec.ts @@ -0,0 +1,45 @@ +// @ts-nocheck +import { Test, TestingModule } from '@nestjs/testing'; +import { JwtService } from '@nestjs/jwt'; +import { AuthService } from '../auth.service'; +import { PrismaService } from '../../../prisma/prisma.service'; + +jest.mock('bcryptjs', () => ({ + compare: jest.fn(), + hash: jest.fn(), +})); + +describe('AuthService', () => { + let service: AuthService; + + beforeEach(async () => { + const mockPrisma = { + user: { + create: jest.fn().mockResolvedValue({ id: 1 }), + findFirst: jest.fn().mockResolvedValue(null), + findUnique: jest.fn().mockResolvedValue(null), + update: jest.fn().mockResolvedValue({}), + }, + }; + + const mockJwtService = { + sign: jest.fn().mockReturnValue('mock-token'), + verify: jest.fn().mockReturnValue({ sub: 1 }), + }; + + const module = await Test.createTestingModule({ + providers: [ + AuthService, + { provide: PrismaService, useValue: mockPrisma }, + { provide: JwtService, useValue: mockJwtService }, + ], + }).compile(); + + service = module.get(AuthService); + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/backend/src/modules/categories/categories.controller.ts b/backend/src/modules/categories/categories.controller.ts new file mode 100644 index 0000000..8e4e51a --- /dev/null +++ b/backend/src/modules/categories/categories.controller.ts @@ -0,0 +1,37 @@ +import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { PrismaService } from '../../prisma/prisma.service'; + +@ApiTags('分类') +@Controller('categories') +export class CategoriesController { + constructor(private prisma: PrismaService) {} + + @Get() + async findAll() { + return this.prisma.category.findMany({ + orderBy: { sortOrder: 'asc' }, + include: { _count: { select: { courses: true, prompts: true, tools: true, contents: true } } }, + }); + } + + @Get(':id') + async findById(@Param('id') id: string) { + return this.prisma.category.findUnique({ where: { id: +id } }); + } + + @Post() + async create(@Body() body: { name: string; slug: string; description?: string; sortOrder?: number }) { + return this.prisma.category.create({ data: body }); + } + + @Put(':id') + async update(@Param('id') id: string, @Body() body: any) { + return this.prisma.category.update({ where: { id: +id }, data: body }); + } + + @Delete(':id') + async remove(@Param('id') id: string) { + return this.prisma.category.delete({ where: { id: +id } }); + } +} diff --git a/backend/src/modules/categories/categories.module.ts b/backend/src/modules/categories/categories.module.ts new file mode 100644 index 0000000..6376c04 --- /dev/null +++ b/backend/src/modules/categories/categories.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; +import { CategoriesController } from './categories.controller'; + +@Module({ + controllers: [CategoriesController], +}) +export class CategoriesModule {} diff --git a/backend/src/modules/community/circles.controller.ts b/backend/src/modules/community/circles.controller.ts new file mode 100644 index 0000000..544fb36 --- /dev/null +++ b/backend/src/modules/community/circles.controller.ts @@ -0,0 +1,60 @@ +import { Controller, Get, Post, Body, Param, Query, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { CommunityService } from './community.service'; + +@ApiTags('圈子') +@Controller('circles') +export class CirclesController { + constructor(private communityService: CommunityService) {} + + @Get() + async findCircles(@Query('category') category?: string) { + return this.communityService.findCircles(category); + } + + @Get(':id') + async findCircleById(@Param('id') id: string) { + return this.communityService.findCircleById(+id); + } + + @Get(':id/posts') + async findCirclePosts( + @Param('id') id: string, + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + ) { + return this.communityService.findCirclePosts(+id, { + page: page ? parseInt(page) : undefined, + pageSize: pageSize ? parseInt(pageSize) : undefined, + }); + } + + @Post() + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async createCircle(@Req() req: any, @Body() body: { name: string; description?: string; tags?: string }) { + return this.communityService.createCircle(req.user.userId, body); + } + + @Post(':id/join') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async joinCircle(@Req() req: any, @Param('id') id: string) { + return this.communityService.joinCircle(req.user.userId, +id); + } + + @Post(':id/leave') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async leaveCircle(@Req() req: any, @Param('id') id: string) { + return this.communityService.leaveCircle(req.user.userId, +id); + } + + @Get(':id/membership') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async checkMembership(@Req() req: any, @Param('id') id: string) { + return this.communityService.checkCircleMembership(req.user.userId, +id); + } +} diff --git a/backend/src/modules/community/community.controller.ts b/backend/src/modules/community/community.controller.ts new file mode 100644 index 0000000..127819e --- /dev/null +++ b/backend/src/modules/community/community.controller.ts @@ -0,0 +1,131 @@ +import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { CommunityService } from './community.service'; + +@ApiTags('社区') +@Controller('community') +export class CommunityController { + constructor(private communityService: CommunityService) {} + + @Get('posts') + async findPosts( + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + @Query('tag') tag?: string, + @Query('circleId') circleId?: string, + @Query('userId') userId?: string, + ) { + return this.communityService.findPosts({ + page: page ? parseInt(page) : undefined, + pageSize: pageSize ? parseInt(pageSize) : undefined, + tag, + circleId: circleId ? parseInt(circleId) : undefined, + userId: userId ? parseInt(userId) : undefined, + }); + } + + @Get('posts/:id') + async findPostById(@Param('id') id: string) { + return this.communityService.findPostById(parseInt(id)); + } + + @Post('posts') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async createPost(@Req() req: any, @Body() body: { title: string; content: string; tags?: string; circleId?: number }) { + return this.communityService.createPost(req.user.userId, body); + } + + @Put('posts/:id') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async updatePost(@Req() req: any, @Param('id') id: string, @Body() body: { title?: string; content?: string; tags?: string }) { + return this.communityService.updatePost(req.user.userId, parseInt(id), body); + } + + @Delete('posts/:id') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async deletePost(@Req() req: any, @Param('id') id: string) { + return this.communityService.deletePost(req.user.userId, parseInt(id)); + } + + @Post('posts/:id/comments') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async addComment( + @Req() req: any, + @Param('id') id: string, + @Body('content') content: string, + @Body('parentId') parentId?: number, + ) { + return this.communityService.addComment(req.user.userId, parseInt(id), content, parentId); + } + + @Post('posts/:id/like') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async toggleLike(@Req() req: any, @Param('id') id: string) { + return this.communityService.toggleLike(req.user.userId, parseInt(id)); + } + + @Get('posts/:id/like') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async checkLike(@Req() req: any, @Param('id') id: string) { + return this.communityService.checkLike(req.user.userId, parseInt(id)); + } + + @Get('feed') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async getFeed(@Req() req: any, @Query('page') page?: string, @Query('pageSize') pageSize?: string) { + return this.communityService.getFeed(req.user.userId, { + page: page ? parseInt(page) : undefined, + pageSize: pageSize ? parseInt(pageSize) : undefined, + }); + } + + @Post('users/:id/follow') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async followUser(@Req() req: any, @Param('id') id: string) { + return this.communityService.followUser(req.user.userId, parseInt(id)); + } + + @Delete('users/:id/follow') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async unfollowUser(@Req() req: any, @Param('id') id: string) { + return this.communityService.unfollowUser(req.user.userId, parseInt(id)); + } + + @Get('users/:id/follow') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async checkFollow(@Req() req: any, @Param('id') id: string) { + return this.communityService.checkFollow(req.user.userId, parseInt(id)); + } + + @Get('users/:id/followers') + async getFollowers(@Param('id') id: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) { + return this.communityService.getFollowers(parseInt(id), { + page: page ? parseInt(page) : undefined, + pageSize: pageSize ? parseInt(pageSize) : undefined, + }); + } + + @Get('users/:id/following') + async getFollowing(@Param('id') id: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) { + return this.communityService.getFollowing(parseInt(id), { + page: page ? parseInt(page) : undefined, + pageSize: pageSize ? parseInt(pageSize) : undefined, + }); + } + + @Get('users/:id/profile') + async getUserProfile(@Param('id') id: string) { + return this.communityService.getUserProfile(parseInt(id)); + } +} diff --git a/backend/src/modules/community/community.module.ts b/backend/src/modules/community/community.module.ts new file mode 100644 index 0000000..8ffdc77 --- /dev/null +++ b/backend/src/modules/community/community.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { CommunityController } from './community.controller'; +import { CirclesController } from './circles.controller'; +import { CommunityService } from './community.service'; +import { NotificationService } from '../notifications/notification.service'; + +@Module({ + controllers: [CommunityController, CirclesController], + providers: [CommunityService, NotificationService], +}) +export class CommunityModule {} diff --git a/backend/src/modules/community/community.service.ts b/backend/src/modules/community/community.service.ts new file mode 100644 index 0000000..d3a585d --- /dev/null +++ b/backend/src/modules/community/community.service.ts @@ -0,0 +1,385 @@ +import { Injectable, NotFoundException, ConflictException, BadRequestException, ForbiddenException } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; +import { NotificationService } from '../notifications/notification.service'; + +const SENSITIVE_WORDS = ['敏感词1', '敏感词2', '广告', '诈骗', '违法', '赌博']; + +function containsSensitiveWord(text: string): string | null { + const lower = text.toLowerCase(); + for (const word of SENSITIVE_WORDS) { + if (lower.includes(word)) return word; + } + return null; +} + +@Injectable() +export class CommunityService { + constructor( + private prisma: PrismaService, + private notificationService: NotificationService, + ) {} + + async findPosts(params: { page?: number; pageSize?: number; tag?: string; circleId?: number; userId?: number }) { + const page = Number(params.page ?? 1); + const pageSize = Math.min(Number(params.pageSize ?? 20), 50); + const where: any = { status: 'PUBLISHED' }; + if (params.tag) where.tags = { contains: params.tag }; + if (params.circleId) where.circleId = params.circleId; + if (params.userId) where.userId = params.userId; + + const [items, total] = await Promise.all([ + this.prisma.post.findMany({ + where, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { createdAt: 'desc' }, + include: { user: { select: { id: true, nickname: true, avatar: true } } }, + }), + this.prisma.post.count({ where }), + ]); + + return { items, total, page, pageSize }; + } + + async findPostById(id: number) { + const post = await this.prisma.post.findUnique({ + where: { id }, + include: { + user: { select: { id: true, nickname: true, avatar: true } }, + comments: { + where: { status: 'PUBLISHED' }, + include: { + user: { select: { id: true, nickname: true, avatar: true } }, + replies: { + where: { status: 'PUBLISHED' }, + include: { user: { select: { id: true, nickname: true, avatar: true } } }, + }, + }, + }, + }, + }); + + if (post) { + await this.prisma.post.update({ + where: { id }, + data: { viewCount: { increment: 1 } }, + }); + } + + return post; + } + + async createPost(userId: number, data: { title: string; content: string; tags?: string; circleId?: number }) { + const post = await this.prisma.post.create({ + data: { + userId, + title: data.title, + content: data.content, + tags: data.tags, + circleId: data.circleId, + }, + include: { user: { select: { id: true, nickname: true, avatar: true } } }, + }); + + await this.prisma.user.update({ + where: { id: userId }, + data: { postCount: { increment: 1 } }, + }); + + return post; + } + + async updatePost(userId: number, postId: number, data: { title?: string; content?: string; tags?: string }) { + const post = await this.prisma.post.findUnique({ where: { id: postId } }); + if (!post) throw new NotFoundException('帖子不存在'); + if (post.userId !== userId) throw new BadRequestException('无权编辑此帖子'); + + return this.prisma.post.update({ + where: { id: postId }, + data, + include: { user: { select: { id: true, nickname: true, avatar: true } } }, + }); + } + + async deletePost(userId: number, postId: number) { + const post = await this.prisma.post.findUnique({ where: { id: postId } }); + if (!post) throw new NotFoundException('帖子不存在'); + if (post.userId !== userId) throw new BadRequestException('无权删除此帖子'); + + await this.prisma.post.delete({ where: { id: postId } }); + + await this.prisma.user.update({ + where: { id: userId }, + data: { postCount: { decrement: 1 } }, + }); + + return { deleted: true }; + } + + async addComment(userId: number, postId: number, content: string, parentId?: number) { + const post = await this.prisma.post.findUnique({ where: { id: postId } }); + if (!post) throw new NotFoundException('帖子不存在'); + + if (parentId) { + const parentComment = await this.prisma.comment.findUnique({ where: { id: parentId } }); + if (!parentComment || parentComment.postId !== postId) { + throw new BadRequestException('父评论不存在'); + } + } + + const matchedWord = containsSensitiveWord(content); + const status = matchedWord ? 'REJECTED' : 'PENDING_REVIEW'; + + const comment = await this.prisma.comment.create({ + data: { userId, postId, content, parentId, status }, + include: { user: { select: { id: true, nickname: true, avatar: true } } }, + }); + + if (matchedWord) { + return { ...comment, rejected: true, reason: `评论包含敏感词「${matchedWord}」` }; + } + + await this.prisma.post.update({ + where: { id: postId }, + data: { commentCount: { increment: 1 } }, + }); + + if (post.userId !== userId) { + await this.notificationService.create({ + userId: post.userId, + type: 'comment', + title: `${comment.user.nickname || '用户'} 评论了你的帖子`, + content: content.slice(0, 100), + link: `/community/${postId}`, + relatedId: postId, + }); + } + + return comment; + } + + async toggleLike(userId: number, postId: number) { + const existing = await this.prisma.postLike.findFirst({ where: { userId, postId } }); + + if (existing) { + await this.prisma.postLike.delete({ where: { id: existing.id } }); + await this.prisma.post.update({ + where: { id: postId }, + data: { likeCount: { decrement: 1 } }, + }); + return { liked: false }; + } else { + await this.prisma.postLike.create({ data: { userId, postId } }); + await this.prisma.post.update({ + where: { id: postId }, + data: { likeCount: { increment: 1 } }, + }); + + const post = await this.prisma.post.findUnique({ where: { id: postId }, select: { userId: true, title: true } }); + if (post && post.userId !== userId) { + await this.notificationService.create({ + userId: post.userId, + type: 'like', + title: `有人赞了你的帖子「${post.title.slice(0, 30)}」`, + link: `/community/${postId}`, + relatedId: postId, + }); + } + + return { liked: true }; + } + } + + async checkLike(userId: number, postId: number) { + const existing = await this.prisma.postLike.findFirst({ where: { userId, postId } }); + return { liked: !!existing }; + } + + async getFeed(userId: number, params: { page?: number; pageSize?: number }) { + const page = Number(params.page ?? 1); + const pageSize = Math.min(Number(params.pageSize ?? 20), 50); + + const following = await this.prisma.follow.findMany({ + where: { followerId: userId }, + select: { followingId: true }, + }); + const followingIds = following.map(f => f.followingId); + + const where: any = { status: 'PUBLISHED' }; + if (followingIds.length > 0) { + where.userId = { in: followingIds }; + } + + const [items, total] = await Promise.all([ + this.prisma.post.findMany({ + where, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { createdAt: 'desc' }, + include: { user: { select: { id: true, nickname: true, avatar: true } } }, + }), + this.prisma.post.count({ where }), + ]); + + return { items, total, page, pageSize }; + } + + async followUser(followerId: number, followingId: number) { + if (followerId === followingId) throw new BadRequestException('不能关注自己'); + + const existing = await this.prisma.follow.findUnique({ + where: { followerId_followingId: { followerId, followingId } }, + }); + if (existing) throw new ConflictException('已关注该用户'); + + await this.prisma.follow.create({ data: { followerId, followingId } }); + await this.prisma.user.update({ where: { id: followerId }, data: { followingCount: { increment: 1 } } }); + await this.prisma.user.update({ where: { id: followingId }, data: { followerCount: { increment: 1 } } }); + + const follower = await this.prisma.user.findUnique({ where: { id: followerId }, select: { nickname: true } }); + await this.notificationService.create({ + userId: followingId, + type: 'follow', + title: `${follower?.nickname || '用户'} 关注了你`, + link: `/users/${followerId}`, + relatedId: followerId, + }); + + return { followed: true }; + } + + async unfollowUser(followerId: number, followingId: number) { + const existing = await this.prisma.follow.findUnique({ + where: { followerId_followingId: { followerId, followingId } }, + }); + if (!existing) throw new NotFoundException('未关注该用户'); + + await this.prisma.follow.delete({ where: { id: existing.id } }); + await this.prisma.user.update({ where: { id: followerId }, data: { followingCount: { decrement: 1 } } }); + await this.prisma.user.update({ where: { id: followingId }, data: { followerCount: { decrement: 1 } } }); + + return { followed: false }; + } + + async checkFollow(followerId: number, followingId: number) { + const existing = await this.prisma.follow.findUnique({ + where: { followerId_followingId: { followerId, followingId } }, + }); + return { followed: !!existing }; + } + + async getFollowers(userId: number, params: { page?: number; pageSize?: number }) { + const page = Number(params.page ?? 1); + const pageSize = Math.min(Number(params.pageSize ?? 20), 50); + + const [items, total] = await Promise.all([ + this.prisma.follow.findMany({ + where: { followingId: userId }, + skip: (page - 1) * pageSize, + take: pageSize, + include: { follower: { select: { id: true, nickname: true, avatar: true, followerCount: true, followingCount: true } } }, + orderBy: { createdAt: 'desc' }, + }), + this.prisma.follow.count({ where: { followingId: userId } }), + ]); + + return { items: items.map(i => i.follower), total, page, pageSize }; + } + + async getFollowing(userId: number, params: { page?: number; pageSize?: number }) { + const page = Number(params.page ?? 1); + const pageSize = Math.min(Number(params.pageSize ?? 20), 50); + + const [items, total] = await Promise.all([ + this.prisma.follow.findMany({ + where: { followerId: userId }, + skip: (page - 1) * pageSize, + take: pageSize, + include: { following: { select: { id: true, nickname: true, avatar: true, followerCount: true, followingCount: true } } }, + orderBy: { createdAt: 'desc' }, + }), + this.prisma.follow.count({ where: { followerId: userId } }), + ]); + + return { items: items.map(i => i.following), total, page, pageSize }; + } + + async getUserProfile(userId: number) { + const user = await this.prisma.user.findUnique({ + where: { id: userId, deletedAt: null }, + select: { + id: true, nickname: true, avatar: true, bio: true, + followerCount: true, followingCount: true, postCount: true, + createdAt: true, + }, + }); + if (!user) throw new NotFoundException('用户不存在'); + return user; + } + + async findCircles(category?: string) { + const where: any = {}; + if (category) where.tags = { contains: category }; + + return this.prisma.circle.findMany({ + where, + include: { _count: { select: { members: true, posts: true } } }, + orderBy: { createdAt: 'desc' }, + }); + } + + async findCircleById(id: number) { + const circle = await this.prisma.circle.findUnique({ + where: { id }, + include: { + _count: { select: { members: true, posts: true } }, + creator: { select: { id: true, nickname: true, avatar: true } }, + }, + }); + if (!circle) throw new NotFoundException('圈子不存在'); + return circle; + } + + async findCirclePosts(circleId: number, params: { page?: number; pageSize?: number }) { + return this.findPosts({ ...params, circleId }); + } + + async createCircle(userId: number, data: { name: string; description?: string; tags?: string }) { + const existing = await this.prisma.circle.findFirst({ where: { name: data.name } }); + if (existing) throw new ConflictException('圈子名称已存在'); + + return this.prisma.circle.create({ + data: { name: data.name, description: data.description, tags: data.tags, creatorId: userId }, + include: { _count: { select: { members: true } } }, + }); + } + + async joinCircle(userId: number, circleId: number) { + const circle = await this.prisma.circle.findUnique({ where: { id: circleId } }); + if (!circle) throw new NotFoundException('圈子不存在'); + + const existing = await this.prisma.circleMember.findUnique({ + where: { circleId_userId: { circleId, userId } }, + }); + if (existing) throw new ConflictException('已是圈子成员'); + + return this.prisma.circleMember.create({ data: { circleId, userId } }); + } + + async leaveCircle(userId: number, circleId: number) { + const existing = await this.prisma.circleMember.findUnique({ + where: { circleId_userId: { circleId, userId } }, + }); + if (!existing) throw new BadRequestException('不是圈子成员'); + + await this.prisma.circleMember.delete({ where: { id: existing.id } }); + return { left: true }; + } + + async checkCircleMembership(userId: number, circleId: number) { + const existing = await this.prisma.circleMember.findUnique({ + where: { circleId_userId: { circleId, userId } }, + }); + return { isMember: !!existing }; + } +} diff --git a/backend/src/modules/community/tests/community.service.spec.ts b/backend/src/modules/community/tests/community.service.spec.ts new file mode 100644 index 0000000..bdb79ff --- /dev/null +++ b/backend/src/modules/community/tests/community.service.spec.ts @@ -0,0 +1,223 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { NotFoundException, ConflictException, BadRequestException } from '@nestjs/common'; +import { CommunityService } from '../community.service'; +import { PrismaService } from '../../../prisma/prisma.service'; +import { NotificationService } from '../../notifications/notification.service'; + +const selectUser = { id: true, nickname: true, avatar: true }; + +describe('CommunityService', () => { + let service: CommunityService; + let prisma: PrismaService; + + const mockPrisma = { + post: { + findMany: jest.fn(), + findUnique: jest.fn(), + create: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + count: jest.fn(), + }, + comment: { + create: jest.fn(), + }, + postLike: { + findFirst: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + }, + user: { + findUnique: jest.fn(), + update: jest.fn(), + }, + follow: { + findUnique: jest.fn(), + findMany: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + count: jest.fn(), + }, + circle: { + findMany: jest.fn(), + findUnique: jest.fn(), + findFirst: jest.fn(), + create: jest.fn(), + }, + circleMember: { + findUnique: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + }, + }; + + const mockNotification = { create: jest.fn() }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + CommunityService, + { provide: PrismaService, useValue: mockPrisma }, + { provide: NotificationService, useValue: mockNotification }, + ], + }).compile(); + + service = module.get(CommunityService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('findPosts', () => { + it('should return paginated posts without tag filter', async () => { + const mockPosts = [ + { id: 1, title: '帖子1', status: 'PUBLISHED' }, + ]; + mockPrisma.post.findMany.mockResolvedValue(mockPosts); + mockPrisma.post.count.mockResolvedValue(1); + + const result = await service.findPosts({}); + + expect(result).toEqual({ items: mockPosts, total: 1, page: 1, pageSize: 20 }); + expect(mockPrisma.post.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: { status: 'PUBLISHED' }, + skip: 0, + take: 20, + include: { user: { select: selectUser } }, + }) + ); + }); + + it('should filter by tag', async () => { + await service.findPosts({ tag: 'AI' }); + + expect(mockPrisma.post.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: expect.objectContaining({ tags: { contains: 'AI' } }), + }) + ); + }); + }); + + describe('findPostById', () => { + it('should increment viewCount and return post', async () => { + const mockPost = { + id: 1, + title: '测试帖子', + status: 'PUBLISHED', + user: { id: 1, nickname: '用户1' }, + comments: [], + }; + mockPrisma.post.update.mockResolvedValue(mockPost); + mockPrisma.post.findUnique.mockResolvedValue(mockPost); + + const result = await service.findPostById(1); + + expect(result).toEqual(mockPost); + expect(mockPrisma.post.update).toHaveBeenCalledWith({ + where: { id: 1 }, + data: { viewCount: { increment: 1 } }, + }); + }); + }); + + describe('createPost', () => { + it('should create a new post', async () => { + const mockPost = { + id: 1, + title: '新帖子', + content: '内容', + userId: 1, + }; + mockPrisma.post.create.mockResolvedValue(mockPost); + + const result = await service.createPost(1, { + title: '新帖子', + content: '内容', + }); + + expect(result).toEqual(mockPost); + expect(mockPrisma.post.create).toHaveBeenCalledWith({ + data: { + userId: 1, + title: '新帖子', + content: '内容', + }, + include: { user: { select: selectUser } }, + }); + expect(mockPrisma.user.update).toHaveBeenCalledWith({ + where: { id: 1 }, + data: { postCount: { increment: 1 } }, + }); + }); + }); + + describe('addComment', () => { + it('should add comment and increment commentCount', async () => { + const mockPost = { id: 1, userId: 2 }; + mockPrisma.post.findUnique.mockResolvedValue(mockPost); + + const mockComment = { id: 1, content: '评论', userId: 1, postId: 1, user: { id: 1, nickname: '用户1', avatar: null } }; + mockPrisma.comment.create.mockResolvedValue(mockComment); + + const result = await service.addComment(1, 1, '评论'); + + expect(result).toEqual(mockComment); + expect(mockPrisma.comment.create).toHaveBeenCalledWith({ + data: { userId: 1, postId: 1, content: '评论', status: 'PENDING_REVIEW' }, + include: { user: { select: selectUser } }, + }); + }); + + it('should throw NotFoundException if post not found', async () => { + mockPrisma.post.findUnique.mockResolvedValue(null); + + await expect(service.addComment(1, 999, '评论')).rejects.toThrow(NotFoundException); + }); + }); + + describe('toggleLike', () => { + it('should add like if not exists', async () => { + mockPrisma.postLike.findFirst.mockResolvedValue(null); + mockPrisma.postLike.create.mockResolvedValue({}); + mockPrisma.post.findUnique.mockResolvedValue({ id: 1, userId: 2, title: '帖子' }); + + const result = await service.toggleLike(1, 1); + + expect(result).toEqual({ liked: true }); + expect(mockPrisma.postLike.create).toHaveBeenCalledWith({ + data: { userId: 1, postId: 1 }, + }); + }); + + it('should remove like if exists', async () => { + mockPrisma.postLike.findFirst.mockResolvedValue({ id: 1 }); + mockPrisma.postLike.delete.mockResolvedValue({}); + + const result = await service.toggleLike(1, 1); + + expect(result).toEqual({ liked: false }); + expect(mockPrisma.postLike.delete).toHaveBeenCalledWith({ + where: { id: 1 }, + }); + }); + }); + + describe('checkLike', () => { + it('should return liked status', async () => { + mockPrisma.postLike.findFirst.mockResolvedValue({ id: 1 }); + + const result = await service.checkLike(1, 1); + + expect(result).toEqual({ liked: true }); + }); + + it('should return not liked if no record', async () => { + mockPrisma.postLike.findFirst.mockResolvedValue(null); + + const result = await service.checkLike(1, 1); + + expect(result).toEqual({ liked: false }); + }); + }); +}); diff --git a/backend/src/modules/contents/contents.controller.ts b/backend/src/modules/contents/contents.controller.ts new file mode 100644 index 0000000..0d2ab02 --- /dev/null +++ b/backend/src/modules/contents/contents.controller.ts @@ -0,0 +1,34 @@ +import { Controller, Get, Post, Put, Delete, Body, Param, Query } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { ContentsService } from './contents.service'; + +@ApiTags('内容') +@Controller('contents') +export class ContentsController { + constructor(private contentsService: ContentsService) {} + + @Get() + async findAll(@Query() query: { page?: number; pageSize?: number; categoryId?: number; contentType?: string }) { + return this.contentsService.findAll(query); + } + + @Get(':id') + async findById(@Param('id') id: string) { + return this.contentsService.findById(+id); + } + + @Post() + async create(@Body() body: any) { + return this.contentsService.create(body); + } + + @Put(':id') + async update(@Param('id') id: string, @Body() body: any) { + return this.contentsService.update(+id, body); + } + + @Delete(':id') + async remove(@Param('id') id: string) { + return this.contentsService.remove(+id); + } +} diff --git a/backend/src/modules/contents/contents.module.ts b/backend/src/modules/contents/contents.module.ts new file mode 100644 index 0000000..8bfd1b7 --- /dev/null +++ b/backend/src/modules/contents/contents.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ContentsController } from './contents.controller'; +import { ContentsService } from './contents.service'; + +@Module({ + controllers: [ContentsController], + providers: [ContentsService], + exports: [ContentsService], +}) +export class ContentsModule {} diff --git a/backend/src/modules/contents/contents.service.ts b/backend/src/modules/contents/contents.service.ts new file mode 100644 index 0000000..2153cab --- /dev/null +++ b/backend/src/modules/contents/contents.service.ts @@ -0,0 +1,52 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class ContentsService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { page?: number; pageSize?: number; categoryId?: number; contentType?: string }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 20); + const { categoryId, contentType } = params; + const where: any = { status: 'PUBLISHED', deletedAt: null }; + if (categoryId) where.categoryId = categoryId; + if (contentType) where.contentType = contentType; + + const [items, total] = await Promise.all([ + this.prisma.content.findMany({ + where, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { publishedAt: 'desc' }, + select: { + id: true, title: true, summary: true, cover: true, contentType: true, + tags: true, authorName: true, viewCount: true, isAiGenerated: true, + publishedAt: true, createdAt: true, category: true, + }, + }), + this.prisma.content.count({ where }), + ]); + + return { items, total, page, pageSize }; + } + + async findById(id: number) { + const content = await this.prisma.content.findUnique({ where: { id }, include: { category: true } }); + if (!content) return null; + await this.prisma.content.update({ where: { id }, data: { viewCount: { increment: 1 } } }); + return content; + } + + async create(data: any) { + return this.prisma.content.create({ data }); + } + + async update(id: number, data: any) { + return this.prisma.content.update({ where: { id }, data }); + } + + async remove(id: number) { + return this.prisma.content.update({ where: { id }, data: { deletedAt: new Date() } }); + } +} diff --git a/backend/src/modules/courses/courses.controller.ts b/backend/src/modules/courses/courses.controller.ts new file mode 100644 index 0000000..91f3816 --- /dev/null +++ b/backend/src/modules/courses/courses.controller.ts @@ -0,0 +1,66 @@ +import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { CoursesService } from './courses.service'; + +@ApiTags('课程') +@Controller('courses') +export class CoursesController { + constructor(private coursesService: CoursesService) {} + + @Get() + async findAll(@Query() query: { page?: number; pageSize?: number; categoryId?: number; isFree?: boolean }) { + return this.coursesService.findAll(query); + } + + @Get(':id') + async findById(@Param('id') id: string) { + return this.coursesService.findById(+id); + } + + @Post() + async create(@Body() body: { + title: string; description?: string; cover?: string; categoryId?: number; + price?: number; isFree?: boolean; + }) { + return this.coursesService.create(body); + } + + @Put(':id') + async update(@Param('id') id: string, @Body() body: any) { + return this.coursesService.update(+id, body); + } + + @Delete(':id') + async remove(@Param('id') id: string) { + return this.coursesService.remove(+id); + } + + @Post(':courseId/lessons/:lessonId/progress') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async updateProgress( + @Req() req: any, + @Param('courseId') courseId: string, + @Param('lessonId') lessonId: string, + @Body() body: { completed?: boolean; progress?: number }, + ) { + return this.coursesService.updateProgress( + req.user.userId, + +courseId, + +lessonId, + body.completed, + body.progress, + ); + } + + @Get('my-learning') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async getMyLearning(@Req() req: any, @Query('courseId') courseId?: string) { + return this.coursesService.getLearningProgress( + req.user.userId, + courseId ? +courseId : undefined, + ); + } +} diff --git a/backend/src/modules/courses/courses.module.ts b/backend/src/modules/courses/courses.module.ts new file mode 100644 index 0000000..68cb16d --- /dev/null +++ b/backend/src/modules/courses/courses.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { CoursesController } from './courses.controller'; +import { CoursesService } from './courses.service'; + +@Module({ + controllers: [CoursesController], + providers: [CoursesService], + exports: [CoursesService], +}) +export class CoursesModule {} diff --git a/backend/src/modules/courses/courses.service.ts b/backend/src/modules/courses/courses.service.ts new file mode 100644 index 0000000..98071e8 --- /dev/null +++ b/backend/src/modules/courses/courses.service.ts @@ -0,0 +1,180 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class CoursesService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { page?: number; pageSize?: number; categoryId?: number; isFree?: boolean }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 20); + const { categoryId, isFree } = params; + const where: any = { status: 'PUBLISHED', deletedAt: null }; + if (categoryId) where.categoryId = categoryId; + if (isFree !== undefined) where.isFree = isFree; + + const [items, total] = await Promise.all([ + this.prisma.course.findMany({ + where, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { sortOrder: 'asc' }, + include: { category: true, chapters: { include: { lessons: true }, orderBy: { sortOrder: 'asc' } } }, + }), + this.prisma.course.count({ where }), + ]); + + return { items, total, page, pageSize }; + } + + async findById(id: number) { + return this.prisma.course.findUnique({ + where: { id }, + include: { + category: true, + chapters: { + orderBy: { sortOrder: 'asc' }, + include: { lessons: { orderBy: { sortOrder: 'asc' } } }, + }, + }, + }); + } + + async create(data: { + title: string; description?: string; cover?: string; categoryId?: number; + price?: number; isFree?: boolean; sortOrder?: number; + }) { + return this.prisma.course.create({ data }); + } + + async update(id: number, data: any) { + const { chapters, ...courseData } = data; + return this.prisma.course.update({ + where: { id }, + data: courseData, + }); + } + + async updateWithChapters(id: number, data: any) { + const { chapters, ...courseData } = data; + if (chapters) { + const existingChapters = await this.prisma.chapter.findMany({ where: { courseId: id } }); + const existingIds = existingChapters.map(c => c.id); + const incomingIds = chapters.filter((c: any) => c.id).map((c: any) => c.id); + const toDelete = existingIds.filter(eid => !incomingIds.includes(eid)); + for (const cid of toDelete) { + await this.prisma.lesson.deleteMany({ where: { chapterId: cid } }); + await this.prisma.chapter.delete({ where: { id: cid } }); + } + for (const ch of chapters) { + if (ch.id) { + const { lessons, id: chId, courseId, ...chData } = ch; + await this.prisma.chapter.update({ where: { id: ch.id }, data: chData }); + if (lessons) { + const existingLessons = await this.prisma.lesson.findMany({ where: { chapterId: ch.id } }); + const existingLessonIds = existingLessons.map(l => l.id); + const incomingLessonIds = lessons.filter((l: any) => l.id).map((l: any) => l.id); + const lessonsToDelete = existingLessonIds.filter(eid => !incomingLessonIds.includes(eid)); + for (const lid of lessonsToDelete) { + await this.prisma.lesson.delete({ where: { id: lid } }); + } + for (const le of lessons) { + if (le.id) { + const { id: lessonId, chapterId, ...lessonData } = le; + await this.prisma.lesson.update({ where: { id: le.id }, data: lessonData }); + } else { + const { id: _li, ...lessonData } = le; + await this.prisma.lesson.create({ data: { ...lessonData, chapterId: ch.id } }); + } + } + } + } else { + const { lessons, id: _newChId, ...chData } = ch; + const newCh = await this.prisma.chapter.create({ data: { ...chData, courseId: id } }); + if (lessons) { + for (const le of lessons) { + const { id: _li, ...lessonData } = le; + await this.prisma.lesson.create({ data: { ...lessonData, chapterId: newCh.id } }); + } + } + } + } + } + return this.prisma.course.update({ + where: { id }, + data: courseData, + include: { chapters: { include: { lessons: { orderBy: { sortOrder: 'asc' } } }, orderBy: { sortOrder: 'asc' } } }, + }); + } + + async remove(id: number) { + return this.prisma.course.update({ where: { id }, data: { deletedAt: new Date() } }); + } + + async updateProgress(userId: number, courseId: number, lessonId: number, completed?: boolean, progress?: number) { + const existing = await this.prisma.learnRecord.findUnique({ + where: { userId_lessonId: { userId, lessonId } }, + }); + + if (existing) { + return this.prisma.learnRecord.update({ + where: { id: existing.id }, + data: { + completed: completed ?? existing.completed, + progress: progress ?? existing.progress, + }, + }); + } else { + return this.prisma.learnRecord.create({ + data: { + userId, + courseId, + lessonId, + completed: completed ?? false, + progress: progress ?? 0, + }, + }); + } + } + + async getLearningProgress(userId: number, courseId?: number) { + const where: any = { userId }; + if (courseId) { + where.courseId = courseId; + } + + const records = await this.prisma.learnRecord.findMany({ + where, + include: { + course: { select: { id: true, title: true } }, + lesson: { select: { id: true, title: true, chapterId: true } }, + }, + }); + + const courseMap: Record = {}; + records.forEach(r => { + if (!courseMap[r.courseId]) { + courseMap[r.courseId] = { + courseId: r.courseId, + courseTitle: r.course.title, + totalLessons: 0, + completedLessons: 0, + progress: 0, + records: [], + }; + } + courseMap[r.courseId].records.push(r); + courseMap[r.courseId].totalLessons++; + if (r.completed) courseMap[r.courseId].completedLessons++; + }); + + Object.values(courseMap).forEach(c => { + c.progress = c.totalLessons > 0 ? Math.round((c.completedLessons / c.totalLessons) * 100) : 0; + }); + + return { + items: Object.values(courseMap), + total: records.length, + }; + } +} diff --git a/backend/src/modules/courses/tests/courses.service.spec.ts b/backend/src/modules/courses/tests/courses.service.spec.ts new file mode 100644 index 0000000..c35e243 --- /dev/null +++ b/backend/src/modules/courses/tests/courses.service.spec.ts @@ -0,0 +1,279 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { CoursesService } from '../courses.service'; +import { PrismaService } from '../../../prisma/prisma.service'; + +describe('CoursesService', () => { + let service: CoursesService; + let prisma: PrismaService; + + const mockPrisma = { + course: { + findMany: jest.fn(), + findUnique: jest.fn(), + create: jest.fn(), + update: jest.fn(), + count: jest.fn(), + }, + chapter: { + findMany: jest.fn(), + create: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + deleteMany: jest.fn(), + }, + lesson: { + findMany: jest.fn(), + create: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + deleteMany: jest.fn(), + }, + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + CoursesService, + { provide: PrismaService, useValue: mockPrisma }, + ], + }).compile(); + + service = module.get(CoursesService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('findAll', () => { + it('should return paginated courses with chapters/lessons', async () => { + const mockCourses = [ + { id: 1, title: 'AI 入门', status: 'PUBLISHED', chapters: [{ id: 1, lessons: [{ id: 1 }] }] }, + ]; + mockPrisma.course.findMany.mockResolvedValue(mockCourses); + mockPrisma.course.count.mockResolvedValue(1); + + const result = await service.findAll({ page: 1, pageSize: 20 }); + + expect(result).toEqual({ items: mockCourses, total: 1, page: 1, pageSize: 20 }); + expect(mockPrisma.course.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: { status: 'PUBLISHED', deletedAt: null }, + skip: 0, + take: 20, + }) + ); + }); + + it('should filter by categoryId', async () => { + mockPrisma.course.findMany.mockResolvedValue([]); + mockPrisma.course.count.mockResolvedValue(0); + + await service.findAll({ categoryId: 3 }); + + expect(mockPrisma.course.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: expect.objectContaining({ categoryId: 3 }), + }) + ); + }); + + it('should filter free courses', async () => { + mockPrisma.course.findMany.mockResolvedValue([]); + mockPrisma.course.count.mockResolvedValue(0); + + await service.findAll({ isFree: true }); + + expect(mockPrisma.course.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: expect.objectContaining({ isFree: true }), + }) + ); + }); + + it('should apply pagination correctly', async () => { + mockPrisma.course.findMany.mockResolvedValue([]); + mockPrisma.course.count.mockResolvedValue(50); + + const result = await service.findAll({ page: 3, pageSize: 10 }); + + expect(result.page).toBe(3); + expect(result.pageSize).toBe(10); + expect(mockPrisma.course.findMany).toHaveBeenCalledWith( + expect.objectContaining({ skip: 20, take: 10 }) + ); + }); + }); + + describe('findById', () => { + it('should return course with chapters and lessons', async () => { + const mockCourse = { + id: 1, + title: 'AI 入门', + chapters: [{ id: 1, title: '第一章', lessons: [{ id: 1, title: '第一课' }] }], + }; + mockPrisma.course.findUnique.mockResolvedValue(mockCourse); + + const result = await service.findById(1); + + expect(result).toEqual(mockCourse); + expect(mockPrisma.course.findUnique).toHaveBeenCalledWith({ + where: { id: 1 }, + include: expect.objectContaining({ + chapters: expect.objectContaining({ + include: { lessons: expect.any(Object) }, + }), + }), + }); + }); + + it('should return null for non-existent course', async () => { + mockPrisma.course.findUnique.mockResolvedValue(null); + + const result = await service.findById(999); + + expect(result).toBeNull(); + }); + }); + + describe('create', () => { + it('should create a new course', async () => { + const newCourse = { id: 2, title: '新课程', isFree: true }; + mockPrisma.course.create.mockResolvedValue(newCourse); + + const result = await service.create({ title: '新课程', isFree: true }); + + expect(result).toEqual(newCourse); + expect(mockPrisma.course.create).toHaveBeenCalledWith({ + data: { title: '新课程', isFree: true }, + }); + }); + + it('should create course with all fields', async () => { + mockPrisma.course.create.mockResolvedValue({ id: 3 }); + + await service.create({ + title: '完整课程', + description: '描述', + categoryId: 1, + price: 99, + isFree: false, + sortOrder: 5, + }); + + expect(mockPrisma.course.create).toHaveBeenCalledWith({ + data: { + title: '完整课程', + description: '描述', + categoryId: 1, + price: 99, + isFree: false, + sortOrder: 5, + }, + }); + }); + }); + + describe('update', () => { + it('should update course fields', async () => { + mockPrisma.course.update.mockResolvedValue({ id: 1, title: '更新标题' }); + + const result = await service.update(1, { title: '更新标题' }); + + expect(result).toEqual({ id: 1, title: '更新标题' }); + expect(mockPrisma.course.update).toHaveBeenCalledWith({ + where: { id: 1 }, + data: { title: '更新标题' }, + }); + }); + + it('should strip chapters from course data update', async () => { + mockPrisma.course.update.mockResolvedValue({ id: 1 }); + + await service.update(1, { title: 'test', chapters: [{ title: 'ch1' }] }); + + expect(mockPrisma.course.update).toHaveBeenCalledWith({ + where: { id: 1 }, + data: { title: 'test' }, // chapters stripped + }); + }); + }); + + describe('remove', () => { + it('should soft-delete a course', async () => { + mockPrisma.course.update.mockResolvedValue({ id: 1, deletedAt: new Date() }); + + const result = await service.remove(1); + + expect(result).toBeDefined(); + expect(mockPrisma.course.update).toHaveBeenCalledWith({ + where: { id: 1 }, + data: { deletedAt: expect.any(Date) }, + }); + }); + }); + + describe('updateWithChapters', () => { + beforeEach(() => { + mockPrisma.chapter.findMany.mockResolvedValue([]); + mockPrisma.course.update.mockResolvedValue({ id: 1 }); + }); + + it('should create new chapters and lessons', async () => { + mockPrisma.chapter.findMany.mockResolvedValue([]); + mockPrisma.chapter.create.mockResolvedValue({ id: 10 }); + mockPrisma.lesson.create.mockResolvedValue({ id: 20 }); + + const result = await service.updateWithChapters(1, { + title: '更新课程', + chapters: [ + { + title: '新章节', + sortOrder: 1, + lessons: [{ title: '新课时', sortOrder: 1, status: 'PUBLISHED' }], + }, + ], + }); + + expect(result).toBeDefined(); + expect(mockPrisma.chapter.create).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + title: '新章节', + courseId: 1, + }), + }) + ); + }); + + it('should delete removed chapters', async () => { + mockPrisma.chapter.findMany.mockResolvedValue([ + { id: 5, courseId: 1, title: '旧章节', sortOrder: 1 }, + ]); + mockPrisma.lesson.deleteMany.mockResolvedValue({ count: 0 }); + mockPrisma.chapter.delete.mockResolvedValue({ id: 5 }); + + await service.updateWithChapters(1, { + title: '更新', + chapters: [], // no chapters = delete everything + }); + + expect(mockPrisma.chapter.delete).toHaveBeenCalledWith({ where: { id: 5 } }); + }); + + it('should update existing chapters', async () => { + mockPrisma.chapter.findMany.mockResolvedValue([ + { id: 5, courseId: 1, title: '旧章节', sortOrder: 1 }, + ]); + mockPrisma.lesson.findMany.mockResolvedValue([]); + mockPrisma.chapter.update.mockResolvedValue({ id: 5 }); + + await service.updateWithChapters(1, { + chapters: [{ id: 5, title: '更新章节', sortOrder: 2 }], + }); + + expect(mockPrisma.chapter.update).toHaveBeenCalledWith({ + where: { id: 5 }, + data: { title: '更新章节', sortOrder: 2 }, + }); + }); + }); +}); diff --git a/backend/src/modules/dashboard/dashboard.controller.ts b/backend/src/modules/dashboard/dashboard.controller.ts new file mode 100644 index 0000000..e05ee65 --- /dev/null +++ b/backend/src/modules/dashboard/dashboard.controller.ts @@ -0,0 +1,37 @@ +import { Controller, Get, Put, Body, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { DashboardService } from './dashboard.service'; + +@ApiTags('仪表盘') +@Controller('dashboard') +@UseGuards(AuthGuard('jwt')) +@ApiBearerAuth() +export class DashboardController { + constructor(private dashboardService: DashboardService) {} + + @Get('stats') + async getStats(@Req() req: any) { + return this.dashboardService.getStats(req.user.userId); + } + + @Get('progress') + async getProgress(@Req() req: any) { + return this.dashboardService.getProgress(req.user.userId); + } + + @Get('favorites') + async getFavorites(@Req() req: any) { + return this.dashboardService.getFavorites(req.user.userId); + } + + @Get('profile') + async getProfile(@Req() req: any) { + return this.dashboardService.getProfile(req.user.userId); + } + + @Put('profile') + async updateProfile(@Req() req: any, @Body() body: { nickname?: string; avatar?: string }) { + return this.dashboardService.updateProfile(req.user.userId, body); + } +} diff --git a/backend/src/modules/dashboard/dashboard.module.ts b/backend/src/modules/dashboard/dashboard.module.ts new file mode 100644 index 0000000..c4a4a45 --- /dev/null +++ b/backend/src/modules/dashboard/dashboard.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { DashboardController } from './dashboard.controller'; +import { DashboardService } from './dashboard.service'; + +@Module({ + controllers: [DashboardController], + providers: [DashboardService], +}) +export class DashboardModule {} diff --git a/backend/src/modules/dashboard/dashboard.service.ts b/backend/src/modules/dashboard/dashboard.service.ts new file mode 100644 index 0000000..d751464 --- /dev/null +++ b/backend/src/modules/dashboard/dashboard.service.ts @@ -0,0 +1,201 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class DashboardService { + constructor(private prisma: PrismaService) {} + + async getStats(userId: number) { + const user = await this.prisma.user.findUnique({ + where: { id: userId, deletedAt: null }, + select: { + nickname: true, + avatar: true, + memberPlan: true, + memberExpire: true, + sandboxDaily: true, + createdAt: true, + }, + }); + if (!user) throw new NotFoundException('用户不存在'); + + const learnRecords = await this.prisma.learnRecord.findMany({ + where: { userId }, + select: { courseId: true, completed: true }, + }); + + const courseIds = [...new Set(learnRecords.map(r => r.courseId))]; + const completedCount = learnRecords.filter(r => r.completed).length; + const inProgressCourses = courseIds.length; + + const favoriteCount = await this.prisma.promptFavorite.count({ where: { userId } }); + + const today = new Date(); + today.setHours(0, 0, 0, 0); + const todayCount = await this.prisma.learnRecord.count({ + where: { userId, updatedAt: { gte: today } }, + }); + + const firstRecord = await this.prisma.learnRecord.findFirst({ + where: { userId }, + orderBy: { createdAt: 'asc' }, + select: { createdAt: true }, + }); + + const studyDays = firstRecord + ? Math.max(1, Math.ceil((Date.now() - firstRecord.createdAt.getTime()) / 86400000)) + : 0; + + return { + user: { + nickname: user.nickname, + avatar: user.avatar, + memberPlan: user.memberPlan, + memberExpire: user.memberExpire, + sandboxDaily: user.sandboxDaily, + joinedAt: user.createdAt, + }, + stats: { + inProgressCourses, + completedLessons: completedCount, + favoritePrompts: favoriteCount, + studyDays, + todayLearned: todayCount, + }, + }; + } + + async getProgress(userId: number) { + const learnRecords = await this.prisma.learnRecord.findMany({ + where: { userId }, + include: { + course: { select: { id: true, title: true, cover: true } }, + lesson: { select: { id: true, title: true } }, + }, + orderBy: { updatedAt: 'desc' }, + }); + + const courseMap = new Map(); + + for (const record of learnRecords) { + if (!courseMap.has(record.courseId)) { + const totalLessons = await this.prisma.lesson.count({ + where: { chapter: { courseId: record.courseId } }, + }); + courseMap.set(record.courseId, { + course: record.course, + lessons: [], + completedCount: 0, + totalCount: totalLessons, + }); + } + const entry = courseMap.get(record.courseId)!; + entry.lessons.push({ + id: record.lesson.id, + title: record.lesson.title, + completed: record.completed, + progress: record.progress, + updatedAt: record.updatedAt, + }); + if (record.completed) entry.completedCount++; + } + + const courses = Array.from(courseMap.values()).map(entry => ({ + course: entry.course, + progress: entry.totalCount > 0 ? Math.round((entry.completedCount / entry.totalCount) * 100) : 0, + completedCount: entry.completedCount, + totalCount: entry.totalCount, + recentLessons: entry.lessons.slice(0, 5), + })); + + const recentRecords = learnRecords.slice(0, 10).map(r => ({ + lessonId: r.lesson.id, + lessonTitle: r.lesson.title, + courseId: r.course.id, + courseTitle: r.course.title, + completed: r.completed, + progress: r.progress, + updatedAt: r.updatedAt, + })); + + return { courses, recentRecords }; + } + + async getFavorites(userId: number) { + const favorites = await this.prisma.promptFavorite.findMany({ + where: { userId }, + include: { + prompt: { + select: { + id: true, + title: true, + description: true, + model: true, + viewCount: true, + likeCount: true, + createdAt: true, + }, + }, + }, + orderBy: { createdAt: 'desc' }, + }); + + return favorites.map(f => ({ + id: f.id, + promptId: f.prompt.id, + title: f.prompt.title, + description: f.prompt.description, + model: f.prompt.model, + viewCount: f.prompt.viewCount, + likeCount: f.prompt.likeCount, + favoritedAt: f.createdAt, + })); + } + + async getProfile(userId: number) { + const user = await this.prisma.user.findUnique({ + where: { id: userId, deletedAt: null }, + select: { + id: true, + phone: true, + email: true, + nickname: true, + avatar: true, + status: true, + memberPlan: true, + memberExpire: true, + sandboxDaily: true, + createdAt: true, + }, + }); + if (!user) throw new NotFoundException('用户不存在'); + return user; + } + + async updateProfile(userId: number, data: { nickname?: string; avatar?: string }) { + const user = await this.prisma.user.findUnique({ + where: { id: userId, deletedAt: null }, + }); + if (!user) throw new NotFoundException('用户不存在'); + + return this.prisma.user.update({ + where: { id: userId }, + data: { + ...(data.nickname !== undefined && { nickname: data.nickname }), + ...(data.avatar !== undefined && { avatar: data.avatar }), + }, + select: { + id: true, + phone: true, + email: true, + nickname: true, + avatar: true, + status: true, + memberPlan: true, + memberExpire: true, + sandboxDaily: true, + createdAt: true, + }, + }); + } +} diff --git a/backend/src/modules/enterprise/enterprise.controller.ts b/backend/src/modules/enterprise/enterprise.controller.ts new file mode 100644 index 0000000..a615ee9 --- /dev/null +++ b/backend/src/modules/enterprise/enterprise.controller.ts @@ -0,0 +1,90 @@ +import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { EnterpriseService } from './enterprise.service'; + +@ApiTags('企业版') +@Controller('enterprise') +export class EnterpriseController { + constructor(private enterpriseService: EnterpriseService) {} + + @Post('organizations') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async create(@Req() req: any, @Body() body: { name: string; description?: string; contactName?: string; contactPhone?: string }) { + return this.enterpriseService.createOrganization(req.user.userId, body); + } + + @Get('organizations') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async list(@Query('page') page?: string, @Query('pageSize') pageSize?: string) { + return this.enterpriseService.listOrganizations( + page ? parseInt(page) : 1, + pageSize ? parseInt(pageSize) : 20, + ); + } + + @Get('organizations/:id') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async get(@Param('id') id: string) { + return this.enterpriseService.getOrganization(parseInt(id)); + } + + @Put('organizations/:id') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async update(@Param('id') id: string, @Body() body: { name?: string; description?: string; contactName?: string; contactPhone?: string }) { + return this.enterpriseService.updateOrganization(parseInt(id), body); + } + + @Post('organizations/:id/members') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async addMember(@Req() req: any, @Param('id') id: string, @Body() body: { userId: number; role?: string }) { + return this.enterpriseService.addMember(parseInt(id), req.user.userId, body.userId, body.role); + } + + @Delete('organizations/:orgId/members/:userId') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async removeMember(@Req() req: any, @Param('orgId') orgId: string, @Param('userId') userId: string) { + return this.enterpriseService.removeMember(parseInt(orgId), parseInt(userId), req.user.userId); + } + + @Post('organizations/:id/assignments') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async assignCourse(@Req() req: any, @Param('id') id: string, @Body() body: { courseId: number; deadline?: string }) { + return this.enterpriseService.assignCourse(parseInt(id), body.courseId, req.user.userId, body.deadline); + } + + @Delete('organizations/:orgId/assignments/:courseId') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async removeAssignment(@Param('orgId') orgId: string, @Param('courseId') courseId: string) { + return this.enterpriseService.removeAssignment(parseInt(orgId), parseInt(courseId)); + } + + @Get('organizations/:id/progress') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async getProgress(@Param('id') id: string) { + return this.enterpriseService.getOrgProgress(parseInt(id)); + } + + @Get('organizations/:id/report') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async getReport(@Param('id') id: string) { + return this.enterpriseService.getOrganizationReport(parseInt(id)); + } + + @Get('my') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async myOrganizations(@Req() req: any) { + return this.enterpriseService.getMyOrganizations(req.user.userId); + } +} diff --git a/backend/src/modules/enterprise/enterprise.module.ts b/backend/src/modules/enterprise/enterprise.module.ts new file mode 100644 index 0000000..37ee978 --- /dev/null +++ b/backend/src/modules/enterprise/enterprise.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { EnterpriseController } from './enterprise.controller'; +import { EnterpriseService } from './enterprise.service'; + +@Module({ + controllers: [EnterpriseController], + providers: [EnterpriseService], + exports: [EnterpriseService], +}) +export class EnterpriseModule {} diff --git a/backend/src/modules/enterprise/enterprise.service.ts b/backend/src/modules/enterprise/enterprise.service.ts new file mode 100644 index 0000000..1867ca3 --- /dev/null +++ b/backend/src/modules/enterprise/enterprise.service.ts @@ -0,0 +1,221 @@ +import { Injectable, NotFoundException, ConflictException, BadRequestException, ForbiddenException } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class EnterpriseService { + constructor(private prisma: PrismaService) {} + + async createOrganization(userId: number, data: { name: string; description?: string; contactName?: string; contactPhone?: string }) { + const existing = await this.prisma.organization.findFirst({ where: { name: data.name } }); + if (existing) throw new ConflictException('组织名称已存在'); + + const org = await this.prisma.organization.create({ + data: { name: data.name, description: data.description, contactName: data.contactName, contactPhone: data.contactPhone }, + }); + + await this.prisma.organizationMember.create({ + data: { organizationId: org.id, userId, role: 'ADMIN' }, + }); + + await this.prisma.organization.update({ + where: { id: org.id }, + data: { memberCount: { increment: 1 } }, + }); + + return org; + } + + async listOrganizations(page = 1, pageSize = 20) { + page = Number(page); + pageSize = Number(pageSize); + const skip = (page - 1) * pageSize; + const [items, total] = await Promise.all([ + this.prisma.organization.findMany({ + skip, take: pageSize, + orderBy: { createdAt: 'desc' }, + include: { _count: { select: { members: true, assignments: true } } }, + }), + this.prisma.organization.count(), + ]); + return { items, total, page, pageSize }; + } + + async getOrganization(id: number) { + const org = await this.prisma.organization.findUnique({ + where: { id }, + include: { + _count: { select: { members: true, assignments: true } }, + members: { + include: { user: { select: { id: true, nickname: true, avatar: true, email: true, phone: true } } }, + }, + assignments: { + include: { course: { select: { id: true, title: true, cover: true } } }, + }, + }, + }); + if (!org) throw new NotFoundException('组织不存在'); + return org; + } + + async updateOrganization(id: number, data: { name?: string; description?: string; contactName?: string; contactPhone?: string }) { + const org = await this.prisma.organization.findUnique({ where: { id } }); + if (!org) throw new NotFoundException('组织不存在'); + return this.prisma.organization.update({ where: { id }, data }); + } + + async addMember(orgId: number, adminId: number, userId: number, role = 'MEMBER') { + const org = await this.prisma.organization.findUnique({ where: { id: orgId } }); + if (!org) throw new NotFoundException('组织不存在'); + + const caller = await this.prisma.organizationMember.findUnique({ + where: { organizationId_userId: { organizationId: orgId, userId: adminId } }, + }); + if (!caller || caller.role !== 'ADMIN') throw new ForbiddenException('只有管理员可管理成员'); + + const membership = await this.prisma.organizationMember.findUnique({ + where: { organizationId_userId: { organizationId: orgId, userId } }, + }); + if (membership) throw new ConflictException('该用户已是组织成员'); + + await this.prisma.organizationMember.create({ + data: { organizationId: orgId, userId, role }, + }); + await this.prisma.organization.update({ + where: { id: orgId }, + data: { memberCount: { increment: 1 } }, + }); + return { added: true }; + } + + async removeMember(orgId: number, userId: number, callerId: number) { + const membership = await this.prisma.organizationMember.findUnique({ + where: { organizationId_userId: { organizationId: orgId, userId } }, + }); + if (!membership) throw new NotFoundException('该用户不是组织成员'); + if (membership.role === 'ADMIN') throw new BadRequestException('不能移除管理员'); + + const caller = await this.prisma.organizationMember.findUnique({ + where: { organizationId_userId: { organizationId: orgId, userId: callerId } }, + }); + if (!caller || caller.role !== 'ADMIN') throw new ForbiddenException('只有管理员可管理成员'); + + await this.prisma.organizationMember.delete({ where: { id: membership.id } }); + await this.prisma.organization.update({ + where: { id: orgId }, + data: { memberCount: { decrement: 1 } }, + }); + return { removed: true }; + } + + async assignCourse(orgId: number, courseId: number, assignedBy: number, deadline?: string) { + const [org, course] = await Promise.all([ + this.prisma.organization.findUnique({ where: { id: orgId } }), + this.prisma.course.findUnique({ where: { id: courseId } }), + ]); + if (!org) throw new NotFoundException('组织不存在'); + if (!course) throw new NotFoundException('课程不存在'); + + const existing = await this.prisma.courseAssignment.findFirst({ + where: { organizationId: orgId, courseId }, + }); + if (existing) throw new ConflictException('该课程已分配给此组织'); + + return this.prisma.courseAssignment.create({ + data: { + organizationId: orgId, + courseId, + assignedBy, + deadline: deadline ? new Date(deadline) : undefined, + }, + include: { course: { select: { id: true, title: true, cover: true } } }, + }); + } + + async removeAssignment(orgId: number, courseId: number) { + const assignment = await this.prisma.courseAssignment.findFirst({ + where: { organizationId: orgId, courseId }, + }); + if (!assignment) throw new NotFoundException('未找到该课程分配'); + + await this.prisma.courseAssignment.delete({ where: { id: assignment.id } }); + return { removed: true }; + } + + async getOrgProgress(orgId: number) { + const members = await this.prisma.organizationMember.findMany({ + where: { organizationId: orgId, status: 'ACTIVE' }, + select: { userId: true }, + }); + const userIds = members.map(m => m.userId); + + const assignments = await this.prisma.courseAssignment.findMany({ + where: { organizationId: orgId }, + include: { course: { select: { id: true, title: true } } }, + }); + + const courseIds = assignments.map(a => a.courseId); + + const records = await this.prisma.learnRecord.findMany({ + where: { userId: { in: userIds }, courseId: { in: courseIds } }, + }); + + const totalLessons = await this.prisma.lesson.count({ + where: { chapter: { courseId: { in: courseIds } } }, + }); + + const completedCount = records.filter(r => r.completed).length; + const activeMembers = userIds.length; + + const progressByCourse = courseIds.map(courseId => { + const courseLessons = records.filter(r => r.courseId === courseId); + const uniqueLessons = new Set(courseLessons.map(r => r.lessonId)); + return { + courseId, + completedLessons: courseLessons.filter(r => r.completed).length, + totalUniqueLessons: uniqueLessons.size, + }; + }); + + return { + totalMembers: activeMembers, + totalCourses: courseIds.length, + completedLessons: completedCount, + totalLessons, + completionRate: totalLessons > 0 ? Math.round((completedCount / (totalLessons * Math.max(activeMembers, 1))) * 100) : 0, + progressByCourse, + }; + } + + async getMyOrganizations(userId: number) { + const memberships = await this.prisma.organizationMember.findMany({ + where: { userId }, + include: { + organization: { + include: { _count: { select: { members: true, assignments: true } } }, + }, + }, + }); + return memberships.map(m => ({ ...m.organization, role: m.role })); + } + + async getOrganizationReport(orgId: number) { + const org = await this.getOrganization(orgId); + const progress = await this.getOrgProgress(orgId); + + const memberProgress = await Promise.all( + org.members.map(async (member) => { + const records = await this.prisma.learnRecord.count({ + where: { userId: member.user.id, completed: true }, + }); + return { user: member.user, completedLessons: records }; + }), + ); + + return { + organization: { id: org.id, name: org.name, memberCount: org._count.members }, + summary: progress, + memberProgress, + assignments: org.assignments, + }; + } +} diff --git a/backend/src/modules/enterprise/tests/enterprise.service.spec.ts b/backend/src/modules/enterprise/tests/enterprise.service.spec.ts new file mode 100644 index 0000000..851a3aa --- /dev/null +++ b/backend/src/modules/enterprise/tests/enterprise.service.spec.ts @@ -0,0 +1,158 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { NotFoundException, ConflictException, BadRequestException } from '@nestjs/common'; +import { EnterpriseService } from '../enterprise.service'; +import { PrismaService } from '../../../prisma/prisma.service'; + +describe('EnterpriseService', () => { + let service: EnterpriseService; + let prisma: PrismaService; + + const mockPrisma = { + organization: { + findFirst: jest.fn(), + findUnique: jest.fn(), + findMany: jest.fn(), + create: jest.fn(), + update: jest.fn(), + count: jest.fn(), + }, + organizationMember: { + findUnique: jest.fn(), + findMany: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + }, + courseAssignment: { + findFirst: jest.fn(), + findMany: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + }, + course: { + findUnique: jest.fn(), + }, + learnRecord: { + findMany: jest.fn(), + count: jest.fn(), + }, + lesson: { + count: jest.fn(), + }, + user: { + findUnique: jest.fn(), + }, + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + EnterpriseService, + { provide: PrismaService, useValue: mockPrisma }, + ], + }).compile(); + + service = module.get(EnterpriseService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('createOrganization', () => { + it('should create organization and add creator as admin', async () => { + mockPrisma.organization.findFirst.mockResolvedValue(null); + mockPrisma.organization.create.mockResolvedValue({ id: 1, name: '测试企业', memberCount: 0 }); + mockPrisma.organizationMember.create.mockResolvedValue({}); + mockPrisma.organization.update.mockResolvedValue({}); + + const result = await service.createOrganization(1, { name: '测试企业' }); + + expect(result).toEqual({ id: 1, name: '测试企业', memberCount: 0 }); + expect(mockPrisma.organization.create).toHaveBeenCalledWith({ + data: { name: '测试企业', description: undefined, contactName: undefined, contactPhone: undefined }, + }); + expect(mockPrisma.organizationMember.create).toHaveBeenCalledWith({ + data: { organizationId: 1, userId: 1, role: 'ADMIN' }, + }); + }); + + it('should throw ConflictException if name exists', async () => { + mockPrisma.organization.findFirst.mockResolvedValue({ id: 1 }); + + await expect(service.createOrganization(1, { name: '测试企业' })) + .rejects.toThrow(ConflictException); + }); + }); + + describe('getOrganization', () => { + it('should return organization with members and assignments', async () => { + const mockOrg = { + id: 1, name: '测试企业', + _count: { members: 2, assignments: 1 }, + members: [{ id: 1, userId: 1, user: { id: 1, nickname: '用户1' } }], + assignments: [{ id: 1, courseId: 1, course: { id: 1, title: '课程1' } }], + }; + mockPrisma.organization.findUnique.mockResolvedValue(mockOrg); + + const result = await service.getOrganization(1); + expect(result).toEqual(mockOrg); + }); + + it('should throw NotFoundException if not found', async () => { + mockPrisma.organization.findUnique.mockResolvedValue(null); + await expect(service.getOrganization(999)).rejects.toThrow(NotFoundException); + }); + }); + + describe('addMember', () => { + it('should add member to organization', async () => { + mockPrisma.organization.findUnique.mockResolvedValue({ id: 1 }); + mockPrisma.organizationMember.findUnique + .mockResolvedValueOnce({ role: 'ADMIN' }) // caller is admin + .mockResolvedValueOnce(null); // user not yet member + mockPrisma.organizationMember.create.mockResolvedValue({}); + mockPrisma.organization.update.mockResolvedValue({}); + + const result = await service.addMember(1, 1, 2); + expect(result).toEqual({ added: true }); + }); + + it('should throw ConflictException if already member', async () => { + mockPrisma.organization.findUnique.mockResolvedValue({ id: 1 }); + mockPrisma.organizationMember.findUnique + .mockResolvedValueOnce({ role: 'ADMIN' }) // caller is admin + .mockResolvedValueOnce({ id: 1 }); // user already member + + await expect(service.addMember(1, 1, 2)).rejects.toThrow(ConflictException); + }); + }); + + describe('assignCourse', () => { + it('should assign course to organization', async () => { + mockPrisma.organization.findUnique.mockResolvedValue({ id: 1 }); + mockPrisma.course.findUnique.mockResolvedValue({ id: 1 }); + mockPrisma.courseAssignment.findFirst.mockResolvedValue(null); + mockPrisma.courseAssignment.create.mockResolvedValue({ + id: 1, courseId: 1, course: { id: 1, title: '课程1' }, + }); + + const result = await service.assignCourse(1, 1, 1); + expect(result).toHaveProperty('id'); + }); + + it('should throw NotFoundException if org not found', async () => { + mockPrisma.organization.findUnique.mockResolvedValue(null); + await expect(service.assignCourse(1, 1, 1)).rejects.toThrow(NotFoundException); + }); + }); + + describe('listOrganizations', () => { + it('should return paginated organizations', async () => { + mockPrisma.organization.findMany.mockResolvedValue([{ id: 1, name: '测试企业' }]); + mockPrisma.organization.count.mockResolvedValue(1); + + const result = await service.listOrganizations(1, 20); + expect(result.items).toHaveLength(1); + expect(result.total).toBe(1); + expect(result.page).toBe(1); + }); + }); +}); diff --git a/backend/src/modules/learning/learning.controller.ts b/backend/src/modules/learning/learning.controller.ts new file mode 100644 index 0000000..b35c78a --- /dev/null +++ b/backend/src/modules/learning/learning.controller.ts @@ -0,0 +1,22 @@ +import { Controller, Get, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { LearningService } from './learning.service'; + +@ApiTags('学习分析') +@Controller('learning') +@UseGuards(AuthGuard('jwt')) +@ApiBearerAuth() +export class LearningController { + constructor(private learningService: LearningService) {} + + @Get('analytics') + async getAnalytics(@Req() req: any) { + return this.learningService.getAnalytics(req.user.userId); + } + + @Get('path') + async getLearningPath(@Req() req: any) { + return this.learningService.getLearningPath(req.user.userId); + } +} diff --git a/backend/src/modules/learning/learning.module.ts b/backend/src/modules/learning/learning.module.ts new file mode 100644 index 0000000..a288993 --- /dev/null +++ b/backend/src/modules/learning/learning.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { LearningController } from './learning.controller'; +import { LearningService } from './learning.service'; + +@Module({ + controllers: [LearningController], + providers: [LearningService], + exports: [LearningService], +}) +export class LearningModule {} diff --git a/backend/src/modules/learning/learning.service.ts b/backend/src/modules/learning/learning.service.ts new file mode 100644 index 0000000..21ee1a2 --- /dev/null +++ b/backend/src/modules/learning/learning.service.ts @@ -0,0 +1,192 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +const KNOWLEDGE_DOMAINS = [ + { id: 'ai-basics', name: 'AI 基础知识', keywords: ['AI', '人工智能', '大模型', 'chatgpt', 'gpt', '大语言模型', 'llm', '深度学习', '神经网络', 'machine learning', '机器学习'] }, + { id: 'prompt-engineering', name: '提示词工程', keywords: ['提示词', 'prompt', 'system prompt', 'role', 'few-shot', 'chain-of-thought', 'cot'] }, + { id: 'programming', name: '编程开发', keywords: ['python', 'javascript', 'typescript', 'java', '代码', '函数', '算法', 'debug', 'bug', '编程', '开发', 'react', 'vue', 'node'] }, + { id: 'writing', name: '写作创作', keywords: ['写作', '文章', '文案', '润色', '作文', '创作', '故事', '小说', '博客'] }, + { id: 'english', name: '英语学习', keywords: ['英语', 'english', '翻译', '语法', 'grammar', 'vocabulary', '口语', '写作', '阅读'] }, + { id: 'data-science', name: '数据分析', keywords: ['数据', '分析', '统计', '图表', '可视化', 'sql', 'excel', 'pandas', 'numpy', '数据分析'] }, + { id: 'office', name: '办公效率', keywords: ['ppt', 'excel', 'word', '办公', '邮件', '报告', '文档', '会议', '总结'] }, + { id: 'career', name: '职业发展', keywords: ['简历', '面试', '求职', '职业', '工作', '升职', '薪资'] }, +]; + +const COURSE_RECOMMENDATIONS: Record = { + 'ai-basics': [ + { title: 'AI 通识:零基础入门', url: '/courses' }, + { title: '大模型原理与应用', url: '/courses' }, + ], + 'prompt-engineering': [ + { title: '提示词工程从入门到精通', url: '/courses' }, + { title: '高级 Prompt 技巧', url: '/prompts' }, + ], + 'programming': [ + { title: '用 Python 入门 AI 编程', url: '/courses' }, + { title: 'AI 辅助编程实战', url: '/sandbox' }, + ], + 'writing': [ + { title: 'AI 写作实战指南', url: '/prompts/workshop' }, + { title: '内容创作与润色技巧', url: '/courses' }, + ], + 'english': [ + { title: 'AI 辅助英语学习', url: '/sandbox' }, + { title: '英语写作提升课程', url: '/courses' }, + ], + 'data-science': [ + { title: '数据分析入门', url: '/courses' }, + { title: 'Python 数据分析', url: '/courses' }, + ], + 'office': [ + { title: '用 AI 提升 10 倍办公效率', url: '/courses' }, + { title: 'AI 办公自动化', url: '/courses' }, + ], + 'career': [ + { title: 'AI 时代职业规划', url: '/courses' }, + { title: '面试技巧与简历优化', url: '/sandbox' }, + ], +}; + +@Injectable() +export class LearningService { + constructor(private prisma: PrismaService) {} + + async getAnalytics(userId: number) { + const sessions = await this.prisma.sandboxSession.findMany({ + where: { userId }, + orderBy: { createdAt: 'desc' }, + take: 100, + }); + + const domainCounts: Record = {}; + const domainDates: Record = {}; + const totalSessions = sessions.length; + + for (const domain of KNOWLEDGE_DOMAINS) { + domainCounts[domain.id] = 0; + } + + for (const session of sessions) { + const searchText = `${session.title} ${session.messages || ''}`.toLowerCase(); + for (const domain of KNOWLEDGE_DOMAINS) { + const matched = domain.keywords.some(kw => searchText.includes(kw)); + if (matched) { + domainCounts[domain.id] = (domainCounts[domain.id] || 0) + 1; + if (!domainDates[domain.id] || session.createdAt.toISOString() > domainDates[domain.id]) { + domainDates[domain.id] = session.createdAt.toISOString(); + } + } + } + } + + const domains = KNOWLEDGE_DOMAINS.map(d => { + const count = domainCounts[d.id] || 0; + const totalSessionsForUser = Math.max(totalSessions, 1); + const mastery = Math.min(Math.round((count / Math.max(totalSessionsForUser * 0.3, 1)) * 100), 100); + return { + id: d.id, + name: d.name, + sessionCount: count, + mastery, + lastActive: domainDates[d.id] || null, + weak: mastery < 30, + }; + }); + + const weakDomains = domains.filter(d => d.weak); + const recommendations = weakDomains.length > 0 + ? weakDomains.slice(0, 3).flatMap(d => (COURSE_RECOMMENDATIONS[d.id] || []).slice(0, 2)) + : [{ title: '探索更多知识领域', url: '/sandbox' }]; + + return { + domains, + totalSessions, + weakDomains: weakDomains.map(d => d.name), + recommendations: [...new Map(recommendations.map(r => [r.title, r])).values()], + }; + } + + async getLearningPath(userId: number) { + const sessions = await this.prisma.sandboxSession.findMany({ + where: { userId }, + select: { title: true, messages: true }, + }); + + const allText = sessions.map(s => `${s.title} ${s.messages || ''}`.toLowerCase()).join(' '); + + const stages = [ + { + id: 'basics', + title: '认识大模型', + icon: '🤖', + description: '了解 AI 和大型语言模型的基本概念,学会如何使用 AI 工具。', + tasks: [ + { label: '了解 AI 基本概念', action: '向 AI 提问什么是人工智能', keyword: '人工智能' }, + { label: '认识大语言模型', action: '向 AI 提问什么是大模型', keyword: '大模型' }, + { label: '体验 AI 对话', action: '在沙盒中发起一次对话', keyword: '' }, + ], + links: [ + { title: 'AI 通识:零基础入门', url: '/courses' }, + { title: '打开 AI 沙盒', url: '/sandbox' }, + ], + }, + { + id: 'prompt', + title: '提示词工程', + icon: '✍️', + description: '学习如何编写高质量的提示词,掌握与 AI 高效沟通的技巧。', + tasks: [ + { label: '了解提示词基础', action: '询问提示词编写技巧', keyword: '提示词' }, + { label: '练习提示词编写', action: '在提示词工坊中测试', keyword: '' }, + { label: '保存优质提示词', action: '将好的提示词保存到库中', keyword: '' }, + ], + links: [ + { title: '提示词工坊', url: '/prompts/workshop' }, + { title: '提示词库', url: '/prompts' }, + ], + }, + { + id: 'advanced', + title: '模型微调与高级应用', + icon: '⚙️', + description: '了解模型微调、RAG、Function Calling 等高级技术。', + tasks: [ + { label: '了解模型微调', action: '询问什么是模型微调', keyword: '微调' }, + { label: '了解 RAG', action: '询问什么是 RAG 检索增强', keyword: 'rag' }, + { label: '了解 Function Calling', action: '询问 function calling 是什么', keyword: 'function calling' }, + ], + links: [ + { title: 'AI 沙盒 - 对比模式', url: '/sandbox/compare' }, + { title: '代码沙盒', url: '/sandbox/code' }, + ], + }, + { + id: 'agent', + title: 'Agent 开发', + icon: '🚀', + description: '学习构建 AI Agent,实现自动化任务和复杂工作流。', + tasks: [ + { label: '了解 AI Agent', action: '询问什么是 AI Agent', keyword: 'agent' }, + { label: '学习工具调用', action: '询问 AI 工具调用机制', keyword: 'tool' }, + { label: '实践项目', action: '尝试用 AI 构建一个小项目', keyword: '' }, + ], + links: [ + { title: '代码沙盒 - 运行项目', url: '/sandbox/code' }, + { title: '对比实验室', url: '/sandbox/compare' }, + ], + }, + ]; + + return stages.map(stage => { + const completedCount = stage.tasks.filter(t => !t.keyword || allText.includes(t.keyword)).length; + const progress = stage.tasks.length > 0 ? Math.round((completedCount / stage.tasks.length) * 100) : 0; + return { + ...stage, + completedCount, + totalTasks: stage.tasks.length, + progress, + unlocked: true, + }; + }); + } +} diff --git a/backend/src/modules/models/models.controller.ts b/backend/src/modules/models/models.controller.ts new file mode 100644 index 0000000..eead913 --- /dev/null +++ b/backend/src/modules/models/models.controller.ts @@ -0,0 +1,19 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { ModelsService } from './models.service'; + +@ApiTags('AI 模型') +@Controller('models') +export class ModelsController { + constructor(private modelsService: ModelsService) {} + + @Get() + async findAll(@Query('featured') featured?: string) { + return this.modelsService.findAll({ featured: featured === 'true' }); + } + + @Get(':id') + async findById(@Param('id') id: string) { + return this.modelsService.findById(parseInt(id, 10)); + } +} diff --git a/backend/src/modules/models/models.module.ts b/backend/src/modules/models/models.module.ts new file mode 100644 index 0000000..e96a261 --- /dev/null +++ b/backend/src/modules/models/models.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { ModelsController } from './models.controller'; +import { ModelsService } from './models.service'; + +@Module({ + controllers: [ModelsController], + providers: [ModelsService], +}) +export class ModelsModule {} diff --git a/backend/src/modules/models/models.service.ts b/backend/src/modules/models/models.service.ts new file mode 100644 index 0000000..bd4a090 --- /dev/null +++ b/backend/src/modules/models/models.service.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class ModelsService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { featured?: boolean }) { + const where: any = { status: 'ACTIVE' }; + if (params.featured) where.isFeatured = true; + + return this.prisma.aiModel.findMany({ + where, + orderBy: { sortOrder: 'asc' }, + }); + } + + async findById(id: number) { + return this.prisma.aiModel.findUnique({ where: { id } }); + } +} diff --git a/backend/src/modules/notifications/notification.controller.ts b/backend/src/modules/notifications/notification.controller.ts new file mode 100644 index 0000000..c0a5303 --- /dev/null +++ b/backend/src/modules/notifications/notification.controller.ts @@ -0,0 +1,35 @@ +import { Controller, Get, Patch, Param, Query, Req, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { NotificationService } from './notification.service'; + +@ApiTags('通知') +@Controller('notifications') +@UseGuards(AuthGuard('jwt')) +@ApiBearerAuth() +export class NotificationController { + constructor(private notificationService: NotificationService) {} + + @Get() + async findAll(@Req() req: any, @Query('page') page?: string, @Query('pageSize') pageSize?: string) { + return this.notificationService.findAll(req.user.userId, page ? parseInt(page) : 1, pageSize ? parseInt(pageSize) : 20); + } + + @Get('unread') + async countUnread(@Req() req: any) { + const count = await this.notificationService.countUnread(req.user.userId); + return { count }; + } + + @Patch(':id/read') + async markAsRead(@Req() req: any, @Param('id') id: string) { + await this.notificationService.markAsRead(parseInt(id), req.user.userId); + return { ok: true }; + } + + @Patch('read-all') + async markAllAsRead(@Req() req: any) { + await this.notificationService.markAllAsRead(req.user.userId); + return { ok: true }; + } +} diff --git a/backend/src/modules/notifications/notification.module.ts b/backend/src/modules/notifications/notification.module.ts new file mode 100644 index 0000000..d94cc81 --- /dev/null +++ b/backend/src/modules/notifications/notification.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { NotificationController } from './notification.controller'; +import { NotificationService } from './notification.service'; + +@Module({ + controllers: [NotificationController], + providers: [NotificationService], + exports: [NotificationService], +}) +export class NotificationModule {} diff --git a/backend/src/modules/notifications/notification.service.ts b/backend/src/modules/notifications/notification.service.ts new file mode 100644 index 0000000..31db9ee --- /dev/null +++ b/backend/src/modules/notifications/notification.service.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class NotificationService { + constructor(private prisma: PrismaService) {} + + async create(data: { userId: number; type: string; title: string; content?: string; link?: string; relatedId?: number }) { + return this.prisma.notification.create({ data }); + } + + async findAll(userId: number, page = 1, pageSize = 20) { + const [items, total] = await Promise.all([ + this.prisma.notification.findMany({ + where: { userId }, + orderBy: { createdAt: 'desc' }, + skip: (page - 1) * pageSize, + take: pageSize, + }), + this.prisma.notification.count({ where: { userId } }), + ]); + return { items, total, page, pageSize, unread: items.filter(n => !n.isRead).length }; + } + + async countUnread(userId: number) { + return this.prisma.notification.count({ where: { userId, isRead: false } }); + } + + async markAsRead(id: number, userId: number) { + return this.prisma.notification.updateMany({ + where: { id, userId }, + data: { isRead: true }, + }); + } + + async markAllAsRead(userId: number) { + return this.prisma.notification.updateMany({ + where: { userId, isRead: false }, + data: { isRead: true }, + }); + } +} diff --git a/backend/src/modules/orders/orders.controller.ts b/backend/src/modules/orders/orders.controller.ts new file mode 100644 index 0000000..87c342a --- /dev/null +++ b/backend/src/modules/orders/orders.controller.ts @@ -0,0 +1,42 @@ +import { Controller, Post, Get, Body, Param, Query, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth, ApiBody } from '@nestjs/swagger'; +import { IsNumber, IsString, IsOptional, IsIn } from 'class-validator'; +import { AuthGuard } from '@nestjs/passport'; +import { OrdersService } from './orders.service'; + +class CreateOrderDto { + @IsNumber() + amount: number; + + @IsString() + @IsIn(['MONTHLY', 'YEARLY', 'COURSE']) + planType: string; + + @IsOptional() + @IsString() + payChannel?: string; +} + +@ApiTags('订单') +@Controller('orders') +@UseGuards(AuthGuard('jwt')) +@ApiBearerAuth() +export class OrdersController { + constructor(private ordersService: OrdersService) {} + + @Post('create') + @ApiBody({ type: CreateOrderDto }) + async create(@Req() req: any, @Body() body: CreateOrderDto) { + return this.ordersService.create(req.user.userId, body); + } + + @Get() + async findByUser(@Req() req: any, @Query() query: { page?: number; pageSize?: number }) { + return this.ordersService.findByUser(req.user.userId, query); + } + + @Get(':orderNo') + async findByOrderNo(@Param('orderNo') orderNo: string) { + return this.ordersService.findByOrderNo(orderNo); + } +} diff --git a/backend/src/modules/orders/orders.module.ts b/backend/src/modules/orders/orders.module.ts new file mode 100644 index 0000000..e17448f --- /dev/null +++ b/backend/src/modules/orders/orders.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { OrdersController } from './orders.controller'; +import { OrdersService } from './orders.service'; +import { PaymentModule } from '../payment/payment.module'; + +@Module({ + imports: [PaymentModule], + controllers: [OrdersController], + providers: [OrdersService], + exports: [OrdersService], +}) +export class OrdersModule {} diff --git a/backend/src/modules/orders/orders.service.ts b/backend/src/modules/orders/orders.service.ts new file mode 100644 index 0000000..f40b5d4 --- /dev/null +++ b/backend/src/modules/orders/orders.service.ts @@ -0,0 +1,83 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; +import { PaymentService } from '../payment/payment.service'; + +@Injectable() +export class OrdersService { + constructor( + private prisma: PrismaService, + private paymentService: PaymentService, + ) {} + + async create(userId: number, data: { amount: number; planType: string; payChannel?: string }) { + const orderNo = `YZR${Date.now()}${Math.random().toString(36).slice(2, 8).toUpperCase()}`; + + const order = await this.prisma.order.create({ + data: { + orderNo, + userId, + amount: data.amount, + planType: data.planType, + payChannel: data.payChannel || 'wxpay', + }, + }); + + // If paying via WeChat, create unified order + if (data.payChannel === 'wxpay' || !data.payChannel) { + try { + const planLabels: Record = { + MONTHLY: '宇之然AI月卡会员', + YEARLY: '宇之然AI年卡会员', + }; + const payResult = await this.paymentService.createUnifiedOrder({ + description: planLabels[data.planType] || '宇之然AI会员充值', + outTradeNo: orderNo, + amount: data.amount, + }); + return { order, payResult }; + } catch { + return { order, payResult: null }; + } + } + + return { order }; + } + + async findByUser(userId: number, params: { page?: number; pageSize?: number }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 20); + const [items, total] = await Promise.all([ + this.prisma.order.findMany({ + where: { userId }, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { createdAt: 'desc' }, + }), + this.prisma.order.count({ where: { userId } }), + ]); + return { items, total, page, pageSize }; + } + + async findByOrderNo(orderNo: string) { + return this.prisma.order.findUnique({ where: { orderNo } }); + } + + async getCurrentSubscription(userId: number) { + const now = new Date(); + return this.prisma.subscription.findFirst({ + where: { + userId, + status: 'ACTIVE', + endDate: { gt: now }, + }, + orderBy: { endDate: 'desc' }, + }); + } + + async getSubscriptions(userId: number) { + return this.prisma.subscription.findMany({ + where: { userId }, + orderBy: { createdAt: 'desc' }, + }); + } +} diff --git a/backend/src/modules/orders/subscriptions.controller.ts b/backend/src/modules/orders/subscriptions.controller.ts new file mode 100644 index 0000000..c71d1db --- /dev/null +++ b/backend/src/modules/orders/subscriptions.controller.ts @@ -0,0 +1,22 @@ +import { Controller, Get, Post, Body, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { OrdersService } from './orders.service'; + +@ApiTags('订阅') +@Controller('subscriptions') +@UseGuards(AuthGuard('jwt')) +@ApiBearerAuth() +export class SubscriptionsController { + constructor(private ordersService: OrdersService) {} + + @Get('current') + async getCurrentSubscription(@Req() req: any) { + return this.ordersService.getCurrentSubscription(req.user.userId); + } + + @Get() + async getSubscriptions(@Req() req: any) { + return this.ordersService.getSubscriptions(req.user.userId); + } +} diff --git a/backend/src/modules/orders/tests/orders.service.spec.ts b/backend/src/modules/orders/tests/orders.service.spec.ts new file mode 100644 index 0000000..9bc2ae3 --- /dev/null +++ b/backend/src/modules/orders/tests/orders.service.spec.ts @@ -0,0 +1,169 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { OrdersService } from '../orders.service'; +import { PrismaService } from '../../../prisma/prisma.service'; +import { PaymentService } from '../../payment/payment.service'; + +describe('OrdersService', () => { + let service: OrdersService; + let prisma: PrismaService; + let paymentService: PaymentService; + + const mockPrisma = { + order: { + create: jest.fn(), + findMany: jest.fn(), + findUnique: jest.fn(), + update: jest.fn(), + count: jest.fn(), + }, + subscription: { + findFirst: jest.fn(), + findMany: jest.fn(), + }, + }; + + const mockPaymentService = { + createUnifiedOrder: jest.fn(), + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + OrdersService, + { provide: PrismaService, useValue: mockPrisma }, + { provide: PaymentService, useValue: mockPaymentService }, + ], + }).compile(); + + service = module.get(OrdersService); + prisma = module.get(PrismaService); + paymentService = module.get(PaymentService); + jest.clearAllMocks(); + }); + + describe('create', () => { + it('should create order and call payment service for wxpay', async () => { + const mockOrder = { + id: 1, + orderNo: 'YZR123', + amount: 29.9, + planType: 'MONTHLY', + payChannel: 'wxpay', + }; + mockPrisma.order.create.mockResolvedValue(mockOrder); + mockPaymentService.createUnifiedOrder.mockResolvedValue({ + prepay_id: 'wx123', + nonceStr: 'abc', + }); + + const result = await service.create(1, { + amount: 29.9, + planType: 'MONTHLY', + payChannel: 'wxpay', + }); + + expect(result).toHaveProperty('order'); + expect(result).toHaveProperty('payResult'); + expect(mockPrisma.order.create).toHaveBeenCalledWith({ + data: expect.objectContaining({ + userId: 1, + amount: 29.9, + planType: 'MONTHLY', + payChannel: 'wxpay', + }), + }); + }); + + it('should create order without payment for non-wxpay channels', async () => { + const mockOrder = { + id: 1, + orderNo: 'YZR123', + amount: 199, + planType: 'YEARLY', + payChannel: 'alipay', + }; + mockPrisma.order.create.mockResolvedValue(mockOrder); + + const result = await service.create(1, { + amount: 199, + planType: 'YEARLY', + payChannel: 'alipay', + }); + + expect(result).toEqual({ order: mockOrder }); + expect(mockPaymentService.createUnifiedOrder).not.toHaveBeenCalled(); + }); + }); + + describe('findByUser', () => { + it('should return paginated orders for user', async () => { + const mockOrders = [ + { id: 1, orderNo: 'YZR123', amount: 29.9 } + ]; + mockPrisma.order.findMany.mockResolvedValue(mockOrders); + mockPrisma.order.count.mockResolvedValue(1); + + const result = await service.findByUser(1, { page: 1, pageSize: 20 }); + + expect(result).toEqual({ + items: mockOrders, + total: 1, + page: 1, + pageSize: 20, + }); + }); + }); + + describe('findByOrderNo', () => { + it('should return order by orderNo', async () => { + const mockOrder = { id: 1, orderNo: 'YZR123' }; + mockPrisma.order.findUnique.mockResolvedValue(mockOrder); + + const result = await service.findByOrderNo('YZR123'); + + expect(result).toEqual(mockOrder); + expect(mockPrisma.order.findUnique).toHaveBeenCalledWith({ + where: { orderNo: 'YZR123' }, + }); + }); + }); + + describe('getCurrentSubscription', () => { + it('should return active subscription', async () => { + const mockSub = { + id: 1, + userId: 1, + plan: 'YEARLY', + status: 'ACTIVE', + endDate: new Date(Date.now() + 86400000), // 明天到期 + }; + mockPrisma.subscription.findFirst.mockResolvedValue(mockSub); + + const result = await service.getCurrentSubscription(1); + + expect(result).toEqual(mockSub); + }); + + it('should return null if no active subscription', async () => { + mockPrisma.subscription.findFirst.mockResolvedValue(null); + + const result = await service.getCurrentSubscription(1); + + expect(result).toBeNull(); + }); + }); + + describe('getSubscriptions', () => { + it('should return all subscriptions for user', async () => { + const mockSubs = [ + { id: 1, plan: 'MONTHLY' }, + { id: 2, plan: 'YEARLY' }, + ]; + mockPrisma.subscription.findMany.mockResolvedValue(mockSubs); + + const result = await service.getSubscriptions(1); + + expect(result).toEqual(mockSubs); + }); + }); +}); diff --git a/backend/src/modules/payment/payment.controller.ts b/backend/src/modules/payment/payment.controller.ts new file mode 100644 index 0000000..50a36a9 --- /dev/null +++ b/backend/src/modules/payment/payment.controller.ts @@ -0,0 +1,69 @@ +import { Controller, Post, Get, Body, Req, Headers, HttpCode, Query } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBody, ApiQuery } from '@nestjs/swagger'; +import { IsString, IsNumber, IsOptional, IsIn } from 'class-validator'; +import { PaymentService } from './payment.service'; + +class UnifiedOrderDto { + @IsString() + description: string; + + @IsString() + outTradeNo: string; + + @IsNumber() + amount: number; + + @IsOptional() + @IsString() + openid?: string; + + @IsOptional() + @IsIn(['JSAPI', 'NATIVE', 'MWEB']) + tradeType?: 'JSAPI' | 'NATIVE' | 'MWEB'; +} + +class RefundDto { + @IsString() + outTradeNo: string; + + @IsNumber() + amount: number; + + @IsOptional() + @IsString() + reason?: string; +} + +@ApiTags('支付') +@Controller('payment') +export class PaymentController { + constructor(private paymentService: PaymentService) {} + + @Post('wxpay/unified-order') + @ApiOperation({ summary: '微信支付统一下单' }) + @ApiBody({ type: UnifiedOrderDto }) + async unifiedOrder(@Body() body: UnifiedOrderDto) { + return this.paymentService.createUnifiedOrder(body); + } + + @Post('wxpay/notify') + @HttpCode(200) + @ApiOperation({ summary: '微信支付回调通知' }) + async notify(@Req() req: any, @Headers('wechatpay-signature') signature: string) { + return this.paymentService.handleNotify(req.body, signature); + } + + @Post('wxpay/refund') + @ApiOperation({ summary: '微信支付退款' }) + @ApiBody({ type: RefundDto }) + async refund(@Body() body: RefundDto) { + return this.paymentService.refund(body.outTradeNo, body.amount, body.reason); + } + + @Get('wxpay/query') + @ApiOperation({ summary: '查询微信支付订单' }) + @ApiQuery({ name: 'outTradeNo', required: true }) + async query(@Query('outTradeNo') outTradeNo: string) { + return this.paymentService.queryOrder(outTradeNo); + } +} diff --git a/backend/src/modules/payment/payment.module.ts b/backend/src/modules/payment/payment.module.ts new file mode 100644 index 0000000..495fb56 --- /dev/null +++ b/backend/src/modules/payment/payment.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { PaymentController } from './payment.controller'; +import { PaymentService } from './payment.service'; +import { PrismaModule } from '../../prisma/prisma.module'; + +@Module({ + imports: [PrismaModule], + controllers: [PaymentController], + providers: [PaymentService], + exports: [PaymentService], +}) +export class PaymentModule {} diff --git a/backend/src/modules/payment/payment.service.ts b/backend/src/modules/payment/payment.service.ts new file mode 100644 index 0000000..636ae11 --- /dev/null +++ b/backend/src/modules/payment/payment.service.ts @@ -0,0 +1,326 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; +import * as path from 'path'; + +// WeChat Pay V3 SDK types +interface WxPayConfig { + appId: string; + mchId: string; + apiKey: string; + certPath: string; + keyPath: string; + notifyUrl: string; +} + +export interface UnifiedOrderResult { + prepay_id: string; + nonceStr: string; + timeStamp: string; + package: string; + paySign: string; + signType: string; +} + +@Injectable() +export class PaymentService { + private readonly logger = new Logger(PaymentService.name); + private config: WxPayConfig; + private wxPay: any; + + constructor(private prisma: PrismaService) { + this.config = { + appId: process.env.WX_APPID || '', + mchId: process.env.WX_MCHID || process.env.WX_PAY_MCH_ID || '1108945993', + apiKey: process.env.WX_API_KEY || process.env.WX_PAY_API_KEY || '8Kj9mP2nQ5rT7vW1xY3zA4bC6dE8fG0h', + certPath: process.env.WX_CERT_PATH || path.resolve(__dirname, '../../../cert/key/apiclient_cert.pem'), + keyPath: process.env.WX_KEY_PATH || path.resolve(__dirname, '../../../cert/key/apiclient_key.pem'), + notifyUrl: process.env.WX_NOTIFY_URL || 'https://yuzhiran.com/api/v1/payment/wxpay/notify', + }; + + try { + const fs = require('fs'); + const { WechatPay } = require('wechat-pay-nodejs'); + this.wxPay = new WechatPay({ + appid: this.config.appId, + mchid: this.config.mchId, + key: this.config.apiKey, + cert_private_content: fs.readFileSync(this.config.keyPath), + cert_public_content: fs.readFileSync(this.config.certPath), + }); + this.logger.log(`微信支付初始化成功 (商户号: ${this.config.mchId})`); + } catch (err: any) { + this.logger.warn(`微信支付 SDK 初始化失败: ${err.message},将使用模拟模式`); + this.wxPay = null; + } + } + + async createUnifiedOrder(params: { + description: string; + outTradeNo: string; + amount: number; + openid?: string; + tradeType?: 'JSAPI' | 'NATIVE' | 'MWEB'; + }): Promise { + const { description, outTradeNo, amount, openid, tradeType = 'JSAPI' } = params; + + if (!this.wxPay) { + return { ...this.mockPayResult(outTradeNo, amount), codeUrl: 'mock://pay' }; + } + + try { + const baseParams = { + description, + out_trade_no: outTradeNo, + amount: { total: Math.round(amount * 100) }, + notify_url: this.config.notifyUrl, + }; + + let result: any; + if (tradeType === 'NATIVE') { + result = await this.wxPay.prepayNative({ + ...baseParams, + product_id: outTradeNo, + }); + } else if (tradeType === 'MWEB') { + result = await this.wxPay.prepayMweb({ + ...baseParams, + scene_info: { payer_client_ip: '127.0.0.1' }, + }); + } else { + result = await this.wxPay.prepayJsapi({ + ...baseParams, + payer: { openid: openid || 'oVtFy6Wv8L0lKJ9xG2rH3nM5pQ7sT1uZ' }, + }); + } + + if (result.success && result.data) { + const response: any = { + prepay_id: result.data.package?.replace('prepay_id=', '') || result.data.prepay_id || '', + nonceStr: result.data.nonceStr || result.data.nonce_str, + timeStamp: result.data.timeStamp || String(Math.floor(Date.now() / 1000)), + paySign: result.data.paySign || result.data.sign, + signType: 'RSA', + }; + if (result.data.code_url) response.codeUrl = result.data.code_url; + if (result.data.mweb_url) response.mwebUrl = result.data.mweb_url; + return response; + } + throw new Error(result.errMsg || '下单失败'); + } catch (err: any) { + this.logger.error(`微信支付统一下单失败: ${err.message}`); + return { ...this.mockPayResult(outTradeNo, amount), codeUrl: 'mock://pay' }; + } + } + + async handleNotify(body: any, signature: string): Promise<{ code: string; message: string }> { + if (!this.wxPay) { + // 模拟模式:尝试更新订单状态 + try { + const data = typeof body === 'string' ? JSON.parse(body) : body; + const outTradeNo = data.out_trade_no || (data.resource && data.resource.out_trade_no); + if (outTradeNo) { + await this.updateOrderAndMembership(outTradeNo, data.amount?.total || 0); + } + } catch (err) { + this.logger.warn(`模拟模式处理通知失败: ${err.message}`); + } + return { code: 'SUCCESS', message: '模拟模式-通知处理成功' }; + } + + try { + const verified = this.wxPay.verifySignature(body, signature); + if (!verified) { + return { code: 'FAIL', message: '签名验证失败' }; + } + + const data = typeof body === 'string' ? JSON.parse(body) : body; + const { event_type, resource } = data; + + if (event_type === 'TRANSACTION.SUCCESS') { + const ciphertext = resource.ciphertext; + const associatedData = resource.associated_data; + const nonce = resource.nonce; + + const decrypted = this.wxPay.decryptGCM(ciphertext, associatedData, nonce); + const payResult = typeof decrypted === 'string' ? JSON.parse(decrypted) : decrypted; + + this.logger.log(`支付成功: ${payResult.out_trade_no}, 金额: ${payResult.amount.total}`); + + // 更新订单状态和会员订阅 + await this.updateOrderAndMembership(payResult.out_trade_no, payResult.amount.total); + + return { code: 'SUCCESS', message: '支付成功' }; + } + + return { code: 'SUCCESS', message: '已接收' }; + } catch (err: any) { + this.logger.error(`支付通知处理失败: ${err.message}`); + return { code: 'FAIL', message: err.message }; + } + } + + private async updateOrderAndMembership(outTradeNo: string, paidAmountTotal: number) { + const order = await this.prisma.order.findUnique({ + where: { orderNo: outTradeNo }, + include: { user: true }, + }); + + if (!order) { + this.logger.warn(`订单不存在: ${outTradeNo}`); + return; + } + + if (order.status === 'PAID') { + this.logger.log(`订单已支付,跳过重复处理: ${outTradeNo}`); + return; + } + + // 验证金额(微信支付单位:分,订单单位:元) + const paidAmount = paidAmountTotal / 100; + if (Math.abs(paidAmount - order.amount) > 0.01) { + this.logger.warn(`支付金额不一致: 订单${order.amount}元,支付${paidAmount}元`); + } + + // 更新订单状态为已支付 + await this.prisma.order.update({ + where: { id: order.id }, + data: { status: 'PAID', paidAt: new Date() }, + }); + + // 处理会员订阅(仅限MONTHLY/YEARLY计划) + if (order.planType === 'MONTHLY' || order.planType === 'YEARLY') { + const durationDays = order.planType === 'MONTHLY' ? 30 : 365; + const now = new Date(); + let subscriptionEndDate: Date; + + // 查询现有活跃订阅 + const existingSub = await this.prisma.subscription.findFirst({ + where: { + userId: order.userId, + status: 'ACTIVE', + endDate: { gt: now }, + }, + }); + + if (existingSub) { + // 延长现有订阅 + subscriptionEndDate = new Date(existingSub.endDate.getTime() + durationDays * 24 * 60 * 60 * 1000); + await this.prisma.subscription.update({ + where: { id: existingSub.id }, + data: { endDate: subscriptionEndDate }, + }); + } else { + // 创建新订阅 + subscriptionEndDate = new Date(now); + subscriptionEndDate.setDate(subscriptionEndDate.getDate() + durationDays); + await this.prisma.subscription.create({ + data: { + userId: order.userId, + plan: order.planType as any, + startDate: now, + endDate: subscriptionEndDate, + status: 'ACTIVE', + }, + }); + } + + // 更新用户会员状态 + await this.prisma.user.update({ + where: { id: order.userId }, + data: { + memberPlan: order.planType as any, + memberExpire: subscriptionEndDate, + }, + }); + + this.logger.log(`会员订阅更新成功: 用户${order.userId}, 类型${order.planType}, 到期${subscriptionEndDate}`); + } + } + + async refund(outTradeNo: string, amount: number, reason?: string) { + if (!this.wxPay) { + this.logger.log(`模拟退款: ${outTradeNo}`); + // 模拟退款成功后更新订单状态 + try { + await this.prisma.order.update({ + where: { orderNo: outTradeNo }, + data: { status: 'REFUNDED' }, + }); + } catch(err) { + this.logger.warn(`模拟退款更新订单失败: ${err.message}`); + } + return { code: 'SUCCESS', message: '模拟退款成功' }; + } + + try { + const result = await this.wxPay.refunds({ + out_trade_no: outTradeNo, + out_refund_no: `REFUND_${outTradeNo}_${Date.now()}`, + amount: { + refund: Math.round(amount * 100), + total: Math.round(amount * 100), + currency: 'CNY', + }, + reason: reason || '用户申请退款', + }); + + // 退款成功后更新订单状态 + if (result.success) { + await this.prisma.order.update({ + where: { orderNo: outTradeNo }, + data: { status: 'REFUNDED' }, + }).catch(err => this.logger.warn(`退款更新订单失败: ${err.message}`)); + } + + return result; + } catch (err: any) { + this.logger.error(`退款失败: ${err.message}`); + throw err; + } + } + + async queryOrder(outTradeNo: string) { + // 先查本地订单状态 + const localOrder = await this.prisma.order.findUnique({ + where: { orderNo: outTradeNo }, + include: { user: { select: { id: true, nickname: true, memberPlan: true, memberExpire: true } } }, + }); + + if (!this.wxPay) { + return { + trade_state: localOrder?.status === 'PAID' ? 'SUCCESS' : 'NOTPAY', + out_trade_no: outTradeNo, + localStatus: localOrder?.status, + amount: localOrder?.amount, + planType: localOrder?.planType, + }; + } + + const wxResult = await this.wxPay.queryByOutTradeNo(outTradeNo); + return { + ...wxResult, + localStatus: localOrder?.status, + localAmount: localOrder?.amount, + user: localOrder?.user, + }; + } + + private mockPayResult(outTradeNo: string, amount: number): UnifiedOrderResult { + const nonceStr = this.generateNonceStr(); + const timeStamp = String(Math.floor(Date.now() / 1000)); + const prepayId = `wx${Date.now()}${Math.random().toString(36).slice(2, 10)}`; + + return { + prepay_id: prepayId, + nonceStr, + timeStamp, + package: `prepay_id=${prepayId}`, + paySign: 'MOCK_SIGN_FOR_DEVELOPMENT', + signType: 'RSA', + }; + } + + private generateNonceStr(): string { + return Math.random().toString(36).substring(2, 18) + Math.random().toString(36).substring(2, 18); + } +} diff --git a/backend/src/modules/payment/tests/payment.service.spec.ts b/backend/src/modules/payment/tests/payment.service.spec.ts new file mode 100644 index 0000000..69670b6 --- /dev/null +++ b/backend/src/modules/payment/tests/payment.service.spec.ts @@ -0,0 +1,19 @@ +// @ts-nocheck +import { Test, TestingModule } from '@nestjs/testing'; +import { PaymentService } from '../payment.service'; +import { PrismaService } from '../../../prisma/prisma.service'; + +describe('PaymentService', () => { + let service: PaymentService; + + beforeEach(async () => { + const module = await Test.createTestingModule({ + providers: [PaymentService, { provide: PrismaService, useValue: {} }], + }).compile(); + service = module.get(PaymentService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/backend/src/modules/prompts/prompts.controller.ts b/backend/src/modules/prompts/prompts.controller.ts new file mode 100644 index 0000000..90ed9ca --- /dev/null +++ b/backend/src/modules/prompts/prompts.controller.ts @@ -0,0 +1,44 @@ +import { Controller, Get, Post, Body, Param, Query, UseGuards, Req } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { PromptsService } from './prompts.service'; + +@ApiTags('提示词') +@Controller('prompts') +export class PromptsController { + constructor(private promptsService: PromptsService) {} + + @Get() + async findAll(@Query() query: { page?: number; pageSize?: number; categoryId?: number; search?: string }) { + return this.promptsService.findAll(query); + } + + @Get(':id') + async findById(@Param('id') id: string) { + return this.promptsService.findById(+id); + } + + @Post() + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async create(@Req() req: any, @Body() body: { title: string; content: string; description?: string; categoryId?: number; tags?: string; model?: string }) { + return this.promptsService.create({ ...body, authorId: req.user.userId }); + } + + @Post(':id/favorite') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async toggleFavorite(@Req() req: any, @Param('id') id: string) { + return this.promptsService.toggleFavorite(req.user.userId, +id); + } + + @Get('favorites') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async findFavorites(@Req() req: any, @Query('page') page?: string, @Query('pageSize') pageSize?: string) { + return this.promptsService.findFavorites(req.user.userId, { + page: page ? parseInt(page) : undefined, + pageSize: pageSize ? parseInt(pageSize) : undefined, + }); + } +} diff --git a/backend/src/modules/prompts/prompts.module.ts b/backend/src/modules/prompts/prompts.module.ts new file mode 100644 index 0000000..04f12c8 --- /dev/null +++ b/backend/src/modules/prompts/prompts.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { PromptsController } from './prompts.controller'; +import { PromptsService } from './prompts.service'; + +@Module({ + controllers: [PromptsController], + providers: [PromptsService], + exports: [PromptsService], +}) +export class PromptsModule {} diff --git a/backend/src/modules/prompts/prompts.service.ts b/backend/src/modules/prompts/prompts.service.ts new file mode 100644 index 0000000..e0c2a72 --- /dev/null +++ b/backend/src/modules/prompts/prompts.service.ts @@ -0,0 +1,82 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class PromptsService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { page?: number; pageSize?: number; categoryId?: number; search?: string }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 20); + const { categoryId, search } = params; + const where: any = { status: 'PUBLISHED', deletedAt: null, isPublic: true }; + if (categoryId) where.categoryId = categoryId; + if (search) { + where.OR = [ + { title: { contains: search } }, + { content: { contains: search } }, + ]; + } + + const [items, total] = await Promise.all([ + this.prisma.prompt.findMany({ + where, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { likeCount: 'desc' }, + select: { + id: true, title: true, description: true, content: true, + tags: true, model: true, viewCount: true, likeCount: true, + createdAt: true, category: true, author: { select: { nickname: true } }, + }, + }), + this.prisma.prompt.count({ where }), + ]); + + return { items, total, page, pageSize }; + } + + async findById(id: number) { + await this.prisma.prompt.update({ where: { id }, data: { viewCount: { increment: 1 } } }); + return this.prisma.prompt.findUnique({ + where: { id }, + include: { category: true, author: { select: { nickname: true } } }, + }); + } + + async create(data: { title: string; content: string; description?: string; categoryId?: number; tags?: string; model?: string; authorId?: number }) { + return this.prisma.prompt.create({ data }); + } + + async toggleFavorite(userId: number, promptId: number) { + const existing = await this.prisma.promptFavorite.findUnique({ + where: { userId_promptId: { userId, promptId } }, + }); + + if (existing) { + await this.prisma.promptFavorite.delete({ where: { id: existing.id } }); + await this.prisma.prompt.update({ where: { id: promptId }, data: { likeCount: { decrement: 1 } } }); + return { favorited: false }; + } + + await this.prisma.promptFavorite.create({ data: { userId, promptId } }); + await this.prisma.prompt.update({ where: { id: promptId }, data: { likeCount: { increment: 1 } } }); + return { favorited: true }; + } + + async findFavorites(userId: number, params: { page?: number; pageSize?: number }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 20); + const [items, total] = await Promise.all([ + this.prisma.promptFavorite.findMany({ + where: { userId }, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { createdAt: 'desc' }, + include: { prompt: true }, + }), + this.prisma.promptFavorite.count({ where: { userId } }), + ]); + return { items, total, page, pageSize }; + } +} diff --git a/backend/src/modules/prompts/tests/prompts.service.spec.ts b/backend/src/modules/prompts/tests/prompts.service.spec.ts new file mode 100644 index 0000000..ddf4ed4 --- /dev/null +++ b/backend/src/modules/prompts/tests/prompts.service.spec.ts @@ -0,0 +1,161 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PrismaService } from '../../../prisma/prisma.service'; +import { PromptsService } from '../prompts.service'; + +describe('PromptsService', () => { + let service: PromptsService; + let prisma: PrismaService; + + const mockPrisma = { + prompt: { + findMany: jest.fn(), + findUnique: jest.fn(), + create: jest.fn(), + update: jest.fn(), + count: jest.fn(), + }, + promptFavorite: { + findMany: jest.fn(), + findUnique: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + count: jest.fn(), + }, + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + PromptsService, + { provide: PrismaService, useValue: mockPrisma }, + ], + }).compile(); + + service = module.get(PromptsService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('findAll', () => { + it('should return paginated prompts with default params', async () => { + const mockPrompts = [ + { id: 1, title: '提示词1', status: 'PUBLISHED', deletedAt: null, isPublic: true }, + ]; + mockPrisma.prompt.findMany.mockResolvedValue(mockPrompts); + mockPrisma.prompt.count.mockResolvedValue(1); + + const result = await service.findAll({}); + + expect(result).toEqual({ items: mockPrompts, total: 1, page: 1, pageSize: 20 }); + expect(mockPrisma.prompt.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: { status: 'PUBLISHED', deletedAt: null, isPublic: true }, + skip: 0, + take: 20, + }) + ); + }); + + it('should filter by categoryId', async () => { + await service.findAll({ categoryId: 5 }); + expect(mockPrisma.prompt.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: expect.objectContaining({ categoryId: 5 }), + }) + ); + }); + + it('should search by keyword', async () => { + await service.findAll({ search: 'AI' }); + expect(mockPrisma.prompt.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: expect.objectContaining({ + OR: [{ title: { contains: 'AI' } }, { content: { contains: 'AI' } }], + }), + }) + ); + }); + }); + + describe('findById', () => { + it('should increment viewCount and return prompt', async () => { + const mockPrompt = { id: 1, title: '测试提示词', viewCount: 10 }; + mockPrisma.prompt.findUnique.mockResolvedValue(mockPrompt); + + const result = await service.findById(1); + + expect(result).toEqual(mockPrompt); + expect(mockPrisma.prompt.update).toHaveBeenCalledWith({ + where: { id: 1 }, + data: { viewCount: { increment: 1 } }, + }); + }); + }); + + describe('create', () => { + it('should create a new prompt', async () => { + const promptData = { + title: '新提示词', + content: '内容', + description: '描述', + categoryId: 1, + tags: 'AI,提示词', + model: 'gpt-3.5', + authorId: 1, + }; + const created = { id: 1, ...promptData }; + mockPrisma.prompt.create.mockResolvedValue(created); + + const result = await service.create(promptData); + + expect(result).toEqual(created); + expect(mockPrisma.prompt.create).toHaveBeenCalledWith({ data: promptData }); + }); + }); + + describe('toggleFavorite', () => { + it('should add favorite if not exists', async () => { + mockPrisma.promptFavorite.findUnique.mockResolvedValue(null); + mockPrisma.promptFavorite.create.mockResolvedValue({}); + mockPrisma.prompt.update.mockResolvedValue({}); + + const result = await service.toggleFavorite(1, 1); + + expect(result).toEqual({ favorited: true }); + expect(mockPrisma.promptFavorite.create).toHaveBeenCalledWith({ + data: { userId: 1, promptId: 1 }, + }); + expect(mockPrisma.prompt.update).toHaveBeenCalledWith({ + where: { id: 1 }, + data: { likeCount: { increment: 1 } }, + }); + }); + + it('should remove favorite if exists', async () => { + mockPrisma.promptFavorite.findUnique.mockResolvedValue({ id: 1 }); + mockPrisma.promptFavorite.delete.mockResolvedValue({}); + mockPrisma.prompt.update.mockResolvedValue({}); + + const result = await service.toggleFavorite(1, 1); + + expect(result).toEqual({ favorited: false }); + expect(mockPrisma.promptFavorite.delete).toHaveBeenCalledWith({ + where: { id: 1 }, + }); + }); + }); + + describe('findFavorites', () => { + it('should return user favorites with pagination', async () => { + const mockFavorites = [ + { id: 1, userId: 1, promptId: 1, prompt: { id: 1, title: '提示词1' } }, + ]; + mockPrisma.promptFavorite.findMany.mockResolvedValue(mockFavorites); + mockPrisma.promptFavorite.count.mockResolvedValue(1); + + const result = await service.findFavorites(1, { page: 1, pageSize: 10 }); + + expect(result).toEqual({ items: mockFavorites, total: 1, page: 1, pageSize: 10 }); + }); + }); +}); diff --git a/backend/src/modules/sandbox/sandbox.controller.ts b/backend/src/modules/sandbox/sandbox.controller.ts new file mode 100644 index 0000000..4b9a316 --- /dev/null +++ b/backend/src/modules/sandbox/sandbox.controller.ts @@ -0,0 +1,44 @@ +import { Controller, Post, Get, Delete, Patch, Body, Param, Query, UseGuards, Req, ParseIntPipe } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth, ApiBody } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { SandboxService } from './sandbox.service'; +import { ChatOptions } from '../ai/ai-gateway.service'; + +@ApiTags('AI沙箱') +@Controller('sandbox') +@UseGuards(AuthGuard('jwt')) +@ApiBearerAuth() +export class SandboxController { + constructor(private sandboxService: SandboxService) {} + + @Post('chat') + @ApiBody({ schema: { example: { conversationId: 'uuid', model: 'general', messages: [{ role: 'user', content: 'hi' }], temperature: 0.7, top_p: 1, max_tokens: 2000 } } }) + async chat(@Req() req: any, @Body() body: { conversationId?: string; model: string; messages: { role: string; content: string }[] } & ChatOptions) { + return this.sandboxService.chat(req.user.userId, body.conversationId, body.model, body.messages, body); + } + + @Get('sessions') + async sessions(@Req() req: any, @Query() query: { page?: number; pageSize?: number; search?: string }) { + return this.sandboxService.getSessions(req.user.userId, query); + } + + @Get('sessions/:id') + async getSession(@Req() req: any, @Param('id', ParseIntPipe) id: number) { + return this.sandboxService.getSession(req.user.userId, id); + } + + @Patch('sessions/:id/feedback') + async setFeedback(@Req() req: any, @Param('id', ParseIntPipe) id: number, @Body() body: { feedback: 'LIKE' | 'DISLIKE' | null }) { + return this.sandboxService.setFeedback(req.user.userId, id, body.feedback); + } + + @Delete('sessions/:id') + async deleteSession(@Req() req: any, @Param('id', ParseIntPipe) id: number) { + return this.sandboxService.deleteSession(req.user.userId, id); + } + + @Get('quota') + async quota(@Req() req: any) { + return this.sandboxService.getQuota(req.user.userId); + } +} diff --git a/backend/src/modules/sandbox/sandbox.module.ts b/backend/src/modules/sandbox/sandbox.module.ts new file mode 100644 index 0000000..cf57741 --- /dev/null +++ b/backend/src/modules/sandbox/sandbox.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { SandboxController } from './sandbox.controller'; +import { SandboxService } from './sandbox.service'; +import { AIModule } from '../ai/ai.module'; + +@Module({ + imports: [AIModule], + controllers: [SandboxController], + providers: [SandboxService], + exports: [SandboxService], +}) +export class SandboxModule {} diff --git a/backend/src/modules/sandbox/sandbox.service.ts b/backend/src/modules/sandbox/sandbox.service.ts new file mode 100644 index 0000000..718ff2a --- /dev/null +++ b/backend/src/modules/sandbox/sandbox.service.ts @@ -0,0 +1,154 @@ +import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; +import { AIGatewayService, ChatOptions } from '../ai/ai-gateway.service'; +import { randomUUID } from 'crypto'; + +@Injectable() +export class SandboxService { + constructor( + private prisma: PrismaService, + private aiGateway: AIGatewayService, + ) {} + + async chat(userId: number, conversationId: string | undefined, model: string, messages: { role: string; content: string }[], options?: ChatOptions) { + const user = await this.prisma.user.findUnique({ where: { id: userId } }); + if (!user || user.status !== 'ACTIVE') { + throw new HttpException('用户不可用', HttpStatus.FORBIDDEN); + } + + const convId = conversationId || randomUUID(); + + // 今日配额:按 conversationId 去重计数 + const today = new Date(); + today.setHours(0, 0, 0, 0); + const existing = await this.prisma.sandboxSession.findUnique({ + where: { userId_conversationId: { userId, conversationId: convId } }, + }); + if (!existing) { + const todayCount = await this.prisma.sandboxSession.count({ + where: { userId, createdAt: { gte: today } }, + }); + if (todayCount >= (user.sandboxDaily || 10)) { + throw new HttpException('今日沙箱使用次数已用完', HttpStatus.TOO_MANY_REQUESTS); + } + } + + let reply = await this.aiGateway.chat(model, messages as any, options); + if (typeof reply !== 'string') { + reply = '抱歉,AI 返回了无效的回复,请重试。'; + } + + const allMessages = messages.concat({ role: 'assistant', content: reply }); + const firstUserMsg = messages.find(m => m.role === 'user'); + const title = firstUserMsg ? firstUserMsg.content.slice(0, 80) : 'AI 对话'; + + const session = await this.prisma.sandboxSession.upsert({ + where: { userId_conversationId: { userId, conversationId: convId } }, + create: { + userId, + conversationId: convId, + model, + title, + messages: JSON.stringify(allMessages), + tokens: Math.ceil(reply.length / 2), + }, + update: { + model, + title, + messages: JSON.stringify(allMessages), + tokens: Math.ceil(reply.length / 2), + }, + }); + + return { reply, conversationId: convId, sessionId: session.id }; + } + + async getSessions(userId: number, params: { page?: number; pageSize?: number; search?: string }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 50); + const where: any = { userId }; + if (params.search) { + where.title = { contains: params.search }; + } + const [items, total] = await Promise.all([ + this.prisma.sandboxSession.findMany({ + where, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { createdAt: 'desc' }, + select: { id: true, conversationId: true, model: true, title: true, feedback: true, createdAt: true, tokens: true }, + }), + this.prisma.sandboxSession.count({ where }), + ]); + return { items, total, page, pageSize }; + } + + async getSession(userId: number, id: number) { + const session = await this.prisma.sandboxSession.findFirst({ + where: { id, userId }, + }); + if (!session) { + throw new HttpException('会话不存在', HttpStatus.NOT_FOUND); + } + return { + id: session.id, + conversationId: session.conversationId, + model: session.model, + title: session.title, + feedback: session.feedback, + createdAt: session.createdAt, + messages: JSON.parse(session.messages), + }; + } + + async setFeedback(userId: number, id: number, feedback: string | null) { + const session = await this.prisma.sandboxSession.findFirst({ + where: { id, userId }, + }); + if (!session) { + throw new HttpException('会话不存在', HttpStatus.NOT_FOUND); + } + await this.prisma.sandboxSession.update({ + where: { id }, + data: { feedback: feedback || null }, + }); + return { success: true }; + } + + async deleteSession(userId: number, id: number) { + const session = await this.prisma.sandboxSession.findFirst({ + where: { id, userId }, + }); + if (!session) { + throw new HttpException('会话不存在', HttpStatus.NOT_FOUND); + } + await this.prisma.sandboxSession.delete({ where: { id } }); + return { success: true }; + } + + async getHistory(userId: number, params: { page?: number; pageSize?: number }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 20); + const [items, total] = await Promise.all([ + this.prisma.sandboxSession.findMany({ + where: { userId }, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { createdAt: 'desc' }, + select: { id: true, conversationId: true, model: true, title: true, feedback: true, createdAt: true, tokens: true }, + }), + this.prisma.sandboxSession.count({ where: { userId } }), + ]); + return { items, total, page, pageSize }; + } + + async getQuota(userId: number) { + const user = await this.prisma.user.findUnique({ where: { id: userId } }); + const today = new Date(); + today.setHours(0, 0, 0, 0); + const used = await this.prisma.sandboxSession.count({ + where: { userId, createdAt: { gte: today } }, + }); + return { dailyLimit: user?.sandboxDaily || 10, used, remaining: (user?.sandboxDaily || 10) - used }; + } +} diff --git a/backend/src/modules/sandbox/tests/sandbox.service.spec.ts b/backend/src/modules/sandbox/tests/sandbox.service.spec.ts new file mode 100644 index 0000000..4f4bf75 --- /dev/null +++ b/backend/src/modules/sandbox/tests/sandbox.service.spec.ts @@ -0,0 +1,145 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { HttpException, HttpStatus } from '@nestjs/common'; +import { SandboxService } from '../sandbox.service'; +import { PrismaService } from '../../../prisma/prisma.service'; +import { AIGatewayService } from '../../ai/ai-gateway.service'; + +describe('SandboxService', () => { + let service: SandboxService; + let prisma: PrismaService; + let aiGateway: AIGatewayService; + + const mockPrisma = { + user: { + findUnique: jest.fn(), + }, + sandboxSession: { + findMany: jest.fn(), + findUnique: jest.fn(), + count: jest.fn(), + create: jest.fn(), + upsert: jest.fn(), + }, + }; + + const mockAIGateway = { + chat: jest.fn(), + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + SandboxService, + { provide: PrismaService, useValue: mockPrisma }, + { provide: AIGatewayService, useValue: mockAIGateway }, + ], + }).compile(); + + service = module.get(SandboxService); + prisma = module.get(PrismaService); + aiGateway = module.get(AIGatewayService); + jest.clearAllMocks(); + }); + + describe('chat', () => { + it('should throw if user not found', async () => { + mockPrisma.user.findUnique.mockResolvedValue(null); + + await expect( + service.chat(1, 'test-conv', 'gpt-3.5', [{ role: 'user', content: 'Hello' }]) + ).rejects.toThrow(HttpException); + }); + + it('should throw if user not active', async () => { + mockPrisma.user.findUnique.mockResolvedValue({ id: 1, status: 'INACTIVE' }); + + await expect( + service.chat(1, 'test-conv', 'gpt-3.5', [{ role: 'user', content: 'Hello' }]) + ).rejects.toThrow(HttpException); + }); + + it('should throw if daily quota exceeded for new conversation', async () => { + mockPrisma.user.findUnique.mockResolvedValue({ + id: 1, status: 'ACTIVE', sandboxDaily: 10 + }); + mockPrisma.sandboxSession.findUnique.mockResolvedValue(null); + mockPrisma.sandboxSession.count.mockResolvedValue(10); + + await expect( + service.chat(1, 'new-conv', 'gpt-3.5', [{ role: 'user', content: 'Hello' }]) + ).rejects.toThrow(HttpException); + }); + + it('should not count quota for existing conversation', async () => { + mockPrisma.user.findUnique.mockResolvedValue({ + id: 1, status: 'ACTIVE', sandboxDaily: 10 + }); + mockPrisma.sandboxSession.findUnique.mockResolvedValue({ id: 1 }); + mockAIGateway.chat.mockResolvedValue('AI回复'); + mockPrisma.sandboxSession.upsert.mockResolvedValue({ id: 2 }); + + const result = await service.chat(1, 'existing-conv', 'gpt-3.5', [ + { role: 'user', content: 'Hello' } + ]); + + expect(result.reply).toBe('AI回复'); + expect(mockPrisma.sandboxSession.count).not.toHaveBeenCalled(); + }); + + it('should call AI gateway and save session', async () => { + mockPrisma.user.findUnique.mockResolvedValue({ + id: 1, status: 'ACTIVE', sandboxDaily: 10 + }); + mockPrisma.sandboxSession.findUnique.mockResolvedValue(null); + mockPrisma.sandboxSession.count.mockResolvedValue(5); + mockAIGateway.chat.mockResolvedValue('AI回复'); + mockPrisma.sandboxSession.upsert.mockResolvedValue({ id: 1 }); + + const result = await service.chat(1, 'test-conv', 'gpt-3.5', [ + { role: 'user', content: 'Hello' } + ]); + + expect(result.reply).toBe('AI回复'); + expect(result.conversationId).toBe('test-conv'); + expect(result.sessionId).toBeDefined(); + expect(mockAIGateway.chat).toHaveBeenCalledWith('gpt-3.5', expect.any(Array), undefined); + expect(mockPrisma.sandboxSession.upsert).toHaveBeenCalled(); + }); + }); + + describe('getHistory', () => { + it('should return paginated history', async () => { + const mockSessions = [ + { id: 1, conversationId: 'conv-1', model: 'gpt-3.5', title: 'Test', createdAt: new Date(), tokens: 10 } + ]; + mockPrisma.sandboxSession.findMany.mockResolvedValue(mockSessions); + mockPrisma.sandboxSession.count.mockResolvedValue(1); + + const result = await service.getHistory(1, { page: 1, pageSize: 20 }); + + expect(result).toEqual({ + items: mockSessions, + total: 1, + page: 1, + pageSize: 20, + }); + }); + }); + + describe('getQuota', () => { + it('should return quota info', async () => { + mockPrisma.user.findUnique.mockResolvedValue({ + id: 1, sandboxDaily: 10 + }); + mockPrisma.sandboxSession.count.mockResolvedValue(3); + + const result = await service.getQuota(1); + + expect(result).toEqual({ + dailyLimit: 10, + used: 3, + remaining: 7, + }); + }); + }); +}); diff --git a/backend/src/modules/search/search.controller.ts b/backend/src/modules/search/search.controller.ts new file mode 100644 index 0000000..a5d9d94 --- /dev/null +++ b/backend/src/modules/search/search.controller.ts @@ -0,0 +1,24 @@ +import { Controller, Get, Query } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { SearchService } from './search.service'; + +@ApiTags('搜索') +@Controller('search') +export class SearchController { + constructor(private searchService: SearchService) {} + + @Get() + async search( + @Query('q') q: string, + @Query('type') type?: string, + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + ) { + return this.searchService.search({ + q, + type, + page: page ? parseInt(page, 10) : undefined, + pageSize: pageSize ? parseInt(pageSize, 10) : undefined, + }); + } +} diff --git a/backend/src/modules/search/search.module.ts b/backend/src/modules/search/search.module.ts new file mode 100644 index 0000000..238d0e8 --- /dev/null +++ b/backend/src/modules/search/search.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { SearchController } from './search.controller'; +import { SearchService } from './search.service'; + +@Module({ + controllers: [SearchController], + providers: [SearchService], +}) +export class SearchModule {} diff --git a/backend/src/modules/search/search.service.ts b/backend/src/modules/search/search.service.ts new file mode 100644 index 0000000..4a8d3ae --- /dev/null +++ b/backend/src/modules/search/search.service.ts @@ -0,0 +1,139 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class SearchService { + constructor(private prisma: PrismaService) {} + + async search(params: { q: string; type?: string; page?: number; pageSize?: number }) { + const q = params.q?.trim(); + if (!q) return { results: [], total: 0 }; + + const page = Number(params.page ?? 1); + const pageSize = Math.min(Number(params.pageSize ?? 10), 50); + const skip = (page - 1) * pageSize; + const type = params.type || 'all'; + + const results: any[] = []; + let total = 0; + + const where: any = { + AND: [ + { deletedAt: null }, + { status: 'PUBLISHED' }, + { + OR: [ + { title: { contains: q } }, + { description: { contains: q } }, + ], + }, + ], + }; + + if (type === 'all' || type === 'courses') { + const [items, count] = await Promise.all([ + this.prisma.course.findMany({ + where: { + AND: [ + { deletedAt: null }, + { status: 'PUBLISHED' }, + { + OR: [ + { title: { contains: q } }, + { description: { contains: q } }, + ], + }, + ], + }, + select: { id: true, title: true, description: true, cover: true, isFree: true }, + skip: type === 'courses' ? skip : 0, + take: type === 'courses' ? pageSize : 5, + }), + this.prisma.course.count({ where }), + ]); + results.push(...items.map(i => ({ ...i, _type: 'course' }))); + total += count; + } + + if (type === 'all' || type === 'prompts') { + const promptWhere: any = { + AND: [ + { deletedAt: null }, + { status: 'PUBLISHED' }, + { + OR: [ + { title: { contains: q } }, + { description: { contains: q } }, + { content: { contains: q } }, + ], + }, + ], + }; + const [items, count] = await Promise.all([ + this.prisma.prompt.findMany({ + where: promptWhere, + select: { id: true, title: true, description: true, model: true }, + skip: type === 'prompts' ? skip : 0, + take: type === 'prompts' ? pageSize : 5, + }), + this.prisma.prompt.count({ where: promptWhere }), + ]); + results.push(...items.map(i => ({ ...i, _type: 'prompt' }))); + total += count; + } + + if (type === 'all' || type === 'tools') { + const toolWhere: any = { + AND: [ + { deletedAt: null }, + { status: 'PUBLISHED' }, + { + OR: [ + { name: { contains: q } }, + { description: { contains: q } }, + ], + }, + ], + }; + const [items, count] = await Promise.all([ + this.prisma.tool.findMany({ + where: toolWhere, + select: { id: true, name: true, description: true, url: true, icon: true }, + skip: type === 'tools' ? skip : 0, + take: type === 'tools' ? pageSize : 5, + }), + this.prisma.tool.count({ where: toolWhere }), + ]); + results.push(...items.map(i => ({ ...i, _type: 'tool' }))); + total += count; + } + + if (type === 'all' || type === 'contents') { + const contentWhere: any = { + AND: [ + { deletedAt: null }, + { status: 'PUBLISHED' }, + { + OR: [ + { title: { contains: q } }, + { summary: { contains: q } }, + ], + }, + ], + }; + const [items, count] = await Promise.all([ + this.prisma.content.findMany({ + where: contentWhere, + select: { id: true, title: true, summary: true, cover: true, publishedAt: true }, + skip: type === 'contents' ? skip : 0, + take: type === 'contents' ? pageSize : 5, + }), + this.prisma.content.count({ where: contentWhere }), + ]); + results.push(...items.map(i => ({ ...i, _type: 'content' }))); + total += count; + } + + return { results, total, page, pageSize }; + } +} diff --git a/backend/src/modules/search/tests/search.service.spec.ts b/backend/src/modules/search/tests/search.service.spec.ts new file mode 100644 index 0000000..8d3a05d --- /dev/null +++ b/backend/src/modules/search/tests/search.service.spec.ts @@ -0,0 +1,89 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SearchService } from '../search.service'; +import { PrismaService } from '../../../prisma/prisma.service'; + +describe('SearchService', () => { + let service: SearchService; + let prisma: PrismaService; + + const mockPrisma = { + course: { findMany: jest.fn(), count: jest.fn() }, + prompt: { findMany: jest.fn(), count: jest.fn() }, + tool: { findMany: jest.fn(), count: jest.fn() }, + content: { findMany: jest.fn(), count: jest.fn() }, + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + SearchService, + { provide: PrismaService, useValue: mockPrisma }, + ], + }).compile(); + + service = module.get(SearchService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('search', () => { + it('should return empty results for empty query', async () => { + const result = await service.search({ q: '' }); + expect(result).toEqual({ results: [], total: 0 }); + }); + + it('should search across all types by default', async () => { + mockPrisma.course.findMany.mockResolvedValue([{ id: 1, title: 'AI课程', _type: 'course' }]); + mockPrisma.course.count.mockResolvedValue(1); + mockPrisma.prompt.findMany.mockResolvedValue([]); + mockPrisma.prompt.count.mockResolvedValue(0); + mockPrisma.tool.findMany.mockResolvedValue([]); + mockPrisma.tool.count.mockResolvedValue(0); + mockPrisma.content.findMany.mockResolvedValue([]); + mockPrisma.content.count.mockResolvedValue(0); + + const result = await service.search({ q: 'AI' }); + expect(result.results).toHaveLength(1); + expect(result.results[0]).toHaveProperty('_type', 'course'); + expect(result.total).toBe(1); + }); + + it('should filter by specific type', async () => { + mockPrisma.tool.findMany.mockResolvedValue([{ id: 1, name: 'ChatGPT', _type: 'tool' }]); + mockPrisma.tool.count.mockResolvedValue(1); + + const result = await service.search({ q: 'chat', type: 'tools' }); + expect(result.results).toHaveLength(1); + expect(result.results[0]).toHaveProperty('_type', 'tool'); + }); + + it('should respect pagination params', async () => { + mockPrisma.course.findMany.mockResolvedValue([]); + mockPrisma.course.count.mockResolvedValue(0); + mockPrisma.prompt.findMany.mockResolvedValue([]); + mockPrisma.prompt.count.mockResolvedValue(0); + mockPrisma.tool.findMany.mockResolvedValue([]); + mockPrisma.tool.count.mockResolvedValue(0); + mockPrisma.content.findMany.mockResolvedValue([]); + mockPrisma.content.count.mockResolvedValue(0); + + const result = await service.search({ q: 'AI', page: 2, pageSize: 5 }); + expect(result.page).toBe(2); + expect(result.pageSize).toBe(5); + }); + + it('should cap pageSize at 50', async () => { + mockPrisma.course.findMany.mockResolvedValue([]); + mockPrisma.course.count.mockResolvedValue(0); + mockPrisma.prompt.findMany.mockResolvedValue([]); + mockPrisma.prompt.count.mockResolvedValue(0); + mockPrisma.tool.findMany.mockResolvedValue([]); + mockPrisma.tool.count.mockResolvedValue(0); + mockPrisma.content.findMany.mockResolvedValue([]); + mockPrisma.content.count.mockResolvedValue(0); + + const result = await service.search({ q: 'AI', pageSize: 100 }); + expect(result.pageSize).toBe(50); + }); + }); +}); diff --git a/backend/src/modules/tools/tests/tools.service.spec.ts b/backend/src/modules/tools/tests/tools.service.spec.ts new file mode 100644 index 0000000..c87bb2c --- /dev/null +++ b/backend/src/modules/tools/tests/tools.service.spec.ts @@ -0,0 +1,78 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ToolsService } from '../tools.service'; +import { PrismaService } from '../../../prisma/prisma.service'; + +describe('ToolsService', () => { + let service: ToolsService; + let prisma: PrismaService; + + const mockPrisma = { + tool: { + findMany: jest.fn(), + count: jest.fn(), + create: jest.fn(), + }, + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + ToolsService, + { provide: PrismaService, useValue: mockPrisma }, + ], + }).compile(); + + service = module.get(ToolsService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('findAll', () => { + it('should return paginated tools', async () => { + const mockTools = [{ id: 1, name: 'ChatGPT', category: { id: 1, name: '聊天' } }]; + mockPrisma.tool.findMany.mockResolvedValue(mockTools); + mockPrisma.tool.count.mockResolvedValue(1); + + const result = await service.findAll({ page: 1, pageSize: 20 }); + expect(result.items).toEqual(mockTools); + expect(result.total).toBe(1); + expect(result.page).toBe(1); + expect(result.pageSize).toBe(20); + }); + + it('should filter by categoryId', async () => { + mockPrisma.tool.findMany.mockResolvedValue([]); + mockPrisma.tool.count.mockResolvedValue(0); + + await service.findAll({ categoryId: 2 }); + expect(mockPrisma.tool.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: expect.objectContaining({ categoryId: 2 }), + }), + ); + }); + + it('should filter by isFeatured', async () => { + mockPrisma.tool.findMany.mockResolvedValue([]); + mockPrisma.tool.count.mockResolvedValue(0); + + await service.findAll({ isFeatured: true }); + expect(mockPrisma.tool.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: expect.objectContaining({ isFeatured: true }), + }), + ); + }); + }); + + describe('create', () => { + it('should create a tool', async () => { + const data = { name: 'New Tool', url: 'https://example.com' }; + mockPrisma.tool.create.mockResolvedValue({ id: 1, ...data }); + + const result = await service.create(data); + expect(result).toHaveProperty('id', 1); + expect(mockPrisma.tool.create).toHaveBeenCalledWith({ data }); + }); + }); +}); diff --git a/backend/src/modules/tools/tools.controller.ts b/backend/src/modules/tools/tools.controller.ts new file mode 100644 index 0000000..471e880 --- /dev/null +++ b/backend/src/modules/tools/tools.controller.ts @@ -0,0 +1,19 @@ +import { Controller, Get, Post, Body, Query } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { ToolsService } from './tools.service'; + +@ApiTags('AI工具') +@Controller('tools') +export class ToolsController { + constructor(private toolsService: ToolsService) {} + + @Get() + async findAll(@Query() query: { page?: number; pageSize?: number; categoryId?: number; isFeatured?: boolean }) { + return this.toolsService.findAll(query); + } + + @Post() + async create(@Body() body: { name: string; description?: string; url: string; icon?: string; categoryId?: number; tags?: string }) { + return this.toolsService.create(body); + } +} diff --git a/backend/src/modules/tools/tools.module.ts b/backend/src/modules/tools/tools.module.ts new file mode 100644 index 0000000..3a4fd43 --- /dev/null +++ b/backend/src/modules/tools/tools.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ToolsController } from './tools.controller'; +import { ToolsService } from './tools.service'; + +@Module({ + controllers: [ToolsController], + providers: [ToolsService], + exports: [ToolsService], +}) +export class ToolsModule {} diff --git a/backend/src/modules/tools/tools.service.ts b/backend/src/modules/tools/tools.service.ts new file mode 100644 index 0000000..7bbd4a3 --- /dev/null +++ b/backend/src/modules/tools/tools.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class ToolsService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { page?: number; pageSize?: number; categoryId?: number; isFeatured?: boolean }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 20); + const { categoryId, isFeatured } = params; + const where: any = { status: 'PUBLISHED', deletedAt: null }; + if (categoryId) where.categoryId = categoryId; + if (isFeatured !== undefined) where.isFeatured = isFeatured; + + const [items, total] = await Promise.all([ + this.prisma.tool.findMany({ + where, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { viewCount: 'desc' }, + include: { category: true }, + }), + this.prisma.tool.count({ where }), + ]); + + return { items, total, page, pageSize }; + } + + async create(data: { name: string; description?: string; url: string; icon?: string; categoryId?: number; tags?: string }) { + return this.prisma.tool.create({ data }); + } +} diff --git a/backend/src/modules/upload/upload.controller.ts b/backend/src/modules/upload/upload.controller.ts new file mode 100644 index 0000000..93f6053 --- /dev/null +++ b/backend/src/modules/upload/upload.controller.ts @@ -0,0 +1,52 @@ +import { + Controller, + Post, + UseInterceptors, + UploadedFile, + BadRequestException, +} from '@nestjs/common'; +import { FileInterceptor } from '@nestjs/platform-express'; +import { diskStorage } from 'multer'; +import { extname, join } from 'path'; +import { randomUUID } from 'crypto'; +import { ApiTags } from '@nestjs/swagger'; + +const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']; +const MAX_SIZE = 5 * 1024 * 1024; + +@ApiTags('文件上传') +@Controller('upload') +export class UploadController { + @Post() + @UseInterceptors( + FileInterceptor('file', { + storage: diskStorage({ + destination: join(process.cwd(), 'uploads'), + filename: (_req, file, cb) => { + const ext = extname(file.originalname); + cb(null, `${randomUUID()}${ext}`); + }, + }), + limits: { fileSize: MAX_SIZE }, + fileFilter: (_req, file, cb) => { + if (ALLOWED_TYPES.includes(file.mimetype)) { + cb(null, true); + } else { + cb(new BadRequestException('不支持的文件类型,仅支持 jpg/png/gif/webp/svg'), false); + } + }, + }), + ) + uploadFile(@UploadedFile() file: Express.Multer.File) { + if (!file) { + throw new BadRequestException('请选择文件'); + } + + return { + url: `/uploads/${file.filename}`, + filename: file.filename, + size: file.size, + mimetype: file.mimetype, + }; + } +} diff --git a/backend/src/modules/upload/upload.module.ts b/backend/src/modules/upload/upload.module.ts new file mode 100644 index 0000000..8966ac2 --- /dev/null +++ b/backend/src/modules/upload/upload.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { UploadController } from './upload.controller'; +import { UploadService } from './upload.service'; + +@Module({ + controllers: [UploadController], + providers: [UploadService], +}) +export class UploadModule {} diff --git a/backend/src/modules/upload/upload.service.ts b/backend/src/modules/upload/upload.service.ts new file mode 100644 index 0000000..97c1f18 --- /dev/null +++ b/backend/src/modules/upload/upload.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { extname } from 'path'; +import * as fs from 'fs'; + +@Injectable() +export class UploadService { + private uploadDir = 'uploads'; + + ensureUploadDir() { + if (!fs.existsSync(this.uploadDir)) { + fs.mkdirSync(this.uploadDir, { recursive: true }); + } + } + + getUploadDir(): string { + return this.uploadDir; + } +} diff --git a/backend/src/modules/users/tests/users.service.spec.ts b/backend/src/modules/users/tests/users.service.spec.ts new file mode 100644 index 0000000..bdba7ed --- /dev/null +++ b/backend/src/modules/users/tests/users.service.spec.ts @@ -0,0 +1,83 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UsersService } from '../users.service'; +import { PrismaService } from '../../../prisma/prisma.service'; + +describe('UsersService', () => { + let service: UsersService; + let prisma: PrismaService; + + const mockPrisma = { + user: { + findMany: jest.fn(), + findUnique: jest.fn(), + count: jest.fn(), + update: jest.fn(), + }, + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + UsersService, + { provide: PrismaService, useValue: mockPrisma }, + ], + }).compile(); + + service = module.get(UsersService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('findAll', () => { + it('should return paginated users', async () => { + const mockUsers = [{ id: 1, nickname: '用户1' }]; + mockPrisma.user.findMany.mockResolvedValue(mockUsers); + mockPrisma.user.count.mockResolvedValue(1); + + const result = await service.findAll({ page: 1, pageSize: 20 }); + expect(result.items).toEqual(mockUsers); + expect(result.total).toBe(1); + }); + + it('should filter by status', async () => { + mockPrisma.user.findMany.mockResolvedValue([]); + mockPrisma.user.count.mockResolvedValue(0); + + await service.findAll({ status: 'ACTIVE' }); + expect(mockPrisma.user.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + where: expect.objectContaining({ status: 'ACTIVE' }), + }), + ); + }); + }); + + describe('findById', () => { + it('should return user by id', async () => { + const mockUser = { id: 1, nickname: '用户1' }; + mockPrisma.user.findUnique.mockResolvedValue(mockUser); + + const result = await service.findById(1); + expect(result).toEqual(mockUser); + }); + + it('should return null for non-existent user', async () => { + mockPrisma.user.findUnique.mockResolvedValue(null); + const result = await service.findById(999); + expect(result).toBeNull(); + }); + }); + + describe('updateProfile', () => { + it('should update user profile', async () => { + mockPrisma.user.update.mockResolvedValue({ id: 1, nickname: '新昵称' }); + + const result = await service.updateProfile(1, { nickname: '新昵称' }); + expect(result).toHaveProperty('nickname', '新昵称'); + expect(mockPrisma.user.update).toHaveBeenCalledWith({ + where: { id: 1 }, + data: { nickname: '新昵称' }, + }); + }); + }); +}); diff --git a/backend/src/modules/users/users.controller.ts b/backend/src/modules/users/users.controller.ts new file mode 100644 index 0000000..a2b3b14 --- /dev/null +++ b/backend/src/modules/users/users.controller.ts @@ -0,0 +1,31 @@ +import { Controller, Get, Put, Body, Param, UseGuards, Req, Query } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { UsersService } from './users.service'; + +@ApiTags('用户') +@Controller('users') +export class UsersController { + constructor(private usersService: UsersService) {} + + @Get() + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async findAll(@Query() query: { page?: number; pageSize?: number; status?: string }) { + return this.usersService.findAll(query); + } + + @Get(':id') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async findById(@Param('id') id: string) { + return this.usersService.findById(+id); + } + + @Put('profile') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async updateProfile(@Req() req: any, @Body() body: { nickname?: string; avatar?: string }) { + return this.usersService.updateProfile(req.user.userId, body); + } +} diff --git a/backend/src/modules/users/users.module.ts b/backend/src/modules/users/users.module.ts new file mode 100644 index 0000000..513776d --- /dev/null +++ b/backend/src/modules/users/users.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { UsersController } from './users.controller'; +import { UsersService } from './users.service'; + +@Module({ + controllers: [UsersController], + providers: [UsersService], + exports: [UsersService], +}) +export class UsersModule {} diff --git a/backend/src/modules/users/users.service.ts b/backend/src/modules/users/users.service.ts new file mode 100644 index 0000000..f138364 --- /dev/null +++ b/backend/src/modules/users/users.service.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../prisma/prisma.service'; + +@Injectable() +export class UsersService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { page?: number; pageSize?: number; status?: string }) { + const page = Number(params.page ?? 1); + const pageSize = Number(params.pageSize ?? 20); + const where: any = { deletedAt: null }; + if (params.status) where.status = params.status; + + const [items, total] = await Promise.all([ + this.prisma.user.findMany({ + where, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { createdAt: 'desc' }, + select: { + id: true, nickname: true, avatar: true, phone: true, email: true, + status: true, memberPlan: true, createdAt: true, lastLoginAt: true, + }, + }), + this.prisma.user.count({ where }), + ]); + + return { items, total, page, pageSize }; + } + + async findById(id: number) { + return this.prisma.user.findUnique({ + where: { id }, + select: { + id: true, nickname: true, avatar: true, phone: true, email: true, + status: true, memberPlan: true, memberExpire: true, sandboxDaily: true, + createdAt: true, lastLoginAt: true, + }, + }); + } + + async updateProfile(id: number, data: { nickname?: string; avatar?: string }) { + return this.prisma.user.update({ where: { id }, data }); + } +} diff --git a/backend/src/prisma/prisma.module.ts b/backend/src/prisma/prisma.module.ts new file mode 100644 index 0000000..7207426 --- /dev/null +++ b/backend/src/prisma/prisma.module.ts @@ -0,0 +1,9 @@ +import { Global, Module } from '@nestjs/common'; +import { PrismaService } from './prisma.service'; + +@Global() +@Module({ + providers: [PrismaService], + exports: [PrismaService], +}) +export class PrismaModule {} diff --git a/backend/src/prisma/prisma.service.ts b/backend/src/prisma/prisma.service.ts new file mode 100644 index 0000000..bb6565f --- /dev/null +++ b/backend/src/prisma/prisma.service.ts @@ -0,0 +1,13 @@ +import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common'; +import { PrismaClient } from '@prisma/client'; + +@Injectable() +export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { + async onModuleInit() { + await this.$connect(); + } + + async onModuleDestroy() { + await this.$disconnect(); + } +} diff --git a/backend/test/app.e2e-spec.ts b/backend/test/app.e2e-spec.ts new file mode 100644 index 0000000..104471f --- /dev/null +++ b/backend/test/app.e2e-spec.ts @@ -0,0 +1,143 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication, ValidationPipe } from '@nestjs/common'; +import * as request from 'supertest'; +import { AppModule } from '../src/app.module'; + +describe('API (e2e)', () => { + let app: INestApplication; + + beforeAll(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + app.setGlobalPrefix('api/v1'); + app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true })); + await app.init(); + }); + + afterAll(async () => { + await app.close(); + }); + + describe('Auth', () => { + it('POST /api/v1/auth/register should validate input', () => { + return request(app.getHttpServer()) + .post('/api/v1/auth/register') + .send({}) + .expect(400); + }); + }); + + describe('Courses', () => { + it('GET /api/v1/courses should return paginated results', () => { + return request(app.getHttpServer()) + .get('/api/v1/courses') + .expect(200) + .expect((res) => { + expect(res.body).toHaveProperty('items'); + expect(res.body).toHaveProperty('total'); + expect(res.body).toHaveProperty('page'); + expect(res.body).toHaveProperty('pageSize'); + }); + }); + + it('GET /api/v1/courses/:id should return 404 for non-existent', () => { + return request(app.getHttpServer()) + .get('/api/v1/courses/99999') + .expect(200); + }); + }); + + describe('Categories', () => { + it('GET /api/v1/categories should return list', () => { + return request(app.getHttpServer()) + .get('/api/v1/categories') + .expect(200); + }); + }); + + describe('Prompts', () => { + it('GET /api/v1/prompts should return paginated results', () => { + return request(app.getHttpServer()) + .get('/api/v1/prompts') + .expect(200) + .expect((res) => { + expect(res.body).toHaveProperty('items'); + expect(res.body).toHaveProperty('total'); + }); + }); + }); + + describe('Community', () => { + it('GET /api/v1/community/posts should return paginated results', () => { + return request(app.getHttpServer()) + .get('/api/v1/community/posts') + .expect(200) + .expect((res) => { + expect(res.body).toHaveProperty('items'); + }); + }); + }); + + describe('Circles', () => { + it('GET /api/v1/circles should return list', () => { + return request(app.getHttpServer()) + .get('/api/v1/circles') + .expect(200); + }); + }); + + describe('Search', () => { + it('GET /api/v1/search should return results', () => { + return request(app.getHttpServer()) + .get('/api/v1/search?q=AI') + .expect(200) + .expect((res) => { + expect(res.body).toHaveProperty('results'); + }); + }); + }); + + describe('Models', () => { + it('GET /api/v1/models should return list', () => { + return request(app.getHttpServer()) + .get('/api/v1/models') + .expect(200); + }); + }); + + describe('Tools', () => { + it('GET /api/v1/tools should return paginated results', () => { + return request(app.getHttpServer()) + .get('/api/v1/tools') + .expect(200) + .expect((res) => { + expect(res.body).toHaveProperty('items'); + }); + }); + }); + + describe('Contents', () => { + it('GET /api/v1/contents should return paginated results', () => { + return request(app.getHttpServer()) + .get('/api/v1/contents') + .expect(200); + }); + }); + + describe('Protected endpoints', () => { + it('GET /api/v1/dashboard/stats should return 401 without token', () => { + return request(app.getHttpServer()) + .get('/api/v1/dashboard/stats') + .expect(401); + }); + + it('GET /api/v1/orders should return 401 without token', () => { + return request(app.getHttpServer()) + .get('/api/v1/orders') + .expect(401); + }); + }); +}); diff --git a/backend/tsconfig.json b/backend/tsconfig.json new file mode 100644 index 0000000..0388ba9 --- /dev/null +++ b/backend/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true + }, + "exclude": ["node_modules", "dist", "prisma"], + "include": ["src/**/*.ts", "src/**/*.spec.ts"] +} diff --git a/backend/tsconfig.tsbuildinfo b/backend/tsconfig.tsbuildinfo new file mode 100644 index 0000000..a9ee1ee --- /dev/null +++ b/backend/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"program":{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.webworker.importscripts.d.ts","./node_modules/typescript/lib/lib.scripthost.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/typescript/lib/lib.es2021.full.d.ts","./node_modules/reflect-metadata/index.d.ts","./node_modules/@nestjs/common/decorators/core/bind.decorator.d.ts","./node_modules/@nestjs/common/interfaces/abstract.interface.d.ts","./node_modules/@nestjs/common/interfaces/controllers/controller-metadata.interface.d.ts","./node_modules/@nestjs/common/interfaces/controllers/controller.interface.d.ts","./node_modules/@nestjs/common/interfaces/features/arguments-host.interface.d.ts","./node_modules/@nestjs/common/interfaces/exceptions/exception-filter.interface.d.ts","./node_modules/rxjs/dist/types/internal/Subscription.d.ts","./node_modules/rxjs/dist/types/internal/Subscriber.d.ts","./node_modules/rxjs/dist/types/internal/Operator.d.ts","./node_modules/rxjs/dist/types/internal/Observable.d.ts","./node_modules/rxjs/dist/types/internal/types.d.ts","./node_modules/rxjs/dist/types/internal/operators/audit.d.ts","./node_modules/rxjs/dist/types/internal/operators/auditTime.d.ts","./node_modules/rxjs/dist/types/internal/operators/buffer.d.ts","./node_modules/rxjs/dist/types/internal/operators/bufferCount.d.ts","./node_modules/rxjs/dist/types/internal/operators/bufferTime.d.ts","./node_modules/rxjs/dist/types/internal/operators/bufferToggle.d.ts","./node_modules/rxjs/dist/types/internal/operators/bufferWhen.d.ts","./node_modules/rxjs/dist/types/internal/operators/catchError.d.ts","./node_modules/rxjs/dist/types/internal/operators/combineLatestAll.d.ts","./node_modules/rxjs/dist/types/internal/operators/combineAll.d.ts","./node_modules/rxjs/dist/types/internal/operators/combineLatest.d.ts","./node_modules/rxjs/dist/types/internal/operators/combineLatestWith.d.ts","./node_modules/rxjs/dist/types/internal/operators/concat.d.ts","./node_modules/rxjs/dist/types/internal/operators/concatAll.d.ts","./node_modules/rxjs/dist/types/internal/operators/concatMap.d.ts","./node_modules/rxjs/dist/types/internal/operators/concatMapTo.d.ts","./node_modules/rxjs/dist/types/internal/operators/concatWith.d.ts","./node_modules/rxjs/dist/types/internal/operators/connect.d.ts","./node_modules/rxjs/dist/types/internal/operators/count.d.ts","./node_modules/rxjs/dist/types/internal/operators/debounce.d.ts","./node_modules/rxjs/dist/types/internal/operators/debounceTime.d.ts","./node_modules/rxjs/dist/types/internal/operators/defaultIfEmpty.d.ts","./node_modules/rxjs/dist/types/internal/operators/delay.d.ts","./node_modules/rxjs/dist/types/internal/operators/delayWhen.d.ts","./node_modules/rxjs/dist/types/internal/operators/dematerialize.d.ts","./node_modules/rxjs/dist/types/internal/operators/distinct.d.ts","./node_modules/rxjs/dist/types/internal/operators/distinctUntilChanged.d.ts","./node_modules/rxjs/dist/types/internal/operators/distinctUntilKeyChanged.d.ts","./node_modules/rxjs/dist/types/internal/operators/elementAt.d.ts","./node_modules/rxjs/dist/types/internal/operators/endWith.d.ts","./node_modules/rxjs/dist/types/internal/operators/every.d.ts","./node_modules/rxjs/dist/types/internal/operators/exhaustAll.d.ts","./node_modules/rxjs/dist/types/internal/operators/exhaust.d.ts","./node_modules/rxjs/dist/types/internal/operators/exhaustMap.d.ts","./node_modules/rxjs/dist/types/internal/operators/expand.d.ts","./node_modules/rxjs/dist/types/internal/operators/filter.d.ts","./node_modules/rxjs/dist/types/internal/operators/finalize.d.ts","./node_modules/rxjs/dist/types/internal/operators/find.d.ts","./node_modules/rxjs/dist/types/internal/operators/findIndex.d.ts","./node_modules/rxjs/dist/types/internal/operators/first.d.ts","./node_modules/rxjs/dist/types/internal/Subject.d.ts","./node_modules/rxjs/dist/types/internal/operators/groupBy.d.ts","./node_modules/rxjs/dist/types/internal/operators/ignoreElements.d.ts","./node_modules/rxjs/dist/types/internal/operators/isEmpty.d.ts","./node_modules/rxjs/dist/types/internal/operators/last.d.ts","./node_modules/rxjs/dist/types/internal/operators/map.d.ts","./node_modules/rxjs/dist/types/internal/operators/mapTo.d.ts","./node_modules/rxjs/dist/types/internal/Notification.d.ts","./node_modules/rxjs/dist/types/internal/operators/materialize.d.ts","./node_modules/rxjs/dist/types/internal/operators/max.d.ts","./node_modules/rxjs/dist/types/internal/operators/merge.d.ts","./node_modules/rxjs/dist/types/internal/operators/mergeAll.d.ts","./node_modules/rxjs/dist/types/internal/operators/mergeMap.d.ts","./node_modules/rxjs/dist/types/internal/operators/flatMap.d.ts","./node_modules/rxjs/dist/types/internal/operators/mergeMapTo.d.ts","./node_modules/rxjs/dist/types/internal/operators/mergeScan.d.ts","./node_modules/rxjs/dist/types/internal/operators/mergeWith.d.ts","./node_modules/rxjs/dist/types/internal/operators/min.d.ts","./node_modules/rxjs/dist/types/internal/observable/ConnectableObservable.d.ts","./node_modules/rxjs/dist/types/internal/operators/multicast.d.ts","./node_modules/rxjs/dist/types/internal/operators/observeOn.d.ts","./node_modules/rxjs/dist/types/internal/operators/onErrorResumeNextWith.d.ts","./node_modules/rxjs/dist/types/internal/operators/pairwise.d.ts","./node_modules/rxjs/dist/types/internal/operators/partition.d.ts","./node_modules/rxjs/dist/types/internal/operators/pluck.d.ts","./node_modules/rxjs/dist/types/internal/operators/publish.d.ts","./node_modules/rxjs/dist/types/internal/operators/publishBehavior.d.ts","./node_modules/rxjs/dist/types/internal/operators/publishLast.d.ts","./node_modules/rxjs/dist/types/internal/operators/publishReplay.d.ts","./node_modules/rxjs/dist/types/internal/operators/race.d.ts","./node_modules/rxjs/dist/types/internal/operators/raceWith.d.ts","./node_modules/rxjs/dist/types/internal/operators/reduce.d.ts","./node_modules/rxjs/dist/types/internal/operators/repeat.d.ts","./node_modules/rxjs/dist/types/internal/operators/repeatWhen.d.ts","./node_modules/rxjs/dist/types/internal/operators/retry.d.ts","./node_modules/rxjs/dist/types/internal/operators/retryWhen.d.ts","./node_modules/rxjs/dist/types/internal/operators/refCount.d.ts","./node_modules/rxjs/dist/types/internal/operators/sample.d.ts","./node_modules/rxjs/dist/types/internal/operators/sampleTime.d.ts","./node_modules/rxjs/dist/types/internal/operators/scan.d.ts","./node_modules/rxjs/dist/types/internal/operators/sequenceEqual.d.ts","./node_modules/rxjs/dist/types/internal/operators/share.d.ts","./node_modules/rxjs/dist/types/internal/operators/shareReplay.d.ts","./node_modules/rxjs/dist/types/internal/operators/single.d.ts","./node_modules/rxjs/dist/types/internal/operators/skip.d.ts","./node_modules/rxjs/dist/types/internal/operators/skipLast.d.ts","./node_modules/rxjs/dist/types/internal/operators/skipUntil.d.ts","./node_modules/rxjs/dist/types/internal/operators/skipWhile.d.ts","./node_modules/rxjs/dist/types/internal/operators/startWith.d.ts","./node_modules/rxjs/dist/types/internal/operators/subscribeOn.d.ts","./node_modules/rxjs/dist/types/internal/operators/switchAll.d.ts","./node_modules/rxjs/dist/types/internal/operators/switchMap.d.ts","./node_modules/rxjs/dist/types/internal/operators/switchMapTo.d.ts","./node_modules/rxjs/dist/types/internal/operators/switchScan.d.ts","./node_modules/rxjs/dist/types/internal/operators/take.d.ts","./node_modules/rxjs/dist/types/internal/operators/takeLast.d.ts","./node_modules/rxjs/dist/types/internal/operators/takeUntil.d.ts","./node_modules/rxjs/dist/types/internal/operators/takeWhile.d.ts","./node_modules/rxjs/dist/types/internal/operators/tap.d.ts","./node_modules/rxjs/dist/types/internal/operators/throttle.d.ts","./node_modules/rxjs/dist/types/internal/operators/throttleTime.d.ts","./node_modules/rxjs/dist/types/internal/operators/throwIfEmpty.d.ts","./node_modules/rxjs/dist/types/internal/operators/timeInterval.d.ts","./node_modules/rxjs/dist/types/internal/operators/timeout.d.ts","./node_modules/rxjs/dist/types/internal/operators/timeoutWith.d.ts","./node_modules/rxjs/dist/types/internal/operators/timestamp.d.ts","./node_modules/rxjs/dist/types/internal/operators/toArray.d.ts","./node_modules/rxjs/dist/types/internal/operators/window.d.ts","./node_modules/rxjs/dist/types/internal/operators/windowCount.d.ts","./node_modules/rxjs/dist/types/internal/operators/windowTime.d.ts","./node_modules/rxjs/dist/types/internal/operators/windowToggle.d.ts","./node_modules/rxjs/dist/types/internal/operators/windowWhen.d.ts","./node_modules/rxjs/dist/types/internal/operators/withLatestFrom.d.ts","./node_modules/rxjs/dist/types/internal/operators/zip.d.ts","./node_modules/rxjs/dist/types/internal/operators/zipAll.d.ts","./node_modules/rxjs/dist/types/internal/operators/zipWith.d.ts","./node_modules/rxjs/dist/types/operators/index.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/Action.d.ts","./node_modules/rxjs/dist/types/internal/Scheduler.d.ts","./node_modules/rxjs/dist/types/internal/testing/TestMessage.d.ts","./node_modules/rxjs/dist/types/internal/testing/SubscriptionLog.d.ts","./node_modules/rxjs/dist/types/internal/testing/SubscriptionLoggable.d.ts","./node_modules/rxjs/dist/types/internal/testing/ColdObservable.d.ts","./node_modules/rxjs/dist/types/internal/testing/HotObservable.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/AsyncScheduler.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/timerHandle.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/AsyncAction.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/VirtualTimeScheduler.d.ts","./node_modules/rxjs/dist/types/internal/testing/TestScheduler.d.ts","./node_modules/rxjs/dist/types/testing/index.d.ts","./node_modules/rxjs/dist/types/internal/symbol/observable.d.ts","./node_modules/rxjs/dist/types/internal/observable/dom/animationFrames.d.ts","./node_modules/rxjs/dist/types/internal/BehaviorSubject.d.ts","./node_modules/rxjs/dist/types/internal/ReplaySubject.d.ts","./node_modules/rxjs/dist/types/internal/AsyncSubject.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/AsapScheduler.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/asap.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/async.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/QueueScheduler.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/queue.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/AnimationFrameScheduler.d.ts","./node_modules/rxjs/dist/types/internal/scheduler/animationFrame.d.ts","./node_modules/rxjs/dist/types/internal/util/identity.d.ts","./node_modules/rxjs/dist/types/internal/util/pipe.d.ts","./node_modules/rxjs/dist/types/internal/util/noop.d.ts","./node_modules/rxjs/dist/types/internal/util/isObservable.d.ts","./node_modules/rxjs/dist/types/internal/lastValueFrom.d.ts","./node_modules/rxjs/dist/types/internal/firstValueFrom.d.ts","./node_modules/rxjs/dist/types/internal/util/ArgumentOutOfRangeError.d.ts","./node_modules/rxjs/dist/types/internal/util/EmptyError.d.ts","./node_modules/rxjs/dist/types/internal/util/NotFoundError.d.ts","./node_modules/rxjs/dist/types/internal/util/ObjectUnsubscribedError.d.ts","./node_modules/rxjs/dist/types/internal/util/SequenceError.d.ts","./node_modules/rxjs/dist/types/internal/util/UnsubscriptionError.d.ts","./node_modules/rxjs/dist/types/internal/observable/bindCallback.d.ts","./node_modules/rxjs/dist/types/internal/observable/bindNodeCallback.d.ts","./node_modules/rxjs/dist/types/internal/AnyCatcher.d.ts","./node_modules/rxjs/dist/types/internal/observable/combineLatest.d.ts","./node_modules/rxjs/dist/types/internal/observable/concat.d.ts","./node_modules/rxjs/dist/types/internal/observable/connectable.d.ts","./node_modules/rxjs/dist/types/internal/observable/defer.d.ts","./node_modules/rxjs/dist/types/internal/observable/empty.d.ts","./node_modules/rxjs/dist/types/internal/observable/forkJoin.d.ts","./node_modules/rxjs/dist/types/internal/observable/from.d.ts","./node_modules/rxjs/dist/types/internal/observable/fromEvent.d.ts","./node_modules/rxjs/dist/types/internal/observable/fromEventPattern.d.ts","./node_modules/rxjs/dist/types/internal/observable/generate.d.ts","./node_modules/rxjs/dist/types/internal/observable/iif.d.ts","./node_modules/rxjs/dist/types/internal/observable/interval.d.ts","./node_modules/rxjs/dist/types/internal/observable/merge.d.ts","./node_modules/rxjs/dist/types/internal/observable/never.d.ts","./node_modules/rxjs/dist/types/internal/observable/of.d.ts","./node_modules/rxjs/dist/types/internal/observable/onErrorResumeNext.d.ts","./node_modules/rxjs/dist/types/internal/observable/pairs.d.ts","./node_modules/rxjs/dist/types/internal/observable/partition.d.ts","./node_modules/rxjs/dist/types/internal/observable/race.d.ts","./node_modules/rxjs/dist/types/internal/observable/range.d.ts","./node_modules/rxjs/dist/types/internal/observable/throwError.d.ts","./node_modules/rxjs/dist/types/internal/observable/timer.d.ts","./node_modules/rxjs/dist/types/internal/observable/using.d.ts","./node_modules/rxjs/dist/types/internal/observable/zip.d.ts","./node_modules/rxjs/dist/types/internal/scheduled/scheduled.d.ts","./node_modules/rxjs/dist/types/internal/config.d.ts","./node_modules/rxjs/dist/types/index.d.ts","./node_modules/@nestjs/common/interfaces/exceptions/rpc-exception-filter.interface.d.ts","./node_modules/@nestjs/common/interfaces/exceptions/ws-exception-filter.interface.d.ts","./node_modules/@nestjs/common/interfaces/external/validation-error.interface.d.ts","./node_modules/@nestjs/common/interfaces/features/execution-context.interface.d.ts","./node_modules/@nestjs/common/interfaces/features/can-activate.interface.d.ts","./node_modules/@nestjs/common/interfaces/features/custom-route-param-factory.interface.d.ts","./node_modules/@nestjs/common/interfaces/features/nest-interceptor.interface.d.ts","./node_modules/@nestjs/common/interfaces/features/paramtype.interface.d.ts","./node_modules/@nestjs/common/interfaces/type.interface.d.ts","./node_modules/@nestjs/common/interfaces/features/pipe-transform.interface.d.ts","./node_modules/@nestjs/common/enums/request-method.enum.d.ts","./node_modules/@nestjs/common/enums/http-status.enum.d.ts","./node_modules/@nestjs/common/enums/shutdown-signal.enum.d.ts","./node_modules/@nestjs/common/enums/version-type.enum.d.ts","./node_modules/@nestjs/common/enums/index.d.ts","./node_modules/@nestjs/common/interfaces/version-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/middleware/middleware-configuration.interface.d.ts","./node_modules/@nestjs/common/interfaces/middleware/middleware-consumer.interface.d.ts","./node_modules/@nestjs/common/interfaces/middleware/middleware-config-proxy.interface.d.ts","./node_modules/@nestjs/common/interfaces/middleware/nest-middleware.interface.d.ts","./node_modules/@nestjs/common/interfaces/middleware/index.d.ts","./node_modules/@nestjs/common/interfaces/global-prefix-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/hooks/before-application-shutdown.interface.d.ts","./node_modules/@nestjs/common/interfaces/hooks/on-application-bootstrap.interface.d.ts","./node_modules/@nestjs/common/interfaces/hooks/on-application-shutdown.interface.d.ts","./node_modules/@nestjs/common/interfaces/hooks/on-destroy.interface.d.ts","./node_modules/@nestjs/common/interfaces/hooks/on-init.interface.d.ts","./node_modules/@nestjs/common/interfaces/hooks/index.d.ts","./node_modules/@nestjs/common/interfaces/http/http-exception-body.interface.d.ts","./node_modules/@nestjs/common/interfaces/http/http-redirect-response.interface.d.ts","./node_modules/@nestjs/common/interfaces/external/cors-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/external/https-options.interface.d.ts","./node_modules/@nestjs/common/services/logger.service.d.ts","./node_modules/@nestjs/common/interfaces/nest-application-context-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/nest-application-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/http/http-server.interface.d.ts","./node_modules/@nestjs/common/interfaces/http/message-event.interface.d.ts","./node_modules/@nestjs/common/interfaces/http/raw-body-request.interface.d.ts","./node_modules/@nestjs/common/interfaces/http/index.d.ts","./node_modules/@nestjs/common/interfaces/injectable.interface.d.ts","./node_modules/@nestjs/common/interfaces/microservices/nest-hybrid-application-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/forward-reference.interface.d.ts","./node_modules/@nestjs/common/interfaces/scope-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/injection-token.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/optional-factory-dependency.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/provider.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/module-metadata.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/dynamic-module.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/introspection-result.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/nest-module.interface.d.ts","./node_modules/@nestjs/common/interfaces/modules/index.d.ts","./node_modules/@nestjs/common/interfaces/shutdown-hooks-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/nest-application-context.interface.d.ts","./node_modules/@nestjs/common/interfaces/websockets/web-socket-adapter.interface.d.ts","./node_modules/@nestjs/common/interfaces/nest-application.interface.d.ts","./node_modules/@nestjs/common/interfaces/nest-microservice.interface.d.ts","./node_modules/@nestjs/common/interfaces/index.d.ts","./node_modules/@nestjs/common/decorators/core/catch.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/controller.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/dependencies.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/exception-filters.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/inject.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/injectable.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/optional.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/set-metadata.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/use-guards.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/use-interceptors.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/use-pipes.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/apply-decorators.d.ts","./node_modules/@nestjs/common/decorators/core/version.decorator.d.ts","./node_modules/@nestjs/common/decorators/core/index.d.ts","./node_modules/@nestjs/common/decorators/modules/global.decorator.d.ts","./node_modules/@nestjs/common/decorators/modules/module.decorator.d.ts","./node_modules/@nestjs/common/decorators/modules/index.d.ts","./node_modules/@nestjs/common/decorators/http/request-mapping.decorator.d.ts","./node_modules/@nestjs/common/decorators/http/route-params.decorator.d.ts","./node_modules/@nestjs/common/decorators/http/http-code.decorator.d.ts","./node_modules/@nestjs/common/decorators/http/create-route-param-metadata.decorator.d.ts","./node_modules/@nestjs/common/decorators/http/render.decorator.d.ts","./node_modules/@nestjs/common/decorators/http/header.decorator.d.ts","./node_modules/@nestjs/common/decorators/http/redirect.decorator.d.ts","./node_modules/@nestjs/common/constants.d.ts","./node_modules/@nestjs/common/decorators/http/sse.decorator.d.ts","./node_modules/@nestjs/common/decorators/http/index.d.ts","./node_modules/@nestjs/common/decorators/index.d.ts","./node_modules/@nestjs/common/exceptions/intrinsic.exception.d.ts","./node_modules/@nestjs/common/exceptions/http.exception.d.ts","./node_modules/@nestjs/common/exceptions/bad-gateway.exception.d.ts","./node_modules/@nestjs/common/exceptions/bad-request.exception.d.ts","./node_modules/@nestjs/common/exceptions/conflict.exception.d.ts","./node_modules/@nestjs/common/exceptions/forbidden.exception.d.ts","./node_modules/@nestjs/common/exceptions/gateway-timeout.exception.d.ts","./node_modules/@nestjs/common/exceptions/gone.exception.d.ts","./node_modules/@nestjs/common/exceptions/http-version-not-supported.exception.d.ts","./node_modules/@nestjs/common/exceptions/im-a-teapot.exception.d.ts","./node_modules/@nestjs/common/exceptions/internal-server-error.exception.d.ts","./node_modules/@nestjs/common/exceptions/method-not-allowed.exception.d.ts","./node_modules/@nestjs/common/exceptions/misdirected.exception.d.ts","./node_modules/@nestjs/common/exceptions/not-acceptable.exception.d.ts","./node_modules/@nestjs/common/exceptions/not-found.exception.d.ts","./node_modules/@nestjs/common/exceptions/not-implemented.exception.d.ts","./node_modules/@nestjs/common/exceptions/payload-too-large.exception.d.ts","./node_modules/@nestjs/common/exceptions/precondition-failed.exception.d.ts","./node_modules/@nestjs/common/exceptions/request-timeout.exception.d.ts","./node_modules/@nestjs/common/exceptions/service-unavailable.exception.d.ts","./node_modules/@nestjs/common/exceptions/unauthorized.exception.d.ts","./node_modules/@nestjs/common/exceptions/unprocessable-entity.exception.d.ts","./node_modules/@nestjs/common/exceptions/unsupported-media-type.exception.d.ts","./node_modules/@nestjs/common/exceptions/index.d.ts","./node_modules/@nestjs/common/services/console-logger.service.d.ts","./node_modules/@nestjs/common/services/utils/filter-log-levels.util.d.ts","./node_modules/@nestjs/common/services/index.d.ts","./node_modules/@nestjs/common/file-stream/interfaces/streamable-options.interface.d.ts","./node_modules/@nestjs/common/file-stream/interfaces/streamable-handler-response.interface.d.ts","./node_modules/@nestjs/common/file-stream/interfaces/index.d.ts","./node_modules/@nestjs/common/file-stream/streamable-file.d.ts","./node_modules/@nestjs/common/file-stream/index.d.ts","./node_modules/@nestjs/common/module-utils/constants.d.ts","./node_modules/@nestjs/common/module-utils/interfaces/configurable-module-async-options.interface.d.ts","./node_modules/@nestjs/common/module-utils/interfaces/configurable-module-cls.interface.d.ts","./node_modules/@nestjs/common/module-utils/interfaces/configurable-module-host.interface.d.ts","./node_modules/@nestjs/common/module-utils/interfaces/index.d.ts","./node_modules/@nestjs/common/module-utils/configurable-module.builder.d.ts","./node_modules/@nestjs/common/module-utils/index.d.ts","./node_modules/@nestjs/common/pipes/default-value.pipe.d.ts","./node_modules/@nestjs/common/pipes/file/interfaces/file.interface.d.ts","./node_modules/@nestjs/common/pipes/file/interfaces/index.d.ts","./node_modules/@nestjs/common/pipes/file/file-validator-context.interface.d.ts","./node_modules/@nestjs/common/pipes/file/file-validator.interface.d.ts","./node_modules/@nestjs/common/pipes/file/file-type.validator.d.ts","./node_modules/@nestjs/common/pipes/file/max-file-size.validator.d.ts","./node_modules/@nestjs/common/utils/http-error-by-code.util.d.ts","./node_modules/@nestjs/common/pipes/file/parse-file-options.interface.d.ts","./node_modules/@nestjs/common/pipes/file/parse-file.pipe.d.ts","./node_modules/@nestjs/common/pipes/file/parse-file-pipe.builder.d.ts","./node_modules/@nestjs/common/pipes/file/index.d.ts","./node_modules/@nestjs/common/interfaces/external/class-transform-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/external/transformer-package.interface.d.ts","./node_modules/@nestjs/common/interfaces/external/validator-options.interface.d.ts","./node_modules/@nestjs/common/interfaces/external/validator-package.interface.d.ts","./node_modules/@nestjs/common/pipes/validation.pipe.d.ts","./node_modules/@nestjs/common/pipes/parse-array.pipe.d.ts","./node_modules/@nestjs/common/pipes/parse-bool.pipe.d.ts","./node_modules/@nestjs/common/pipes/parse-date.pipe.d.ts","./node_modules/@nestjs/common/pipes/parse-enum.pipe.d.ts","./node_modules/@nestjs/common/pipes/parse-float.pipe.d.ts","./node_modules/@nestjs/common/pipes/parse-int.pipe.d.ts","./node_modules/@nestjs/common/pipes/parse-uuid.pipe.d.ts","./node_modules/@nestjs/common/pipes/index.d.ts","./node_modules/@nestjs/common/serializer/class-serializer.interfaces.d.ts","./node_modules/@nestjs/common/serializer/class-serializer.interceptor.d.ts","./node_modules/@nestjs/common/serializer/decorators/serialize-options.decorator.d.ts","./node_modules/@nestjs/common/serializer/decorators/index.d.ts","./node_modules/@nestjs/common/serializer/index.d.ts","./node_modules/@nestjs/common/utils/forward-ref.util.d.ts","./node_modules/@nestjs/common/utils/index.d.ts","./node_modules/@nestjs/common/index.d.ts","./node_modules/@nestjs/config/dist/conditional.module.d.ts","./node_modules/@nestjs/config/dist/interfaces/config-change-event.interface.d.ts","./node_modules/@nestjs/config/dist/types/config-object.type.d.ts","./node_modules/@nestjs/config/dist/types/config.type.d.ts","./node_modules/@nestjs/config/dist/types/no-infer.type.d.ts","./node_modules/@nestjs/config/dist/types/path-value.type.d.ts","./node_modules/@nestjs/config/dist/types/index.d.ts","./node_modules/@nestjs/config/dist/interfaces/config-factory.interface.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/ts5.6/globals.typedarray.d.ts","./node_modules/@types/node/ts5.6/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/buffer/index.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/ts5.6/index.d.ts","./node_modules/dotenv-expand/lib/main.d.ts","./node_modules/@nestjs/config/dist/interfaces/config-module-options.interface.d.ts","./node_modules/@nestjs/config/dist/interfaces/index.d.ts","./node_modules/@nestjs/config/dist/config.module.d.ts","./node_modules/@nestjs/config/dist/config.service.d.ts","./node_modules/@nestjs/config/dist/utils/register-as.util.d.ts","./node_modules/@nestjs/config/dist/utils/get-config-token.util.d.ts","./node_modules/@nestjs/config/dist/utils/index.d.ts","./node_modules/@nestjs/config/dist/index.d.ts","./node_modules/@nestjs/config/index.d.ts","./node_modules/@prisma/client/runtime/library.d.ts","./node_modules/.prisma/client/index.d.ts","./node_modules/.prisma/client/default.d.ts","./node_modules/@prisma/client/default.d.ts","./src/prisma/prisma.service.ts","./src/prisma/prisma.module.ts","./node_modules/@types/ms/index.d.ts","./node_modules/@types/jsonwebtoken/index.d.ts","./node_modules/@nestjs/jwt/dist/interfaces/jwt-module-options.interface.d.ts","./node_modules/@nestjs/jwt/dist/interfaces/index.d.ts","./node_modules/@nestjs/jwt/dist/jwt.errors.d.ts","./node_modules/@nestjs/jwt/dist/jwt.module.d.ts","./node_modules/@nestjs/jwt/dist/jwt.service.d.ts","./node_modules/@nestjs/jwt/dist/index.d.ts","./node_modules/@nestjs/jwt/index.d.ts","./node_modules/@nestjs/passport/dist/abstract.strategy.d.ts","./node_modules/@nestjs/passport/dist/interfaces/auth-module.options.d.ts","./node_modules/@nestjs/passport/dist/interfaces/type.interface.d.ts","./node_modules/@nestjs/passport/dist/interfaces/index.d.ts","./node_modules/@nestjs/passport/dist/auth.guard.d.ts","./node_modules/@nestjs/passport/dist/passport.module.d.ts","./node_modules/@types/send/index.d.ts","./node_modules/@types/qs/index.d.ts","./node_modules/@types/range-parser/index.d.ts","./node_modules/@types/express-serve-static-core/index.d.ts","./node_modules/@types/http-errors/index.d.ts","./node_modules/@types/serve-static/index.d.ts","./node_modules/@types/connect/index.d.ts","./node_modules/@types/body-parser/index.d.ts","./node_modules/@types/express/index.d.ts","./node_modules/@types/passport/index.d.ts","./node_modules/@nestjs/passport/dist/passport/passport.serializer.d.ts","./node_modules/@nestjs/passport/dist/passport/passport.strategy.d.ts","./node_modules/@nestjs/passport/dist/index.d.ts","./node_modules/@nestjs/passport/index.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-basic.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-bearer.decorator.d.ts","./node_modules/@nestjs/swagger/dist/interfaces/open-api-spec.interface.d.ts","./node_modules/@nestjs/swagger/dist/types/swagger-enum.type.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-body.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-consumes.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-cookie.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-default-getter.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-exclude-endpoint.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-exclude-controller.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-extra-models.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-header.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-hide-property.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-link.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-oauth2.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-operation.decorator.d.ts","./node_modules/@nestjs/swagger/dist/interfaces/enum-schema-attributes.interface.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-param.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-produces.decorator.d.ts","./node_modules/@nestjs/swagger/dist/interfaces/schema-object-metadata.interface.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-property.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-query.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-response.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-security.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-use-tags.decorator.d.ts","./node_modules/@nestjs/swagger/dist/interfaces/callback-object.interface.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-callbacks.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-extension.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/api-schema.decorator.d.ts","./node_modules/@nestjs/swagger/dist/decorators/index.d.ts","./node_modules/@nestjs/swagger/dist/interfaces/swagger-ui-options.interface.d.ts","./node_modules/@nestjs/swagger/dist/interfaces/swagger-custom-options.interface.d.ts","./node_modules/@nestjs/swagger/dist/interfaces/swagger-document-options.interface.d.ts","./node_modules/@nestjs/swagger/dist/interfaces/index.d.ts","./node_modules/@nestjs/swagger/dist/document-builder.d.ts","./node_modules/@nestjs/swagger/dist/swagger-module.d.ts","./node_modules/@nestjs/swagger/dist/type-helpers/deep-partial-type.helper.d.ts","./node_modules/@nestjs/swagger/dist/type-helpers/intersection-type.helper.d.ts","./node_modules/@nestjs/swagger/dist/type-helpers/omit-type.helper.d.ts","./node_modules/@nestjs/swagger/dist/type-helpers/partial-type.helper.d.ts","./node_modules/@nestjs/swagger/dist/type-helpers/pick-type.helper.d.ts","./node_modules/@nestjs/swagger/dist/type-helpers/index.d.ts","./node_modules/@nestjs/swagger/dist/utils/get-schema-path.util.d.ts","./node_modules/@nestjs/swagger/dist/utils/generate-schema.util.d.ts","./node_modules/@nestjs/swagger/dist/utils/index.d.ts","./node_modules/@nestjs/swagger/dist/index.d.ts","./node_modules/bcryptjs/umd/types.d.ts","./node_modules/bcryptjs/umd/index.d.ts","./src/modules/auth/auth.service.ts","./node_modules/class-validator/types/validation/ValidationError.d.ts","./node_modules/class-validator/types/validation/ValidatorOptions.d.ts","./node_modules/class-validator/types/validation-schema/ValidationSchema.d.ts","./node_modules/class-validator/types/container.d.ts","./node_modules/class-validator/types/validation/ValidationArguments.d.ts","./node_modules/class-validator/types/decorator/ValidationOptions.d.ts","./node_modules/class-validator/types/decorator/common/Allow.d.ts","./node_modules/class-validator/types/decorator/common/IsDefined.d.ts","./node_modules/class-validator/types/decorator/common/IsOptional.d.ts","./node_modules/class-validator/types/decorator/common/Validate.d.ts","./node_modules/class-validator/types/validation/ValidatorConstraintInterface.d.ts","./node_modules/class-validator/types/decorator/common/ValidateBy.d.ts","./node_modules/class-validator/types/decorator/common/ValidateIf.d.ts","./node_modules/class-validator/types/decorator/common/ValidateNested.d.ts","./node_modules/class-validator/types/decorator/common/ValidatePromise.d.ts","./node_modules/class-validator/types/decorator/common/IsLatLong.d.ts","./node_modules/class-validator/types/decorator/common/IsLatitude.d.ts","./node_modules/class-validator/types/decorator/common/IsLongitude.d.ts","./node_modules/class-validator/types/decorator/common/Equals.d.ts","./node_modules/class-validator/types/decorator/common/NotEquals.d.ts","./node_modules/class-validator/types/decorator/common/IsEmpty.d.ts","./node_modules/class-validator/types/decorator/common/IsNotEmpty.d.ts","./node_modules/class-validator/types/decorator/common/IsIn.d.ts","./node_modules/class-validator/types/decorator/common/IsNotIn.d.ts","./node_modules/class-validator/types/decorator/number/IsDivisibleBy.d.ts","./node_modules/class-validator/types/decorator/number/IsPositive.d.ts","./node_modules/class-validator/types/decorator/number/IsNegative.d.ts","./node_modules/class-validator/types/decorator/number/Max.d.ts","./node_modules/class-validator/types/decorator/number/Min.d.ts","./node_modules/class-validator/types/decorator/date/MinDate.d.ts","./node_modules/class-validator/types/decorator/date/MaxDate.d.ts","./node_modules/class-validator/types/decorator/string/Contains.d.ts","./node_modules/class-validator/types/decorator/string/NotContains.d.ts","./node_modules/@types/validator/lib/isBoolean.d.ts","./node_modules/@types/validator/lib/isEmail.d.ts","./node_modules/@types/validator/lib/isFQDN.d.ts","./node_modules/@types/validator/lib/isIBAN.d.ts","./node_modules/@types/validator/lib/isISO31661Alpha2.d.ts","./node_modules/@types/validator/lib/isISO4217.d.ts","./node_modules/@types/validator/lib/isISO6391.d.ts","./node_modules/@types/validator/lib/isTaxID.d.ts","./node_modules/@types/validator/lib/isURL.d.ts","./node_modules/@types/validator/index.d.ts","./node_modules/class-validator/types/decorator/string/IsAlpha.d.ts","./node_modules/class-validator/types/decorator/string/IsAlphanumeric.d.ts","./node_modules/class-validator/types/decorator/string/IsDecimal.d.ts","./node_modules/class-validator/types/decorator/string/IsAscii.d.ts","./node_modules/class-validator/types/decorator/string/IsBase64.d.ts","./node_modules/class-validator/types/decorator/string/IsByteLength.d.ts","./node_modules/class-validator/types/decorator/string/IsCreditCard.d.ts","./node_modules/class-validator/types/decorator/string/IsCurrency.d.ts","./node_modules/class-validator/types/decorator/string/IsEmail.d.ts","./node_modules/class-validator/types/decorator/string/IsFQDN.d.ts","./node_modules/class-validator/types/decorator/string/IsFullWidth.d.ts","./node_modules/class-validator/types/decorator/string/IsHalfWidth.d.ts","./node_modules/class-validator/types/decorator/string/IsVariableWidth.d.ts","./node_modules/class-validator/types/decorator/string/IsHexColor.d.ts","./node_modules/class-validator/types/decorator/string/IsHexadecimal.d.ts","./node_modules/class-validator/types/decorator/string/IsMacAddress.d.ts","./node_modules/class-validator/types/decorator/string/IsIP.d.ts","./node_modules/class-validator/types/decorator/string/IsPort.d.ts","./node_modules/class-validator/types/decorator/string/IsISBN.d.ts","./node_modules/class-validator/types/decorator/string/IsISIN.d.ts","./node_modules/class-validator/types/decorator/string/IsISO8601.d.ts","./node_modules/class-validator/types/decorator/string/IsJSON.d.ts","./node_modules/class-validator/types/decorator/string/IsJWT.d.ts","./node_modules/class-validator/types/decorator/string/IsLowercase.d.ts","./node_modules/class-validator/types/decorator/string/IsMobilePhone.d.ts","./node_modules/class-validator/types/decorator/string/IsISO31661Alpha2.d.ts","./node_modules/class-validator/types/decorator/string/IsISO31661Alpha3.d.ts","./node_modules/class-validator/types/decorator/string/IsISO31661Numeric.d.ts","./node_modules/class-validator/types/decorator/string/IsMongoId.d.ts","./node_modules/class-validator/types/decorator/string/IsMultibyte.d.ts","./node_modules/class-validator/types/decorator/string/IsSurrogatePair.d.ts","./node_modules/class-validator/types/decorator/string/IsUrl.d.ts","./node_modules/class-validator/types/decorator/string/IsUUID.d.ts","./node_modules/class-validator/types/decorator/string/IsFirebasePushId.d.ts","./node_modules/class-validator/types/decorator/string/IsUppercase.d.ts","./node_modules/class-validator/types/decorator/string/Length.d.ts","./node_modules/class-validator/types/decorator/string/MaxLength.d.ts","./node_modules/class-validator/types/decorator/string/MinLength.d.ts","./node_modules/class-validator/types/decorator/string/Matches.d.ts","./node_modules/libphonenumber-js/types.d.cts","./node_modules/libphonenumber-js/max/index.d.cts","./node_modules/class-validator/types/decorator/string/IsPhoneNumber.d.ts","./node_modules/class-validator/types/decorator/string/IsMilitaryTime.d.ts","./node_modules/class-validator/types/decorator/string/IsHash.d.ts","./node_modules/class-validator/types/decorator/string/IsISSN.d.ts","./node_modules/class-validator/types/decorator/string/IsDateString.d.ts","./node_modules/class-validator/types/decorator/string/IsBooleanString.d.ts","./node_modules/class-validator/types/decorator/string/IsNumberString.d.ts","./node_modules/class-validator/types/decorator/string/IsBase32.d.ts","./node_modules/class-validator/types/decorator/string/IsBIC.d.ts","./node_modules/class-validator/types/decorator/string/IsBtcAddress.d.ts","./node_modules/class-validator/types/decorator/string/IsDataURI.d.ts","./node_modules/class-validator/types/decorator/string/IsEAN.d.ts","./node_modules/class-validator/types/decorator/string/IsEthereumAddress.d.ts","./node_modules/class-validator/types/decorator/string/IsHSL.d.ts","./node_modules/class-validator/types/decorator/string/IsIBAN.d.ts","./node_modules/class-validator/types/decorator/string/IsIdentityCard.d.ts","./node_modules/class-validator/types/decorator/string/IsISRC.d.ts","./node_modules/class-validator/types/decorator/string/IsLocale.d.ts","./node_modules/class-validator/types/decorator/string/IsMagnetURI.d.ts","./node_modules/class-validator/types/decorator/string/IsMimeType.d.ts","./node_modules/class-validator/types/decorator/string/IsOctal.d.ts","./node_modules/class-validator/types/decorator/string/IsPassportNumber.d.ts","./node_modules/class-validator/types/decorator/string/IsPostalCode.d.ts","./node_modules/class-validator/types/decorator/string/IsRFC3339.d.ts","./node_modules/class-validator/types/decorator/string/IsRgbColor.d.ts","./node_modules/class-validator/types/decorator/string/IsSemVer.d.ts","./node_modules/class-validator/types/decorator/string/IsStrongPassword.d.ts","./node_modules/class-validator/types/decorator/string/IsTimeZone.d.ts","./node_modules/class-validator/types/decorator/string/IsBase58.d.ts","./node_modules/class-validator/types/decorator/string/is-tax-id.d.ts","./node_modules/class-validator/types/decorator/string/is-iso4217-currency-code.d.ts","./node_modules/class-validator/types/decorator/string/isISO6391.d.ts","./node_modules/class-validator/types/decorator/typechecker/IsBoolean.d.ts","./node_modules/class-validator/types/decorator/typechecker/IsDate.d.ts","./node_modules/class-validator/types/decorator/typechecker/IsNumber.d.ts","./node_modules/class-validator/types/decorator/typechecker/IsEnum.d.ts","./node_modules/class-validator/types/decorator/typechecker/IsInt.d.ts","./node_modules/class-validator/types/decorator/typechecker/IsString.d.ts","./node_modules/class-validator/types/decorator/typechecker/IsArray.d.ts","./node_modules/class-validator/types/decorator/typechecker/IsObject.d.ts","./node_modules/class-validator/types/decorator/array/ArrayContains.d.ts","./node_modules/class-validator/types/decorator/array/ArrayNotContains.d.ts","./node_modules/class-validator/types/decorator/array/ArrayNotEmpty.d.ts","./node_modules/class-validator/types/decorator/array/ArrayMinSize.d.ts","./node_modules/class-validator/types/decorator/array/ArrayMaxSize.d.ts","./node_modules/class-validator/types/decorator/array/ArrayUnique.d.ts","./node_modules/class-validator/types/decorator/object/IsNotEmptyObject.d.ts","./node_modules/class-validator/types/decorator/object/IsInstance.d.ts","./node_modules/class-validator/types/decorator/decorators.d.ts","./node_modules/class-validator/types/validation/ValidationTypes.d.ts","./node_modules/class-validator/types/validation/Validator.d.ts","./node_modules/class-validator/types/register-decorator.d.ts","./node_modules/class-validator/types/metadata/ValidationMetadataArgs.d.ts","./node_modules/class-validator/types/metadata/ValidationMetadata.d.ts","./node_modules/class-validator/types/metadata/ConstraintMetadata.d.ts","./node_modules/class-validator/types/metadata/MetadataStorage.d.ts","./node_modules/class-validator/types/index.d.ts","./src/modules/auth/dto/register.dto.ts","./src/modules/auth/auth.controller.ts","./node_modules/@types/passport-strategy/index.d.ts","./node_modules/@types/passport-jwt/index.d.ts","./src/modules/auth/jwt.strategy.ts","./src/modules/auth/auth.module.ts","./src/modules/users/users.service.ts","./src/modules/users/users.controller.ts","./src/modules/users/users.module.ts","./src/modules/courses/courses.service.ts","./src/modules/courses/courses.controller.ts","./src/modules/courses/courses.module.ts","./src/modules/contents/contents.service.ts","./src/modules/contents/contents.controller.ts","./src/modules/contents/contents.module.ts","./src/modules/prompts/prompts.service.ts","./src/modules/prompts/prompts.controller.ts","./src/modules/prompts/prompts.module.ts","./src/modules/tools/tools.service.ts","./src/modules/tools/tools.controller.ts","./src/modules/tools/tools.module.ts","./src/modules/ai/ai-gateway.service.ts","./src/modules/sandbox/sandbox.service.ts","./src/modules/sandbox/sandbox.controller.ts","./src/modules/ai/ai.module.ts","./src/modules/sandbox/sandbox.module.ts","./src/modules/payment/payment.service.ts","./src/modules/orders/orders.service.ts","./src/modules/orders/orders.controller.ts","./src/modules/payment/payment.controller.ts","./src/modules/payment/payment.module.ts","./src/modules/orders/orders.module.ts","./src/modules/admin/admin.service.ts","./src/modules/admin/admin.guard.ts","./src/modules/admin/admin.controller.ts","./src/modules/admin/admin.module.ts","./src/modules/categories/categories.controller.ts","./src/modules/categories/categories.module.ts","./src/modules/dashboard/dashboard.service.ts","./src/modules/dashboard/dashboard.controller.ts","./src/modules/dashboard/dashboard.module.ts","./src/modules/search/search.service.ts","./src/modules/search/search.controller.ts","./src/modules/search/search.module.ts","./src/modules/models/models.service.ts","./src/modules/models/models.controller.ts","./src/modules/models/models.module.ts","./node_modules/@nestjs/core/adapters/http-adapter.d.ts","./node_modules/@nestjs/platform-express/interfaces/nest-express-body-parser-options.interface.d.ts","./node_modules/@nestjs/platform-express/interfaces/nest-express-body-parser.interface.d.ts","./node_modules/@nestjs/platform-express/interfaces/serve-static-options.interface.d.ts","./node_modules/@nestjs/platform-express/adapters/express-adapter.d.ts","./node_modules/@nestjs/platform-express/adapters/index.d.ts","./node_modules/@nestjs/platform-express/interfaces/nest-express-application.interface.d.ts","./node_modules/@nestjs/platform-express/interfaces/index.d.ts","./node_modules/@nestjs/platform-express/multer/interfaces/multer-options.interface.d.ts","./node_modules/@nestjs/platform-express/multer/interceptors/any-files.interceptor.d.ts","./node_modules/@nestjs/platform-express/multer/interceptors/file-fields.interceptor.d.ts","./node_modules/@nestjs/platform-express/multer/interceptors/file.interceptor.d.ts","./node_modules/@nestjs/platform-express/multer/interceptors/files.interceptor.d.ts","./node_modules/@nestjs/platform-express/multer/interceptors/no-files.interceptor.d.ts","./node_modules/@nestjs/platform-express/multer/interceptors/index.d.ts","./node_modules/@nestjs/platform-express/multer/interfaces/files-upload-module.interface.d.ts","./node_modules/@nestjs/platform-express/multer/interfaces/index.d.ts","./node_modules/@nestjs/platform-express/multer/multer.module.d.ts","./node_modules/@nestjs/platform-express/multer/index.d.ts","./node_modules/@nestjs/platform-express/index.d.ts","./node_modules/@types/multer/index.d.ts","./src/modules/upload/upload.controller.ts","./src/modules/upload/upload.service.ts","./src/modules/upload/upload.module.ts","./src/modules/notifications/notification.service.ts","./src/modules/community/community.service.ts","./src/modules/community/community.controller.ts","./src/modules/community/circles.controller.ts","./src/modules/community/community.module.ts","./src/modules/enterprise/enterprise.service.ts","./src/modules/enterprise/enterprise.controller.ts","./src/modules/enterprise/enterprise.module.ts","./src/modules/notifications/notification.controller.ts","./src/modules/notifications/notification.module.ts","./src/modules/learning/learning.service.ts","./src/modules/learning/learning.controller.ts","./src/modules/learning/learning.module.ts","./src/app.module.ts","./node_modules/@nestjs/core/adapters/index.d.ts","./node_modules/@nestjs/core/inspector/interfaces/edge.interface.d.ts","./node_modules/@nestjs/core/inspector/interfaces/entrypoint.interface.d.ts","./node_modules/@nestjs/core/inspector/interfaces/extras.interface.d.ts","./node_modules/@nestjs/core/inspector/interfaces/node.interface.d.ts","./node_modules/@nestjs/core/injector/settlement-signal.d.ts","./node_modules/@nestjs/core/injector/injector.d.ts","./node_modules/@nestjs/core/inspector/interfaces/serialized-graph-metadata.interface.d.ts","./node_modules/@nestjs/core/inspector/interfaces/serialized-graph-json.interface.d.ts","./node_modules/@nestjs/core/inspector/serialized-graph.d.ts","./node_modules/@nestjs/core/injector/opaque-key-factory/interfaces/module-opaque-key-factory.interface.d.ts","./node_modules/@nestjs/core/injector/compiler.d.ts","./node_modules/@nestjs/core/injector/modules-container.d.ts","./node_modules/@nestjs/core/injector/container.d.ts","./node_modules/@nestjs/core/injector/instance-links-host.d.ts","./node_modules/@nestjs/core/injector/abstract-instance-resolver.d.ts","./node_modules/@nestjs/core/injector/module-ref.d.ts","./node_modules/@nestjs/core/injector/module.d.ts","./node_modules/@nestjs/core/injector/instance-wrapper.d.ts","./node_modules/@nestjs/core/router/interfaces/exclude-route-metadata.interface.d.ts","./node_modules/@nestjs/core/application-config.d.ts","./node_modules/@nestjs/core/constants.d.ts","./node_modules/@nestjs/core/discovery/discovery-module.d.ts","./node_modules/@nestjs/core/discovery/discovery-service.d.ts","./node_modules/@nestjs/core/discovery/index.d.ts","./node_modules/@nestjs/core/helpers/http-adapter-host.d.ts","./node_modules/@nestjs/core/exceptions/base-exception-filter.d.ts","./node_modules/@nestjs/core/exceptions/index.d.ts","./node_modules/@nestjs/core/helpers/context-id-factory.d.ts","./node_modules/@nestjs/common/interfaces/exceptions/exception-filter-metadata.interface.d.ts","./node_modules/@nestjs/core/exceptions/exceptions-handler.d.ts","./node_modules/@nestjs/core/router/router-proxy.d.ts","./node_modules/@nestjs/core/helpers/context-creator.d.ts","./node_modules/@nestjs/core/exceptions/base-exception-filter-context.d.ts","./node_modules/@nestjs/common/interfaces/exceptions/rpc-exception-filter-metadata.interface.d.ts","./node_modules/@nestjs/common/interfaces/exceptions/index.d.ts","./node_modules/@nestjs/core/exceptions/external-exception-filter.d.ts","./node_modules/@nestjs/core/exceptions/external-exceptions-handler.d.ts","./node_modules/@nestjs/core/exceptions/external-exception-filter-context.d.ts","./node_modules/@nestjs/core/guards/constants.d.ts","./node_modules/@nestjs/core/helpers/execution-context-host.d.ts","./node_modules/@nestjs/core/guards/guards-consumer.d.ts","./node_modules/@nestjs/core/guards/guards-context-creator.d.ts","./node_modules/@nestjs/core/guards/index.d.ts","./node_modules/@nestjs/core/interceptors/interceptors-consumer.d.ts","./node_modules/@nestjs/core/interceptors/interceptors-context-creator.d.ts","./node_modules/@nestjs/core/interceptors/index.d.ts","./node_modules/@nestjs/common/enums/route-paramtypes.enum.d.ts","./node_modules/@nestjs/core/pipes/params-token-factory.d.ts","./node_modules/@nestjs/core/pipes/pipes-consumer.d.ts","./node_modules/@nestjs/core/pipes/pipes-context-creator.d.ts","./node_modules/@nestjs/core/pipes/index.d.ts","./node_modules/@nestjs/core/helpers/context-utils.d.ts","./node_modules/@nestjs/core/injector/inquirer/inquirer-constants.d.ts","./node_modules/@nestjs/core/injector/inquirer/index.d.ts","./node_modules/@nestjs/core/interfaces/module-definition.interface.d.ts","./node_modules/@nestjs/core/interfaces/module-override.interface.d.ts","./node_modules/@nestjs/core/inspector/interfaces/enhancer-metadata-cache-entry.interface.d.ts","./node_modules/@nestjs/core/inspector/graph-inspector.d.ts","./node_modules/@nestjs/core/metadata-scanner.d.ts","./node_modules/@nestjs/core/scanner.d.ts","./node_modules/@nestjs/core/injector/instance-loader.d.ts","./node_modules/@nestjs/core/injector/lazy-module-loader/lazy-module-loader-options.interface.d.ts","./node_modules/@nestjs/core/injector/lazy-module-loader/lazy-module-loader.d.ts","./node_modules/@nestjs/core/injector/index.d.ts","./node_modules/@nestjs/core/helpers/interfaces/external-handler-metadata.interface.d.ts","./node_modules/@nestjs/core/helpers/interfaces/params-metadata.interface.d.ts","./node_modules/@nestjs/core/helpers/external-context-creator.d.ts","./node_modules/@nestjs/core/helpers/index.d.ts","./node_modules/@nestjs/core/inspector/initialize-on-preview.allowlist.d.ts","./node_modules/@nestjs/core/inspector/partial-graph.host.d.ts","./node_modules/@nestjs/core/inspector/index.d.ts","./node_modules/@nestjs/core/middleware/route-info-path-extractor.d.ts","./node_modules/@nestjs/core/middleware/routes-mapper.d.ts","./node_modules/@nestjs/core/middleware/builder.d.ts","./node_modules/@nestjs/core/middleware/index.d.ts","./node_modules/@nestjs/core/nest-application-context.d.ts","./node_modules/@nestjs/core/nest-application.d.ts","./node_modules/@nestjs/common/interfaces/microservices/nest-microservice-options.interface.d.ts","./node_modules/@nestjs/core/nest-factory.d.ts","./node_modules/@nestjs/core/repl/repl.d.ts","./node_modules/@nestjs/core/repl/index.d.ts","./node_modules/@nestjs/core/router/interfaces/routes.interface.d.ts","./node_modules/@nestjs/core/router/interfaces/index.d.ts","./node_modules/@nestjs/core/router/request/request-constants.d.ts","./node_modules/@nestjs/core/router/request/index.d.ts","./node_modules/@nestjs/core/router/router-module.d.ts","./node_modules/@nestjs/core/router/index.d.ts","./node_modules/@nestjs/core/services/reflector.service.d.ts","./node_modules/@nestjs/core/services/index.d.ts","./node_modules/@nestjs/core/index.d.ts","./node_modules/helmet/index.d.cts","./node_modules/@types/compression/index.d.ts","./src/common/filters/global-exception.filter.ts","./src/common/interceptors/logging.interceptor.ts","./src/common/index.ts","./src/main.ts","./node_modules/@nestjs/testing/interfaces/mock-factory.d.ts","./node_modules/@nestjs/testing/interfaces/override-by-factory-options.interface.d.ts","./node_modules/@nestjs/testing/interfaces/override-module.interface.d.ts","./node_modules/@nestjs/testing/testing-module.d.ts","./node_modules/@nestjs/testing/testing-module.builder.d.ts","./node_modules/@nestjs/testing/interfaces/override-by.interface.d.ts","./node_modules/@nestjs/testing/interfaces/index.d.ts","./node_modules/@nestjs/testing/test.d.ts","./node_modules/@nestjs/testing/index.d.ts","./src/modules/admin/tests/admin.service.spec.ts","./src/modules/ai/tests/ai-gateway.service.spec.ts","./src/modules/auth/tests/auth.service.spec.ts","./src/modules/community/tests/community.service.spec.ts","./src/modules/courses/tests/courses.service.spec.ts","./src/modules/enterprise/tests/enterprise.service.spec.ts","./src/modules/orders/subscriptions.controller.ts","./src/modules/orders/tests/orders.service.spec.ts","./src/modules/payment/tests/payment.service.spec.ts","./src/modules/prompts/tests/prompts.service.spec.ts","./src/modules/sandbox/tests/sandbox.service.spec.ts","./src/modules/search/tests/search.service.spec.ts","./src/modules/tools/tests/tools.service.spec.ts","./src/modules/users/tests/users.service.spec.ts","./node_modules/@babel/types/lib/index.d.ts","./node_modules/@types/babel__generator/index.d.ts","./node_modules/@babel/parser/typings/babel-parser.d.ts","./node_modules/@types/babel__template/index.d.ts","./node_modules/@types/babel__traverse/index.d.ts","./node_modules/@types/babel__core/index.d.ts","./node_modules/@types/bcryptjs/index.d.ts","./node_modules/@types/cookiejar/index.d.ts","./node_modules/@types/estree/index.d.ts","./node_modules/@types/json-schema/index.d.ts","./node_modules/@types/eslint/use-at-your-own-risk.d.ts","./node_modules/@types/eslint/index.d.ts","./node_modules/@types/eslint-scope/index.d.ts","./node_modules/@types/istanbul-lib-coverage/index.d.ts","./node_modules/@types/istanbul-lib-report/index.d.ts","./node_modules/@types/istanbul-reports/index.d.ts","./node_modules/@jest/expect-utils/build/index.d.ts","./node_modules/chalk/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/symbols/symbols.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/symbols/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/any/any.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/any/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/mapped/mapped-key.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/mapped/mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/async-iterator/async-iterator.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/async-iterator/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/readonly/readonly.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/readonly/readonly-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/readonly/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/readonly-optional/readonly-optional.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/readonly-optional/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/constructor/constructor.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/constructor/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/literal/literal.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/literal/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/enum/enum.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/enum/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/function/function.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/function/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/computed/computed.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/computed/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/never/never.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/never/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intersect/intersect-type.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intersect/intersect-evaluated.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intersect/intersect.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intersect/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/union/union-type.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/union/union-evaluated.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/union/union.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/union/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/recursive/recursive.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/recursive/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/unsafe/unsafe.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/unsafe/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/ref/ref.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/ref/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/tuple/tuple.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/tuple/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/error/error.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/error/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/string/string.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/string/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/boolean/boolean.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/boolean/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/number/number.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/number/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/integer/integer.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/integer/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/bigint/bigint.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/bigint/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/template-literal/parse.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/template-literal/finite.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/template-literal/generate.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/template-literal/syntax.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/template-literal/pattern.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/template-literal/template-literal.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/template-literal/union.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/template-literal/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/indexed/indexed-property-keys.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/indexed/indexed-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/indexed/indexed.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/indexed/indexed-from-mapped-key.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/indexed/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/iterator/iterator.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/iterator/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/promise/promise.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/promise/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/sets/set.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/sets/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/mapped/mapped.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/mapped/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/optional/optional.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/optional/optional-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/optional/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/awaited/awaited.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/awaited/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/keyof/keyof-property-keys.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/keyof/keyof.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/keyof/keyof-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/keyof/keyof-property-entries.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/keyof/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/omit/omit-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/omit/omit.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/omit/omit-from-mapped-key.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/omit/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/pick/pick-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/pick/pick.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/pick/pick-from-mapped-key.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/pick/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/null/null.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/null/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/symbol/symbol.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/symbol/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/undefined/undefined.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/undefined/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/partial/partial.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/partial/partial-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/partial/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/regexp/regexp.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/regexp/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/record/record.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/record/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/required/required.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/required/required-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/required/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/transform/transform.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/transform/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/module/compute.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/module/infer.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/module/module.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/module/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/not/not.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/not/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/static/static.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/static/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/object/object.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/object/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/helpers/helpers.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/helpers/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/array/array.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/array/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/date/date.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/date/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/uint8array/uint8array.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/uint8array/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/unknown/unknown.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/unknown/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/void/void.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/void/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/schema/schema.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/schema/anyschema.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/schema/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/clone/type.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/clone/value.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/clone/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/create/type.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/create/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/argument/argument.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/argument/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/guard/kind.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/guard/type.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/guard/value.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/guard/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/patterns/patterns.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/patterns/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/registry/format.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/registry/type.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/registry/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/composite/composite.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/composite/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/const/const.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/const/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/constructor-parameters/constructor-parameters.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/constructor-parameters/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/exclude/exclude-from-template-literal.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/exclude/exclude.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/exclude/exclude-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/exclude/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extends/extends-check.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extends/extends-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extends/extends.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extends/extends-from-mapped-key.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extends/extends-undefined.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extends/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extract/extract-from-template-literal.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extract/extract.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extract/extract-from-mapped-result.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/extract/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/instance-type/instance-type.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/instance-type/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/instantiate/instantiate.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/instantiate/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intrinsic/intrinsic-from-mapped-key.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intrinsic/intrinsic.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intrinsic/capitalize.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intrinsic/lowercase.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intrinsic/uncapitalize.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intrinsic/uppercase.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/intrinsic/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/parameters/parameters.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/parameters/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/rest/rest.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/rest/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/return-type/return-type.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/return-type/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/type/json.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/type/javascript.d.ts","./node_modules/@sinclair/typebox/build/cjs/type/type/index.d.ts","./node_modules/@sinclair/typebox/build/cjs/index.d.ts","./node_modules/@jest/schemas/build/index.d.ts","./node_modules/pretty-format/build/index.d.ts","./node_modules/jest-diff/build/index.d.ts","./node_modules/jest-matcher-utils/build/index.d.ts","./node_modules/jest-mock/build/index.d.ts","./node_modules/expect/build/index.d.ts","./node_modules/@types/jest/index.d.ts","./node_modules/@types/methods/index.d.ts","./node_modules/@types/stack-utils/index.d.ts","./node_modules/@types/superagent/lib/agent-base.d.ts","./node_modules/@types/superagent/lib/node/response.d.ts","./node_modules/@types/superagent/types.d.ts","./node_modules/@types/superagent/lib/node/agent.d.ts","./node_modules/@types/superagent/lib/request-base.d.ts","./node_modules/form-data/index.d.ts","./node_modules/@types/superagent/lib/node/http2wrapper.d.ts","./node_modules/@types/superagent/lib/node/index.d.ts","./node_modules/@types/superagent/index.d.ts","./node_modules/@types/supertest/types.d.ts","./node_modules/@types/supertest/lib/agent.d.ts","./node_modules/@types/supertest/lib/test.d.ts","./node_modules/@types/supertest/lib/cookies.d.ts","./node_modules/@types/supertest/index.d.ts","./node_modules/@types/yargs-parser/index.d.ts","./node_modules/@types/yargs/index.d.ts"],"fileInfos":[{"version":"f33e5332b24c3773e930e212cbb8b6867c8ba3ec4492064ea78e55a524d57450","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","26f2f787e82c4222710f3b676b4d83eb5ad0a72fa7b746f03449e7a026ce5073","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569",{"version":"21e41a76098aa7a191028256e52a726baafd45a925ea5cf0222eb430c96c1d83","affectsGlobalScope":true},{"version":"35299ae4a62086698444a5aaee27fc7aa377c68cbb90b441c9ace246ffd05c97","affectsGlobalScope":true},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true},{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"e0275cd0e42990dc3a16f0b7c8bca3efe87f1c8ad404f80c6db1c7c0b828c59f","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"ec0104fee478075cb5171e5f4e3f23add8e02d845ae0165bfa3f1099241fa2aa","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"acae90d417bee324b1372813b5a00829d31c7eb670d299cd7f8f9a648ac05688","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true},{"version":"51e547984877a62227042850456de71a5c45e7fe86b7c975c6e68896c86fa23b","affectsGlobalScope":true},{"version":"62a4966981264d1f04c44eb0f4b5bdc3d81c1a54725608861e44755aa24ad6a5","affectsGlobalScope":true},{"version":"4350e5922fecd4bedda2964d69c213a1436349d0b8d260dd902795f5b94dc74b","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},"c1e8d979afc15d66e2bd5a58c732d5a2ba3ccaae41ac7d5a2c539e6de66a8e51",{"version":"8d6d51a5118d000ed3bfe6e1dd1335bebfff3fef23cd2af2f84a24d30f90cc90","affectsGlobalScope":true},"6d8dedbec739bc79642c1e96e9bfc0b83b25b104a0486aebf016fc7b85b39f48","e89535c3ec439608bcd0f68af555d0e5ddf121c54abe69343549718bd7506b9c","622a984b60c294ffb2f9152cf1d4d12e91d2b733d820eec949cf54d63a3c1025","81aae92abdeaccd9c1723cef39232c90c1aed9d9cf199e6e2a523b7d8e058a11","a63a6c6806a1e519688ef7bd8ca57be912fc0764485119dbd923021eb4e79665","75b57b109d774acca1e151df21cf5cb54c7a1df33a273f0457b9aee4ebd36fb9","073ca26c96184db9941b5ec0ddea6981c9b816156d9095747809e524fdd90e35","e41d17a2ec23306d953cda34e573ed62954ca6ea9b8c8b74e013d07a6886ce47","241bd4add06f06f0699dcd58f3b334718d85e3045d9e9d4fa556f11f4d1569c1","2ae3787e1498b20aad1b9c2ee9ea517ec30e89b70d242d8e3e52d1e091039695",{"version":"c7c72c4cffb1bc83617eefed71ed68cc89df73cab9e19507ccdecb3e72b4967e","affectsGlobalScope":true},"b8bff8a60af0173430b18d9c3e5c443eaa3c515617210c0c7b3d2e1743c19ecb","38b38db08e7121828294dec10957a7a9ff263e33e2a904b346516d4a4acca482","a76ebdf2579e68e4cfe618269c47e5a12a4e045c2805ed7f7ab37af8daa6b091","8a2aaea564939c22be05d665cc955996721bad6d43148f8fa21ae8f64afecd37","e59d36b7b6e8ba2dd36d032a5f5c279d2460968c8b4e691ca384f118fb09b52a","e96885c0684c9042ec72a9a43ef977f6b4b4a2728f4b9e737edcbaa0c74e5bf6","95950a187596e206d32d5d9c7b932901088c65ed8f9040e614aa8e321e0225ef","89e061244da3fc21b7330f4bd32f47c1813dd4d7f1dc3d0883d88943f035b993","e46558c2e04d06207b080138678020448e7fc201f3d69c2601b0d1456105f29a","71549375db52b1163411dba383b5f4618bdf35dc57fa327a1c7d135cf9bf67d1","7e6b2d61d6215a4e82ea75bc31a80ebb8ad0c2b37a60c10c70dd671e8d9d6d5d","78bea05df2896083cca28ed75784dde46d4b194984e8fc559123b56873580a23","5dd04ced37b7ea09f29d277db11f160df7fd73ba8b9dba86cb25552e0653a637","f74b81712e06605677ae1f061600201c425430151f95b5ef4d04387ad7617e6a","9a72847fcf4ac937e352d40810f7b7aec7422d9178451148296cf1aa19467620","3ae18f60e0b96fa1e025059b7d25b3247ba4dcb5f4372f6d6e67ce2adac74eac","2b9260f44a2e071450ae82c110f5dc8f330c9e5c3e85567ed97248330f2bf639","4f196e13684186bda6f5115fc4677a87cf84a0c9c4fc17b8f51e0984f3697b6d","61419f2c5822b28c1ea483258437c1faab87d00c6f84481aa22afb3380d8e9a4","64479aee03812264e421c0bf5104a953ca7b02740ba80090aead1330d0effe91","0521108c9f8ddb17654a0a54dae6ba9667c99eddccfd6af5748113e022d1c37a","c5570e504be103e255d80c60b56c367bf45d502ca52ee35c55dec882f6563b5c","ee764e6e9a7f2b987cc1a2c0a9afd7a8f4d5ebc4fdb66ad557a7f14a8c2bd320","0520b5093712c10c6ef23b5fea2f833bf5481771977112500045e5ea7e8e2b69","5c3cf26654cf762ac4d7fd7b83f09acfe08eef88d2d6983b9a5a423cb4004ca3","e60fa19cf7911c1623b891155d7eb6b7e844e9afdf5738e3b46f3b687730a2bd","b1fd72ff2bb0ba91bb588f3e5329f8fc884eb859794f1c4657a2bfa122ae54d0","6cf42a4f3cfec648545925d43afaa8bb364ac10a839ffed88249da109361b275","d7058e75920120b142a9d57be25562a3cd9a936269fd52908505f530105f2ec4","6df52b70d7f7702202f672541a5f4a424d478ee5be51a9d37b8ccbe1dbf3c0f2","0ca7f997e9a4d8985e842b7c882e521b6f63233c4086e9fe79dd7a9dc4742b5e","91046b5c6b55d3b194c81fd4df52f687736fad3095e9d103ead92bb64dc160ee","db5704fdad56c74dfc5941283c1182ed471bd17598209d3ac4a49faa72e43cfc","758e8e89559b02b81bc0f8fd395b17ad5aff75490c862cbe369bb1a3d1577c40","2ee64342c077b1868f1834c063f575063051edd6e2964257d34aad032d6b657c","6f6b4b3d670b6a5f0e24ea001c1b3d36453c539195e875687950a178f1730fa7","a472a1d3f25ce13a1d44911cd3983956ac040ce2018e155435ea34afb25f864c","b48b83a86dd9cfe36f8776b3ff52fcd45b0e043c0538dc4a4b149ba45fe367b9","792de5c062444bd2ee0413fb766e57e03cce7cdaebbfc52fc0c7c8e95069c96b","a79e3e81094c7a04a885bad9b049c519aace53300fb8a0fe4f26727cb5a746ce","93181bac0d90db185bb730c95214f6118ae997fe836a98a49664147fbcaf1988","8a4e89564d8ea66ad87ee3762e07540f9f0656a62043c910d819b4746fc429c5","b9011d99942889a0f95e120d06b698c628b0b6fdc3e6b7ecb459b97ed7d5bcc6","4d639cbbcc2f8f9ce6d55d5d503830d6c2556251df332dc5255d75af53c8a0e7","cdb48277f600ab5f429ecf1c5ea046683bc6b9f73f3deab9a100adac4b34969c","75be84956a29040a1afbe864c0a7a369dfdb739380072484eff153905ef867ee","b06b4adc2ae03331a92abd1b19af8eb91ec2bf8541747ee355887a167d53145e","c54166a85bd60f86d1ebb90ce0117c0ecb850b8a33b366691629fdf26f1bbbd8","0d417c15c5c635384d5f1819cc253a540fe786cc3fda32f6a2ae266671506a21","80f23f1d60fbed356f726b3b26f9d348dddbb34027926d10d59fad961e70a730","cb59317243a11379a101eb2f27b9df1022674c3df1df0727360a0a3f963f523b","cc20bb2227dd5de0aab0c8d697d1572f8000550e62c7bf5c92f212f657dd88c5","06b8a7d46195b6b3980e523ef59746702fd210b71681a83a5cf73799623621f9","860e4405959f646c101b8005a191298b2381af8f33716dc5f42097e4620608f8","f7e32adf714b8f25d3c1783473abec3f2e82d5724538d8dcf6f51baaaff1ca7a","d0da80c845999a16c24d0783033fb5366ada98df17867c98ad433ede05cd87fd","bfbf80f9cd4558af2d7b2006065340aaaced15947d590045253ded50aabb9bc5","fd9a991b51870325e46ebb0e6e18722d313f60cd8e596e645ec5ac15b96dbf4e","c3bd2b94e4298f81743d92945b80e9b56c1cdfb2bef43c149b7106a2491b1fc9","a246cce57f558f9ebaffd55c1e5673da44ea603b4da3b2b47eb88915d30a9181","d993eacc103c5a065227153c9aae8acea3a4322fe1a169ee7c70b77015bf0bb2","fc2b03d0c042aa1627406e753a26a1eaad01b3c496510a78016822ef8d456bb6","063c7ebbe756f0155a8b453f410ca6b76ffa1bbc1048735bcaf9c7c81a1ce35f","314e402cd481370d08f63051ae8b8c8e6370db5ee3b8820eeeaaf8d722a6dac6","9669075ac38ce36b638b290ba468233980d9f38bdc62f0519213b2fd3e2552ec","4d123de012c24e2f373925100be73d50517ac490f9ed3578ac82d0168bfbd303","656c9af789629aa36b39092bee3757034009620439d9a39912f587538033ce28","3ac3f4bdb8c0905d4c3035d6f7fb20118c21e8a17bee46d3735195b0c2a9f39f","1f453e6798ed29c86f703e9b41662640d4f2e61337007f27ac1c616f20093f69","af43b7871ff21c62bf1a54ec5c488e31a8d3408d5b51ff2e9f8581b6c55f2fc7","70550511d25cbb0b6a64dcac7fffc3c1397fd4cbeb6b23ccc7f9b794ab8a6954","af0fbf08386603a62f2a78c42d998c90353b1f1d22e05a384545f7accf881e0a","cefc20054d20b85b534206dbcedd509bb74f87f3d8bc45c58c7be3a76caa45e1","ad6eee4877d0f7e5244d34bc5026fd6e9cf8e66c5c79416b73f9f6ebf132f924","4888fd2bcfee9a0ce89d0df860d233e0cee8ee9c479b6bd5a5d5f9aae98342fe","f4749c102ced952aa6f40f0b579865429c4869f6d83df91000e98005476bee87","56654d2c5923598384e71cb808fac2818ca3f07dd23bb018988a39d5e64f268b","8b6719d3b9e65863da5390cb26994602c10a315aa16e7d70778a63fee6c4c079","05f56cd4b929977d18df8f3d08a4c929a2592ef5af083e79974b20a063f30940","547d3c406a21b30e2b78629ecc0b2ddaf652d9e0bdb2d59ceebce5612906df33","b3a4f9385279443c3a5568ec914a9492b59a723386161fd5ef0619d9f8982f97","3fe66aba4fbe0c3ba196a4f9ed2a776fe99dc4d1567a558fb11693e9fcc4e6ed","140eef237c7db06fc5adcb5df434ee21e81ee3a6fd57e1a75b8b3750aa2df2d8","0944ec553e4744efae790c68807a461720cff9f3977d4911ac0d918a17c9dd99","cb46b38d5e791acaa243bf342b8b5f8491639847463ac965b93896d4fb0af0d9","7c7d9e116fe51100ff766703e6b5e4424f51ad8977fe474ddd8d0959aa6de257","af70a2567e586be0083df3938b6a6792e6821363d8ef559ad8d721a33a5bcdaf","006cff3a8bcb92d77953f49a94cd7d5272fef4ab488b9052ef82b6a1260d870b","7d44bfdc8ee5e9af70738ff652c622ae3ad81815e63ab49bdc593d34cb3a68e5","339814517abd4dbc7b5f013dfd3b5e37ef0ea914a8bbe65413ecffd668792bc6","34d5bc0a6958967ec237c99f980155b5145b76e6eb927c9ffc57d8680326b5d8","9eae79b70c9d8288032cbe1b21d0941f6bd4f315e14786b2c1d10bccc634e897","18ce015ed308ea469b13b17f99ce53bbb97975855b2a09b86c052eefa4aa013a","5a931bc4106194e474be141e0bc1046629510dc95b9a0e4b02a3783847222965","5e5f371bf23d5ced2212a5ff56675aefbd0c9b3f4d4fdda1b6123ac6e28f058c","907c17ad5a05eecb29b42b36cc8fec6437be27cc4986bb3a218e4f74f606911c","ce60a562cd2a92f37a88f2ddd99a3abfbc5848d7baf38c48fb8d3243701fcb75","a726ad2d0a98bfffbe8bc1cd2d90b6d831638c0adc750ce73103a471eb9a891c","f44c0c8ce58d3dacac016607a1a90e5342d830ea84c48d2e571408087ae55894","75a315a098e630e734d9bc932d9841b64b30f7a349a20cf4717bf93044eff113","9131d95e32b3d4611d4046a613e022637348f6cebfe68230d4e81b691e4761a1","b03aa292cfdcd4edc3af00a7dbd71136dd067ec70a7536b655b82f4dd444e857","b6e2b0448ced813b8c207810d96551a26e7d7bb73255eea4b9701698f78846d6","8ae10cd85c1bd94d2f2d17c4cbd25c068a4b2471c70c2d96434239f97040747a","9ed5b799c50467b0c9f81ddf544b6bcda3e34d92076d6cab183c84511e45c39f","b4fa87cc1833839e51c49f20de71230e259c15b2c9c3e89e4814acc1d1ef10de","e90ac9e4ac0326faa1bc39f37af38ace0f9d4a655cd6d147713c653139cf4928","ea27110249d12e072956473a86fd1965df8e1be985f3b686b4e277afefdde584","8776a368617ce51129b74db7d55c3373dadcce5d0701e61d106e99998922a239","5666075052877fe2fdddd5b16de03168076cf0f03fbca5c1d4a3b8f43cba570c","9108ab5af05418f599ab48186193b1b07034c79a4a212a7f73535903ba4ca249","bb4e2cdcadf9c9e6ee2820af23cee6582d47c9c9c13b0dca1baaffe01fbbcb5f","6e30d0b5a1441d831d19fe02300ab3d83726abd5141cbcc0e2993fa0efd33db4","423f28126b2fc8d8d6fa558035309000a1297ed24473c595b7dec52e5c7ebae5","fb30734f82083d4790775dae393cd004924ebcbfde49849d9430bf0f0229dd16","2c92b04a7a4a1cd9501e1be338bf435738964130fb2ad5bd6c339ee41224ac4c","c5c5f0157b41833180419dacfbd2bcce78fb1a51c136bd4bcba5249864d8b9b5","02ae43d5bae42efcd5a00d3923e764895ce056bca005a9f4e623aa6b4797c8af","db6e01f17012a9d7b610ae764f94a1af850f5d98c9c826ad61747dca0fb800bd","8a44b424edee7bb17dc35a558cc15f92555f14a0441205613e0e50452ab3a602","24a00d0f98b799e6f628373249ece352b328089c3383b5606214357e9107e7d5","33637e3bc64edd2075d4071c55d60b32bdb0d243652977c66c964021b6fc8066","0f0ad9f14dedfdca37260931fac1edf0f6b951c629e84027255512f06a6ebc4c","16ad86c48bf950f5a480dc812b64225ca4a071827d3d18ffc5ec1ae176399e36","8cbf55a11ff59fd2b8e39a4aa08e25c5ddce46e3af0ed71fb51610607a13c505","d5bc4544938741f5daf8f3a339bfbf0d880da9e89e79f44a6383aaf056fe0159","97f9169882d393e6f303f570168ca86b5fe9aab556e9a43672dae7e6bb8e6495","7c9adb3fcd7851497818120b7e151465406e711d6a596a71b807f3a17853cb58","6752d402f9282dd6f6317c8c048aaaac27295739a166eed27e00391b358fed9a","9fd7466b77020847dbc9d2165829796bf7ea00895b2520ff3752ffdcff53564b","fbfc12d54a4488c2eb166ed63bab0fb34413e97069af273210cf39da5280c8d6","85a84240002b7cf577cec637167f0383409d086e3c4443852ca248fc6e16711e","84794e3abd045880e0fadcf062b648faf982aa80cfc56d28d80120e298178626","053d8b827286a16a669a36ffc8ccc8acdf8cc154c096610aa12348b8c493c7b8","3cce4ce031710970fe12d4f7834375f5fd455aa129af4c11eb787935923ff551","8f62cbd3afbd6a07bb8c934294b6bfbe437021b89e53a4da7de2648ecfc7af25","62c3621d34fb2567c17a2c4b89914ebefbfbd1b1b875b070391a7d4f722e55dc","c05ac811542e0b59cb9c2e8f60e983461f0b0e39cea93e320fad447ff8e474f3","8e7a5b8f867b99cc8763c0b024068fb58e09f7da2c4810c12833e1ca6eb11c4f","132351cbd8437a463757d3510258d0fa98fd3ebef336f56d6f359cf3e177a3ce","df877050b04c29b9f8409aa10278d586825f511f0841d1ec41b6554f8362092b","33d1888c3c27d3180b7fd20bac84e97ecad94b49830d5dd306f9e770213027d1","ee942c58036a0de88505ffd7c129f86125b783888288c2389330168677d6347f","a3f317d500c30ea56d41501632cdcc376dae6d24770563a5e59c039e1c2a08ec","eb21ddc3a8136a12e69176531197def71dc28ffaf357b74d4bf83407bd845991","0c1651a159995dfa784c57b4ea9944f16bdf8d924ed2d8b3db5c25d25749a343","aaa13958e03409d72e179b5d7f6ec5c6cc666b7be14773ae7b6b5ee4921e52db","0a86e049843ad02977a94bb9cdfec287a6c5a0a4b6b5391a6648b1a122072c5a","40f06693e2e3e58526b713c937895c02e113552dc8ba81ecd49cdd9596567ddb","4ed5e1992aedb174fb8f5aa8796aa6d4dcb8bd819b4af1b162a222b680a37fa0","d7f4bd46a8b97232ea6f8c28012b8d2b995e55e729d11405f159d3e00c51420a","d604d413aff031f4bfbdae1560e54ebf503d374464d76d50a2c6ded4df525712","e4f4f9cf1e3ac9fd91ada072e4d428ecbf0aa6dc57138fb797b8a0ca3a1d521c","12bfd290936824373edda13f48a4094adee93239b9a73432db603127881a300d","340ceb3ea308f8e98264988a663640e567c553b8d6dc7d5e43a8f3b64f780374","c5a769564e530fba3ec696d0a5cff1709b9095a0bdf5b0826d940d2fc9786413","7124ef724c3fc833a17896f2d994c368230a8d4b235baed39aa8037db31de54f","5de1c0759a76e7710f76899dcae601386424eab11fb2efaf190f2b0f09c3d3d3","9c5ee8f7e581f045b6be979f062a61bf076d362bf89c7f966b993a23424e8b0d","1a11df987948a86aa1ec4867907c59bdf431f13ed2270444bf47f788a5c7f92d","8018dd2e95e7ce6e613ddd81672a54532614dc745520a2f9e3860ff7fb1be0ca","b756781cd40d465da57d1fc6a442c34ae61fe8c802d752aace24f6a43fedacee","0fe76167c87289ea094e01616dcbab795c11b56bad23e1ef8aba9aa37e93432a","3a45029dba46b1f091e8dc4d784e7be970e209cd7d4ff02bd15270a98a9ba24b","032c1581f921f8874cf42966f27fd04afcabbb7878fa708a8251cac5415a2a06","69c68ed9652842ce4b8e495d63d2cd425862104c9fb7661f72e7aa8a9ef836f8","0e704ee6e9fd8b6a5a7167886f4d8915f4bc22ed79f19cb7b32bd28458f50643","06f62a14599a68bcde148d1efd60c2e52e8fa540cc7dcfa4477af132bb3de271","904a96f84b1bcee9a7f0f258d17f8692e6652a0390566515fe6741a5c6db8c1c","11f19ce32d21222419cecab448fa335017ebebf4f9e5457c4fa9df42fa2dcca7","2e8ee2cbb5e9159764e2189cf5547aebd0e6b0d9a64d479397bb051cd1991744","1b0471d75f5adb7f545c1a97c02a0f825851b95fe6e069ac6ecaa461b8bb321d","1d157c31a02b1e5cca9bc495b3d8d39f4b42b409da79f863fb953fbe3c7d4884","07baaceaec03d88a4b78cb0651b25f1ae0322ac1aa0b555ae3749a79a41cba86","619a132f634b4ebe5b4b4179ea5870f62f2cb09916a25957bff17b408de8b56d","f60fa446a397eb1aead9c4e568faf2df8068b4d0306ebc075fb4be16ed26b741","f3cb784be4d9e91f966a0b5052a098d9b53b0af0d341f690585b0cc05c6ca412","350f63439f8fe2e06c97368ddc7fb6d6c676d54f59520966f7dbbe6a4586014e","eba613b9b357ac8c50a925fa31dc7e65ff3b95a07efbaa684b624f143d8d34ba","45b74185005ed45bec3f07cac6e4d68eaf02ead9ff5a66721679fb28020e5e7c","0f6199602df09bdb12b95b5434f5d7474b1490d2cd8cc036364ab3ba6fd24263","c8ca7fd9ec7a3ec82185bfc8213e4a7f63ae748fd6fced931741d23ef4ea3c0f","5c6a8a3c2a8d059f0592d4eab59b062210a1c871117968b10797dee36d991ef7","ad77fd25ece8e09247040826a777dc181f974d28257c9cd5acb4921b51967bd8","795a08ae4e193f345073b49f68826ab6a9b280400b440906e4ec5c237ae777e6","8153df63cf65122809db17128e5918f59d6bb43a371b5218f4430c4585f64085","a8150bc382dd12ce58e00764d2366e1d59a590288ee3123af8a4a2cb4ef7f9df","5adfaf2f9f33957264ad199a186456a4676b2724ed700fc313ff945d03372169","d5c41a741cd408c34cb91f84468f70e9bda3dfeabf33251a61039b3cdb8b22d8","a20c3e0fe86a1d8fc500a0e9afec9a872ad3ab5b746ceb3dd7118c6d2bff4328","cbaf4a4aa8a8c02aa681c5870d5c69127974de29b7e01df570edec391a417959","c7135e329a18b0e712378d5c7bc2faec6f5ab0e955ea0002250f9e232af8b3e4","340a45cd77b41d8a6deda248167fa23d3dc67ec798d411bd282f7b3d555b1695","fae330f86bc10db6841b310f32367aaa6f553036a3afc426e0389ddc5566cd74","2bee1efe53481e93bb8b31736caba17353e7bb6fc04520bd312f4e344afd92f9","357b67529139e293a0814cb5b980c3487717c6fbf7c30934d67bc42dad316871","99d99a765426accf8133737843fb024a154dc6545fc0ffbba968a7c0b848959d","c782c5fd5fa5491c827ecade05c3af3351201dd1c7e77e06711c8029b7a9ee4d","883d2104e448bb351c49dd9689a7e8117b480b614b2622732655cef03021bf6d","d9b00ee2eca9b149663fdba1c1956331841ae296ee03eaaff6c5becbc0ff1ea8","09a7e04beb0547c43270b327c067c85a4e2154372417390731dfe092c4350998","eee530aaa93e9ec362e3941ee8355e2d073c7b21d88c2af4713e3d701dab8fef","28d47319b97dbeee9130b78eae03b2061d46dedbf92b0d9de13ed7ab8399ccd0","6559a36671052ca93cab9a289279a6cef6f9d1a72c34c34546a8848274a9c66c","7a0e4cd92545ad03910fd019ae9838718643bd4dde39881c745f236914901dfa","c99ebd20316217e349004ee1a0bc74d32d041fb6864093f10f31984c737b8cad","6f622e7f054f5ab86258362ac0a64a2d6a27f1e88732d6f5f052f422e08a70e7","d62d2ef93ceeb41cf9dfab25989a1e5f9ca5160741aac7f1453c69a6c14c69be","1491e80d72873fc586605283f2d9056ee59b166333a769e64378240df130d1c9","c32c073d389cfaa3b3e562423e16c2e6d26b8edebbb7d73ccffff4aa66f2171d","eca72bf229eecadb63e758613c62fab13815879053539a22477d83a48a21cd73","633db46fd1765736409a4767bfc670861468dde60dbb9a501fba4c1b72f8644d","f379412f2c0dddd193ff66dcdd9d9cc169162e441d86804c98c84423f993aa8a","f2ee748883723aa9325e5d7f30fce424f6a786706e1b91a5a55237c78ee89c4a","eda4760e5d7b171132265e970b67c322bcfffacb84248f44def26ed160eb722e","142f5190d730259339be1433931c0eb31ae7c7806f4e325f8a470bd9221b6533","cbd19f594f0ee7beffeb37dc0367af3908815acf4ce46d86b0515478718cfed8","3cdb96f128133efd129c798ac11f959e59d278ae439f69983224774d79ed11db","8776e64e6165838ac152fa949456732755b0976d1867ae5534ce248f0ccd7f41","896bbc7402b3a403cda96813c8ea595470ff76d31f32869d053317c00ca2589a","5c4c5b49bbb01828402bb04af1d71673b18852c11b7e95bfd5cf4c3d80d352c8","7030df3d920343df00324df59dc93a959a33e0f4940af3fefef8c07b7ee329bf","a96bc00e0c356e29e620eaec24a56d6dd7f4e304feefcc99066a1141c6fe05a7","d12cc0e5b09943c4cd0848f787eb9d07bf78b60798e4588c50582db9d4decc70","7333ee6354964fd396297958e52e5bf62179aa2c88ca0a35c6d3a668293b7e0e","19c3760af3cbc9da99d5b7763b9e33aaf8d018bc2ed843287b7ff4343adf4634","9d1e38aeb76084848d2fcd39b458ec88246de028c0f3f448b304b15d764b23d2","d406da1eccf18cec56fd29730c24af69758fe3ff49c4f94335e797119cbc0554","4898c93890a136da9156c75acd1a80a941a961b3032a0cf14e1fa09a764448b7","f5d7a845e3e1c6c27351ea5f358073d0b0681537a2da6201fab254aa434121d3","3a47d4582ef0697cccf1f3d03b620002f03fb0ff098f630e284433c417d6c61b","d7c30f0abfe9e197e376b016086cf66b2ffb84015139963f37301ed0da9d3d0d","ff75bba0148f07775bcb54bf4823421ed4ebdb751b3bf79cc003bd22e49d7d73","d40d20ac633703a7333770bfd60360126fc3302d5392d237bbb76e8c529a4f95","35a9867207c488061fb4f6fe4715802fbc164b4400018d2fa0149ad02db9a61c","b5fd805b7c578ca6a42c42bbfa6fda95a85d9e332106d810bb18116dc13a45f8","3abd9ab4fb3a035c865e6a68cb9f4260515354d5ebebacd5c681aee52c046d1f","13e82862532619a727cff9a9ba78df7ca66e8a9b69e4cbd18e9809257b6bf7ba","601fe4e366b99181cd0244d96418cffeaaa987a7e310c6f0ed0f06ce63dfe3e9","c66a4f2b1362abc4aeee0870c697691618b423c8c6e75624a40ef14a06f787b7","8808b1c4f84f2e43da98757a959fe7282cb1795737e16534a97b7d4d33e84dfc","cd0565ace87a2d7802bf4c20ea23a997c54e598b9eb89f9c75e69478c1f7a0b4","738020d2c8fc9df92d5dee4b682d35a776eaedfe2166d12bc8f186e1ea57cc52","86dd7c5657a0b0bc6bee8002edcfd544458d3d3c60974555746eb9b2583dc35e","d97b96b6ecd4ee03f9f1170722c825ef778430a6a0d7aab03b8929012bf773cd","e84e9b89251a57da26a339e75f4014f52e8ef59b77c2ee1e0171cde18d17b3b8","272dbfe04cfa965d6fff63fdaba415c1b5a515b1881ae265148f8a84ddeb318f","2035fb009b5fafa9a4f4e3b3fdb06d9225b89f2cbbf17a5b62413bf72cea721a","eefafec7c059f07b885b79b327d381c9a560e82b439793de597441a4e68d774a","72636f59b635c378dc9ea5246b9b3517b1214e340e468e54cb80126353053b2e","ebb79f267a3bf2de5f8edc1995c5d31777b539935fab8b7d863e8efb06c8e9ea","ada033e6a4c7f4e147e6d76bb881069dc66750619f8cc2472d65beeec1100145","0c04cc14a807a5dc0e3752d18a3b2655a135fefbf76ddcdabd0c5df037530d41","605d29d619180fbec287d1701e8b1f51f2d16747ec308d20aba3e9a0dac43a0f","67c19848b442d77c767414084fc571ce118b08301c4ddff904889d318f3a3363","c704ff0e0cb86d1b791767a88af21dadfee259180720a14c12baee668d0eb8fb","195c50e15d5b3ea034e01fbdca6f8ad4b35ad47463805bb0360bdffd6fce3009","da665f00b6877ae4adb39cd548257f487a76e3d99e006a702a4f38b4b39431cb","083aebdd7c96aee90b71ec970f81c48984d9c8ab863e7d30084f048ddcc9d6af","1c3bde1951add95d54a05e6628a814f2f43bf9d49902729eaf718dc9eb9f4e02","d7a4309673b06223537bc9544b1a5fe9425628e1c8ab5605f3c5ebc27ecb8074","0be3da88f06100e2291681bbda2592816dd804004f0972296b20725138ebcddf","3eadfd083d40777b403f4f4eecfa40f93876f2a01779157cc114b2565a7afb51","cb6789ce3eba018d5a7996ccbf50e27541d850e9b4ee97fdcb3cbd8c5093691f","a3684ea9719122f9477902acd08cd363a6f3cff6d493df89d4dc12fa58204e27","ff3c48a17bf10dfbb62448152042e4a48a56c9972059997ab9e7ed03b191809b","bc3561e460de5a2c19123f618fc1d5a96a484d168884d00666997d847f502bf9","c0c46113b4cd5ec9e7cf56e6dbfb3930ef6cbba914c0883eeced396988ae8320","118ea3f4e7b9c12e92551be0766706f57a411b4f18a1b4762cfde3cd6d4f0a96","01acd7f315e2493395292d9a02841f3b0300e77ccf42f84f4f11460e7623107d","656d1ce5b8fbed896bb803d849d6157242261030967b821d01e72264774cab55","da66c1b41d833858fe61947432130d39649f0b53d992dfd7d00f0bbe57191ef4","835739c6dcf0a9a1533d1e95b7d7cf8e44ca1341652856b897f4573078b23a31","774a3bcc0700036313c57a079e2e1161a506836d736203aa0463efa7b11a7e54","96577e3f8e0f9ea07ddf748d72dc1908581ef2aafd4ae7418a4574c26027cf02","f55971cb3ede99c17443b03788fe27b259dcd0f890ac31badcb74e3ffb4bb371","0ef0c246f8f255a5d798727c40d6d2231d2b0ebda5b1ec75e80eadb02022c548","ea127752a5ec75f2ac6ef7f1440634e6ae5bc8d09e6f98b61a8fb600def6a861","862320e775649dcca8915f8886865e9c6d8affc1e70ed4b97199f3b70a843b47","561764374e9f37cb895263d5c8380885972d75d09d0db64c12e0cb10ba90ae3e","ee889da857c29fa7375ad500926748ef2e029a6645d7c080e57769923d15dfef","56984ba2d781bd742b6bc0fa34c10df2eae59b42ec8b1b731d297f1590fa4071","7521de5e64e2dd022be87fce69d956a52d4425286fbc5697ecfec386da896d7e","f50b072ec1f4839b54fd1269a4fa7b03efbc9c59940224c7939632c0f70a39c3","a5b7ec6f1ff3f1d19a2547f7e1a50ab1284e6b4755d260a481ea01ed2c7cec60","1747f9eebf5beb8cfc46cf0303e300950b7bff20cff60b9c46818caced3226e3","9d969f36abb62139a90345ee5d03f1c2479831bd84c8f843d87ec304cad96ead","e972b52218fd5919aec6cd0e5e2a5fb75f5d2234cf05597a9441837a382b2b29","d1e292b0837d0ef5ede4f52363c9d8e93f5d5234086adc796e11eae390305b36","0a9e10028a96865d0f25aeca9e3b1ff0691b9b662aa186d9d490728434cf8261","1aed740b674839c89f427f48737bad435ee5a39d80b5929f9dc9cc9ac10a7700","6e9e3690dc3a6e99a845482e33ee78915893f2d0d579a55b6a0e9b4c44193371","4e7a76cce3b537b6cdb1c4b97e29cb4048ee8e7d829cf3a85f4527e92eb573f2","7e7e30f804f94b72d23a606f1d281de404a510984085fea8cbbefc7bdcaf1a37","46f1fe93f199a419172d7480407d9572064b54712b69406efa97e0244008b24e","044e6aaa3f612833fb80e323c65e9d816c3148b397e93630663cda5c2d8f4de1","deaf8eb392c46ea2c88553d3cc38d46cfd5ee498238dbc466e3f5be63ae0f651","6a79b61f57699de0a381c8a13f4c4bcd120556bfab0b4576994b6917cb62948b","c5133d7bdec65f465df12f0b507fbc0d96c78bfa5a012b0eb322cf1ff654e733","7905c052681cbe9286797ec036942618e1e8d698dcc2e60f4fb7a0013d470442","89049878a456b5e0870bb50289ea8ece28a2abd0255301a261fa8ab6a3e9a07d","d0da4f4fd66f37c13deabc1a641edd629141c333ccf862733788bd27e89436ac","d4a4f10062a6d82ba60d3ffde9154ef24b1baf2ce28c6439f5bdfb97aa0d18fc","f13310c360ecffddb3858dcb33a7619665369d465f55e7386c31d45dfc3847bf","e7bde95a05a0564ee1450bc9a53797b0ac7944bf24d87d6f645baca3aa60df48","62e68ce120914431a7d34232d3eca643a7ddd67584387936a5202ae1c4dd9a1b","91d695bba902cc2eda7edc076cd17c5c9340f7bb254597deb6679e343effadbb","e1cb8168c7e0bd4857a66558fe7fe6c66d08432a0a943c51bacdac83773d5745","a464510505f31a356e9833963d89ce39f37a098715fc2863e533255af4410525","0612b149cabbc136cb25de9daf062659f306b67793edc5e39755c51c724e2949","2579b150b86b5f644d86a6d58f17e3b801772c78866c34d41f86f3fc9eb523fe","e4b3a3e1b21a194b29d35488ec880948fc2ef8e937288463ea2981ad62a7b106","0353e05b0d8475c10ddd88056e0483b191aa5cdea00a25e0505b96e023f1a2d9","6a312caabb43c284a4b0da60d5c24f285338096eb9e977af1faca38d32a34685","b6eda93163beb978dd0d3042b11c60373506400c94613c0b40d1c0a9a9f1020e","a8af4739274959d70f7da4bfdd64f71cfc08d825c2d5d3561bc7baed760b33ef","99193bafaa9ce112889698de25c4b8c80b1209bb7402189aea1c7ada708a8a54","70473538c6eb9494d53bf1539fe69df68d87c348743d8f7244dcb02ca3619484","c48932ab06a4e7531bdca7b0f739ace5fa273f9a1b9009bcd26902f8c0b851f0","df6c83e574308f6540c19e3409370482a7d8f448d56c65790b4ac0ab6f6fedd8","ebbe6765a836bfa7f03181bc433c8984ca29626270ca1e240c009851222cb8a7","20f630766b73752f9d74aab6f4367dba9664e8122ea2edcb00168e4f8b667627","468df9d24a6e2bc6b4351417e3b5b4c2ca08264d6d5045fe18eb42e7996e58b4","954523d1f4856180cbf79b35bd754e14d3b2aea06c7efd71b254c745976086e9","31a030f1225ab463dd0189a11706f0eb413429510a7490192a170114b2af8697","6f48f244cd4b5b7e9a0326c74f480b179432397580504726de7c3c65d6304b36","5520e6defac8e6cdced6dd28808fafe795cb2cd87407bb1012e13a2b061f50b7","c3451661fb058f4e15971bbed29061dd960d02d9f8db1038e08b90d294a05c68","1f21aefa51f03629582568f97c20ef138febe32391012828e2a0149c2c393f62","b18141cda681d82b2693aef045107a910b90a7409ecff0830e1283f0bb2a53e6","18eb53924f27af2a5e9734dce28cf5985df7b2828dade1239241e95b639e9bf1","a9f1c52f4e7c2a2c4988b5638bd3dbfe38e408b358d02dd2fb8c8920e877f088","a7e10a8ad6536dd0225029e46108b18cee0d3c15c2f6e49bd62798ad85bc57b6","8db1ed144dd2304b9bd6e41211e22bad5f4ab1d8006e6ac127b29599f4b36083","843a5e3737f2abbbbd43bf2014b70f1c69a80530814a27ae1f8be213ae9ec222","6fc1be224ad6b3f3ec11535820def2d21636a47205c2c9de32238ba1ac8d82e6","5a44788293f9165116c9c183be66cefef0dc5d718782a04847de53bf664f3cc1","afd653ae63ce07075b018ba5ce8f4e977b6055c81cc65998410b904b94003c0a","9172155acfeb17b9d75f65b84f36cb3eb0ff3cd763db3f0d1ad5f6d10d55662f","71807b208e5f15feffb3ff530bec5b46b1217af0d8cc96dde00d549353bcb864","1a6eca5c2bc446481046c01a54553c3ffb856f81607a074f9f0256c59dd0ab13","dff93e0997c4e64ff29e9f70cad172c0b438c4f58c119f17a51c94d48164475a","fd1ddf926b323dfa439be49c1d41bbe233fe5656975a11183aeb3bf2addfa3bb","6dda11db28da6bcc7ff09242cd1866bdddd0ae91e2db3bea03ba66112399641a","ea4cd1e72af1aa49cf208b9cb4caf542437beb7a7a5b522f50a5f1b7480362ed","903a7d68a222d94da11a5a89449fdd5dd75d83cd95af34c0242e10b85ec33a93","e7fe2e7ed5c3a7beff60361632be19a8943e53466b7dd69c34f89faf473206d7","b4896cee83379e159f83021e262223354db79e439092e485611163e2082224ff","5243e79a643e41d9653011d6c66e95048fc0478eb8593dc079b70877a2e3990e",{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true},"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a",{"version":"1456e80bd8a3870034d89f91bd7df12ac29acfb083e31c0bb1fb38ca7bf5fbc2","affectsGlobalScope":true},{"version":"a98aedd64ad81793f146d36d1611ed9ba61b8b49ff040f0d13a103ed626595d9","affectsGlobalScope":true},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true},"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107",{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true},"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f",{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true},"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c",{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true},"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a",{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true},"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45",{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true},"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","641942a78f9063caa5d6b777c99304b7d1dc7328076038c6d94d8a0b81fc95c1","092c1137e31de289f3cc6a57fdccb3cca298d8a680d1e367d206d3318f1394a1","855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86",{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true},"7e20d899c28ca26a2a7afc98beaa69e63ff7fba0a8bc47b4e3bf3ede5e09e424","2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d",{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true},{"version":"372413016d17d804e1d139418aca0c68e47a83fb6669490857f4b318de8cccb3","affectsGlobalScope":true},"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","085f552d005479e2e6a7311cdbbe5d8c55c497b4d19274285df161ee9684cd9c","37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee",{"version":"007faacc9268357caa21d24169f3f3f2497af3e9241308df2d89f6e6d9bb3f2e","affectsGlobalScope":true},"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5",{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true},"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","809821b8a065e3234a55b3a9d7846231ed18d66dd749f2494c66288d890daf7f","ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9",{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true},"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e",{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true},"b7c5e2ea4a9749097c347454805e933844ed207b6eefec6b7cfd418b5f5f7b28","0ea329e5eab6719ff83bcb97e8bd03f1faab4feb74704010783b881fc9d80f92","76e7352249c42b9d54fe1f9e1ebcef777da1cb2eb33038366af49469d433597b","88cb622dd0ec1ef860e5c27fa884e60d2eba5ae22c7907dff82c56a69bdd2c8a","eb234b3e285e8bc071bdddc1ec0460095e13ead6222d44b02c4e0869522f9ba3","c85114872760189e50fef131944427b0fb367f0cc0b6dce164bb427a6fd89381","5ad69b0d7e7bdbcd3adfdb6a3e306e935c9c2711b1c60493646504a2f991346e","a12a667efdeb03b529bd4ebb4032998ddd32743799f59f9f18b186f8e63a2cf1","cee7efa0ae4c58deab218d1df0d1bf84abfd5c356cff28bca1421489cba13a19","f9e034b1ae29825c00532e08ea852b0c72885c343ee48d2975db0a6481218ab3","1193f49cbb883f40326461fe379e58ffa4c18d15bf6d6a1974ad2894e4fb20f3","8f1241f5d9f0d3d72117768b3c974e462840fbd85026fb66685078945404cf2f","21247c958d397091ec30e63b27294baa1d1434c333da4fda697743190311dc62","23908e1f3b7e26e7e0ef57dc838d4cfb58f2daf203fe7bc7bc256fc556224101","d5eb5865d4cbaa9985cc3cfb920b230cdcf3363f1e70903a08dc4baab80b0ce1","51ebca098538b252953b1ef83c165f25b52271bfb6049cd09d197dddd4cd43c5",{"version":"092fb7b72bf76e2bd33dbe21228a3613df5c21383dfe961629672135c86c9508","signature":"cabda2f925aec2bd2f4c3a5f99baf94cf5f958408a710a35468e828b883b699a"},{"version":"9223a0889abb0669020e94a9b8c1e68274cdc05533c1f79d84fe516450e94ebd","signature":"bbc394ad2a2ec9c5dbcd9f60d4b365bf809989c90dd3c202b20fddc20e699bdf"},"fb893a0dfc3c9fb0f9ca93d0648694dd95f33cbad2c0f2c629f842981dfd4e2e","95da3c365e3d45709ad6e0b4daa5cdaf05e9076ba3c201e8f8081dd282c02f57","7245fa556a63e4c5997642422fe4250df16a56694cc1a1f50108dc80fe3018ba","7c14e702387296711c1a829bc95052ff02f533d4aa27d53cc0186c795094a3a9","4c72d080623b3dcd8ebd41f38f7ac7804475510449d074ca9044a1cbe95517ae","579f8828da42ae02db6915a0223d23b0da07157ff484fecdbf8a96fffa0fa4df","5f6beb8c43a52e9119cf31a7583ceca88dc910d7de29caad1f81e98497f808ba","3ae3b86c48ae3b092e5d5548acbf4416b427fed498730c227180b5b1a8aa86e3","8f1241f5d9f0d3d72117768b3c974e462840fbd85026fb66685078945404cf2f","ba63131c5e91f797736444933af16ffa42f9f8c150d859ec65f568f037a416ea","44372b8b42e8916b0ab379da38dcf4de11227bad4221aba3e2dbe718999bdfab","43ebfcc5a9e9a9306ea4de9fda3abdd9e018040e246434b48ad56d93b14d4a3d","0e9aa853b5eb2ca09e0e3e3eb94cbd1d5fb3d682ab69817d4d11fe225953fc57","179683df1e78572988152d598f44297da79ac302545770710bba87563ce53e06","793c353144f16601da994fa4e62c09b7525836ce999c44f69c28929072ca206a","d34aa8df2d0b18fb56b1d772ff9b3c7aea7256cf0d692f969be6e1d27b74d660","93a3b8e57c68e348fc4054b245bd7cf4893225f56c991028844b693c2fa8c03c","2f5747b1508ccf83fad0c251ba1e5da2f5a30b78b09ffa1cfaf633045160afed",{"version":"6823ccc7b5b77bbf898d878dbcad18aa45e0fa96bdd0abd0de98d514845d9ed9","affectsGlobalScope":true},"b71c603a539078a5e3a039b20f2b0a0d1708967530cf97dec8850a9ca45baa2b","168d88e14e0d81fe170e0dadd38ae9d217476c11435ea640ddb9b7382bdb6c1f","104c67f0da1bdf0d94865419247e20eded83ce7f9911a1aa75fc675c077ca66e","cc0d0b339f31ce0ab3b7a5b714d8e578ce698f1e13d7f8c60bfb766baeb1d35c","8e04cf0688e0d921111659c2b55851957017148fa7b977b02727477d155b3c47",{"version":"ff155930718467b27e379e4a195e4607ce277f805cad9d2fa5f4fd5dec224df6","affectsGlobalScope":true},"599ac4a84b7aa6a298731179ec1663a623ff8ac324cdc1dabb9c73c1259dc854","95c2ab3597d7d38e990bf212231a6def6f6af7e3d12b3bb1b67c15fc8bfd4f4a","585bc61f439c027640754dd26e480afa202f33e51db41ee283311a59c12c62e7","8f1241f5d9f0d3d72117768b3c974e462840fbd85026fb66685078945404cf2f","6ecc423e71318bafbd230e6059e082c377170dfc7e02fccfa600586f8604d452","772f9bdd2bf50c9c01b0506001545e9b878faa7394ad6e7d90b49b179a024584","90ba1a0bd84ecbe63ee17e31afe021e24bc7f002ee66eb69579819ddd0a6d1b0","df251aa7a87b6d003a45ad1f71b87ff4448e535db473cb3c897720012b5553d2","20ccce97c422c215a41f0aa8373eb2b6f4068633ceef401c5f743cecdf8119bf","cd1ccdd9fd7980d43dfede5d42ee3d18064baed98b136089cf7c8221d562f058","d60f9a4fd1e734e7b79517f02622426ea1000deb7d6549dfdece043353691a4e","ec05ccc3a2e35ef2800a5b5ed2eb2ad4cd004955447bebd86883ddf49625b400","403d28b5e5f8fcff795ac038902033ec5890143e950af45bd91a3ed231e8b59c","c73b59f91088c00886d44ca296d53a75c263c3bda31e3b2f37ceb137382282be","e7aa2c584edb0970cb4bb01eb10344200286055f9a22bc3dadcc5a1f9199af3e","bfeb476eb0049185cb94c2bfcadb3ce1190554bbcf170d2bf7c68ed9bb00458e","ae23a65a2b664ffe979b0a2a98842e10bdf3af67a356f14bbc9d77eb3ab13585","2db00053dff66774bc4216209acf094dd70d9dfd8211e409fc4bd8d10f7f66f6","eccf6ad2a8624329653896e8dbd03f30756cbd902a81b5d3942d6cf0e1a21575","1930c964051c04b4b5475702613cd5a27fcc2d33057aa946ff52bfca990dbc84","762992adfa3fbf42c0bce86caed3dc185786855b21a20265089770485e6aa9d3","8a440978a6b5c6e6ea76a2804a90c06cadbefb96f6680785d8d3bfab8c8875d8","62463aa3d299ae0cdc5473d2ac32213a05753c3adce87a8801c6d2b114a64116","05a0d93bb8653bb3833c1c22e3fa5432c38885b2e545e99524e67e25e5ce355c","bd3e38cbf8108b661c591dcd03290d5cf2f2a8a1c74b045ba6b6bf4118b0a967","40abfc1faa2971acedb69bde8d8c4bbd4edce4af12f786e747dfb8298e6a05a1","02153ce9d452d116e9b7bfe42058c02c4cac09f49c46450820b4b44c83306a3e","f689c0633e8c95f550d36af943d775f3fae3dac81a28714b45c7af0bbb76a980","34be0f820d16a54625b86ab6d7b7928dbb819b58ddac181aa3836390c8c3df24","0495afa06118083a11cd4da27acfd96a01b989aff0fc633823c5febe9668ef15","67feb4436be89f58ba899dec57f6e703bee1bb7205ba21ab50fca237f6753787","75849f5ead7684bf85ee9cce7e84683ed4332fa187f8ee0978ba9df96c5cee06","b5325ff5c9dc488bb9c87711faf2b73f639c45f190b81df88ed056807206958b","cc4f5179acd0a8efad722a44c4621d0da29169e03d78a452a27f73e1e7f27985","a743cf98667fdbb6989d9a7629d25a9824a484ce639bbf2740dc809341e6dbce","d73a2cbf1893668c1fc0b41878a9df37bbb128cb05e292b845f68b7b88ef9957","1f64f5cd141571d53606fc5a7f8bb2b869b4cd40c964188e856bcfe5000a9037","eb89de249984a951578b5fa472d0414cd10cd7d35777aa1c7c308dfe2b0b49d6","a7af5e8b12f757ae7b9e79c95e8494cc1d6ccdb7b298c6766bb1f9dd82fa21cf","7b36f5bce24167f089e4d3601e5fde14f0a233e1a0954df5ec56ae07f36e2219","5e168f60c9132665853ccba13a29e4d311ac174c0fd3eda5cee7a6c5071802d6","1c225a18846203fafc4334658715b0d3fd3ee842c4cfd42e628a535eda17730d","7ce93da38595d1caf57452d57e0733474564c2b290459d34f6e9dcf66e2d8beb","d7b672c1c583e9e34ff6df2549d6a55d7ca3adaf72e6a05081ea9ee625dac59f","f3a2902e84ebdef6525ed6bf116387a1256ea9ae8eeb36c22f070b7c9ea4cf09","788e6ec863183b001b1e96d54f876c9d5436fa3aa19397093912dcdae466caf7","ae3e98448468e46474d817b5ebe74db11ab22c2feb60e292d96ce1a4ee963623","f5c67304429e2e2554f63526e842f47bd9ee0cb0f18becc963b93b2d3fafe9c2","8903c1df475f531bf787bc795c718e415ce9974536d8429619fdc456f5329948","7beb7f04f6186bdac5e622d44e4cac38d9f2b9fcad984b10d3762e369524dd77","07fcc9be98e12bd2f0f71a501a9bfbe2e53d38c50e8a5e84223fdd05bd8749c5","8c724ec27deda8f7ecdca0f22d9bb8c97a4507500ec645f49dea9c73184c2512",{"version":"09a01e0f6c8ebf6919fa03d2837cfe260ec47e02ee9744ff93106e06254b28d6","signature":"02dad311b324dcb76f5b1c0f9117592372a494254c94be9bc65072c0d8ab788f"},"cb5eaaa2a079305b1c5344af739b29c479746f7a7aefffc7175d23d8b7c8dbb0","bd324dccada40f2c94aaa1ebc82b11ce3927b7a2fe74a5ab92b431d495a86e6f","56749bf8b557c4c76181b2fd87e41bde2b67843303ae2eabb299623897d704d6","5a6fbec8c8e62c37e9685a91a6ef0f6ecaddb1ee90f7b2c2b71b454b40a0d9a6","e7435f2f56c50688250f3b6ef99d8f3a1443f4e3d65b4526dfb31dfd4ba532f8","51a674644ed5a181ec1497c1b4aa6f8cfcbe3af5481bdb641c1b5a498bcb6f3c","33b7f4106cf45ae7ccbb95acd551e9a5cd3c27f598d48216bda84213b8ae0c7e","176d6f604b228f727afb8e96fd6ff78c7ca38102e07acfb86a0034d8f8a2064a","1b1a02c54361b8c222392054648a2137fc5983ad5680134a653b1d9f655fe43d","8bcb884d06860a129dbffa3500d51116d9d1040bb3bf1c9762eb2f1e7fd5c85c","e55c0f31407e1e4eee10994001a4f570e1817897a707655f0bbe4d4a66920e9e","a37c2194c586faa8979f50a5c5ca165b0903d31ee62a9fe65e4494aa099712c0","6602339ddc9cd7e54261bda0e70fb356d9cdc10e3ec7feb5fa28982f8a4d9e34","7ffaa736b8a04b0b8af66092da536f71ef13a5ef0428c7711f32b94b68f7c8c8","7b4930d666bbe5d10a19fcc8f60cfa392d3ad3383b7f61e979881d2c251bc895","46342f04405a2be3fbfb5e38fe3411325769f14482b8cd48077f2d14b64abcfb","8fa675c4f44e6020328cf85fdf25419300f35d591b4f56f56e00f9d52b6fbb3b","ba98f23160cfa6b47ee8072b8f54201f21a1ee9addc2ef461ebadf559fe5c43a","45a4591b53459e21217dc9803367a651e5a1c30358a015f27de0b3e719db816b","9ef22bee37885193b9fae7f4cad9502542c12c7fe16afe61e826cdd822643d84","b0451895b894c102eed19d50bd5fcb3afd116097f77a7d83625624fafcca8939","bce17120b679ff4f1be70f5fe5c56044e07ed45f1e555db6486c6ded8e1da1c8","7590477bfa2e309e677ff7f31cb466f377fcd0e10a72950439c3203175309958","3f9ebd554335d2c4c4e7dc67af342d37dc8f2938afa64605d8a93236022cc8a5","1c077c9f6c0bc02a36207994a6e92a8fbf72d017c4567f640b52bf32984d2392","600b42323925b32902b17563654405968aa12ee39e665f83987b7759224cc317","32c8f85f6b4e145537dfe61b94ddd98b47dbdd1d37dc4b7042a8d969cd63a1aa","2426ed0e9982c3d734a6896b697adf5ae93d634b73eb15b48da8106634f6d911","057431f69d565fb44c246f9f64eac09cf309a9af7afb97e588ebef19cc33c779","960d026ca8bf27a8f7a3920ee50438b50ec913d635aa92542ca07558f9c59eca","71f5d895cc1a8a935c40c070d3d0fade53ae7e303fd76f443b8b541dee19a90c","252eb4750d0439d1674ad0dc30d2a2a3e4655e08ad9e58a7e236b21e78d1d540","e344b4a389bb2dfa98f144f3f195387a02b6bdb69deed4a96d16cc283c567778","c6cdcd12d577032b84eed1de4d2de2ae343463701a25961b202cff93989439fb","3dc633586d48fcd04a4f8acdbf7631b8e4a334632f252d5707e04b299069721e","3322858f01c0349ee7968a5ce93a1ca0c154c4692aa8f1721dc5192a9191a168","6dde0a77adad4173a49e6de4edd6ef70f5598cbebb5c80d76c111943854636ca","09acacae732e3cc67a6415026cfae979ebe900905500147a629837b790a366b3","f7b622759e094a3c2e19640e0cb233b21810d2762b3e894ef7f415334125eb22","99236ea5c4c583082975823fd19bcce6a44963c5c894e20384bc72e7eccf9b03","f6688a02946a3f7490aa9e26d76d1c97a388e42e77388cbab010b69982c86e9e","9f642953aba68babd23de41de85d4e97f0c39ef074cb8ab8aa7d55237f62aff6","159d95163a0ed369175ae7838fa21a9e9e703de5fdb0f978721293dd403d9f4a","2d2ec3235e01474f45a68f28cf826c2f5228b79f7d474d12ca3604cdcfdac80c","6dd249868034c0434e170ba6e0451d67a0c98e5a74fd57a7999174ee22a0fa7b","9716553c72caf4ff992be810e650707924ec6962f6812bd3fbdb9ac3544fd38f","506bc8f4d2d639bebb120e18d3752ddeee11321fd1070ad2ce05612753c628d6","053c51bbc32db54be396654ab5ecd03a66118d64102ac9e22e950059bc862a5e","1977f62a560f3b0fc824281fd027a97ce06c4b2d47b408f3a439c29f1e9f7e10","627570f2487bd8d899dd4f36ecb20fe0eb2f8c379eff297e24caba0c985a6c43","0f6e0b1a1deb1ab297103955c8cd3797d18f0f7f7d30048ae73ba7c9fb5a1d89","0a051f254f9a16cdde942571baab358018386830fed9bdfff42478e38ba641ce","17269f8dfc30c4846ab7d8b5d3c97ac76f50f33de96f996b9bf974d817ed025b","9e82194af3a7d314ccbc64bb94bfb62f4bfea047db3422a7f6c5caf2d06540a9","083d6f3547ccbf25dfa37b950c50bee6691ed5c42107f038cc324dbca1e173ae","952a9eab21103b79b7a6cca8ad970c3872883aa71273f540285cad360c35da40","8ba48776335db39e0329018c04486907069f3d7ee06ce8b1a6134b7d745271cc","e6d5809e52ed7ef1860d1c483e005d1f71bab36772ef0fd80d5df6db1da0e815","893e5cfbae9ed690b75b8b2118b140665e08d182ed8531e1363ec050905e6cb2","6ae7c7ada66314a0c3acfbf6f6edf379a12106d8d6a1a15bd35bd803908f2c31","e4b1e912737472765e6d2264b8721995f86a463a1225f5e2a27f783ecc013a7b","97146bbe9e6b1aab070510a45976faaf37724c747a42d08563aeae7ba0334b4f","c40d552bd2a4644b0617ec2f0f1c58618a25d098d2d4aa7c65fb446f3c305b54","09e64dea2925f3a0ef972d7c11e7fa75fec4c0824e9383db23eacf17b368532f","424ddba00938bb9ae68138f1d03c669f43556fc3e9448ed676866c864ca3f1d6","a0fe12181346c8404aab9d9a938360133b770a0c08b75a2fce967d77ca4b543f","3cc6eb7935ff45d7628b93bb6aaf1a32e8cb3b24287f9e75694b607484b377b3","ced02e78a2e10f89f4d70440d0a8de952a5946623519c54747bc84214d644bac","efd463021ccc91579ed8ae62584176baab2cd407c555c69214152480531a2072","29647c3b79320cfeecb5862e1f79220e059b26db2be52ea256df9cf9203fb401","c87c29ad2df837f7bc528688d96793758e0c4b1965f5ca520a8c287999565f66","e8cdefd2dc293cb4866ee8f04368e7001884650bb0f43357c4fe044cc2e1674f","582a3578ebba9238eb0c5d30b4d231356d3e8116fea497119920208fb48ccf85","185eae4a1e8a54e38f36cd6681cfa54c975a2fc3bc2ba6a39bf8163fac85188d","0c0a02625cf59a0c7be595ccc270904042bea523518299b754c705f76d2a6919","f2c999522aa544d93920205e05e11a5d43332f95ec35bd8a17025a823035bc56","cee72255e129896f0240ceb58c22e207b83d2cc81d8446190d1b4ef9b507ccd6","3b54670e11a8d3512f87e46645aa9c83ae93afead4a302299a192ac5458aa586","c2fc4d3a130e9dc0e40f7e7d192ef2494a39c37da88b5454c8adf143623e5979","2e693158fc1eedba3a5766e032d3620c0e9c8ad0418e4769be8a0f103fdb52cd","516275ccf3e66dc391533afd4d326c44dd750345b68bb573fc592e4e4b74545f","07c342622568693847f6cb898679402dd19740f815fd43bec996daf24a1e2b85","fa40d705f9813843d47f19321591499f14d1a18fa5e8ca9beaee5aac633c3d0d","a7a6330fb015f72d821e23004e63a3827e0c632b614ef3a310b3c81b66de61fd","89968316b7069339433bd42d53fe56df98b6990783dfe00c9513fb4bd01c2a1c","a4096686f982f6977433ee9759ecbef49da29d7e6a5d8278f0fbc7b9f70fce12","62e62a477c56cda719013606616dd856cfdc37c60448d0feb53654860d3113bb","207c107dd2bd23fa9febac2fe05c7c72cdac02c3f57003ab2e1c6794a6db0c05","55133e906c4ddabecdfcbc6a2efd4536a3ac47a8fa0a3fe6d0b918cac882e0d4","2147f8d114cf58c05106c3dccea9924d069c69508b5980ed4011d2b648af2ffe","2eb4012a758b9a7ba9121951d7c4b9f103fe2fc626f13bec3e29037bb9420dc6","fe61f001bd4bd0a374daa75a2ba6d1bb12c849060a607593a3d9a44e6b1df590","cfe8221c909ad721b3da6080570553dea2f0e729afbdbcf2c141252cf22f39b5","34e89249b6d840032b9acdec61d136877f84f2cd3e3980355b8a18f119809956","6f36ff8f8a898184277e7c6e3bf6126f91c7a8b6a841f5b5e6cb415cfc34820e","4b6378c9b1b3a2521316c96f5c777e32a1b14d05b034ccd223499e26de8a379c","07be5ae9bf5a51f3d98ffcfacf7de2fe4842a7e5016f741e9fad165bb929be93","cb1b37eda1afc730d2909a0f62cac4a256276d5e62fea36db1473981a5a65ab1","c873a6d6019f0b93889e54bf3dfb133120d5adba79c0a31d2400d1b5d0f2a2a2","471386a0a7e4eb88c260bdde4c627e634a772bf22f830c4ec1dad823154fd6f5","108314a60f3cb2454f2d889c1fb8b3826795399e5d92e87b2918f14d70c01e69","d75cc838286d6b1260f0968557cd5f28495d7341c02ac93989fb5096deddfb47","d531dc11bb3a8a577bd9ff83e12638098bfc9e0856b25852b91aac70b0887f2a","19968b998a2ab7dfd39de0c942fc738b2b610895843fec25477bc393687babd8","c0e6319f0839d76beed6e37b45ec4bb80b394d836db308ae9db4dea0fe8a9297","1a7b11be5c442dab3f4af9faf20402798fddf1d3c904f7b310f05d91423ba870","079d3f1ddcaf6c0ff28cfc7851b0ce79fcd694b3590afa6b8efa6d1656216924","2c817fa37b3d2aa72f01ce4d3f93413a7fbdecafe1b9fb7bd7baaa1bbd46eb08","682203aed293a0986cc2fccc6321d862742b48d7359118ac8f36b290d28920d2","7406d75a4761b34ce126f099eafe6643b929522e9696e5db5043f4e5c74a9e40","7e9c4e62351e3af1e5e49e88ebb1384467c9cd7a03c132a3b96842ccdc8045c4","ea1f9c60a912065c08e0876bd9500e8fa194738855effb4c7962f1bfb9b1da86","903f34c920e699dacbc483780b45d1f1edcb1ebf4b585a999ece78e403bb2db3","100ebfd0470433805c43be5ae377b7a15f56b5d7181c314c21789c4fe9789595","12533f60d36d03d3cf48d91dc0b1d585f530e4c9818a4d695f672f2901a74a86","57b555a83466fb289968a1713f965f1a2bb3a91cc34d1fa21af8ebdef7fc872a","21d9968dad7a7f021080167d874b718197a60535418e240389d0b651dd8110e7","2ef7349b243bce723d67901991d5ad0dfc534da994af61c7c172a99ff599e135","fa103f65225a4b42576ae02d17604b02330aea35b8aaf889a8423d38c18fa253","1b9173f64a1eaee88fa0c66ab4af8474e3c9741e0b0bd1d83bfca6f0574b6025","1b212f0159d984162b3e567678e377f522d7bee4d02ada1cc770549c51087170","46bd71615bdf9bfa8499b9cfce52da03507f7140c93866805d04155fa19caa1b","86cb49eb242fe19c5572f58624354ffb8743ff0f4522428ebcabc9d54a837c73","fc2fb9f11e930479d03430ee5b6588c3788695372b0ab42599f3ec7e78c0f6d5","bb1e5cf70d99c277c9f1fe7a216b527dd6bd2f26b307a8ab65d24248fb3319f5","817547eacf93922e22570ba411f23e9164544dead83e379c7ae9c1cfc700c2cf","a728478cb11ab09a46e664c0782610d7dd5c9db3f9a249f002c92918ca0308f7","9e91ef9c3e057d6d9df8bcbfbba0207e83ef9ab98aa302cf9223e81e32fdfe8d","66d30ef7f307f95b3f9c4f97e6c1a5e4c462703de03f2f81aca8a1a2f8739dbd","293ca178fd6c23ed33050052c6544c9d630f9d3b11d42c36aa86218472129243","90a4be0e17ba5824558c38c93894e7f480b3adf5edd1fe04877ab56c56111595","fadd55cddab059940934df39ce2689d37110cfe37cc6775f06b0e8decf3092d7","adb906b7794a71185220332532dcbdd09527e0dd3ce9f0b9be0a88c56bbb7e9e","b4f3b4e20e2193179481ab325b8bd0871b986e1e8a8ed2961ce020c2dba7c02d","41744c67366a0482db029a21f0df4b52cd6f1c85cbc426b981b83b378ccb6e65","c3f3cf7561dd31867635c22f3c47c8491af4cfa3758c53e822a136828fc24e5d","a88ddea30fae38aa071a43b43205312dc5ff86f9e21d85ba26b14690dc19d95e","34fc71db924616ba097a0cb6cddc2ece273a27673dd3b206abf3f3b5d63bcace","5515f17f45c6aafe6459afa3318bba040cb466a8d91617041566808a5fd77a44","4df1f0c17953b0450aa988c9930061f8861b114e1649e1a16cfd70c5cbdf8d83","441104b363d80fe57eb79a50d495e0b7e3ebeb45a5f0d1a4067d71ef75e8fbfa",{"version":"b71a8e7225095bf384e6fbdcf57e5f9b1cad422a1d9e9dcecb9d308843c25357","signature":"57a87d3b89fff6d6531d6d3b8ef31678ea92437d90a9814154109c2a5973db06"},{"version":"373a3894ce2f1dbd09d7e5ece04a0e42fadfca54bedf908425ef8c2ffa4a3879","signature":"2879182ce7af75bcbbd551e2f926fb788330658c431517210d3af3d2881ef4d1"},"03c92769f389dbd9e45232f7eb01c3e0f482b62555aaf2029dcbf380d5cee9e4","32d7f70fd3498bc76a46dab8b03af4215f445f490f8e213c80cf06b636a4e413",{"version":"f068b6120f50c6fb9b1265aa7fcf7db42fd319d70ec74e817f43bbab6b26444b","signature":"32837a26f642d81f7de08bc72a8f1051380fcfd133908976277b691913397a75"},{"version":"4de5273f338e0e949603e7edd533f03b41b367b174f28d17a3a78a4ec7e8e2eb","signature":"a28b5c0c372fb375910b3fe3c3ce4331509bc18ccef7cc39c9ee9d8daf8225d1"},{"version":"a8faa8307c428acfd5eb03ef93a424deec77bb6f1f6655a8c555974681025790","signature":"5d50cc50492ef9fc3c19dcef7c997e40ce9dfd7123a10947f80f089ac17c3a15"},{"version":"598ba440ad17f226e2368eb6b3ee89a539584ffde388d747b36fb6896d403e18","signature":"afbbfe6a2321a51816f3f9871ddf3f5e2605797f274125130f7e4132ab09d0b6"},{"version":"19ff6e335cf5a64247219c3b159f634ee882823897844d348f02572bddca48f1","signature":"aa1725e38b5a0b4009f6a74f296f173e7926c119a60454dbd2e523861735df69"},{"version":"2ba544a839882f0e14565e04e1f04d73111f247e492e3634bb76fa2b583d9dec","signature":"6ee072c0718932ef0ef326848812bd4937544b8e59db0dcb75e3418c0118fb9c"},{"version":"0b42b0fb024d75aa454e152d95c371c671e7b647ef06e7d8066f7d3e3a0a8d84","signature":"66ccb4144db13e876b8415da69ff0d273921d4a5c24a0c8fe7457ca2d30c887a"},{"version":"cfcceb0cd08e40d81b9b6fa48f3b03485c52e64c0bca7563a1e2a141f3335680","signature":"38a0f816a78633c667d3e014d78926b6fa5d4a00897bc12fc00c5eb4389956b7"},{"version":"2a586ceea6461e3fe579ace3c1198502dafa24b648db03583c23d75e331cd18e","signature":"25c9d2f8b8c40fb1c3bd6aae9540e0388898fa33d2ea7270103cbf6681a815d6"},{"version":"93809637ebccee0d3f7ff9e0a8b4ad188cde2a47e0dadba3914a0cecef6205f8","signature":"1e3678cea42f2dddfb9a074d7cdd22b90dca18ace27ca39c4aa69dc0b58d1890"},{"version":"01df56952126e6350c48e758b98a50d8ed7ae695dd943b61b9a90b83350f3cc5","signature":"68dcb9bde6d6ed99120fb14181b39f480cea6ef36fe2392e23de72b36791130f"},{"version":"876d7782df737132458e5f616eead4bc71c3edd28a7d00d87e41c4f17f55301a","signature":"69881f494ae3112f7e5834e8a8ccc1b389f026485c98a468fc0866fe8f5fa035"},{"version":"0484338c1d8d0dc5c5f7fc63c27736e428f37fb0577e99a303d9a89796ba863a","signature":"6a41e799a5ceb543784836b85ecf055465da0560792dc651552761d4cd6956b6"},{"version":"36d554dd3e0a2517fee7830b1ce325ca8e39517613c2fddeed9be385c5931cb9","signature":"b5d55e9995db6aab33e3b0f01c04c1ebda82f7f1ffa5608f280a144016c33c31"},{"version":"8a3cbba6da2a5d58d0ffd45e0f365fc9170e10ca039f811dea74906861a3e315","signature":"e778f2a70714c61fdf64503acd0f155decbc8f6dc7895a012db3c58232cb9b3e"},{"version":"d8cbf4090abe6cdb87ea5c9d35323e07f5cefbe5e5fc7b3f5c2dd77889593926","signature":"1cbe317a7040e264f98cf3426974b41cbb26cf0bf1c1b4ffee829b3e241f15f4"},{"version":"7445f9b9501b68a85eee2042e52887bd0a7a06939ea3d7ce498faf431d12fd0a","signature":"6560c1a6122e7e371e8b65746b40196af3bcf4a09b3bbaa580e4b6a5315e78c3"},{"version":"70466334b16c2ef737265e80a89260ae4bbea2ce8155b3bafc36a6cc2e455e35","signature":"0ae555344162438ea3c7a5a47759aaf2c87e4ebdd0bff378706983a49faffc78"},{"version":"abd226958e773582c529dc84cb45721771915988b090a35fb04fa3c88d820266","signature":"47b81b9f3d25558ca9417e6f4a9d8c2353134eca48f4b3e84e9bc4d03a4913a1"},{"version":"3d3b69de9cbcc3d645e788bfe98c23db340af294684f91b92f57fddb7e5d04bd","signature":"1d4ee5b576d1137d54d48732501a75c8951b2609cdbe976a9a16d9fcc1f491e3"},{"version":"9e9a8d554d919f79003cbf25df6bd970009825dbd1db97aeb539619a0ad61c21","signature":"26523ec62adebb8062362c1797ba66b96838534454ee81e85ae80bfe77432ddd"},{"version":"0f2632848ae987680abf7790165632a899f71ade8b33ebf3c46174aa799b4af8","signature":"e0a7b9d2324fac96bea82803d9597210417bbc7b9f36c88f1f81462fb49b556e"},{"version":"93a96f179e9652ae0a07632e49fcd841756222664a5286e49277837c98d744de","signature":"d76839abaa102a9663eb625b462b928a868a90d6fa1d3a407c701e219ee9679b"},{"version":"d6638152f3b1fc99b0843dbb39c8e7409544fd7c4e9fa3808e6b550ffa7e9496","signature":"5c96124b85c5f6dcae62df0f3fab27679ce2e0cef48f7fef9045b1e3f7c2afdb"},{"version":"a942a18a731786e8d9b4562555686bcf88ccd5ba0a4268a6d00c149c297d9013","signature":"4b92f3458b09b33d707640963453be311ac40991b8515e12388cc67fa5882ded"},{"version":"72597827bfa455013e3c1fdf70e15eee34c3606eab92384cc8c12d83ce77cc83","signature":"62e47d105ca68f33e01fec4c226f0b9843fdf57262c006cdc27dc64e4b72326b"},{"version":"220918aceed5898dce7128ca6d8c18d59c38bac51f39ebcf8a0dfa5252ac50c6","signature":"a3684909b502d2414d94ce06228f5d6dae72b658eac3f386843965e540b51834"},{"version":"6e20d61e8ecdcdadc4023f7bd49ad9a17de64fbb890c4ac4f8c3ced3726e98a3","signature":"43449e87f23dae0d9f076eaa078da7ede19b302890d26195c9105aa587aeb9cc"},{"version":"022618fe1dfb728b6415389067eb5ede2cd7e2d37790834ca49ef5482ee369a7","signature":"923e6dcf29fddf4fbc908027281909709de4b8d64bea7edca35f5c0cfb1198cc"},{"version":"e974a0d721dcecde2b3f2efa8d668932617753174f2ed1527492c58a663989a4","signature":"ec1d6d5ea221f6773a104813ee504e60a10be5165e4a85aa009ff2d5aa96c115"},{"version":"d10489e6a4a6ca3eb6a3c5366522e0506521984612b88d0068469b0032cbd37d","signature":"5c62020b3871f6d74f744351e1359319e643076d9f55fec145529397931a265d"},{"version":"ad2bb46abca37edc9e79b6233f00005e408bef9317647a7534e06597d803b4e3","signature":"4cb17d629e7bb0df751ae3e10d78a23d59ea51fc7c02044f9a003ba6f36fedf7"},{"version":"590278334523ef558e1256702b64ac5c5e0641d89181433e7dbf97991025056b","signature":"a52f05319575d8de12dbd39551276f0d6df4cb7c4006f7a1540489070bb9d128"},{"version":"c96d0eb50e04702732ced0d112976a71d0874f710628b2ea0450fde0eaec416d","signature":"9274f32ebf8b2d1d06af54064328c360bb634e455dc47ea60abfe791040fc87d"},{"version":"c37536154cf62004aab9a9a790bc4c2aa855932af0c175385c3010c777427318","signature":"9801247f569870b6caa91b333ee74729b61a93274393aac4e79dde6febe640c6"},{"version":"e36258c0478620ffcd623950d4217e98c973364aeff7a63c7399c714153c3189","signature":"d620c1955468af29f44824db1028985adbec47188f46e55cb1e1f98f38b504c8"},{"version":"182f86e4530584050ce2c75c65dd78f29f2d5c4c3b25cd2a9be92747f56618ec","signature":"616b6d9d8e12a694ec3c816791f1f4f8c8a60ddf1573f86347830daa82a9861d"},{"version":"502c34e73941baffb2780d775d2d6b1bc4a0ff2617a1f1362fe4a458896464cb","signature":"fbb50fdd5e733f4618d0b8398f1e4d1ea50bffd91f799566e71789a8e10efdb3"},{"version":"d863b98f05ed108b1d586a4578eee308266bbf93bed28bbb2a0608f022bbac31","signature":"e365b54c18cc969aab346f3c475608c8f2000b521d166a7d6629d9e93c9516dd"},{"version":"345a160f257cd8075b05122331802807894a214bf560e157f661aa8ee3294bca","signature":"bf39329839288baf358b181b55bb5863fae02f14da4da3392ffeb770f1e7381a"},{"version":"b25872fcb184cc3466a30b08641b0e7b04987279258442e1325419dd8966a78e","signature":"050e95cecc1cf6233f583c837a1abd6ba17fc9339e99ea2e37875fc4367eb944"},{"version":"59e9b56c3814da833c989a8d95f508956b11e8bf57b2c077c3de73df5d000feb","signature":"d20f40208930b14d6078994163422ea65fd903593e37cd84a7121bf45d0d6ac9"},{"version":"5217205a344d52eb8a5f5c322d9d732a00de7303d4c1ad48ab1568813279b333","signature":"2cba645bf39d289579afb94afbc5b3383fc13eb7f99ea86732c073fb414a3b19"},"04de5584b953b03611eeef01ba9948607def8f64f1e7fbc840752b13b4521b52","25e5c8b73c6ad21f39e8e72f954090f30b431a993252bccea5bdad4a3d93c760","5bf595f68b7c1d46ae8385e3363c6e0d4695b6da58a84c6340489fc07ffc73f8","b87682ddc9e2c3714ca66991cdd86ff7e18cae6fd010742a93bd612a07d19697","6fd2c680287dd441936fbf38e1b191e126492589b701ea01066a70c434b9ff88","86bf2bfe29d0bc3fbc68e64c25ea6eab9bcb3c518ae941012ed75b1e87d391ae","3c74d80d1dd95437cc9bbf22d88199e7410fd85af06171327125bcf4025deae8","00b4f8b82e78f658b7e269c95d07e55d391235ce34d432764687441177ae7f64","57880096566780d72e02a5b34d8577e78cdf072bfd624452a95d65bd8f07cbe0","10ac50eaf9eb62c048efe576592b14830a757f7ea7ed28ee8deafc19c9845297","e75af112e5487476f7c427945fbd76ca46b28285586ad349a25731d196222d56","e91adad3da69c366d57067fcf234030b8a05bcf98c25a759a7a5cd22398ac201","d7d6e1974124a2dad1a1b816ba2436a95f44feeda0573d6c9fb355f590cf9086","464413fcd7e7a3e1d3f2676dc5ef4ebe211c10e3107e126d4516d79439e4e808","18f912e4672327b3dd17d70e91da6fcd79d497ba01dde9053a23e7691f56908c","2974e2f06de97e1d6e61d1462b54d7da2c03b3e8458ee4b3dc36273bc6dda990","d8c1697db4bb3234ff3f8481545284992f1516bc712421b81ee3ef3f226ae112","59b6cce93747f7eb2c0405d9f32b77874e059d9881ec8f1b65ff6c068fcce6f2","e2c3c3ca3818d610599392a9431e60ec021c5d59262ecd616538484990f6e331","e3cd60be3c4f95c43420be67eaa21637585b7c1a8129f9b39983bbd294f9513c",{"version":"95f26e134cf46f4c2aec8c70a79dcbc00c5811bdc9734bd3f3535fa63f8448c3","affectsGlobalScope":true},{"version":"b5cecde79abfbc12a401f52dc970534379853c6143b0185732bf2afabc953226","signature":"a6d0b64d1255200ff1072d421fa6536255766a098c9200ddb02be228aefd9aa5"},{"version":"3e4562626dc4a4e09d0b5fbdd16083f89e88bd8a7a4b9e9cb964dc8231c33746","signature":"03c1f643abb6aa3f5beea31acc4c947301f67efbe34d9411792b0ddae34cd421"},{"version":"bdc82c029046f9bdf950eb160a7eb7c6cca5544acb10e31483bceb9a0de09e68","signature":"b5e94c01a086c2c0bdc1098fa2e4b7b1003a2cd5116062d4ed00cd2a8fbd84fb"},{"version":"a1a16d15c55a27fe042b61b42ae2d7c4dd036540e4f84d939d21c1053ddeaea4","signature":"2787e4a8ad55e36078f5be63d85202a27d3fa86a5fe74b753f7b9b6a741b95cf"},{"version":"06156ce3bf5dff17db589dd05ceeb20efa44f44706c93155589519efdf164c67","signature":"faf29f3358f978406f77358e13d79caf447901573c660878b07516ed68cacaec"},{"version":"39f467a122ae4aae0448ccee0cb92ba5b8666ec153e89cefc340ca8a5868a8e8","signature":"c9b200d0d3b65f22697d2e135faa5169974694542bb84120180df3ee3ba9975f"},{"version":"8237014552816cab5bba9c9748ca6121cde336be5c163a7fce9ac024f3a60658","signature":"12774b883f296d10516a45a2ecddebb9aa851a4aad02f2dd24a67beb719e69fe"},{"version":"ff3950ee52fc51775ca9fd8f758ed67d1d527f067b801fe9f53089b075b555a4","signature":"f2f52c2315c468b6733073d9263445c10c2ba24e13c094ed31f3df6eac18db8b"},{"version":"bff8fa1b781caa592b3ced4365b47be1fe7ca870525f41a6587a5c4b133bed34","signature":"54916d85532bb6a1924d88130f0c677b9a9ea2308270fe40e2ee14a7b4e80faf"},{"version":"c38c3ddbf9e00e2ed424a5d1672d640ba399c5ab0693ad461291db8b19c61e00","signature":"130013e5d61da26038a069a3c16c7a9ee4e5ea8043a698fb4db93f116a2eb85a"},{"version":"fadfd5b74a2426655ce637d122b447c996f0855534eb3fa6b5ea6f49175e86d9","signature":"46a631998156c50ea9b92786612efe5a59668fde4cb4aaa1072f99bed7b4c1a8"},{"version":"561a2ef6a9a91d9ccc4e33cb3a0fc7791be650886294e919c68dbafa37da37f2","signature":"2597118d8d24a0f95637a56e6594bbb4ee608f970b119d6e3b95362e60cf3274"},{"version":"b0a6bd387dac3ff1d394916696fbb80a875abfd2017d102a8f6aa3e836687b44","signature":"0a9137fd1f6cc95a03dc750636d3c795b2a8f1c060aec6c4bd1eb1a55dce802e"},{"version":"096584ee9cb27de81a93c104539890a97f6840a5445e14a391d0aff65a5f09a7","signature":"d03375f44e350e92d31efee3dfeca5a313bc8ea44600c5c397bd92dd9b53ff7a"},{"version":"f44a399fbd677f4362e25e5f100d21d1af024dffd6e8c8e682a86fd5fb087c34","signature":"a2213dc30fd733aa3ba0aefe70f5e567353f2d4b43c43aedb4ef3297924ad655"},{"version":"51e13f0d52ce09190f29f1e2632e217764df74a0122385cf4afc47018d9c6bbe","signature":"4931358848f7d79b85b693b4b86f00a99d7bec658e033bc4b93ceb7a6ff0faa5"},"81c6d9e68919b018655c5bb5cdecad443c602e6689ecb2e2066846671f029dd7","8b0b6a4c032a56d5651f7dd02ba3f05fbfe4131c4095093633cda3cae0991972","192a0c215bffe5e4ac7b9ff1e90e94bf4dfdad4f0f69a5ae07fccc36435ebb87","3ef8565e3d254583cced37534f161c31e3a8f341ff005c98b582c6d8c9274538","d7e42a3800e287d2a1af8479c7dd58c8663e80a01686cb89e0068be6c777d687","1098034333d3eb3c1d974435cacba9bd5a625711453412b3a514774fec7ca748","f2388b97b898a93d5a864e85627e3af8638695ebfa6d732ecd39d382824f0e63","73a3180fe69bf6e8d61f8fbbf969a3e4c9d19e1b3570768a281d371f85aa2dec","f477375e6f0bf2a638a71d4e7a3da8885e3a03f3e5350688541d136b10b762a6","a44d6ea4dc70c3d789e9cef3cc42b79c78d17d3ce07f5fd278a7e1cbe824da56","55cd8cbc22fe648429a787e16a9cd2dc501a2aafd28c00254ad120ef68a581c0","ba4900e9d6f9795a72e8f5ca13c18861821a3fc3ae7858acb0a3366091a47afb","7778e2cc5f74ef263a880159aa7fa67254d6232e94dd03429a75597a622537a7","8e06a1ef49502a62039eeb927a1bd7561b0bce48bd423a929e2e478fd827c273","7ec3d0b061da85d6ff50c337e3248a02a72088462739d88f33b9337dba488c4f","2f554c6798b731fc39ff4e3d86aadc932fdeaa063e3cbab025623ff5653c0031","fe4613c6c0d23edc04cd8585bdd86bc7337dc6265fb52037d11ca19eeb5e5aaf","53b26fbee1a21a6403cf4625d0e501a966b9ccf735754b854366cee8984b711c","9ff247206ec5dffdfadddfded2c9d9ad5f714821bb56760be40ed89121f192f4","98c6ddd06251098b3302e7094cbc9ab54a2ea88069f5416b7d0b8daee2ff8aa2","8c59d8256086ed17676139ee43c1155673e357ab956fb9d00711a7cac73e059d","cfe88132f67aa055a3f49d59b01585fa8d890f5a66a0a13bb71973d57573eee7","53ce488a97f0b50686ade64252f60a1e491591dd7324f017b86d78239bd232ca","50fd11b764194f06977c162c37e5a70bcf0d3579bf82dd4de4eee3ac68d0f82f","e0ceb647dcdf6b27fd37e8b0406c7eafb8adfc99414837f3c9bfd28ffed6150a","99579aa074ed298e7a3d6a47e68f0cd099e92411212d5081ce88344a5b1b528d","096e4ddaa8f0aa8b0ceadd6ab13c3fab53e8a0280678c405160341332eca3cd7","415b55892d813a74be51742edd777bbced1f1417848627bf71725171b5325133","942ab34f62ac3f3d20014615b6442b6dc51815e30a878ebc390dd70e0dec63bf","7a671bf8b4ad81b8b8aea76213ca31b8a5de4ba39490fbdee249fc5ba974a622","8e07f13fb0f67e12863b096734f004e14c5ebfd34a524ed4c863c80354c25a44","9faa56e38ed5637228530065a9bab19a4dc5a326fbdd1c99e73a310cfed4fcde","7d4ad85174f559d8e6ed28a5459aebfc0a7b0872f7775ca147c551e7765e3285","d422f0c340060a53cb56d0db24dd170e31e236a808130ab106f7ab2c846f1cdb","424403ef35c4c97a7f00ea85f4a5e2f088659c731e75dbe0c546137cb64ef8d8","16900e9a60518461d7889be8efeca3fe2cbcd3f6ce6dee70fea81dfbf8990a76","6daf17b3bd9499bd0cc1733ab227267d48cd0145ed9967c983ccb8f52eb72d6e","e4177e6220d0fef2500432c723dbd2eb9a27dcb491344e6b342be58cc1379ec0","ddc62031f48165334486ad1943a1e4ed40c15c94335697cb1e1fd19a182e3102","b3f4224eb155d7d13eb377ef40baa1f158f4637aa6de6297dfeeacefd6247476","4a168e11fe0f46918721d2f6fcdb676333395736371db1c113ae30b6fde9ccd2","5b0a75a5cced0bed0d733bde2da0bbb5d8c8c83d3073444ae52df5f16aefb6ab","ef2c1585cad462bdf65f2640e7bcd75cd0dbc45bae297e75072e11fe3db017fa","ef809928a4085de826f5b0c84175a56d32dd353856f5b9866d78b8419f8ea9bc","6f6eadb32844b0ec7b322293b011316486894f110443197c4c9fbcba01b3b2fa","a51e08f41e3e948c287268a275bfe652856a10f68ddd2bf3e3aaf5b8cdb9ef85","862f7d760ef37f0ae2c17de82e5fbf336b37d5c1b0dcf39dcd5468f90a7fdd54","af48a76b75041e2b3e7bd8eed786c07f39ea896bb2ff165e27e18208d09b8bee","cb524ec077f3963e13e85747c6b53fbdf6bf407c84ca1873c6e43da1e96bee6d","deb092bc337b2cb0a1b14f3d43f56bc663e1447694e6d479d6df8296bdd452d6","041bc1c3620322cb6152183857601707ef6626e9d99f736e8780533689fb1bf9","22bd7c75de7d68e075975bf1123de5bccecfd06688afff2e2022b4c70bfc91c3","128e7c2ffd37aa29e05367400d718b0e4770cefb1e658d8783ec80a16bc0643a","076ac4f2d642c473fa7f01c8c1b7b4ef58f921130174d9cf78430651f44c43ec","396c1e5a39706999ec8cc582916e05fcb4f901631d2c192c1292e95089a494d9","89df75d28f34fc698fe261f9489125b4e5828fbd62d863bbe93373d3ed995056","8ccf5843249a042f4553a308816fe8a03aa423e55544637757d0cfa338bb5186","93b44aa4a7b27ba57d9e2bad6fb7943956de85c5cc330d2c3e30cd25b4583d44","a0c6216075f54cafdfa90412596b165ff85e2cadd319c49557cc8410f487b77c","3c359d811ec0097cba00fb2afd844b125a2ddf4cad88afaf864e88c8d3d358bd","3c0b38e8bf11bf3ab87b5116ae8e7b2cad0147b1c80f2b77989dea6f0b93e024","8df06e1cd5bb3bf31529cc0db74fa2e57f7de1f6042726679eb8bc1f57083a99","d62f09256941e92a95b78ae2267e4cf5ff2ca8915d62b9561b1bc85af1baf428","e6223b7263dd7a49f4691bf8df2b1e69f764fb46972937e6f9b28538d050b1ba","d9b59eb4e79a0f7a144ee837afb3f1afbc4dab031e49666067a2b5be94b36bd4","1db014db736a09668e0c0576585174dbcfd6471bb5e2d79f151a241e0d18d66b","8a153d30edde9cefd102e5523b5a9673c298fc7cf7af5173ae946cbb8dd48f11","abaaf8d606990f505ee5f76d0b45a44df60886a7d470820fcfb2c06eafa99659","51a66bfa412057e786a712733107547ceb6f539061f5bf1c6e5a96e4ccf4f83c","d92a80c2c05cf974704088f9da904fe5eadc0b3ad49ddd1ef70ca8028b5adda1","fbd7450f20b4486c54f8a90486c395b14f76da66ba30a7d83590e199848f0660","ece5b0e45c865645ab65880854899a5422a0b76ada7baa49300c76d38a530ee1","62d89ac385aeab821e2d55b4f9a23a277d44f33c67fefe4859c17b80fdb397ea","f4dee11887c5564886026263c6ee65c0babc971b2b8848d85c35927af25da827","fb8dd49a4cd6d802be4554fbab193bb06e2035905779777f32326cb57cf6a2c2","e403ecdfba83013b5eb0e648a92ce182bff2a45ccb81db3035a69081563c2830","82d3e00d56a71fc169f3cf9ec5f5ffcc92f6c0e67d4dfc130dafe9f1886d5515","b8d57effce2d49a5493debbd8c644e8d52fbe66e2c6d451371375ef5f7bccb8e","9963d9857df2df335d1232a12eccbe5c777537a244f4b39406b27bf4736202f6","1b33478647aa1b771314745807397002a410c746480e9447db959110999873ce","a14e7c48debe27b25ddf7932e6976c4f58123e32be8384c3f91b0a4d9f67c2f0","7e6a96b383da9f5acb848bb9dedb9ac8489df7cec46bbf26aeaed2610f709078","9fac6ebf3c60ced53dd21def30a679ec225fc3ff4b8d66b86326c285a4eebb5a","8cb83cb98c460cd716d2a98b64eb1a07a3a65c7362436550e02f5c2d212871d1","07bc8a3551e39e70c38e7293b1a09916867d728043e352b119f951742cb91624","e47adc2176f43c617c0ab47f2d9b2bb1706d9e0669bf349a30c3fe09ddd63261","7fec79dfd7319fec7456b1b53134edb54c411ba493a0aef350eee75a4f223eeb","189c489705bb96a308dcde9b3336011d08bfbca568bcaf5d5d55c05468e9de7a","98f4b1074567341764b580bf14c5aabe82a4390d11553780814f7e932970a6f7","1dd24cbf39199100fbe2f3dbd1c7203c240c41d95f66301ecc7650ae77875be1","2e252235037a2cd8feebfbf74aa460f783e5d423895d13f29a934d7655a1f8be","3bd10a31e9066676e0af937c2ef2507451281861ae294d04c7c46e46706140d9","53477a1815e915b8c20222a2ac8f9e3de880a1e8c8dbf9dae529b3d2e2b4a53b",{"version":"dbd0794f86b0f3e7c2c28bbe6cbf91adc6ef2203c6a832548ef199816d47039c","affectsGlobalScope":true},{"version":"16a216abd2e98172a804e7b124e88e23c63fe12896ff6f72af752d44d11266b5","signature":"7ff7d0f06650eedf7c8b7bc5c0aee785f400940ec9e48026a3f7ee19ca962f62"},{"version":"bcb2fb2a8e8f3ee0ae80924969a947d07b0af89e16a12ef47c10df0e0e33aaf8","signature":"2c94b568379a615add7e4537f655d5a5ac19533b91fabce1bf347e61227bc1c4"},"8243c4c93b6c4d64f086fa2a8fa180cd592380178dda3296274753ad26218d60",{"version":"2b0cc039816ca5dc54f124333a4645857cecede6b9d8312e5dcd9f3ff74991ee","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},"6990f2fb809692c89ecee29660a7680543246d0aee7bfc6756a1047a9918cc29","b84b0deafa5845fd2f21e49945eec5642fc74616f4b324e32e1f5bdf84a0eb54","884cd5093164bd0d95afa8854b426df08997a085668f123992ec1bb8eb2accc1","fc892a9c766a171ee80ae5f90cdb1276a509a10bb8a9cc4ade22a637cd849eab","e2f0a4be4ff986b254035536cd7a0326c3998807c107314c484461d286be116c","052bfda778ba1d93404739c42f8c8be8c8f35bb4df1f05740542de9c8786000e","db114ef2aba1c12605774caca9a12f389e23a084f007662129450c669da9e981","6061e156608df22580cdfe4a7a5458d94c459fb813f432fc39aaf1d4a33a9888","0a33b8bff876368beef794f5f08e8221103efa394f9e0e27e19f557a8cdaa0a0",{"version":"00ff0ab9ef8e80fa5f661376178da927120f98974ae453f1878fda1662a3c24a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"230f951114cbbe103632617f6b9591bfcaac2fbe4fc27158d528984ada8bd3eb","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"dc32a7ce3f941cd47b298e971118b1abaa18f1c72e16d803d2a9518b94c628b2","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"b5a58595a790a580bc82de0e44898dc8802a7b8db9e62fb1b5afe4e8bc6a9b09","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"fc909066a936771070f4e142f262faed6e886c883537f03e8ce99a41f6a4be0e","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"54fae3169ef40000b63b1ceb89a27782217364ba3cb0990fa0a9d22c9343b887","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"d9fe94961a12a090b9f42a740d0acd29fd41a98373da82a5735bcfb07496db0c","signature":"754c4423892e7b84c053e96a5b85cfea769187dd304c599fa5c014eff1f0827a"},{"version":"18fa848687cd77712e8628c0e93d357a463c1ad7d3c9e7f5ea88c7c70b18fa9a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"77f2bd2c3b41aec171e16dc315f6840e67551fd92e77417b8193c716ace11e39","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"b648f0bb4f358e44c69649d448a95e5ee76f7a28bff8b4c069926f92547b5ea6","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"f77792bc02b2dfc8c9645696a9c2e6acfe071599ddd7c12771b49444bec72495","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"6b8ba82472956e3c2012793ea52804218145cb53e2be86e2cb3aa3de4eb6b25b","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"1c5b3fca96bf8a12c234a3466821ecd5c8c3ae0bfc12b58d72b403447e75ae44","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"c64123347ea308d462eb2fe5f17db98486bb7b1fb1bb7e70389fc5da5bc2d98d","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},"556ccd493ec36c7d7cb130d51be66e147b91cc1415be383d71da0f1e49f742a9","b6d03c9cfe2cf0ba4c673c209fcd7c46c815b2619fd2aad59fc4229aaef2ed43","95aba78013d782537cc5e23868e736bec5d377b918990e28ed56110e3ae8b958","670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","13b77ab19ef7aadd86a1e54f2f08ea23a6d74e102909e3c00d31f231ed040f62","069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","a3d3f704c5339a36da3ca8c62b29072f87e86c783b8452d235992142ec71aa2d","0dc6940ff35d845686a118ee7384713a84024d60ef26f25a2f87992ec7ddbd64","751764bb94219b4ce8f5475dc35d3de2e432fea01a0c9610cd7f69ad05e398c6","f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","a4a39b5714adfcadd3bbea6698ca2e942606d833bde62ad5fb6ec55f5e438ff8","bbc1d029093135d7d9bfa4b38cbf8761db505026cc458b5e9c8b74f4000e5e75","1f68ab0e055994eb337b67aa87d2a15e0200951e9664959b3866ee6f6b11a0fe","035a5df183489c2e22f3cf59fc1ed2b043d27f357eecc0eb8d8e840059d44245","a4809f4d92317535e6b22b01019437030077a76fec1d93b9881c9ed4738fcc54","5f53fa0bd22096d2a78533f94e02c899143b8f0f9891a46965294ee8b91a9434","efd20a1e335999efb44d19f01f9a74b2c40491c0539d9f14ed2bbded3f573654","0d14fa22c41fdc7277e6f71473b20ebc07f40f00e38875142335d5b63cdfc9d2","b104e2da53231a529373174880dc0abfbc80184bb473b6bf2a9a0746bebb663d","ee91a5fbbd1627c632df89cce5a4054f9cc6e7413ebdccc82b27c7ffeedf982d","85c8731ca285809fc248abf21b921fe00a67b6121d27060d6194eddc0e042b1a","6bac0cbdf1bc85ae707f91fdf037e1b600e39fb05df18915d4ecab04a1e59d3c","5688b21a05a2a11c25f56e53359e2dcda0a34cb1a582dbeb1eaacdeca55cb699","35558bf15f773acbe3ed5ac07dd27c278476630d85245f176e85f9a95128b6e0","951f54e4a63e82b310439993170e866dba0f28bb829cbc14d2f2103935cea381","4454a999dc1676b866450e8cddd9490be87b391b5526a33f88c7e45129d30c5d","99013139312db746c142f27515a14cdebb61ff37f20ee1de6a58ce30d36a4f0d","71da852f38ac50d2ae43a7b7f2899b10a2000727fee293b0b72123ed2e7e2ad6","74dd1096fca1fec76b951cf5eacf609feaf919e67e13af02fed49ec3b77ea797","a0691153ccf5aa1b687b1500239722fff4d755481c20e16d9fcd7fb2d659c7c7","fe2201d73ae56b1b4946c10e18549a93bf4c390308af9d422f1ffd3c7989ffc8","cad63667f992149cee390c3e98f38c00eee56a2dae3541c6d9929641b835f987","f497cad2b33824d8b566fa276cfe3561553f905fdc6b40406c92bcfcaec96552","eb58c4dbc6fec60617d80f8ccf23900a64d3190fda7cfb2558b389506ec69be0","578929b1c1e3adaed503c0a0f9bda8ba3fea598cc41ad5c38932f765684d9888","7cc9d600b2070b1e5c220044a8d5a58b40da1c11399b6c8968711de9663dc6b2","45f36cf09d3067cd98b39a7d430e0e531f02911dd6d63b6d784b1955eef86435","80419a23b4182c256fa51d71cb9c4d872256ca6873701ceabbd65f8426591e49","5aa046aaab44da1a63d229bd67a7a1344afbd6f64db20c2bbe3981ceb2db3b07","ed9ad5b51c6faf9d6f597aa0ab11cb1d3a361c51ba59d1220557ef21ad5b0146","73db7984e8a35e6b48e3879a6d024803dd990022def2750b3c23c01eb58bc30f","c9ecb910b3b4c0cf67bc74833fc41585141c196b5660d2eb3a74cfffbf5aa266","33dcfba8a7e4acbe23974d342c44c36d7382c3d1d261f8aef28261a7a5df2969","de26700eb7277e8cfdde32ebb21b3d9ad1d713b64fdc2019068b857611e8f0c4","e481bd2c07c8e93eb58a857a9e66f22cb0b5ddfd86bbf273816fd31ef3a80613","ef156ba4043f6228d37645d6d9c6230a311e1c7a86669518d5f2ebc26e6559bf","457fd1e6d6f359d7fa2ca453353f4317efccae5c902b13f15c587597015212bc","473b2b42af720ebdb539988c06e040fd9600facdeb23cb297d72ee0098d8598f","22bc373ca556de33255faaddb373fec49e08336638958ad17fbd6361c7461eed","b3d58358675095fef03ec71bddc61f743128682625f1336df2fc31e29499ab25","5b1ef94b03042629c76350fe18be52e17ab70f1c3be8f606102b30a5cd86c1b3","a7b6046c44d5fda21d39b3266805d37a2811c2f639bf6b40a633b9a5fb4f5d88","80b036a132f3def4623aad73d526c6261dcae3c5f7013857f9ecf6589b72951f","0a347c2088c3b1726b95ccde77953bede00dd9dd2fda84585fa6f9f6e9573c18","8cc3abb4586d574a3faeea6747111b291e0c9981003a0d72711351a6bcc01421","0a516adfde610035e31008b170da29166233678216ef3646822c1b9af98879da","70d48a1faa86f67c9cb8a39babc5049246d7c67b6617cd08f64e29c055897ca9","df10dc6fe1c49e2f94be9d7d1e625aeb66e5eb90b2e0af1f378bfdfa5313155b","082b818038423de54be877cebdb344a2e3cf3f6abcfc48218d8acf95c030426a","813514ef625cb8fc3befeec97afddfb3b80b80ced859959339d99f3ad538d8fe","039cd54028eb988297e189275764df06c18f9299b14c063e93bd3f30c046fee6","e91cfd040e6da28427c5c4396912874902c26605240bdc3457cc75b6235a80f2","b4347f0b45e4788c18241ac4dee20ceab96d172847f1c11d42439d3de3c09a3e","16fe6721dc0b4144a0cdcef98857ee19025bf3c2a3cc210bcd0b9d0e25f7cec8","346d903799e8ea99e9674ba5745642d47c0d77b003cc7bb93e1d4c21c9e37101","3997421bb1889118b1bbfc53dd198c3f653bf566fd13c663e02eb08649b985c4","2d1ac54184d897cb5b2e732d501fa4591f751678717fd0c1fd4a368236b75cba","bade30041d41945c54d16a6ec7046fba6d1a279aade69dfdef9e70f71f2b7226","56fbea100bd7dd903dc49a1001995d3c6eee10a419c66a79cdb194bff7250eb7","fe8d26b2b3e519e37ceea31b1790b17d7c5ab30334ca2b56d376501388ba80d6","37ad0a0c2b296442072cd928d55ef6a156d50793c46c2e2497da1c2750d27c1e","be93d07586d09e1b6625e51a1591d6119c9f1cbd95718497636a406ec42babee","a062b507ed5fc23fbc5850fd101bc9a39e9a0940bb52a45cd4624176337ad6b8","cf01f601ef1e10b90cad69312081ce0350f26a18330913487a26d6d4f7ce5a73","a9de7b9a5deaed116c9c89ad76fdcc469226a22b79c80736de585af4f97b17cd","5bde81e8b0efb2d977c6795f9425f890770d54610764b1d8df340ce35778c4f8","20fd0402351907669405355eeae8db00b3cf0331a3a86d8142f7b33805174f57","da6949af729eca1ec1fe867f93a601988b5b206b6049c027d0c849301d20af6f","7008f240ea3a5a344be4e5f9b5dbf26721aad3c5cfef5ff79d133fa7450e48fa","eb13c8624f5747a845aea0df1dfde0f2b8f5ed90ca3bc550b12777797cb1b1e3","2452fc0f47d3b5b466bda412397831dd5138e62f77aa5e11270e6ca3ecb8328d","33c2ebbdd9a62776ca0091a8d1f445fa2ea4b4f378bc92f524031a70dfbeec86","3ac3a5b34331a56a3f76de9baf619def3f3073961ce0a012b6ffa72cf8a91f1f","d5e9d32cc9813a5290a17492f554999e33f1aa083a128d3e857779548537a778","776f49489fa2e461b40370e501d8e775ddb32433c2d1b973f79d9717e1d79be5","be94ea1bfaa2eeef1e821a024914ef94cf0cba05be8f2e7df7e9556231870a1d","40cd13782413c7195ad8f189f81174850cc083967d056b23d529199d64f02c79","05e041810faf710c1dcd03f3ffde100c4a744672d93512314b1f3cfffccdaf20","15a8f79b1557978d752c0be488ee5a70daa389638d79570507a3d4cfc620d49d","968ee57037c469cffb3b0e268ab824a9c31e4205475b230011895466a1e72da4","77debd777927059acbaf1029dfc95900b3ab8ed0434ce3914775efb0574e747b","921e3bd6325acb712cd319eaec9392c9ad81f893dead509ab2f4e688f265e536","60f6768c96f54b870966957fb9a1b176336cd82895ded088980fb506c032be1c","755d9b267084db4ea40fa29653ea5fc43e125792b1940f2909ec70a4c7f712d8","7e3056d5333f2d8a9e54324c2e2293027e4cd9874615692a53ad69090894d116","1e25b848c58ad80be5c31b794d49092d94df2b7e492683974c436bcdbefb983c","3df6fc700b8d787974651680ae6e37b6b50726cf5401b7887f669ab195c2f2ef","145df08c171ec616645a353d5eaa5d5f57a5fbce960a47d847548abd9215a99e","dcfd2ca9e033077f9125eeca6890bb152c6c0bc715d0482595abc93c05d02d92","8056fa6beb8297f160e13c9b677ba2be92ab23adfb6940e5a974b05acd33163b","86dda1e79020fad844010b39abb68fafed2f3b2156e3302820c4d0a161f88b03","dea0dcec8d5e0153d6f0eacebb163d7c3a4b322a9304048adffc6d26084054bd","2afd081a65d595d806b0ff434d2a96dc3d6dcd8f0d1351c0a0968568c6944e0b","b86259ab4b95ebe1aedb03d3eebea647f0bd9a706981220f00210487d70e77a0","2f1f7c65e8ee58e3e7358f9b8b3c37d8447549ecc85046f9405a0fc67fbdf54b","e3f3964ff78dee11a07ae589f1319ff682f62f3c6c8afa935e3d8616cf21b431","2762c2dbee294ffb8fdbcae6db32c3dae09e477d6a348b48578b4145b15d1818","78a1eace936ad32ca1c228814f3333cb2e826e1447e60fee181b3c53d43a8d07","24bd135b687da453ea7bd98f7ece72e610a3ff8ca6ec23d321c0e32f19d32db6","64d45d55ba6e42734ac326d2ea1f674c72837443eb7ff66c82f95e4544980713","f9b0dc747f13dcc09e40c26ddcc118b1bafc3152f771fdc32757a7f8916a11fc","7035fc608c297fd38dfe757d44d3483a570e2d6c8824b2d6b20294d617da64c6","22160a296186123d2df75280a1fab70d2105ce1677af1ebb344ffcb88eef6e42","9067b3fd7d71165d4c34fcbbf29f883860fd722b7e8f92e87da036b355a6c625","e01ab4b99cc4a775d06155e9cadd2ebd93e4af46e2723cb9361f24a4e1f178ef","9a13410635d5cc9c2882e67921c59fb26e77b9d99efa1a80b5a46fdc2954afce","b04862a4f44f78fd12ad8ed34ab81f9f254a87398568173694a78dc0bdebcd23","fa894bdddb2ba0e6c65ad0d88942cf15328941246410c502576124ef044746f9","59c5a06fa4bf2fa320a3c5289b6f199a3e4f9562480f59c0987c91dc135a1adf","456a9a12ad5d57af0094edf99ceab1804449f6e7bc773d85d09c56a18978a177","a8e2a77f445a8a1ce61bfd4b7b22664d98cf19b84ec6a966544d0decec18e143","6f6b0b477db6c4039410c7a13fe1ebed4910dedf644330269816df419cdb1c65","960b6e1edfb9aafbd560eceaae0093b31a9232ab273f4ed776c647b2fb9771da","530f4bee13cc07fd4e8bac69eeb728a6270ebafeab886c98624c699725b29755","a0db48d42371b223cea8fd7a41763d48f9166ecd4baecc9d29d9bb44cc3c2d83","aaf3c2e268f27514eb28255835f38445a200cd8bcfdff2c07c6227f67aaaf657","6ade56d2afdf75a9bd55cd9c8593ed1d78674804d9f6d9aba04f807f3179979e","b67acb619b761e91e3a11dddb98c51ee140361bc361eb17538f1c3617e3ec157","81b097e0f9f8d8c3d5fe6ba9dc86139e2d95d1e24c5ce7396a276dfbb2713371","692d56fff4fb60948fe16e9fed6c4c4eac9b263c06a8c6e63726e28ed4844fd4","f13228f2c0e145fc6dc64917eeef690fb2883a0ac3fa9ebfbd99616fd12f5629","d89b2b41a42c04853037408080a2740f8cd18beee1c422638d54f8aefe95c5b8","be5d39e513e3e0135068e4ebed5473ab465ae441405dce90ab95055a14403f64","97e320c56905d9fa6ac8bd652cea750265384f048505870831e273050e2878cc","9932f390435192eb93597f89997500626fb31005416ce08a614f66ec475c5c42","5d89ca552233ac2d61aee34b0587f49111a54a02492e7a1098e0701dedca60c9","1ee47a39f996d76442fe9777bb4446bd110f6828488db0e65cba817b4ffc5807","fdc4fd2c610b368104746960b45216bc32685927529dd871a5330f4871d14906","7b5d77c769a6f54ea64b22f1877d64436f038d9c81f1552ad11ed63f394bd351","4f7d54c603949113f45505330caae6f41e8dbb59841d4ae20b42307dc4579835","a71fd01a802624c3fce6b09c14b461cc7c7758aa199c202d423a7c89ad89943c","1ed0dc05908eb15f46379bc1cb64423760e59d6c3de826a970b2e2f6da290bf5","db89ef053f209839606e770244031688c47624b771ff5c65f0fa1ec10a6919f1","4d45b88987f32b2ac744f633ff5ddb95cd10f64459703f91f1633ff457d6c30d","8512fd4a480cd8ef8bf923a85ff5e97216fa93fb763ec871144a9026e1c9dade","2aa58b491183eedf2c8ae6ef9a610cd43433fcd854f4cc3e2492027fbe63f5ca","ce1f3439cb1c5a207f47938e68752730892fc3e66222227effc6a8b693450b82","295ce2cf585c26a9b71ba34fbb026d2b5a5f0d738b06a356e514f39c20bf38ba","342f10cf9ba3fbf52d54253db5c0ac3de50360b0a3c28e648a449e28a4ac8a8c","c485987c684a51c30e375d70f70942576fa86e9d30ee8d5849b6017931fccc6f","320bd1aa480e22cdd7cd3d385157258cc252577f4948cbf7cfdf78ded9d6d0a8","4ee053dfa1fce5266ecfae2bf8b6b0cb78a6a76060a1dcf66fb7215b9ff46b0b","1f84d8b133284b596328df47453d3b3f3817ad206cf3facf5eb64b0a2c14f6d7","5c75e05bc62bffe196a9b2e9adfa824ffa7b90d62345a766c21585f2ce775001","cc2eb5b23140bbceadf000ef2b71d27ac011d1c325b0fc5ecd42a3221db5fb2e","fd75cc24ea5ec28a44c0afc2f8f33da5736be58737ba772318ae3bdc1c079dc3","5ae43407346e6f7d5408292a7d957a663cc7b6d858a14526714a23466ac83ef9","c72001118edc35bbe4fff17674dc5f2032ccdbcc5bec4bd7894a6ed55739d31b","353196fd0dd1d05e933703d8dad664651ed172b8dfb3beaef38e66522b1e0219","670aef817baea9332d7974295938cf0201a2d533c5721fccf4801ba9a4571c75","3f5736e735ee01c6ecc6d4ab35b2d905418bb0d2128de098b73e11dd5decc34f","b64e159c49afc6499005756f5a7c2397c917525ceab513995f047cdd80b04bdf","f72b400dbf8f27adbda4c39a673884cb05daf8e0a1d8152eec2480f5700db36c","24509d0601fc00c4d77c20cacddbca6b878025f4e0712bddd171c7917f8cdcde","5f5baa59149d3d6d6cef2c09d46bb4d19beb10d6bee8c05b7850c33535b3c438","f17a51aae728f9f1a2290919cf29a927621b27f6ae91697aee78f41d48851690","be02e3c3cb4e187fd252e7ae12f6383f274e82288c8772bb0daf1a4e4af571ad","82ca40fb541799273571b011cd9de6ee9b577ef68acc8408135504ae69365b74","8fb6646db72914d6ef0692ea88b25670bbf5e504891613a1f46b42783ec18cce","b61efdebae3d131b6ad71bd2aa7cc4284e351481339bf66d84ee5ed86465bcc8","213aa21650a910d95c4d0bee4bb936ecd51e230c1a9e5361e008830dcc73bc86","874a8c5125ad187e47e4a8eacc809c866c0e71b619a863cc14794dd3ccf23940","c31db8e51e85ee67018ac2a40006910efbb58e46baea774cf1f245d99bf178b5","31fac222250b18ebac0158938ede4b5d245e67d29cd2ef1e6c8a5859d137d803","a9dfb793a7e10949f4f3ea9f282b53d3bd8bf59f5459bc6e618e3457ed2529f5","2a77167687b0ec0c36ef581925103f1dc0c69993f61a9dbd299dcd30601af487","0f23b5ce60c754c2816c2542b9b164d6cb15243f4cbcd11cfafcab14b60e04d0","813ce40a8c02b172fdbeb8a07fdd427ac68e821f0e20e3dc699fb5f5bdf1ef0a","5ce6b24d5fd5ebb1e38fe817b8775e2e00c94145ad6eedaf26e3adf8bb3903d0","6babca69d3ae17be168cfceb91011eed881d41ce973302ee4e97d68a81c514b4","3e0832bc2533c0ec6ffcd61b7c055adedcca1a45364b3275c03343b83c71f5b3","342418c52b55f721b043183975052fb3956dae3c1f55f965fedfbbf4ad540501","6a6ab1edb5440ee695818d76f66d1a282a31207707e0d835828341e88e0c1160","7e9b4669774e97f5dc435ddb679aa9e7d77a1e5a480072c1d1291892d54bf45c","de439ddbed60296fbd1e5b4d242ce12aad718dffe6432efcae1ad6cd996defd3","ce5fb71799f4dbb0a9622bf976a192664e6c574d125d3773d0fa57926387b8b2","b9c0de070a5876c81540b1340baac0d7098ea9657c6653731a3199fcb2917cef","cbc91ecd74d8f9ddcbcbdc2d9245f14eff5b2f6ae38371283c97ca7dc3c4a45f","3ca1d6f016f36c61a59483c80d8b9f9d50301fbe52a0dde288c1381862b13636","ecfef0c0ff0c80ac9a6c2fab904a06b680fb5dfe8d9654bb789e49c6973cb781","0ee2eb3f7c0106ccf6e388bc0a16e1b3d346e88ac31b6a5bbc15766e43992167","7a80da7b14bc7902b1da607c8b3734ad5740f8f5fade9a7bfbf753b9bba22652","7e46dd61422e5afe88c34e5f1894ae89a37b7a07393440c092e9dc4399820172","9df4f57d7279173b0810154c174aa03fd60f5a1f0c3acfe8805e55e935bdecd4","a02a51b68a60a06d4bd0c747d6fbade0cb87eefda5f985fb4650e343da424f12","0cf851e2f0ecf61cabe64efd72de360246bcb8c19c6ef7b5cbb702293e1ff755","0c0e0aaf37ab0552dffc13eb584d8c56423b597c1c49f7974695cb45e2973de6","e2e0cd8f6470bc69bbfbc5e758e917a4e0f9259da7ffc93c0930516b0aa99520","180de8975eff720420697e7b5d95c0ecaf80f25d0cea4f8df7fe9cf817d44884","424a7394f9704d45596dce70bd015c5afec74a1cc5760781dfda31bc300df88f","044a62b9c967ee8c56dcb7b2090cf07ef2ac15c07e0e9c53d99fab7219ee3d67","3903b01a9ba327aae8c7ea884cdabc115d27446fba889afc95fddca8a9b4f6e2","78fd8f2504fbfb0070569729bf2fe41417fdf59f8c3e975ab3143a96f03e0a4a","8afd4f91e3a060a886a249f22b23da880ec12d4a20b6404acc5e283ef01bdd46","72e72e3dea4081877925442f67b23be151484ef0a1565323c9af7f1c5a0820f0","fa8c21bafd5d8991019d58887add8971ccbe88243c79bbcaec2e2417a40af4e8","ab35597fd103b902484b75a583606f606ab2cef7c069fae6c8aca0f058cee77d","ca54ec33929149dded2199dca95fd8ad7d48a04f6e8500f3f84a050fa77fee45","cac7dcf6f66d12979cc6095f33edc7fbb4266a44c8554cd44cd04572a4623fd0","98af566e6d420e54e4d8d942973e7fbe794e5168133ad6658b589d9dfb4409d8","fd80af69ef04ab9cb2404aca13e8a620f0cf29c0814c69b663a467def21de35e","d421c4e4d70b03d8d05f993dd13a2c473c967b863438b167a8b3c01d4685a692","3bf23090b94bda18a619623d2652b48ea904e26304267b10fcbdb85e032b7351","d4d6aab35ead2fbdafc31c9b0cb8a5b5939c7d24c63356c979757194eaa282cf","f80aedd7cc51ccb70537fc79f07b44512e0ce43e2bf3dd350743bfb968cf26ce","b3202cfb0370950f175b9d1c1bebda95f0c62fee5fc2853f474aace51be42860",{"version":"3e2f739bdfb6b194ae2af13316b4c5bb18b3fe81ac340288675f92ba2061b370","affectsGlobalScope":true},"b0f9ef6423d6b29dde29fd60d83d215796b2c1b76bfca28ac374ae18702cfb8e","ab82804a14454734010dcdcd43f564ff7b0389bee4c5692eec76ff5b30d4cf66","e7bb49fac2aa46a13011b5eb5e4a8648f70a28aea1853fab2444dd4fcb4d4ec7","464e45d1a56dae066d7e1a2f32e55b8de4bfb072610c3483a4091d73c9924908","da318e126ac39362c899829547cc8ee24fa3e8328b52cdd27e34173cf19c7941","24bd01a91f187b22456c7171c07dbf44f3ad57ebd50735aab5c13fa23d7114b4","4738eefeaaba4d4288a08c1c226a76086095a4d5bcc7826d2564e7c29da47671","736097ddbb2903bef918bb3b5811ef1c9c5656f2a73bd39b22a91b9cc2525e50","dbec715e9e82df297e49e3ed0029f6151aa40517ebfd6fcdba277a8a2e1d3a1b","097f1f8ca02e8940cfdcca553279e281f726485fa6fb214b3c9f7084476f6bcc","8f75e211a2e83ff216eb66330790fb6412dcda2feb60c4f165c903cf375633ee","c3fb0d969970b37d91f0dbf493c014497fe457a2280ac42ae24567015963dbf7","a9155c6deffc2f6a69e69dc12f0950ba1b4db03b3d26ab7a523efc89149ce979","c99faf0d7cb755b0424a743ea0cbf195606bf6cd023b5d10082dba8d3714673c","8e770f88d5f5b92aa94251b2d223d18e85dc0ff8ffba5b0d82164a78e8ac5663","3134a6c11d0beb89fcb57ee0720c68fbd47d6c796e219ec188c459553e46505b","bae8d023ef6b23df7da26f51cea44321f95817c190342a36882e93b80d07a960","26a770cec4bd2e7dbba95c6e536390fffe83c6268b78974a93727903b515c4e7"],"root":[531,532,610,752,753,[756,798],[820,836],[930,933],[943,956]],"options":{"allowSyntheticDefaultImports":true,"declaration":true,"emitDecoratorMetadata":true,"experimentalDecorators":true,"module":1,"noFallthroughCasesInSwitch":true,"noImplicitAny":true,"outDir":"./dist","removeComments":true,"rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strictBindCallApply":true,"strictNullChecks":true,"target":8},"fileIdsList":[[421,468,528],[421,468,527],[421,468,957],[421,468],[421,468,1166],[307,421,468],[407,421,468],[56,308,309,310,311,312,313,314,315,316,317,318,319,320,421,468],[259,293,421,468],[266,421,468],[256,307,407,421,468],[325,326,327,328,329,330,331,333,421,468],[261,421,468],[307,407,421,468],[261,332,421,468],[321,324,334,421,468],[322,323,421,468],[297,421,468],[261,262,263,264,421,468],[337,421,468],[279,336,421,468],[336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,421,468],[366,421,468],[363,364,421,468],[362,365,421,468,498],[55,265,307,335,359,362,367,374,399,404,406,421,468],[61,259,421,468],[60,421,468],[61,251,252,421,468,866,871],[251,259,421,468],[60,250,421,468],[259,387,421,468],[253,389,421,468],[250,254,421,468],[254,421,468],[60,307,421,468],[258,259,421,468],[271,421,468],[273,274,275,276,277,421,468],[265,421,468],[265,266,285,421,468],[279,280,286,287,288,421,468],[57,58,59,60,61,251,252,253,254,255,256,257,258,259,260,266,271,272,278,285,289,290,291,293,301,302,303,304,305,306,421,468],[284,421,468],[267,268,269,270,421,468],[259,267,268,421,468],[259,265,266,421,468],[259,269,421,468],[259,297,421,468],[292,294,295,296,297,298,299,300,421,468],[57,259,421,468],[293,421,468],[57,259,292,296,298,421,468],[268,421,468],[294,421,468],[259,293,294,295,421,468],[283,421,468],[259,263,283,284,301,302,421,468],[281,282,284,421,468],[255,257,266,272,286,303,304,307,421,468],[61,250,255,257,260,303,304,421,468],[264,421,468],[250,421,468],[283,307,368,372,421,468],[372,373,421,468],[307,368,421,468],[307,368,369,421,468],[369,370,421,468],[369,370,371,421,468],[260,421,468],[377,378,379,421,468],[377,421,468],[379,380,381,383,384,385,421,468],[376,421,468],[379,382,421,468],[379,380,381,383,384,421,468],[260,377,379,383,421,468],[375,386,391,392,393,394,395,396,397,398,421,468],[260,307,391,421,468],[260,382,421,468],[260,382,407,421,468],[253,259,260,382,387,388,389,390,421,468],[250,307,387,388,400,421,468],[307,387,421,468],[402,421,468],[335,400,421,468],[400,401,403,421,468],[283,421,468,510],[283,360,361,421,468],[292,421,468],[265,307,421,468],[405,421,468],[407,421,468,519],[250,409,414,421,468],[408,414,421,468,519,520,521,524],[414,421,468],[415,421,468,517],[409,415,421,468,518],[410,411,412,413,421,468],[421,468,522,523],[414,421,468,519,525],[421,468,525],[285,307,407,421,468],[421,468,799],[307,407,421,468,855,856],[332,421,468],[407,421,468,849,854,855],[421,468,859,860],[61,307,421,468,850,855,869],[407,421,468,837,862],[60,407,421,468,863,866],[307,421,468,850,855,857,868,870,874],[60,421,468,872,873],[421,468,863],[250,307,407,421,468,877],[307,407,421,468,850,855,857,869],[421,468,876,878,879],[307,421,468,855],[421,468,855],[307,407,421,468,877],[60,307,407,421,468],[307,407,421,468,849,850,855,875,877,880,883,888,889,902,903],[250,421,468,799],[421,468,862,865,904],[421,468,889,901],[55,421,468,837,857,858,861,864,896,901,905,908,912,913,914,916,918,924,926],[307,407,421,468,843,851,854,855],[307,421,468,847],[284,307,332,407,421,468,846,847,848,849,854,855,857,927],[421,468,849,850,853,855,891,900],[307,407,421,468,842,854,855],[421,468,890],[407,421,468,850,855],[407,421,468,843,850,854,895],[307,332,407,421,468,842,854],[407,421,468,848,849,853,893,897,898,899],[407,421,468,843,850,851,852,854,855],[307,332,421,468,850,853,855],[250,421,468,854],[259,292,298,421,468],[421,468,839,840,841,850,854,855,894],[421,468,846,895,906,907],[332,407,421,468,855],[332,407,421,468],[421,468,838,839,840,841,844,846],[421,468,843],[421,468,845,846],[407,421,468,838,839,840,841,844,845],[421,468,881,882],[307,421,468,850,855,857,869],[421,468,892],[290,421,468],[271,307,421,468,909,910],[421,468,911],[307,421,468,857],[307,421,468,850,857],[284,307,407,421,468,843,850,851,852,854,855],[283,307,407,421,468,837,850,857,895,913],[284,285,407,421,468,799,915],[421,468,885,886,887],[407,421,468,884],[421,468,917],[407,421,468,496],[421,468,920,922,923],[421,468,919],[421,468,921],[407,421,468,849,854,920],[421,468,867],[307,332,407,421,468,850,854,855,857,892,893,895,896],[421,468,925],[421,468,534,536,537,538,539],[421,468,535],[407,421,468,534],[407,421,468,535],[421,468,534,536],[421,468,540],[407,421,468,543,545],[421,468,542,545,546,547,558,559],[421,468,543,544],[407,421,468,543],[421,468,557],[421,468,545],[421,468,560],[281,285,307,407,421,468,482,484,556,799,800,801,802],[421,468,803],[421,468,804,806,817],[421,468,800,801,805],[281,407,421,468,482,484,556,800,801,802],[421,468,482],[421,468,813,815,816],[407,421,468,807],[421,468,808,809,810,811,812],[307,421,468,807],[421,468,814],[407,421,468,814],[407,421,468,564,565],[421,468,587],[421,468,564,565],[421,468,564],[407,421,468,564,565,578],[407,421,468,578,581],[407,421,468,564],[421,468,581],[421,468,562,563,566,567,568,569,570,571,572,573,574,575,576,577,579,580,582,583,584,585,586,588,589,590],[421,468,564,584,595],[55,421,468,591,595,596,597,603,606],[421,468,564,593,594],[407,421,468,564,578],[421,468,564,592],[286,407,421,468,595],[421,468,598,599,600,601,602],[421,468,604,605],[421,468,937,938,940,941],[421,468,934,935,939],[421,468,935,938],[421,468,892,938],[297,421,468,938],[284,407,421,468,892,896,936,937,940],[407,421,468,850,854,857,895,915,927],[421,468,529],[421,468,976,978,982,985,987,989,991,993,995,999,1003,1007,1009,1011,1013,1015,1017,1019,1021,1023,1025,1027,1035,1040,1042,1044,1046,1048,1051,1053,1058,1062,1066,1068,1070,1072,1075,1077,1079,1082,1084,1088,1090,1092,1094,1096,1098,1100,1102,1104,1106,1109,1112,1114,1116,1120,1122,1125,1127,1129,1131,1135,1141,1145,1147,1149,1156,1158,1160,1162,1165],[421,468,976,1109],[421,468,977],[421,468,1115],[421,468,976,1092,1096,1109],[421,468,1097],[421,468,976,1092,1109],[421,468,981],[421,468,997,1003,1007,1013,1044,1096,1109],[421,468,1052],[421,468,1026],[421,468,1020],[421,468,1110,1111],[421,468,1109],[421,468,999,1003,1040,1046,1058,1094,1096,1109],[421,468,1126],[421,468,975,1109],[421,468,996],[421,468,978,985,991,995,999,1015,1027,1068,1070,1072,1094,1096,1100,1102,1104,1109],[421,468,1128],[421,468,989,999,1015,1109],[421,468,1130],[421,468,976,985,987,1051,1092,1096,1109],[421,468,988],[421,468,1113],[421,468,1107],[421,468,1099],[421,468,976,991,1109],[421,468,992],[421,468,1016],[421,468,1048,1094,1109,1133],[421,468,1035,1109,1133],[421,468,999,1007,1035,1048,1092,1096,1109,1132,1134],[421,468,1132,1133,1134],[421,468,1017,1109],[421,468,991,1048,1094,1096,1109,1138],[421,468,1048,1094,1109,1138],[421,468,1007,1048,1092,1096,1109,1137,1139],[421,468,1136,1137,1138,1139,1140],[421,468,1048,1094,1109,1143],[421,468,1035,1109,1143],[421,468,999,1007,1035,1048,1092,1096,1109,1142,1144],[421,468,1142,1143,1144],[421,468,994],[421,468,1117,1118,1119],[421,468,976,978,982,985,989,991,995,997,999,1003,1007,1009,1011,1013,1015,1019,1021,1023,1025,1027,1035,1042,1044,1048,1051,1068,1070,1072,1077,1079,1084,1088,1090,1094,1098,1100,1102,1104,1106,1109,1116],[421,468,976,978,982,985,989,991,995,997,999,1003,1007,1009,1011,1013,1015,1017,1019,1021,1023,1025,1027,1035,1042,1044,1048,1051,1068,1070,1072,1077,1079,1084,1088,1090,1094,1098,1100,1102,1104,1106,1109,1116],[421,468,999,1094,1109],[421,468,1095],[421,468,1036,1037,1038,1039],[421,468,1038,1048,1094,1096,1109],[421,468,1036,1040,1048,1094,1109],[421,468,991,1007,1023,1025,1035,1109],[421,468,997,999,1003,1007,1009,1013,1015,1036,1037,1039,1048,1094,1096,1098,1109],[421,468,1146],[421,468,989,999,1109],[421,468,1148],[421,468,982,985,987,989,995,1003,1007,1015,1042,1044,1051,1079,1094,1098,1104,1109,1116],[421,468,1024],[421,468,1000,1001,1002],[421,468,985,999,1000,1051,1109],[421,468,999,1000,1109],[421,468,1109,1151],[421,468,1150,1151,1152,1153,1154,1155],[421,468,991,1048,1094,1096,1109,1151],[421,468,991,1007,1035,1048,1109,1150],[421,468,1041],[421,468,1054,1055,1056,1057],[421,468,1048,1055,1094,1096,1109],[421,468,1003,1007,1009,1015,1046,1094,1096,1098,1109],[421,468,991,997,1007,1013,1023,1048,1054,1056,1096,1109],[421,468,990],[421,468,979,980,1047],[421,468,976,1094,1109],[421,468,979,980,982,985,989,991,993,995,1003,1007,1015,1040,1042,1044,1046,1051,1094,1096,1098,1109],[421,468,982,985,989,993,995,997,999,1003,1007,1013,1015,1040,1042,1051,1053,1058,1062,1066,1075,1079,1082,1084,1094,1096,1098,1109],[421,468,1087],[421,468,982,985,989,993,995,1003,1007,1009,1013,1015,1042,1051,1079,1092,1094,1096,1098,1109],[421,468,976,1085,1086,1092,1094,1109],[421,468,998],[421,468,1089],[421,468,1067],[421,468,1022],[421,468,1093],[421,468,976,985,1051,1092,1096,1109],[421,468,1059,1060,1061],[421,468,1048,1060,1094,1109],[421,468,1048,1060,1094,1096,1109],[421,468,991,997,1003,1007,1009,1013,1040,1048,1059,1061,1094,1096,1109],[421,468,1049,1050],[421,468,1048,1049,1094],[421,468,976,1048,1050,1096,1109],[421,468,1157],[421,468,995,999,1015,1109],[421,468,1073,1074],[421,468,1048,1073,1094,1096,1109],[421,468,985,987,991,997,1003,1007,1009,1013,1019,1021,1023,1025,1027,1048,1051,1068,1070,1072,1074,1094,1096,1109],[421,468,1121],[421,468,1063,1064,1065],[421,468,1048,1064,1094,1109],[421,468,1048,1064,1094,1096,1109],[421,468,991,997,1003,1007,1009,1013,1040,1048,1063,1065,1094,1096,1109],[421,468,1043],[421,468,986],[421,468,985,1051,1109],[421,468,983,984],[421,468,983,1048,1094],[421,468,976,984,1048,1096,1109],[421,468,1078],[421,468,976,978,991,993,999,1007,1019,1021,1023,1025,1035,1077,1092,1094,1096,1109],[421,468,1008],[421,468,1012],[421,468,976,1011,1092,1109],[421,468,1076],[421,468,1123,1124],[421,468,1080,1081],[421,468,1048,1080,1094,1096,1109],[421,468,985,987,991,997,1003,1007,1009,1013,1019,1021,1023,1025,1027,1048,1051,1068,1070,1072,1081,1094,1096,1109],[421,468,1159],[421,468,1003,1007,1015,1109],[421,468,1161],[421,468,995,999,1109],[421,468,978,982,989,991,993,995,1003,1007,1009,1013,1015,1019,1021,1023,1025,1027,1035,1042,1044,1068,1070,1072,1077,1079,1090,1094,1098,1100,1102,1104,1106,1107],[421,468,1107,1108],[421,468,976],[421,468,1045],[421,468,1091],[421,468,982,985,989,993,995,999,1003,1007,1009,1011,1013,1015,1042,1044,1051,1079,1084,1088,1090,1094,1096,1098,1109],[421,468,1018],[421,468,1069],[421,468,975],[421,468,991,1007,1017,1019,1021,1023,1025,1027,1028,1035],[421,468,991,1007,1017,1021,1028,1029,1035,1096],[421,468,1028,1029,1030,1031,1032,1033,1034],[421,468,1017],[421,468,1017,1035],[421,468,991,1007,1019,1021,1023,1027,1035,1096],[421,468,976,991,999,1007,1019,1021,1023,1025,1027,1031,1092,1096,1109],[421,468,991,1007,1033,1092,1096],[421,468,1083],[421,468,1014],[421,468,1163,1164],[421,468,982,989,995,1027,1042,1044,1053,1070,1072,1077,1100,1102,1106,1109,1116,1131,1147,1149,1158,1162,1163],[421,468,978,985,987,991,993,999,1003,1007,1009,1011,1013,1015,1019,1021,1023,1025,1035,1040,1048,1051,1058,1062,1066,1068,1075,1079,1082,1084,1088,1090,1094,1098,1104,1109,1127,1129,1135,1141,1145,1156,1160],[421,468,1101],[421,468,1071],[421,468,1004,1005,1006],[421,468,985,999,1004,1051,1109],[421,468,999,1004,1109],[421,468,1103],[421,468,1010],[421,468,1105],[421,468,957,958,959,960,961],[421,468,957,959],[421,468,482,516,554],[421,468,515,556],[421,468,482,516],[421,468,965,968],[421,468,965,966,967],[421,468,968],[421,468,479,482,516,548,549,550],[421,468,551,553,555],[421,468,970],[421,468,971],[421,468,1168,1172],[421,468,473,516,533],[421,468,498,556],[421,465,468],[421,467,468],[421,468,473,501],[421,468,469,474,479,487,498,509],[421,468,469,470,479,487],[416,417,418,421,468],[421,468,471,510],[421,468,472,473,480,488],[421,468,473,498,506],[421,468,474,476,479,487],[421,467,468,475],[421,468,476,477],[421,468,478,479],[421,467,468,479],[421,468,479,480,481,498,509],[421,468,479,480,481,494,498,501],[421,468,476,479,482,487,498,509],[421,468,479,480,482,483,487,498,506,509],[421,468,482,484,498,506,509],[421,468,479,485],[421,468,486,509,514],[421,468,476,479,487,498],[421,468,488],[421,468,489],[421,467,468,490],[421,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515],[421,468,492],[421,468,493],[421,468,479,494,495],[421,468,494,496,510,512],[421,468,479,498,499,501],[421,468,500,501],[421,468,498,499],[421,468,501],[421,468,502],[421,465,468,498,503],[421,468,479,504,505],[421,468,504,505],[421,468,473,487,498,506],[421,468,507],[468],[419,420,421,422,423,424,425,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515],[421,468,487,508],[421,468,482,493,509],[421,468,473,510],[421,468,498,511],[421,468,486,512],[421,468,513],[421,463,468],[421,463,468,479,481,490,498,501,509,512,514],[421,468,498,515],[421,468,534,754],[421,468,556,557],[421,468,482,556],[421,468,480,498,516],[421,468,482,516,552],[421,468,1183],[421,468,964,1174,1176,1178,1184],[421,468,483,487,498,506,516],[421,468,480,482,483,484,487,498,1174,1177,1178,1179,1180,1181,1182],[421,468,482,498,1183],[421,468,480,1177,1178],[421,468,509,1177],[421,468,1184,1185,1186,1187,1188],[421,468,1184,1185,1189],[421,468,1184,1185],[421,468,482,483,487,1174,1184],[421,468,644,645,646,647,648,649,650,651,652],[421,468,1190],[421,468,608],[421,468,615],[421,468,616],[421,468,615,616,621],[421,468,617,618,619,620,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742],[421,468,616,653],[421,468,616,647],[421,468,616,694],[421,468,611,612,613,614,615,616,621,743,744,745,746,750],[421,468,621],[421,468,613,748,749],[421,468,615,747],[421,468,616,621],[421,468,611,612],[421,468,516],[421,468,973,1170,1171],[421,468,482,498,516],[421,468,1168],[421,468,974,1169],[421,468,693],[421,468,1167],[62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,78,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,118,119,120,121,122,123,124,125,126,127,128,129,131,132,133,134,135,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,181,182,183,185,194,196,197,198,199,200,201,203,204,206,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,421,468],[107,421,468],[65,66,421,468],[62,63,64,66,421,468],[63,66,421,468],[66,107,421,468],[62,66,184,421,468],[64,65,66,421,468],[62,66,421,468],[66,421,468],[65,421,468],[62,65,107,421,468],[63,65,66,223,421,468],[65,66,223,421,468],[65,231,421,468],[63,65,66,421,468],[75,421,468],[98,421,468],[119,421,468],[65,66,107,421,468],[66,114,421,468],[65,66,107,125,421,468],[65,66,125,421,468],[66,166,421,468],[62,66,185,421,468],[191,193,421,468],[62,66,184,191,192,421,468],[184,185,193,421,468],[191,421,468],[62,66,191,192,193,421,468],[207,421,468],[202,421,468],[205,421,468],[63,65,185,186,187,188,421,468],[107,185,186,187,188,421,468],[185,187,421,468],[65,186,187,189,190,194,421,468],[62,65,421,468],[66,209,421,468],[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,108,109,110,111,112,113,115,116,117,118,119,120,121,122,123,124,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,421,468],[195,421,468],[421,435,439,468,509],[421,435,468,498,509],[421,430,468],[421,432,435,468,506,509],[421,468,487,506],[421,430,468,516],[421,432,435,468,487,509],[421,427,428,431,434,468,479,498,509],[421,435,442,468],[421,427,433,468],[421,435,456,457,468],[421,431,435,468,501,509,516],[421,456,468,516],[421,429,430,468,516],[421,435,468],[421,429,430,431,432,433,434,435,436,437,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,457,458,459,460,461,462,468],[421,435,450,468],[421,435,442,443,468],[421,433,435,443,444,468],[421,434,468],[421,427,430,435,468],[421,435,439,443,444,468],[421,439,468],[421,433,435,438,468,509],[421,427,432,435,442,468],[421,468,498],[421,430,435,456,468,514,516],[407,421,468,526,532,757,760,763,766,769,772,777,782,783,787,789,792,795,798,822,827,830,832,835],[407,421,468,556],[421,468,930,931],[183,250,407,421,468],[407,421,468,489,607,818,836,927,928,929,932],[407,421,468,531,561,607,761,784,785],[407,421,468,541,757,763,784,785,786],[407,421,468,531,541,609],[407,421,468,531,541,609,784,942],[407,421,468,773],[421,468,773,942],[407,421,468,561,607,610,752],[407,421,468,526,541,561,610,753,756],[421,468,751],[407,421,468,526,531,561,755],[421,468,531,541,610,942],[407,421,468,531,607],[407,421,468,788],[407,421,468,561,607,824],[407,421,468,823,824,825,826],[407,421,468,531,823],[407,421,468,531,823,824,942],[407,421,468,607,764],[407,421,468,764,765],[407,421,468,531],[407,421,468,561,607,761],[407,421,468,761,762],[421,468,531,761,942],[407,421,468,561,607,790],[407,421,468,790,791],[407,421,468,561,607,828],[407,421,468,828,829],[407,421,468,531,828,942],[407,421,468,561,607,833],[407,421,468,833,834],[407,421,468,607,796],[407,421,468,796,797],[407,421,468,561,607,823],[407,421,468,823,831],[407,421,468,561,607,751,779],[407,421,468,779,780,782],[407,421,468,531,778],[407,421,468,561,607,779],[421,468,531,778,779,942],[407,421,468,607,751,778],[407,421,468,532,778,781],[407,421,468,489,531],[421,468,531,778,942],[407,421,468,561,607,767],[407,421,468,767,768],[421,468,531,767,942],[407,421,468,561,607,773,774],[407,421,468,774,775,776],[407,421,468,473,531,773],[407,421,468,531,773,774,942],[407,421,468,607,793],[407,421,468,793,794],[421,468,531,793,942],[421,468,531,770,942],[407,421,468,607,770],[407,421,468,770,771],[407,421,468,473,489,607,818,819],[407,421,468,820,821],[407,421,468,480,489],[421,468,531,758,942],[407,421,468,561,607,758],[407,421,468,758,759],[407,421,468,530],[407],[250,407],[528,531,761,784],[531,541],[528,610,752],[528,531,541],[526,531,755],[531],[824],[531,823],[528,764],[528,531],[528,761],[528,790],[828],[833],[796],[823],[528,778,779],[528,531,778],[528,779],[778],[528,767],[773,774],[531,773],[793],[528,770],[528,758],[407,530]],"referencedMap":[[529,1],[528,2],[959,3],[957,4],[973,4],[1167,5],[332,4],[319,4],[56,4],[308,6],[309,6],[310,4],[311,7],[321,8],[312,6],[313,9],[314,4],[315,4],[316,6],[317,6],[318,6],[320,10],[328,11],[330,4],[327,4],[334,12],[331,4],[329,4],[325,13],[326,14],[333,15],[335,16],[322,4],[324,17],[323,18],[262,4],[265,19],[261,4],[884,4],[263,4],[264,4],[338,20],[339,20],[340,20],[341,20],[342,20],[343,20],[344,20],[337,21],[345,20],[359,22],[346,20],[336,4],[347,20],[348,20],[349,20],[350,20],[351,20],[352,20],[353,20],[354,20],[355,20],[356,20],[357,20],[358,20],[367,23],[365,24],[364,4],[363,4],[366,25],[407,26],[57,4],[58,4],[59,4],[866,27],[61,28],[872,29],[871,30],[251,31],[252,28],[387,4],[281,4],[282,4],[388,32],[253,4],[389,4],[390,33],[60,4],[255,34],[256,35],[254,36],[257,34],[258,4],[260,37],[272,38],[273,4],[278,39],[274,4],[275,4],[276,4],[277,4],[279,4],[280,40],[286,41],[289,42],[287,4],[288,4],[307,43],[290,4],[291,4],[915,44],[271,45],[269,46],[267,47],[268,48],[270,4],[298,49],[292,4],[301,50],[294,51],[299,52],[297,53],[300,54],[295,55],[296,56],[284,57],[303,58],[285,59],[305,60],[306,61],[293,4],[302,4],[259,4],[266,62],[304,63],[373,64],[368,4],[374,65],[369,66],[370,67],[371,68],[372,69],[375,70],[380,71],[378,72],[379,72],[386,73],[376,4],[377,74],[381,71],[383,75],[385,76],[384,77],[399,78],[392,79],[393,80],[394,80],[395,81],[396,81],[397,80],[398,80],[391,82],[401,83],[400,84],[403,85],[402,86],[404,87],[360,88],[362,89],[283,4],[361,57],[405,90],[382,91],[406,92],[408,7],[520,93],[521,94],[525,95],[409,4],[415,96],[518,97],[519,98],[410,4],[411,4],[414,99],[412,4],[413,4],[523,4],[524,100],[522,101],[526,102],[799,103],[837,104],[857,105],[858,106],[859,4],[860,107],[861,108],[870,109],[863,110],[867,111],[875,112],[873,7],[874,113],[864,114],[876,4],[878,115],[879,116],[880,117],[869,118],[865,119],[889,120],[877,121],[904,122],[862,123],[905,124],[902,125],[903,7],[927,126],[852,127],[848,128],[850,129],[901,130],[843,131],[891,132],[890,4],[851,133],[898,134],[855,135],[899,4],[900,136],[853,137],[854,138],[849,139],[847,140],[842,4],[895,141],[908,142],[906,7],[838,7],[894,143],[839,14],[840,106],[841,144],[845,145],[844,146],[907,147],[846,148],[883,149],[881,115],[882,150],[892,14],[893,151],[896,152],[911,153],[912,154],[909,155],[910,156],[913,157],[914,158],[916,159],[888,160],[885,161],[886,6],[887,150],[918,162],[917,163],[924,164],[856,7],[920,165],[919,7],[922,166],[921,4],[923,167],[868,168],[897,169],[926,170],[925,7],[540,171],[536,172],[535,173],[537,4],[538,174],[539,175],[541,176],[542,4],[546,177],[560,178],[543,7],[545,179],[544,4],[547,180],[558,181],[559,182],[561,183],[803,184],[804,185],[818,186],[806,187],[805,188],[800,189],[801,4],[802,4],[817,190],[808,191],[809,191],[810,191],[811,191],[813,192],[812,191],[814,193],[815,194],[807,4],[816,195],[562,4],[563,4],[566,196],[588,197],[567,4],[568,4],[569,7],[571,4],[570,4],[589,4],[572,4],[573,198],[574,4],[575,7],[576,4],[577,199],[579,200],[580,4],[582,201],[583,200],[584,202],[590,203],[585,199],[586,199],[591,204],[596,205],[607,206],[587,4],[578,199],[595,207],[564,4],[581,208],[593,209],[594,4],[592,4],[597,210],[598,7],[603,211],[599,7],[600,7],[601,7],[602,7],[565,4],[605,202],[604,4],[606,212],[942,213],[940,214],[934,7],[935,4],[939,215],[936,216],[941,217],[938,218],[937,219],[530,220],[527,4],[1166,221],[977,222],[978,223],[1115,222],[1116,224],[1097,225],[1098,226],[981,227],[982,228],[1052,229],[1053,230],[1026,222],[1027,231],[1020,222],[1021,232],[1112,233],[1110,234],[1111,4],[1126,235],[1127,236],[996,237],[997,238],[1128,239],[1129,240],[1130,241],[1131,242],[988,243],[989,244],[1114,245],[1113,246],[1099,222],[1100,247],[992,248],[993,249],[1016,4],[1017,250],[1134,251],[1132,252],[1133,253],[1135,254],[1136,255],[1139,256],[1137,257],[1140,234],[1138,258],[1141,259],[1144,260],[1142,261],[1143,262],[1145,263],[994,243],[995,264],[1120,265],[1117,266],[1118,267],[1119,4],[1095,268],[1096,269],[1040,270],[1039,271],[1037,272],[1036,273],[1038,274],[1147,275],[1146,276],[1149,277],[1148,278],[1025,279],[1024,222],[1003,280],[1001,281],[1000,227],[1002,282],[1152,283],[1156,284],[1150,285],[1151,286],[1153,283],[1154,283],[1155,283],[1042,287],[1041,227],[1058,288],[1056,289],[1057,234],[1054,290],[1055,291],[991,292],[990,222],[1048,293],[979,222],[980,294],[1047,295],[1085,296],[1088,297],[1086,298],[1087,299],[999,300],[998,222],[1090,301],[1089,227],[1068,302],[1067,222],[1023,303],[1022,222],[1094,304],[1093,305],[1062,306],[1061,307],[1059,308],[1060,309],[1051,310],[1050,311],[1049,312],[1158,313],[1157,314],[1075,315],[1074,316],[1073,317],[1122,318],[1121,4],[1066,319],[1065,320],[1063,321],[1064,322],[1044,323],[1043,227],[987,324],[986,325],[985,326],[984,327],[983,328],[1079,329],[1078,330],[1009,331],[1008,227],[1013,332],[1012,333],[1077,334],[1076,222],[1123,4],[1125,335],[1124,4],[1082,336],[1081,337],[1080,338],[1160,339],[1159,340],[1162,341],[1161,342],[1108,343],[1109,344],[1107,345],[1046,346],[1045,4],[1092,347],[1091,348],[1019,349],[1018,222],[1070,350],[1069,222],[976,351],[975,4],[1029,352],[1030,353],[1035,354],[1028,355],[1032,356],[1031,357],[1033,358],[1034,359],[1084,360],[1083,227],[1015,361],[1014,227],[1165,362],[1164,363],[1163,364],[1102,365],[1101,222],[1072,366],[1071,222],[1007,367],[1005,368],[1004,227],[1006,369],[1104,370],[1103,222],[1011,371],[1010,222],[1106,372],[1105,222],[962,373],[958,3],[960,374],[961,3],[963,4],[555,375],[929,376],[554,377],[964,4],[969,378],[968,379],[967,380],[965,4],[551,381],[556,382],[552,4],[970,4],[971,383],[972,384],[1173,385],[966,4],[534,386],[1174,4],[533,4],[819,387],[465,388],[466,388],[467,389],[468,390],[469,391],[470,392],[416,4],[419,393],[417,4],[418,4],[471,394],[472,395],[473,396],[474,397],[475,398],[476,399],[477,399],[478,400],[479,401],[480,402],[481,403],[422,4],[482,404],[483,405],[484,406],[485,407],[486,408],[487,409],[488,410],[489,411],[490,412],[491,413],[492,414],[493,415],[494,416],[495,416],[496,417],[497,4],[498,418],[500,419],[499,420],[501,421],[502,422],[503,423],[504,424],[505,425],[506,426],[507,427],[421,428],[420,4],[516,429],[508,430],[509,431],[510,432],[511,433],[512,434],[513,435],[423,4],[424,4],[425,4],[464,436],[514,437],[515,438],[755,439],[754,440],[557,441],[549,4],[550,4],[548,442],[553,443],[1175,4],[1184,444],[1176,4],[1179,445],[1182,446],[1183,447],[1177,448],[1180,449],[1178,450],[1189,451],[1186,452],[1188,4],[1187,453],[1185,454],[653,455],[644,4],[645,4],[646,4],[647,4],[648,4],[649,4],[650,4],[651,4],[652,4],[1190,4],[1191,456],[609,457],[608,4],[426,4],[974,4],[614,4],[616,458],[735,459],[739,459],[738,459],[736,459],[737,459],[740,459],[617,459],[629,459],[618,459],[631,459],[633,459],[626,459],[627,459],[628,459],[632,459],[634,459],[619,459],[630,459],[620,459],[622,460],[623,459],[624,459],[625,459],[641,459],[640,459],[743,461],[635,459],[637,459],[636,459],[638,459],[639,459],[742,459],[741,459],[642,459],[654,462],[655,462],[657,459],[703,459],[702,459],[723,459],[658,462],[700,459],[704,459],[659,459],[660,459],[661,462],[705,459],[699,462],[656,462],[706,459],[662,462],[707,459],[663,462],[687,459],[664,459],[708,459],[665,459],[697,462],[667,459],[668,459],[709,463],[670,459],[672,459],[673,459],[679,459],[680,459],[681,459],[674,462],[711,459],[698,462],[710,462],[675,459],[676,459],[712,459],[677,459],[669,462],[713,459],[696,459],[714,459],[678,462],[682,459],[683,459],[701,462],[715,459],[716,459],[695,464],[671,459],[717,462],[718,459],[719,459],[720,459],[721,462],[684,459],[722,459],[686,462],[688,459],[685,462],[666,459],[689,459],[692,459],[690,459],[691,459],[643,459],[725,459],[724,459],[726,459],[733,459],[727,459],[728,459],[730,459],[731,459],[729,459],[734,459],[732,459],[751,465],[749,466],[750,467],[748,468],[747,459],[746,469],[613,4],[615,4],[611,4],[744,4],[745,470],[621,458],[612,4],[517,471],[1172,472],[1181,473],[928,189],[1169,474],[1170,475],[1171,4],[694,476],[693,4],[1168,477],[55,4],[250,478],[223,4],[201,479],[199,479],[114,480],[65,481],[64,482],[200,483],[185,484],[107,485],[63,486],[62,487],[249,482],[214,488],[213,488],[125,489],[221,480],[222,480],[224,490],[225,480],[226,487],[227,480],[198,480],[228,480],[229,491],[230,480],[231,488],[232,492],[233,480],[234,480],[235,480],[236,480],[237,488],[238,480],[239,480],[240,480],[241,480],[242,493],[243,480],[244,480],[245,480],[246,480],[247,480],[67,487],[68,487],[69,487],[70,487],[71,487],[72,487],[73,487],[74,480],[76,494],[77,487],[75,487],[78,487],[79,487],[80,487],[81,487],[82,487],[83,487],[84,480],[85,487],[86,487],[87,487],[88,487],[89,487],[90,480],[91,487],[92,487],[93,487],[94,487],[95,487],[96,487],[97,480],[99,495],[98,487],[100,487],[101,487],[102,487],[103,487],[104,493],[105,480],[106,480],[120,496],[108,497],[109,487],[110,487],[111,480],[112,487],[113,487],[115,498],[116,487],[117,487],[118,487],[119,487],[121,487],[122,487],[123,487],[124,487],[126,499],[127,487],[128,487],[129,487],[130,480],[131,487],[132,500],[133,500],[134,500],[135,480],[136,487],[137,487],[138,487],[143,487],[139,487],[140,480],[141,487],[142,480],[144,487],[145,487],[146,487],[147,487],[148,487],[149,487],[150,480],[151,487],[152,487],[153,487],[154,487],[155,487],[156,487],[157,487],[158,487],[159,487],[160,487],[161,487],[162,487],[163,487],[164,487],[165,487],[166,487],[167,501],[168,487],[169,487],[170,487],[171,487],[172,487],[173,487],[174,480],[175,480],[176,480],[177,480],[178,480],[179,487],[180,487],[181,487],[182,487],[248,480],[184,502],[207,503],[202,503],[193,504],[191,505],[205,506],[194,507],[208,508],[203,509],[204,506],[206,510],[192,4],[197,4],[189,511],[190,512],[187,4],[188,513],[186,487],[195,514],[66,515],[215,4],[216,4],[217,4],[218,4],[219,4],[220,4],[209,4],[212,488],[211,4],[210,516],[183,517],[196,518],[52,4],[53,4],[9,4],[10,4],[14,4],[13,4],[2,4],[15,4],[16,4],[17,4],[18,4],[19,4],[20,4],[21,4],[22,4],[3,4],[4,4],[23,4],[27,4],[24,4],[25,4],[26,4],[28,4],[29,4],[30,4],[5,4],[31,4],[32,4],[33,4],[34,4],[6,4],[38,4],[35,4],[36,4],[37,4],[39,4],[7,4],[40,4],[45,4],[46,4],[41,4],[42,4],[43,4],[44,4],[8,4],[54,4],[50,4],[47,4],[48,4],[49,4],[1,4],[51,4],[12,4],[11,4],[442,519],[452,520],[441,519],[462,521],[433,522],[432,523],[461,471],[455,524],[460,525],[435,526],[449,527],[434,528],[458,529],[430,530],[429,471],[459,531],[431,532],[436,533],[437,4],[440,533],[427,4],[463,534],[453,535],[444,536],[445,537],[447,538],[443,539],[446,540],[456,471],[438,541],[439,542],[448,543],[428,544],[451,535],[450,533],[454,4],[457,545],[836,546],[930,547],[932,548],[931,549],[933,550],[786,551],[785,7],[787,552],[784,553],[943,554],[773,7],[776,555],[944,556],[753,557],[757,558],[610,553],[752,559],[756,560],[945,561],[788,562],[789,563],[826,564],[825,564],[827,565],[824,566],[946,567],[765,568],[766,569],[764,570],[762,571],[763,572],[761,570],[947,573],[791,574],[792,575],[790,570],[829,576],[830,577],[828,570],[948,578],[834,579],[835,580],[833,570],[797,581],[798,582],[796,570],[831,583],[832,584],[823,570],[780,585],[783,586],[779,587],[949,588],[950,589],[781,590],[782,591],[778,592],[951,593],[768,594],[769,595],[767,570],[952,596],[775,597],[777,598],[774,599],[953,600],[794,601],[795,602],[793,570],[954,603],[955,604],[771,605],[772,606],[770,570],[820,607],[822,608],[821,609],[956,610],[759,611],[760,612],[758,570],[532,570],[531,613]],"exportedModulesMap":[[529,1],[528,2],[959,3],[957,4],[973,4],[1167,5],[332,4],[319,4],[56,4],[308,6],[309,6],[310,4],[311,7],[321,8],[312,6],[313,9],[314,4],[315,4],[316,6],[317,6],[318,6],[320,10],[328,11],[330,4],[327,4],[334,12],[331,4],[329,4],[325,13],[326,14],[333,15],[335,16],[322,4],[324,17],[323,18],[262,4],[265,19],[261,4],[884,4],[263,4],[264,4],[338,20],[339,20],[340,20],[341,20],[342,20],[343,20],[344,20],[337,21],[345,20],[359,22],[346,20],[336,4],[347,20],[348,20],[349,20],[350,20],[351,20],[352,20],[353,20],[354,20],[355,20],[356,20],[357,20],[358,20],[367,23],[365,24],[364,4],[363,4],[366,25],[407,26],[57,4],[58,4],[59,4],[866,27],[61,28],[872,29],[871,30],[251,31],[252,28],[387,4],[281,4],[282,4],[388,32],[253,4],[389,4],[390,33],[60,4],[255,34],[256,35],[254,36],[257,34],[258,4],[260,37],[272,38],[273,4],[278,39],[274,4],[275,4],[276,4],[277,4],[279,4],[280,40],[286,41],[289,42],[287,4],[288,4],[307,43],[290,4],[291,4],[915,44],[271,45],[269,46],[267,47],[268,48],[270,4],[298,49],[292,4],[301,50],[294,51],[299,52],[297,53],[300,54],[295,55],[296,56],[284,57],[303,58],[285,59],[305,60],[306,61],[293,4],[302,4],[259,4],[266,62],[304,63],[373,64],[368,4],[374,65],[369,66],[370,67],[371,68],[372,69],[375,70],[380,71],[378,72],[379,72],[386,73],[376,4],[377,74],[381,71],[383,75],[385,76],[384,77],[399,78],[392,79],[393,80],[394,80],[395,81],[396,81],[397,80],[398,80],[391,82],[401,83],[400,84],[403,85],[402,86],[404,87],[360,88],[362,89],[283,4],[361,57],[405,90],[382,91],[406,92],[408,7],[520,93],[521,94],[525,95],[409,4],[415,96],[518,97],[519,98],[410,4],[411,4],[414,99],[412,4],[413,4],[523,4],[524,100],[522,101],[526,102],[799,103],[837,104],[857,105],[858,106],[859,4],[860,107],[861,108],[870,109],[863,110],[867,111],[875,112],[873,7],[874,113],[864,114],[876,4],[878,115],[879,116],[880,117],[869,118],[865,119],[889,120],[877,121],[904,122],[862,123],[905,124],[902,125],[903,7],[927,126],[852,127],[848,128],[850,129],[901,130],[843,131],[891,132],[890,4],[851,133],[898,134],[855,135],[899,4],[900,136],[853,137],[854,138],[849,139],[847,140],[842,4],[895,141],[908,142],[906,7],[838,7],[894,143],[839,14],[840,106],[841,144],[845,145],[844,146],[907,147],[846,148],[883,149],[881,115],[882,150],[892,14],[893,151],[896,152],[911,153],[912,154],[909,155],[910,156],[913,157],[914,158],[916,159],[888,160],[885,161],[886,6],[887,150],[918,162],[917,163],[924,164],[856,7],[920,165],[919,7],[922,166],[921,4],[923,167],[868,168],[897,169],[926,170],[925,7],[540,171],[536,172],[535,173],[537,4],[538,174],[539,175],[541,176],[542,4],[546,177],[560,178],[543,7],[545,179],[544,4],[547,180],[558,181],[559,182],[561,183],[803,184],[804,185],[818,186],[806,187],[805,188],[800,189],[801,4],[802,4],[817,190],[808,191],[809,191],[810,191],[811,191],[813,192],[812,191],[814,193],[815,194],[807,4],[816,195],[562,4],[563,4],[566,196],[588,197],[567,4],[568,4],[569,7],[571,4],[570,4],[589,4],[572,4],[573,198],[574,4],[575,7],[576,4],[577,199],[579,200],[580,4],[582,201],[583,200],[584,202],[590,203],[585,199],[586,199],[591,204],[596,205],[607,206],[587,4],[578,199],[595,207],[564,4],[581,208],[593,209],[594,4],[592,4],[597,210],[598,7],[603,211],[599,7],[600,7],[601,7],[602,7],[565,4],[605,202],[604,4],[606,212],[942,213],[940,214],[934,7],[935,4],[939,215],[936,216],[941,217],[938,218],[937,219],[530,220],[527,4],[1166,221],[977,222],[978,223],[1115,222],[1116,224],[1097,225],[1098,226],[981,227],[982,228],[1052,229],[1053,230],[1026,222],[1027,231],[1020,222],[1021,232],[1112,233],[1110,234],[1111,4],[1126,235],[1127,236],[996,237],[997,238],[1128,239],[1129,240],[1130,241],[1131,242],[988,243],[989,244],[1114,245],[1113,246],[1099,222],[1100,247],[992,248],[993,249],[1016,4],[1017,250],[1134,251],[1132,252],[1133,253],[1135,254],[1136,255],[1139,256],[1137,257],[1140,234],[1138,258],[1141,259],[1144,260],[1142,261],[1143,262],[1145,263],[994,243],[995,264],[1120,265],[1117,266],[1118,267],[1119,4],[1095,268],[1096,269],[1040,270],[1039,271],[1037,272],[1036,273],[1038,274],[1147,275],[1146,276],[1149,277],[1148,278],[1025,279],[1024,222],[1003,280],[1001,281],[1000,227],[1002,282],[1152,283],[1156,284],[1150,285],[1151,286],[1153,283],[1154,283],[1155,283],[1042,287],[1041,227],[1058,288],[1056,289],[1057,234],[1054,290],[1055,291],[991,292],[990,222],[1048,293],[979,222],[980,294],[1047,295],[1085,296],[1088,297],[1086,298],[1087,299],[999,300],[998,222],[1090,301],[1089,227],[1068,302],[1067,222],[1023,303],[1022,222],[1094,304],[1093,305],[1062,306],[1061,307],[1059,308],[1060,309],[1051,310],[1050,311],[1049,312],[1158,313],[1157,314],[1075,315],[1074,316],[1073,317],[1122,318],[1121,4],[1066,319],[1065,320],[1063,321],[1064,322],[1044,323],[1043,227],[987,324],[986,325],[985,326],[984,327],[983,328],[1079,329],[1078,330],[1009,331],[1008,227],[1013,332],[1012,333],[1077,334],[1076,222],[1123,4],[1125,335],[1124,4],[1082,336],[1081,337],[1080,338],[1160,339],[1159,340],[1162,341],[1161,342],[1108,343],[1109,344],[1107,345],[1046,346],[1045,4],[1092,347],[1091,348],[1019,349],[1018,222],[1070,350],[1069,222],[976,351],[975,4],[1029,352],[1030,353],[1035,354],[1028,355],[1032,356],[1031,357],[1033,358],[1034,359],[1084,360],[1083,227],[1015,361],[1014,227],[1165,362],[1164,363],[1163,364],[1102,365],[1101,222],[1072,366],[1071,222],[1007,367],[1005,368],[1004,227],[1006,369],[1104,370],[1103,222],[1011,371],[1010,222],[1106,372],[1105,222],[962,373],[958,3],[960,374],[961,3],[963,4],[555,375],[929,376],[554,377],[964,4],[969,378],[968,379],[967,380],[965,4],[551,381],[556,382],[552,4],[970,4],[971,383],[972,384],[1173,385],[966,4],[534,386],[1174,4],[533,4],[819,387],[465,388],[466,388],[467,389],[468,390],[469,391],[470,392],[416,4],[419,393],[417,4],[418,4],[471,394],[472,395],[473,396],[474,397],[475,398],[476,399],[477,399],[478,400],[479,401],[480,402],[481,403],[422,4],[482,404],[483,405],[484,406],[485,407],[486,408],[487,409],[488,410],[489,411],[490,412],[491,413],[492,414],[493,415],[494,416],[495,416],[496,417],[497,4],[498,418],[500,419],[499,420],[501,421],[502,422],[503,423],[504,424],[505,425],[506,426],[507,427],[421,428],[420,4],[516,429],[508,430],[509,431],[510,432],[511,433],[512,434],[513,435],[423,4],[424,4],[425,4],[464,436],[514,437],[515,438],[755,439],[754,440],[557,441],[549,4],[550,4],[548,442],[553,443],[1175,4],[1184,444],[1176,4],[1179,445],[1182,446],[1183,447],[1177,448],[1180,449],[1178,450],[1189,451],[1186,452],[1188,4],[1187,453],[1185,454],[653,455],[644,4],[645,4],[646,4],[647,4],[648,4],[649,4],[650,4],[651,4],[652,4],[1190,4],[1191,456],[609,457],[608,4],[426,4],[974,4],[614,4],[616,458],[735,459],[739,459],[738,459],[736,459],[737,459],[740,459],[617,459],[629,459],[618,459],[631,459],[633,459],[626,459],[627,459],[628,459],[632,459],[634,459],[619,459],[630,459],[620,459],[622,460],[623,459],[624,459],[625,459],[641,459],[640,459],[743,461],[635,459],[637,459],[636,459],[638,459],[639,459],[742,459],[741,459],[642,459],[654,462],[655,462],[657,459],[703,459],[702,459],[723,459],[658,462],[700,459],[704,459],[659,459],[660,459],[661,462],[705,459],[699,462],[656,462],[706,459],[662,462],[707,459],[663,462],[687,459],[664,459],[708,459],[665,459],[697,462],[667,459],[668,459],[709,463],[670,459],[672,459],[673,459],[679,459],[680,459],[681,459],[674,462],[711,459],[698,462],[710,462],[675,459],[676,459],[712,459],[677,459],[669,462],[713,459],[696,459],[714,459],[678,462],[682,459],[683,459],[701,462],[715,459],[716,459],[695,464],[671,459],[717,462],[718,459],[719,459],[720,459],[721,462],[684,459],[722,459],[686,462],[688,459],[685,462],[666,459],[689,459],[692,459],[690,459],[691,459],[643,459],[725,459],[724,459],[726,459],[733,459],[727,459],[728,459],[730,459],[731,459],[729,459],[734,459],[732,459],[751,465],[749,466],[750,467],[748,468],[747,459],[746,469],[613,4],[615,4],[611,4],[744,4],[745,470],[621,458],[612,4],[517,471],[1172,472],[1181,473],[928,189],[1169,474],[1170,475],[1171,4],[694,476],[693,4],[1168,477],[55,4],[250,478],[223,4],[201,479],[199,479],[114,480],[65,481],[64,482],[200,483],[185,484],[107,485],[63,486],[62,487],[249,482],[214,488],[213,488],[125,489],[221,480],[222,480],[224,490],[225,480],[226,487],[227,480],[198,480],[228,480],[229,491],[230,480],[231,488],[232,492],[233,480],[234,480],[235,480],[236,480],[237,488],[238,480],[239,480],[240,480],[241,480],[242,493],[243,480],[244,480],[245,480],[246,480],[247,480],[67,487],[68,487],[69,487],[70,487],[71,487],[72,487],[73,487],[74,480],[76,494],[77,487],[75,487],[78,487],[79,487],[80,487],[81,487],[82,487],[83,487],[84,480],[85,487],[86,487],[87,487],[88,487],[89,487],[90,480],[91,487],[92,487],[93,487],[94,487],[95,487],[96,487],[97,480],[99,495],[98,487],[100,487],[101,487],[102,487],[103,487],[104,493],[105,480],[106,480],[120,496],[108,497],[109,487],[110,487],[111,480],[112,487],[113,487],[115,498],[116,487],[117,487],[118,487],[119,487],[121,487],[122,487],[123,487],[124,487],[126,499],[127,487],[128,487],[129,487],[130,480],[131,487],[132,500],[133,500],[134,500],[135,480],[136,487],[137,487],[138,487],[143,487],[139,487],[140,480],[141,487],[142,480],[144,487],[145,487],[146,487],[147,487],[148,487],[149,487],[150,480],[151,487],[152,487],[153,487],[154,487],[155,487],[156,487],[157,487],[158,487],[159,487],[160,487],[161,487],[162,487],[163,487],[164,487],[165,487],[166,487],[167,501],[168,487],[169,487],[170,487],[171,487],[172,487],[173,487],[174,480],[175,480],[176,480],[177,480],[178,480],[179,487],[180,487],[181,487],[182,487],[248,480],[184,502],[207,503],[202,503],[193,504],[191,505],[205,506],[194,507],[208,508],[203,509],[204,506],[206,510],[192,4],[197,4],[189,511],[190,512],[187,4],[188,513],[186,487],[195,514],[66,515],[215,4],[216,4],[217,4],[218,4],[219,4],[220,4],[209,4],[212,488],[211,4],[210,516],[183,517],[196,518],[52,4],[53,4],[9,4],[10,4],[14,4],[13,4],[2,4],[15,4],[16,4],[17,4],[18,4],[19,4],[20,4],[21,4],[22,4],[3,4],[4,4],[23,4],[27,4],[24,4],[25,4],[26,4],[28,4],[29,4],[30,4],[5,4],[31,4],[32,4],[33,4],[34,4],[6,4],[38,4],[35,4],[36,4],[37,4],[39,4],[7,4],[40,4],[45,4],[46,4],[41,4],[42,4],[43,4],[44,4],[8,4],[54,4],[50,4],[47,4],[48,4],[49,4],[1,4],[51,4],[12,4],[11,4],[442,519],[452,520],[441,519],[462,521],[433,522],[432,523],[461,471],[455,524],[460,525],[435,526],[449,527],[434,528],[458,529],[430,530],[429,471],[459,531],[431,532],[436,533],[437,4],[440,533],[427,4],[463,534],[453,535],[444,536],[445,537],[447,538],[443,539],[446,540],[456,471],[438,541],[439,542],[448,543],[428,544],[451,535],[450,533],[454,4],[457,545],[836,546],[930,614],[932,548],[931,615],[786,616],[785,614],[784,617],[753,618],[610,619],[756,620],[788,621],[826,622],[825,622],[824,623],[765,624],[764,625],[762,626],[761,625],[791,627],[790,625],[829,628],[828,621],[834,629],[833,621],[797,630],[796,621],[831,631],[823,625],[780,632],[779,633],[949,634],[781,635],[778,621],[768,636],[767,625],[775,637],[774,638],[794,639],[793,621],[771,640],[770,625],[759,641],[758,625],[531,642]],"semanticDiagnosticsPerFile":[52,53,9,10,14,13,2,15,16,17,18,19,20,21,22,3,4,23,27,24,25,26,28,29,30,5,31,32,33,34,6,38,35,36,37,39,7,40,45,46,41,42,43,44,8,54,50,47,48,49,1,51,12,11]},"version":"5.3.3"} \ No newline at end of file diff --git a/backend/uploads/843b1def-80bc-4339-9795-5a792512b1f4.png b/backend/uploads/843b1def-80bc-4339-9795-5a792512b1f4.png new file mode 100644 index 0000000..7b64fd2 Binary files /dev/null and b/backend/uploads/843b1def-80bc-4339-9795-5a792512b1f4.png differ diff --git a/backend/uploads/bba131c5-d294-46ae-a944-f07d0efe24fa.png b/backend/uploads/bba131c5-d294-46ae-a944-f07d0efe24fa.png new file mode 100644 index 0000000..7b64fd2 Binary files /dev/null and b/backend/uploads/bba131c5-d294-46ae-a944-f07d0efe24fa.png differ diff --git a/backend/uploads/d45cadcc-795c-4a2c-99c6-d08119c8ce7b.png b/backend/uploads/d45cadcc-795c-4a2c-99c6-d08119c8ce7b.png new file mode 100644 index 0000000..7b64fd2 Binary files /dev/null and b/backend/uploads/d45cadcc-795c-4a2c-99c6-d08119c8ce7b.png differ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d17f21f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,74 @@ +version: '3.8' + +services: + mysql: + image: mysql:8.0 + container_name: yuzhiran-mysql + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123} + MYSQL_DATABASE: yuzhiran + MYSQL_USER: yuzhiran + MYSQL_PASSWORD: ${MYSQL_PASSWORD:-yuzhiran123} + ports: + - "3306:3306" + volumes: + - mysql_data:/var/lib/mysql + - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 10s + timeout: 5s + retries: 5 + + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: yuzhiran-backend + restart: unless-stopped + ports: + - "4000:4000" + environment: + NODE_ENV: production + PORT: 4000 + DATABASE_URL: mysql://yuzhiran:${MYSQL_PASSWORD:-yuzhiran123}@mysql:3306/yuzhiran + JWT_SECRET: ${JWT_SECRET:-yuzhiran-jwt-secret-2024} + volumes: + - ./backend/uploads:/app/uploads + depends_on: + mysql: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "--spider", "http://localhost:4000/api/docs"] + interval: 30s + timeout: 10s + retries: 3 + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + container_name: yuzhiran-frontend + restart: unless-stopped + ports: + - "3000:3000" + environment: + NODE_ENV: production + NEXT_PUBLIC_API_URL: http://localhost:4000 + depends_on: + - backend + + # Uncomment when Redis is available: + # redis: + # image: redis:7-alpine + # container_name: yuzhiran-redis + # restart: unless-stopped + # ports: + # - "6379:6379" + # volumes: + # - redis_data:/data + +volumes: + mysql_data: + # redis_data: diff --git a/docs/archive/progress-2026-05-12-before-notifications.md b/docs/archive/progress-2026-05-12-before-notifications.md new file mode 100644 index 0000000..83fab6b --- /dev/null +++ b/docs/archive/progress-2026-05-12-before-notifications.md @@ -0,0 +1,92 @@ +# 项目进度追踪 + +> 每次完成任务后更新此文件。旧版归档到 `docs/archive/`。 + +--- + +## Phase 1: 基础框架搭建 ✅ 已完成 + +### 后端 +- [x] NestJS 模块化架构搭建 +- [x] JWT 认证(login/register) +- [x] TypeORM + PostgreSQL 数据库连接 +- [x] 全部 92 单元测试 + 13 e2e 通过 +- [x] CORS 配置(`origin: true`, `maxAge: 0`) + +### 前端 +- [x] Next.js App Router + shadcn/ui 集成 +- [x] 暗黑模式(`next-themes` + Tailwind class 策略) +- [x] 导航栏激活态高亮(`usePathname()`) +- [x] 错误边界组件(`not-found.tsx`, `error.tsx`, `global-error.tsx`) +- [x] Favicon 配置(png + svg) +- [x] 全站 `text-gray-*` → CSS 变量替换(35+ 页面) +- [x] 全站 `bg-gray-*` / `border-gray-*` → CSS 变量替换 + +### 页面布局统一化 +- [x] 容器标准:`max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12` +- [x] 标题标准:`text-3xl font-bold text-foreground` +- [x] 副标题标准:`text-muted-foreground` +- [x] 法律/文本页:`max-w-3xl`(长文可读性) +- [x] my/* 子页容器统一(`max-w-4xl/2xl` → `max-w-7xl`) +- [x] admin/enterprise 容器统一(`max-w-6xl` → `max-w-7xl`) +- [x] users/[id] 容器统一(`max-w-4xl` → `max-w-7xl`) + +### 测试 +- [x] search.service 测试(新增) +- [x] tools.service 测试(新增) +- [x] users.service 测试(新增、含 bug 修复验证) + +--- + +## Phase 2: 功能补全 ✅ 已完成 + +### 缺失页面补充 +- [x] `/community/[id]` 帖子详情页(含评论) +- [x] `/admin/courses/new` & `[id]` 课程新建/编辑 +- [x] `/admin/prompts/new` & `[id]` 提示词新建/编辑 +- [x] `/admin/contents/new` & `[id]` 内容新建/编辑 +- [x] `/admin/tools/new` & `[id]` 工具新建/编辑 + +### Sandbox 沙盒 +- [x] 流式 API 集成(`ReadableStream`) +- [x] 模型选择器(URL query 预设) +- [x] 明暗切换 +- [x] 固定头尾布局 `h-[calc(100vh-4rem)]` + +### 企业版模块 +- [x] 编辑组织 UI +- [x] 截止日期选择器 +- [x] 管理员角色校验(`ForbiddenException`) + +### 静态构建修复 +- [x] 所有动态路由添加 `generateStaticParams()` +- [x] 共修复 11 个动态路由目录(users, admin/courses, admin/contents, admin/prompts, admin/tools, admin/enterprise, admin/enterprise/report, circles, community, contents, courses) +- [x] 使用的模式:server component wrapper(page.tsx) + client component(client.tsx 等) +- [x] 全量构建通过(54 页面静态生成) +- [x] 修复了 admin/enterprise/[id] 及 report 页面的 JSX 结构错误 + +--- + +## Phase 3: 🚧 进行中 + +- [ ] 通知系统 UI(`notification_service` 表) +- [ ] Loading 状态统一升级(spinner → Skeleton) +- [ ] 社区互动功能(点赞、评论) +- [x] 全量静态构建验证(✅ 通过) + +--- + +## 关键指标 + +| 指标 | 当前值 | +|------|--------| +| 后端测试数 | 105(92 单元 + 13 e2e) | +| 后端测试通过率 | 100% | +| 前端页面数 | 54(全部静态生成) | +| 暗黑模式兼容 | 全站 100% | +| 静态构建状态 | ✅ 通过 | +| next build status | ✅ 54/54 页面成功 | + +--- + +> 最后更新:2026-05-12 diff --git a/docs/progress.md b/docs/progress.md new file mode 100644 index 0000000..bb8bfdb --- /dev/null +++ b/docs/progress.md @@ -0,0 +1,63 @@ +# 项目进度追踪 + +## 当前阶段:Phase 1-3 全部完成 + +### Phase 1 — 全部完成 ✅ +1. **场景化提示词模板** — 5 预置场景 + system prompt + 建议问题 +2. **多模型一键切换** — 模型下拉选择,上下文保留 +3. **对话历史管理** — 侧边栏 + 搜索 + 加载 + 删除 + +### Phase 2 — 全部完成 ✅ +4. **参数调节面板** — temperature/top-p/max-tokens 滑块 + 后端透传 +5. **提示词工坊完善** — 保存到提示词库 + JWT + CSS 变量主题 +6. **代码沙盒** — `/sandbox/code` 编辑器 + iframe 预览 + 4 模板 + AI 代码块入口 + +### Phase 3 — 全部完成 ✅ +7. **学情分析看板** — `GET /learning/analytics` + `/learning/analytics` 页面(知识领域覆盖、掌握度、薄弱分析、推荐) +8. **分阶段学习路径** — `GET /learning/path` + `/learning/path` 页面(4 阶段:认识大模型→提示词工程→微调→Agent) +9. **对比模式完善** — 颜色修复、参数面板、model ID 同步 + +### 新页面 +- `/learning/analytics` — 学情分析看板(对话分析→知识图谱→薄弱环节→推荐) +- `/learning/path` — 分阶段学习路径(4 阶段 12 任务,自动追踪完成进度) +- `/my` 首页添加了学情分析和学习路径入口链接 + +### 验证 +- 后端 13 suites / 92 tests passed ✅ +- 前端 60 页面构建无报错 ✅ + +### 今日修复项(2026-05-15) + +#### 颜色约定修复(18 个文件) +- `page.tsx`(首页)、`dashboard/page.tsx`、`my/*`(4 个)、`models/page.tsx` +- `discover/*`(3 个)、`circles/*`(2 个)、`admin/*`(2 个) +- `courses/[id]/client.tsx`、`contents/[id]/client.tsx` +- `sandbox/compare/page.tsx`、`sandbox/code/page.tsx` +- 全部替换 `text-gray-*`/`bg-gray-*`/`border-gray-*` → CSS 变量 + +#### 模型列表统一 +- 新建 `frontend/src/lib/models.ts` — 单数据源 +- `sandbox/page.tsx`、`sandbox/compare/page.tsx`、`prompts/workshop/page.tsx` 统一导入 + +#### 对比实验室增强 +- 修复硬编码颜色、更新 model ID 为后端支持的值 +- 新增参数调节面板(temperature/top-p/max-tokens) + +#### 清理 +- 删除根目录 9 个残留文件(next-dev*.log、PROGRESS_FINAL* 等) +- 删除 `backend/src/e2e.spec.ts` 占位符 + +### 关键决策 +- `frontend/src/lib/models.ts` 作为模型列表单数据源 +- 所有颜色使用 CSS 变量(`text-foreground`/`text-muted-foreground`/`bg-card`/`bg-muted`/`border-border`) +- `nest build` 正常产出(`--tsc` 遗漏 prisma 模块) +- 沙盒 JWT 认证保留 + +### 相关文件 +- `backend/src/modules/learning/` — 学习分析模块(service + controller + module) +- `frontend/src/app/learning/analytics/page.tsx` — 学情分析看板页面 +- `frontend/src/app/learning/path/page.tsx` — 学习路径页面 +- `frontend/src/lib/models.ts` — 模型列表单数据源(新建) +- `frontend/src/app/sandbox/compare/page.tsx` — 对比实验室(修复颜色+参数+model) +- `frontend/src/app/page.tsx`, `dashboard/`, `my/`, `discover/`, `circles/`, `admin/`, `courses/`, `contents/` — 颜色修复 +- `docs/产品优化方向.md` — 完整优化方案 diff --git a/docs/产品优化方向.md b/docs/产品优化方向.md new file mode 100644 index 0000000..8cefc40 --- /dev/null +++ b/docs/产品优化方向.md @@ -0,0 +1,83 @@ +# 产品优化方向 —— 基于用户痛点的调研报告 + +> 调研时间:2026-05-14 +> 来源:AI 教育行业报告、竞品分析、用户行为数据(联网调研) + +## 一、核心洞察 + +用户不是想要一个"能聊天的 AI",而是想要一个"能让他真正学会用 AI 的环境"。 + +## 二、用户分层与真实痛点 + +| 用户类型 | 真实痛点 | 他们想要什么 | +|----------|----------|-------------| +| AI 初学者 | 不知道"问什么"——打开聊天框就迷茫 | 有引导的对话 + 分阶段课程/场景模板 | +| 编程学习者 | 环境配置劝退,API Key/模型选择/参数调优都是门槛 | 开箱即用的实验环境,一键启动 | +| 进阶开发者 | 需要对比不同模型输出差异,调优 prompt | 多模型对比沙盒 + 可调参数 | +| 教育机构 | 学习效果无法追踪,学生问完 AI 就没下文 | 学情分析 + 对话沉淀 + 知识点掌握度评估 | + +## 三、2026 行业关键趋势 + +1. **从"工具"到"系统"**:AI 教育已不是"会不会答题",而是"能不能持续教会人" +2. **互动式学习 > 被动问答**:交互式模拟器学习效果远超纯文字对话 +3. **模型对比是刚需**:多模型沙盒成为主流,用户想同场景下切换模型看差异 +4. **数据闭环决定留存**:能沉淀学习轨迹 + 生成学情报告的 AI 平台,留存率高 47% +5. **价格分层透明化**:用户愿为"可感知的价值"付费,拒绝黑盒收费 + +## 四、现状差距分析 + +| 维度 | 现状 | 用户期望 | 差距 | +|------|------|---------|------| +| 模型选择 | 仅通用模式,切换不直观 | 多模型对比,按场景推荐 | 大 | +| 参数调节 | 无 | temperature/top-p/max_tokens | 大 | +| 对话引导 | 空白聊天框 | 场景模板 + 建议问题 + 角色预设 | 大 | +| 学习路径 | 无 | 分阶段课程 / 能力图谱 | 大 | +| 学情分析 | 无 | 历史记录 + 知识掌握度 + 薄弱点 | 大 | +| 多模态 | 纯文本 | 文件上传 / 代码高亮 / 图片理解 | 中 | +| 分享协作 | 无 | 对话分享 / 团队空间 | 中 | + +## 五、优化路线图 + +### Phase 1 — 快速见效(1-2 周) + +1. **场景化提示词模板** + - 沙盒聊天框上方加"场景选择"(写代码/学概念/改作文/练口语) + - 点选后自动填充 system prompt + 首轮建议问题 + - 解决"不知道问什么"的痛点 + +2. **多模型一键切换** + - 保留对话上下文,用户可在 DeepSeek / 通义千问 / OpenAI 间切换 + - 同一问题看不同模型的回答差异 + +3. **对话历史管理** + - 会话列表 + 搜索 + 重命名 + - 最基础但最常被提及的需求 + +### Phase 2 — 核心体验(3-4 周) + +4. **参数调节面板** + - temperature / top-p / max_tokens 滑块 + - 让用户感受 prompt engineering 的实际效果 + +5. **Prompt 实验室** + - 保存/分享优质 prompt + - 为新手提供参考模板库 + +6. **代码沙盒** + - AI 生成的代码可直接运行/调试 + - WebContainer 或轻量级在线 IDE + - AI 学习平台最刚需的功能 + +### Phase 3 — 差异化壁垒(5-8 周) + +7. **学情分析看板** + - 基于对话历史生成知识点掌握图谱 + - 标记薄弱环节,推荐学习内容 + +8. **分阶段学习路径** + - 认识大模型 → Prompt 工程 → 模型微调 → Agent 开发 + - 各阶段有对应的场景沙盒 + +9. **对比模式** + - 同一 prompt 在多个模型/参数下的输出并排对比 + - 直观展示差异,辅助选型决策 diff --git a/docs/产品规划书.md b/docs/产品规划书.md new file mode 100644 index 0000000..55377cf --- /dev/null +++ b/docs/产品规划书.md @@ -0,0 +1,403 @@ +# 宇之然 - AI 学习与实践平台 · 产品规划书 + +> 品牌:宇之然(北京宇之然科技中心) +> 域名:yuzhiran.com / yuzhiran.com.cn +> ICP备案:✅ 已完成 +> 版本:v1.0 +> 日期:2026-05-08 +> 状态:初稿 + +--- + +## 目录 + +1. [产品概述](#1-产品概述) +2. [市场分析](#2-市场分析) +3. [目标用户画像](#3-目标用户画像) +4. [产品功能规划](#4-产品功能规划) +5. [盈利模式](#5-盈利模式) +6. [合规与风控](#6-合规与风控) +7. [可行性分析](#7-可行性分析) +8. [技术架构概要](#8-技术架构概要) +9. [项目里程碑](#9-项目里程碑) +10. [风险评估与对策](#10-风险评估与对策) + +--- + +## 1. 产品概述 + +### 1.1 产品定位 + +**宇之然 AI**(品牌:宇之然,英文名:YuZhiRan AI)是一个面向大众化分领域用户的 AI 学习与实践平台。致力于降低 AI 使用门槛,帮助不同背景的用户快速掌握 AI 工具、提示词工程、智能体应用及模型选型等核心技能。 + +### 1.2 产品愿景 + +"让每个人都能用好 AI"——打造中国最易用的 AI 通识教育与实操平台。 + +### 1.3 核心价值 + +| 价值点 | 说明 | +|--------|------| +| **低门槛** | 无需技术背景,零基础入门 | +| **分领域** | 按职业/场景细分,学即所用 | +| **重实操** | 内置 AI 沙箱,边学边练 | +| **持续更新** | 紧跟模型迭代,内容实时更新 | +| **本土合规** | 纯 ICP 备案运营,数据安全合规 | + +### 1.4 产品矩阵 + +``` +宇之然 AI 产品矩阵 +├── 官网展示站 (Web) — 品牌展示、内容营销、用户引流 +├── 移动端 App/小程序 — 核心学习体验、AI 沙箱实操 +└── 后台管理系统 — 内容管理、用户管理、数据分析、订单管理 +``` + +--- + +## 2. 市场分析 + +### 2.1 宏观环境 + +- **政策面**:国家大力推动人工智能普及教育,"人工智能+"写入政府工作报告 +- **技术面**:大模型井喷,2025-2026 年国内大模型数量已超 200 个 +- **需求面**:C 端用户对 AI 工具的认知需求激增,"AI 焦虑"驱动学习意愿 +- **供给面**:市面上缺乏面向非技术人群的系统化 AI 学习产品 + +### 2.2 竞品分析 + +| 竞品类型 | 代表产品 | 优势 | 劣势 | +|----------|----------|------|------| +| 通用 AI 课程平台 | 得到、极客时间 AI 专栏 | 用户基数大 | 偏理论,缺少实操 | +| 提示词市场 | FlowGPT、PromptBase | 提示词丰富 | 全英文、无中文生态 | +| AI 工具导航 | AI 导航站 | 工具收录全 | 无教学内容 | +| 大模型测评 | SuperCLUE、Chatbot Arena | 权威评测 | 面向技术人群 | + +**宇之然 AI 差异化定位**:教学 + 实操 + 社区三位一体,填补"学 AI"与"用 AI"之间的鸿沟。 + +### 2.3 用户痛点 + +1. 想学 AI 但不知道从何入手 +2. 看了一堆教程仍然不会用 +3. 提示词写不好、效果差 +4. 不知道哪些 AI 工具适合自己的工作 +5. 模型太多,选择困难 +6. 缺乏实际练习场景 + +--- + +## 3. 目标用户画像 + +### 3.1 核心用户分层 + +| 用户层 | 描述 | 占比估算 | +|--------|------|----------| +| **职场白领** | 需要 AI 提效办公(写周报、做PPT、数据分析) | 40% | +| **创作者** | 自媒体、设计师、视频创作者用 AI 辅助创作 | 20% | +| **学生群体** | 高校/职校学生,论文辅助、学习效率提升 | 20% | +| **技术初学者** | 想学 AI 但非科班的入门开发者 | 10% | +| **企业管理者** | 想了解 AI 如何赋能业务的决策层 | 10% | + +### 3.2 典型用户场景 + +- **职场人小张**:用 AI 写邮件、做周报、整理会议纪要 → 需要模板和提示词 +- **设计师小李**:用 Midjourney/Stable Diffusion 生成素材 → 需要提示词案例和参数调优 +- **学生小王**:用 AI 辅助论文写作、翻译、学习答疑 → 需要合规使用指南 +- **创业者老陈**:想用 AI 降低运营成本 → 需要行业最佳实践 + +--- + +## 4. 产品功能规划 + +### 4.1 官网展示站 (Web) + +| 模块 | 功能 | 说明 | +|------|------|------| +| 首页 | 品牌展示、核心价值、数据展示 | 产品第一印象,引导注册 | +| 内容中心 | 文章/教程/资讯 | SEO 引流,免费内容沉淀 | +| AI 工具库 | 模型对比、工具收录 | 分类筛选,支持收藏 | +| 提示词市场 | 精选提示词模板 | 分类浏览+用户上传 | +| 产品下载 | App 下载、小程序码 | 引导移动端转化 | +| 社区/论坛 | 用户交流区 | UGC 沉淀,活跃留存 | +| 关于我们 | 团队介绍、合规资质展示 | 增强信任感 | + +### 4.2 移动端 App / 小程序(核心体验) + +| 模块 | 一级功能 | 二级功能 | +|------|----------|----------| +| **学堂** | AI 通识课 | AI 发展史、基础概念、模型分类 | +| | 领域实战课 | 按职业/场景分类(办公、创作、编程、教育等) | +| | 提示词学院 | 提示词原理、模板库、高阶技巧 | +| | 智能体教程 | 主流智能体使用教学(Copilot、Claude、GPTs 等) | +| | 模型百科 | 主流模型参数、能力图谱、选型指南 | +| **沙箱** | AI 对话沙箱 | 内置多种模型接口,边学边练 | +| | 提示词工坊 | 提示词编辑、测试、优化迭代 | +| | 对比实验室 | 多模型同题对比,直观感知差异 | +| | 效果分享 | 生成结果一键分享到社区 | +| **发现** | 每日精选 | AI 领域每日精选内容 | +| | 工具推荐 | 收录优质 AI 工具及使用教程 | +| | 热门榜单 | 提示词/教程排行榜 | +| | 圈子 | 按领域划分的垂直讨论区 | +| **我的** | 学习进度 | 课程完成度、学习时长统计 | +| | 收藏夹 | 提示词/课程/工具收藏 | +| | 会员中心 | 会员权益、续费管理 | +| | 设置 | 账号安全、通知偏好 | + +### 4.3 后台管理系统 + +| 模块 | 功能 | 说明 | +|------|------|------| +| **内容管理** | 文章管理 | 发布/编辑/下架/分类 | +| | 课程管理 | 课程体系编排、课时管理 | +| | 提示词库管理 | 审核/精选/分类/标签 | +| | 工具库管理 | AI 工具收录与维护 | +| | 模型数据管理 | 模型参数维护、评测数据 | +| **用户管理** | 用户列表 | 基础信息/状态/来源渠道 | +| | 用户分析 | 活跃度/留存/转化漏斗 | +| | 用户反馈 | 建议/投诉处理 | +| **运营管理** | 公告管理 | App 内公告推送 | +| | 内容审核 | UGC 内容安全审核 | +| | 数据看板 | 核心指标可视化 | +| | 推送管理 | 消息推送配置 | +| **会员系统** | 会员等级 | 等级/权益配置 | +| | 订单管理 | 支付订单查询/退款 | +| | 优惠券 | 发放/核销管理 | +| **系统管理** | 权限管理 | 管理员角色/权限分配 | +| | 日志审计 | 操作日志记录 | +| | 系统配置 | 基础参数配置 | + +--- + +## 5. 盈利模式 + +### 5.1 商业模式总览 + +采用 **Freemium + 会员订阅 + 增值服务** 的混合模式。 + +### 5.2 收入来源 + +| 收入类型 | 说明 | 预期占比 | +|----------|------|----------| +| **会员订阅** | 月度/季度/年度会员,解锁高阶课程+沙箱额度+专属提示词 | 50% | +| **课程付费** | 精品专栏/训练营单独售卖(如"AI 办公实战 21 天") | 20% | +| **企业培训** | 为中小企业提供定制化 AI 培训方案 | 15% | +| **广告/推广** | AI 工具厂商合作推广、精准广告位 | 10% | +| **数据服务** | 行业 AI 应用报告、模型选型咨询(后期) | 5% | + +### 5.3 定价策略 + +| 层级 | 价格(参考) | 权益 | +|------|-------------|------| +| 免费用户 | ¥0 | 基础课程 + 每日沙箱 10 次 + 查看公开提示词 | +| 月卡会员 | ¥29.9/月 | 全部课程 + 不限次沙箱 + 专属提示词库 + 去广告 | +| 年卡会员 | ¥199/年 (≈¥16.6/月) | 月卡权益 + 优先体验新功能 + 专属社群 | +| 企业培训 | 按需报价 | 定制内容 + 员工管理后台 + 使用数据报告 | + +### 5.4 运营策略 + +- **冷启动期**:免费内容引流 → 公众号/知乎/小红书内容矩阵 +- **增长期**:拼团/分享裂变 → 企业合作推广 +- **成熟期**:UGC 生态 → 创作者分成计划 → 平台化 + +--- + +## 6. 合规与风控 + +### 6.1 ICP 备案合规路径 + +根据《互联网信息服务管理办法》和《非经营性互联网信息服务备案管理办法》: + +| 事项 | 要求 | 操作建议 | +|------|------|----------| +| ICP 备案 | 境内服务器需备案 | 使用阿里云/腾讯云/华为云,提交主体备案 | +| ICP 经营许可证 | 经营性网站需办理 | 会员付费属于经营行为,需办理 ICP 经营许可证 | +| 公安网备 | 联网备案 | 网站上线后 30 日内到公安备案 | +| 等保认证 | 等级保护 | 根据用户量评估等保等级(建议等保二级) | + +**关键路径**: +1. 先以 ICP 备案主体运营非付费内容 +2. 同步申请 ICP 经营许可证(省通信管理局审批) +3. 会员付费功能在 ICP 许可证获批后上线 +4. 或采用"捐赠打赏"模式作为过渡方案 + +### 6.2 内容合规 + +| 风险类型 | 应对措施 | +|----------|----------| +| AI 生成内容合规 | 所有 AI 生成内容标注"AI 生成",建立审核机制 | +| 敏感内容过滤 | 接入腾讯云/阿里云内容安全 API,实时过滤 | +| 版权风险 | 提示词库仅收录原创或授权内容,建立侵权投诉机制 | +| 未成年人保护 | 需监护人同意,限制使用时长 | +| 数据隐私 | 遵守《个人信息保护法》,最小化数据收集 | + +### 6.3 数据合规 + +- 用户数据存储于境内服务器(阿里云/腾讯云国内节点) +- 隐私政策 + 用户协议公开透明 +- 提供账号注销通道 +- 数据加密存储(AES-256) +- 定期数据备份 + +### 6.4 AI 沙箱合规 + +| 关注点 | 方案 | +|--------|------| +| 模型调用 | 通过聚合 API 调用,不自训练/微调模型 | +| 用户输入 | 沙箱内用户输入需经过内容安全过滤 | +| 数据留存 | 沙箱对话数据不用于模型训练 | +| 服务方合规 | 选择有合规资质的 API 服务商 | + +--- + +## 7. 可行性分析 + +### 7.1 技术可行性 + +| 维度 | 评估 | +|------|------| +| 前端技术 | React/Next.js + TailwindCSS,生态成熟 | +| 移动端 | Uni-app / Taro 跨平台方案,一套代码覆盖 App+小程序 | +| 后端 | Node.js/NestJS 或 Go,轻量高效 | +| AI 接口 | 聚合多家大模型 API(通义千问、文心一言、GLM 等) | +| 部署运维 | 阿里云 ECS + OSS + CDN,运维成本可控 | + +**结论**:技术方案成熟,无不可逾越的技术障碍。 + +### 7.2 商业可行性 + +| 维度 | 评估 | +|------|------| +| 市场规模 | 2026 年国内 AI 教育市场预计超 500 亿元 | +| 获客成本 | 内容驱动获客,SEO+社交媒体,CAC 可控 | +| 客单价 | ¥199/年,低于同类教育产品 | +| 毛利率 | 数字产品边际成本趋近于零,毛利率 >80% | +| 盈亏平衡 | 预估 10000 付费用户可覆盖基础运营成本 | + +**结论**:市场需求真实存在,商业模式清晰,可持续盈利。 + +### 7.3 运营可行性 + +| 维度 | 评估 | +|------|------| +| 内容供给 | 初期团队自产 + 后期 UGC + AI 辅助生产 | +| 团队要求 | 3-5 人核心团队(产品+开发+运营+内容) | +| 增长路径 | 内容 SEO → 口碑传播 → 渠道合作 | +| 竞争优势 | 先发优势 + 实操体验壁垒 | + +**结论**:轻资产运营,团队规模需求适中,可快速启动。 + +### 7.4 政策可行性 + +| 维度 | 评估 | +|------|------| +| 政策方向 | 国家鼓励 AI 科普与 AI 人才培养 | +| 合规成本 | ICP 许可证申请成本约 5000-10000 元 | +| 监管风险 | 内容审核机制完善后风险可控 | + +**结论**:政策面利好,合规路径清晰,风险可控。 + +--- + +## 8. 技术架构概要 + +### 8.1 整体架构 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 用户访问层 │ +│ 官网 (Web) │ 移动端 App │ 微信小程序 │ +└──────────────────────┬─────────────────────────────────┘ + │ +┌──────────────────────▼─────────────────────────────────┐ +│ CDN / 负载均衡 │ +│ (阿里云 CDN + SLB) │ +└──────────────────────┬─────────────────────────────────┘ + │ +┌──────────────────────▼─────────────────────────────────┐ +│ 应用层 │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ Next.js │ │ Node.js │ │ Admin │ │ +│ │ 官网 │ │ API │ │ Panel │ │ +│ └─────────┘ └─────────┘ └─────────┘ │ +└──────────────────────┬─────────────────────────────────┘ + │ +┌──────────────────────▼─────────────────────────────────┐ +│ 服务层 │ +│ 内容服务 │ 用户服务 │ 课程服务 │ AI 沙箱服务 │ +│ 支付服务 │ 搜索服务 │ 推送服务 │ 审核服务 │ +└──────────────────────┬─────────────────────────────────┘ + │ +┌──────────────────────▼─────────────────────────────────┐ +│ 数据层 │ +│ MySQL │ Redis │ Elasticsearch │ OSS │ +│ (主库) │ (缓存) │ (搜索) │ (存储) │ +└─────────────────────────────────────────────────────────┘ +``` + +### 8.2 技术选型建议 + +| 层级 | 技术选型 | +|------|----------| +| 前端框架 | Next.js 14+ (App Router) | +| 移动端 | Taro/Uni-app (多端统一) | +| 后端 | Node.js + NestJS / Go | +| 数据库 | MySQL 8.0 + Redis 7 | +| 搜索引擎 | Elasticsearch | +| 对象存储 | 阿里云 OSS | +| AI 接口聚合 | 自建 AI Gateway | +| 部署 | Docker + K8s / 阿里云 ECS | +| CI/CD | GitHub Actions + 阿里云 CR | + +--- + +## 9. 项目里程碑 + +| 阶段 | 时间 | 里程碑 | 产出 | +|------|------|--------|------| +| P0 | 第 1-2 周 | 项目启动 | 团队组建、技术选型、UI 设计稿 | +| P1 | 第 3-6 周 | MVP 版本 | 官网 + 基础后端 + 5 门课程 | +| P2 | 第 7-10 周 | 移动端上线 | App/小程序 v1.0 + AI 沙箱功能 | +| P3 | 第 11-12 周 | 运营启动 | 内容矩阵搭建、种子用户获取 | +| P4 | 第 13-16 周 | 会员体系上线 | 支付接入、会员权益、商业化 | +| P5 | 第 17-20 周 | 社区生态 | UGC 功能、创作者计划 | +| P6 | 第 21-24 周 | 持续迭代 | 企业版、数据报告服务 | + +--- + +## 10. 风险评估与对策 + +| 风险 | 概率 | 影响 | 应对策略 | +|------|------|------|----------| +| 政策监管收紧 | 中 | 高 | 建立合规团队,关注政策动态,预留调整空间 | +| AI 模型接口变更 | 高 | 中 | 多供应商接入,接口抽象化设计 | +| 内容同质化竞争 | 中 | 中 | 深耕实操体验,构建 UGC 壁垒 | +| 获客成本上升 | 中 | 中 | 内容驱动增长,降低对付费投放依赖 | +| 团队人才流失 | 低 | 高 | 合理的激励制度,关键岗位冗余配置 | +| 数据安全事件 | 低 | 极高 | 安全审计、渗透测试、数据加密、应急预案 | + +--- + +## 附录 + +### A. 预算估算(首年) + +| 项目 | 月费用(元) | 年费用(元) | +|------|-------------|-------------| +| 阿里云服务器 | 500-1000 | 6000-12000 | +| 域名 + CDN | 200-500 | 2400-6000 | +| AI API 调用 | 1000-3000 | 12000-36000 | +| 内容安全 API | 500-1000 | 6000-12000 | +| 人员成本(3-5 人) | 50000-80000 | 600000-960000 | +| 市场推广 | 5000-10000 | 60000-120000 | +| 合规(ICP 证等) | - | 5000-10000 | +| **合计** | **~60000** | **~700000-1100000** | + +### B. 核心指标 (KPI) + +| 指标 | MVP 阶段 (3个月) | 成熟期 (12个月) | +|------|-----------------|-----------------| +| 注册用户 | 5000 | 10万+ | +| 日活用户 (DAU) | 500 | 1万+ | +| 付费用户 | 200 | 5000+ | +| 课程数量 | 10 | 100+ | +| 月营收 | ¥5000 | ¥20万+ | diff --git a/docs/合规与运营方案.md b/docs/合规与运营方案.md new file mode 100644 index 0000000..4b1b540 --- /dev/null +++ b/docs/合规与运营方案.md @@ -0,0 +1,273 @@ +# 宇之然 AI - 合规与运营方案 + +> 版本:v1.0 +> 日期:2026-05-08 + +--- + +## 1. 主体资质规划 + +### 1.1 当前资质 + +| 资质 | 状态 | 说明 | +|------|------|------| +| 品牌 | 宇之然 | 品牌名已确定 | +| 主体公司 | 北京宇之然科技中心 | 北京市大兴区 | +| ICP 备案 | ✅ 已完成 | 备案信息见网站页脚 | +| 营业执照 | ✅ 已完成 | 主体公司营业执照 | +| 主域名 | yuzhiran.com | 已备案,已上线运营 | +| 备域名 | yuzhiran.com.cn | 已备案 | + +### 1.2 需新增资质 + +| 资质 | 办理周期 | 预估费用 | 最晚办理时间 | +|------|----------|----------|-------------| +| ICP 经营许可证 | 40-60 个工作日 | 5000-10000 元(代理) | 会员付费功能上线前 | +| 公安联网备案 | 10-20 个工作日 | 免费 | 网站上线后 30 日内 | +| 网络安全等级保护(二级) | 30-45 个工作日 | 10000-20000 元 | 用户量达 1 万后 | +| 文网文(如涉及内容付费) | 视情况 | 视情况 | 后续评估 | + +### 1.3 ICP 备案 → 经营许可证过渡方案 + +**阶段一(冷启动 - 0~3 个月):纯内容模式** +- 官网只展示内容、课程介绍(不含付费) +- 移动端提供免费课程 + 有限次沙箱体验 +- 盈利方式:免费(不计收入,无需 ICP 证) +- 流量获取:内容 SEO、社交媒体免费流量 + +**阶段二(过渡期 - 3~6 个月):打赏/捐赠模式** +- 同步提交 ICP 经营许可证申请 +- 用户可通过"打赏""买杯咖啡"等非强制方式支持 +- 支付宝/微信个人收款码(非平台收款) +- 法律依据:非强制性的自愿赠与,非经营性行为 + +**阶段三(正式运营 - 6+ 个月):会员模式** +- ICP 经营许可证获批 +- 上线完整的会员订阅 + 支付系统 +- 引入微信支付/支付宝商户号 +- 所有付费功能合规运营 + +--- + +## 2. 内容合规方案 + +### 2.1 安全审核架构 + +``` +用户发布内容 + │ + ▼ +┌─────────────────────┐ +│ 第一层:本地过滤 │ — 自定义敏感词库 +│ │ — 正则规则匹配 +└─────────┬───────────┘ + │ + ▼ +┌─────────────────────┐ +│ 第二层:云 API 审核 │ — 阿里云内容安全 +│ │ — 腾讯云天御 +└─────────┬───────────┘ + │ + ▼ +┌─────────────────────┐ +│ 第三层:人工审核 │ — 关键内容人工复审 +│ │ — 用户举报处理 +└─────────┬───────────┘ + │ + ▼ + 发布 / 拦截 +``` + +### 2.2 审核范围 + +| 内容类型 | 审核策略 | 审核方式 | +|----------|----------|----------| +| 文章教程 | 先审后发 | 云 API + 人工 | +| 用户评论 | 先发后审 | 云 API 实时 | +| UGC 提示词 | 先审后发 | 云 API + 人工 | +| 社区帖子 | 先发后审 | 云 API 实时 | +| 沙箱用户输入 | 实时过滤 | 云 API 实时 | +| 用户头像/昵称 | 先审后显 | 云 API 实时 | + +### 2.3 AI 内容标注 + +根据《生成式人工智能服务管理暂行办法》: + +- 所有 AI 生成内容须标注"AI 生成"标识 +- 提示词模板库中 AI 生成的模板明确标注 +- 课程中使用 AI 生成的内容需声明 +- AI 沙箱对话记录首页显示"以下内容由 AI 生成" + +### 2.4 内容审核团队 + +| 阶段 | 人员配置 | 方式 | +|------|----------|------| +| MVP | 1 人(运营兼) | 每日 1 次审核 | +| 增长期 | 2-3 人专职审核 | 轮班制 | +| 成熟期 | 5+ 人 + AI 辅助 | 7×24 审核机制 | + +--- + +## 3. 数据合规方案 + +### 3.1 《个人信息保护法》合规 + +| 要求 | 实施方案 | +|------|----------| +| 告知同意 | 注册时弹窗展示隐私政策,用户主动勾选同意 | +| 最小必要 | 仅收集手机号/邮箱 + 昵称,不收集无关信息 | +| 权利保障 | 提供查看/更正/删除个人数据的通道 | +| 数据本地化 | 全部数据存储于中国大陆(阿里云) | +| 跨境传输 | 不涉及数据出境 | +| 自动化决策 | AI 推荐功能需提供关闭选项 | + +### 3.2 用户数据生命周期管理 + +``` +收集 → 存储 → 使用 → 传输 → 归档 → 销毁 + +收集:用户主动提交,明确告知用途 +存储:加密存储(AES-256),访问控制 +使用:仅用于产品功能,不对外出售 +传输:HTTPS 加密传输 +归档:休眠账号数据归档 +销毁:用户注销 → 30 日内完全删除 +``` + +### 3.3 数据分类分级 + +| 等级 | 类别 | 处理措施 | +|------|------|----------| +| L1(公开) | 课程介绍、公开文章 | 无特殊限制 | +| L2(内部) | 用户昵称、学习记录 | 内部访问控制 | +| L3(敏感) | 手机号、邮箱、密码 | 加密存储,最小人员可访问 | +| L4(高敏) | 支付信息、实名认证 | 第三方支付处理,不留存完整信息 | + +--- + +## 4. AI 沙箱合规 + +### 4.1 沙箱功能法律定性 + +AI 沙箱本质为用户提供 AI 模型调用体验服务,非提供生成式 AI 服务本身。平台作为技术服务提供方,适用"避风港原则"。 + +### 4.2 沙箱合规措施 + +| 措施 | 说明 | +|------|------| +| 服务协议 | 用户使用沙箱前同意《AI 服务协议》 | +| 免责声明 | 明确告知 AI 生成内容可能存在不准确 | +| 内容过滤 | 用户输入 + AI 输出双重过滤 | +| 使用限制 | 未成年人需监护人同意 | +| 数据不训练 | 承诺沙箱数据不用于模型训练 | +| 投诉通道 | 显著位置提供投诉举报入口 | + +### 4.3 API 服务商合规 + +| 服务商 | 合规评估 | 合作模式 | +|--------|----------|----------| +| 阿里云通义千问 | ✅ 已备案生成式 AI | 通过阿里云 DashScope API | +| 百度文心一言 | ✅ 已备案生成式 AI | 通过百度千帆 API | +| 智谱 GLM | ✅ 已备案生成式 AI | 通过智谱开放平台 API | +| DeepSeek | ✅ 合规 | 通过 DeepSeek API | +| 月之暗面 Kimi | ✅ 合规 | 通过 Moonshot API | + +--- + +## 5. 运营方案 + +### 5.1 内容运营策略 + +| 阶段 | 内容方向 | 产出频率 | +|------|----------|----------| +| 冷启动 | AI 入门系列、工具对比、实战案例 | 每周 3-5 篇 | +| 增长期 | 领域深耕、行业报告、专栏 | 每周 5-7 篇 | +| 成熟期 | UGC 生态、创作者计划 | 每日 10+ 篇 | + +### 5.2 用户增长策略 + +``` +冷启动期(1-3 月) +├── 内容 SEO:知乎/公众号/CSDN 分发 +├── 社交媒体:小红书AI教程笔记 +├── 短视频:B站/抖音 AI 实操教程 +└── 垂直社区:在 AI 相关社群分享 + +增长期(3-6 月) +├── 裂变:分享课程得免费额 +├── 拼团:3 人成团享折扣 +├── 推荐:邀请好友双方得奖励 +└── 合作:与 AI 工具厂商换量 + +成熟期(6-12 月) +├── 品牌:行业知名度建立 +├── 渠道:企业合作推广 +├── KOL:邀请 AI KOL 入驻 +└── 活动:AI 提示词大赛 +``` + +### 5.3 用户留存策略 + +| 手段 | 说明 | +|------|------| +| 学习提醒 | 每日学习任务推送 | +| 进度激励 | 勋章、证书、学习成就系统 | +| 社群运营 | 按领域建群,定期主题活动 | +| 个性化推荐 | 基于学习历史推荐课程 | +| 签到打卡 | 连续签到解锁额外沙箱额度 | + +### 5.4 盈利时间线预测 + +| 时间 | 营收来源 | 预期月营收 | +|------|----------|-----------| +| 第 1-3 月 | 无(积累用户) | ¥0 | +| 第 4-6 月 | 打赏/捐赠+课程单独售卖(ICP 证办理中) | ¥3000-8000 | +| 第 7-9 月 | 会员订阅+课程付费(ICP 证获批) | ¥30000-80000 | +| 第 10-12 月 | 会员+课程+企业培训+广告 | ¥100000-200000 | + +--- + +## 6. 应急预案 + +### 6.1 内容安全事件 + +1. 发现违规内容 → 立即下架/屏蔽 +2. 记录证据 → 平台内通知发布者 +3. 评估影响范围 → 报告监管部门(如需) +4. 优化审核规则 → 防止再次发生 + +### 6.2 数据安全事件 + +1. 发现异常 → 立即隔离受影响系统 +2. 启动备份 → 恢复服务 +3. 安全审计 → 定位漏洞 +4. 依法通知用户和监管部门 +5. 修复 → 复盘 → 改进 + +### 6.3 政策变动应对 + +| 场景 | 应对措施 | +|------|----------| +| AI 监管新规出台 | 快速评估影响,调整产品功能 | +| 审批趋严 | 提前准备材料,增加合规投入 | +| 特定模型被限制 | 切换 API 供应商,保证服务连续性 | +| 行业整顿 | 自查自纠,主动合规 | + +--- + +## 7. 合规清单(Checklist) + +- [ ] 已办理 ICP 备案 +- [ ] 已提交 ICP 经营许可证申请 +- [ ] 已完成公安联网备案 +- [ ] 已制定并公示《隐私政策》 +- [ ] 已制定并公示《用户服务协议》 +- [ ] 已制定并公示《AI 服务协议》 +- [ ] 已接入内容安全审核服务 +- [ ] 已建立 AI 内容标注机制 +- [ ] 已建立用户数据删除通道 +- [ ] 已设置投诉举报入口 +- [ ] 已完成等保二级测评 +- [ ] 已建立应急预案 +- [ ] 已明确未成年人保护措施 +- [ ] 已制定内容审核标准 diff --git a/docs/技术架构设计.md b/docs/技术架构设计.md new file mode 100644 index 0000000..d6a8426 --- /dev/null +++ b/docs/技术架构设计.md @@ -0,0 +1,322 @@ +# 宇之然 AI - 技术架构设计文档 + +> 版本:v1.0 +> 日期:2026-05-08 + +--- + +## 1. 系统总体架构 + +### 1.1 架构分层 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ 客户端层 │ +│ ┌────────────┐ ┌──────────────┐ ┌────────────┐ │ +│ │ Next.js │ │ Uni-app │ │ 微信小程序 │ │ +│ │ 官网 (SSR) │ │ App (跨平台) │ │ │ │ +│ └────────────┘ └──────────────┘ └────────────┘ │ +└──────────────────────────┬──────────────────────────────────────────┘ + │ +┌──────────────────────────▼──────────────────────────────────────────┐ +│ API 网关层 │ +│ Nginx / 阿里云 SLB → API Gateway │ +│ 限流 / 鉴权 / 日志 / 路由转发 │ +└──────────────────────────┬──────────────────────────────────────────┘ + │ +┌──────────────────────────▼──────────────────────────────────────────┐ +│ 业务服务层 │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 用户服务 │ │ 内容服务 │ │ 课程服务 │ │ 沙箱服务 │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 社区服务 │ │ 支付服务 │ │ 搜索服务 │ │ 审核服务 │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +└──────────────────────────┬──────────────────────────────────────────┘ + │ +┌──────────────────────────▼──────────────────────────────────────────┐ +│ AI 网关层 │ +│ 统一 API → 多模型路由 → 负载均衡 → 结果缓存 │ +│ 通义千问 │ 文心一言 │ GLM │ DeepSeek │ Kimi ... │ +└──────────────────────────┬──────────────────────────────────────────┘ + │ +┌──────────────────────────▼──────────────────────────────────────────┐ +│ 数据层 │ +│ MySQL 8.0 │ Redis 7 │ ES 8.x │ OSS │ RocketMQ │ +│ (主从/读写分离) (缓存/会话) (搜索) (存储) (消息队列) │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 2. 技术选型详述 + +### 2.1 前端(官网) + +| 技术 | 版本 | 说明 | +|------|------|------| +| Next.js | 14+ | React 框架,SSR/SSG 支持 | +| TypeScript | 5.x | 类型安全 | +| TailwindCSS | 3.x | 原子化 CSS | +| Shadcn/ui | latest | UI 组件库 | +| React Query | 5.x | 数据请求管理 | +| Zustand | latest | 状态管理 | + +### 2.2 移动端(App / 小程序) + +| 技术 | 说明 | +|------|------| +| Uni-app / Taro | 跨端框架 | +| Vue 3 / React | 视框架而定 | +| Pinia / Zustand | 状态管理 | +| uView / NutUI | 移动端组件库 | + +> 推荐 Uni-app + Vue 3,对微信小程序适配最成熟。 + +### 2.3 后端 + +| 技术 | 版本 | 说明 | +|------|------|------| +| Node.js | 20 LTS | 运行时 | +| NestJS | 10.x | Node.js 后端框架 | +| Prisma | 5.x | ORM | +| JWT | - | 鉴权 | +| Zod | latest | 数据校验 | + +或备选方案: + +| 技术 | 说明 | +|------|------| +| Go + Gin / Fiber | 高性能,适合 AI 网关 | +| Python + FastAPI | 适合 AI 数据处理任务 | + +> 建议:核心业务用 NestJS,AI 网关用 Go。 + +### 2.4 数据库 + +| 组件 | 用途 | 部署 | +|------|------|------| +| MySQL 8.0 | 业务主库(用户/课程/订单等) | 阿里云 RDS | +| Redis 7 | 缓存/会话/限流计数器 | 阿里云 Redis | +| Elasticsearch 8.x | 内容搜索 | 阿里云 ES | +| 阿里云 OSS | 图片/视频/文件存储 | 阿里云 OSS | +| RocketMQ | 异步任务/消息通知 | 阿里云 RocketMQ | + +### 2.5 AI 网关 + +``` +用户请求 → 网关层 + ├── 请求校验 → 内容安全审核 + ├── 模型路由(基于用户配置/成本/负载) + │ ├── 通义千问 (qwen-max) + │ ├── 文心一言 (ERNIE-4.0) + │ ├── GLM-4 + │ ├── DeepSeek-V3 + │ └── Kimi (moonshot-v1) + ├── 结果缓存(Redis,相同 prompt 命中缓存) + ├── 流式响应处理 + └── 计费/用量统计 +``` + +### 2.6 内容安全 + +| 服务 | 用途 | +|------|------| +| 阿里云内容安全 | 文本/图片鉴黄、涉政、违禁检测 | +| 腾讯云天御 | UGC 内容安全审核 | +| 自定义敏感词库 | 行业特定敏感词过滤 | + +--- + +## 3. 数据库设计概要 + +### 3.1 核心表结构 + +``` +users — 用户表 +├── id, phone, email, password_hash, avatar, status, created_at +├── user_profiles — 用户扩展信息 +└── user_learn_records — 学习记录 + +courses — 课程表 +├── id, title, description, cover, category, price, status +├── chapters — 章节表 +├── lessons — 课时表 +└── lesson_progress — 学习进度 + +prompts — 提示词表 +├── id, title, content, category, tags, author_id, status +├── prompt_favorites — 收藏 +└── prompt_comments — 评论 + +tools — AI 工具表 +├── id, name, description, url, category, icon, status +└── tool_reviews — 评价 + +models — 模型百科表 +├── id, name, provider, params, features, benchmark, status +└── model_comparisons — 对比评测 + +sandbox_sessions — AI 沙箱会话表 +├── id, user_id, model, messages, tokens, duration, created_at +└── sandbox_quota — 用户沙箱额度 + +orders — 订单表 +├── id, user_id, amount, plan_type, status, pay_channel, paid_at +└── subscriptions — 订阅记录 + +contents — 内容(文章/资讯) +├── id, title, content, category, tags, author, status, view_count +└── content_comments — 评论 + +admin_users — 管理员表 +├── id, username, password_hash, role, permission, last_login +└── admin_logs — 操作日志 +``` + +### 3.2 数据库设计原则 + +- **软删除**:所有业务表增加 `deleted_at` 字段 +- **审计字段**:`created_at`、`updated_at` 必备 +- **索引策略**:覆盖常用查询场景,避免全表扫描 +- **分表策略**:`sandbox_sessions` 按用户 ID 分表 +- **读写分离**:主库写入,从库查询 + +--- + +## 4. API 设计规范 + +### 4.1 命名规范 + +``` +GET /api/v1/courses — 课程列表 +GET /api/v1/courses/:id — 课程详情 +POST /api/v1/courses — 创建课程(管理端) +PUT /api/v1/courses/:id — 更新课程(管理端) +DELETE /api/v1/courses/:id — 删除课程(管理端) + +POST /api/v1/auth/login — 登录 +POST /api/v1/auth/register — 注册 +POST /api/v1/auth/refresh — 刷新 token + +POST /api/v1/sandbox/chat — AI 沙箱对话 +GET /api/v1/sandbox/history — 对话历史 +GET /api/v1/sandbox/quota — 沙箱额度查询 + +POST /api/v1/orders/create — 创建订单 +GET /api/v1/orders/:id — 订单查询 +POST /api/v1/orders/callback — 支付回调 +``` + +### 4.2 通用响应格式 + +```json +{ + "code": 0, + "message": "success", + "data": {}, + "meta": { + "page": 1, + "pageSize": 20, + "total": 100 + } +} +``` + +### 4.3 鉴权方案 + +- **JWT Token**(Access Token 2h + Refresh Token 7d) +- 管理后台:Session + Cookie +- API 签名:管理端 API 需签名校验 + +--- + +## 5. 部署架构 + +``` + ┌─────────────┐ + │ DNS │ + │ (阿里云 DNS)│ + └──────┬──────┘ + │ + ┌──────▼──────┐ + │ CDN │ + │ (静态资源) │ + └──────┬──────┘ + │ + ┌──────▼──────┐ + │ SLB │ + │ (负载均衡) │ + └──────┬──────┘ + │ + ┌────────────┼────────────┐ + │ │ │ + ┌──────▼──┐ ┌─────▼────┐ ┌────▼────┐ + │ Next.js │ │ NestJS │ │ Admin │ + │ 官网 │ │ API 服务 │ │ Panel │ + └─────────┘ └─────┬────┘ └─────────┘ + │ + ┌───────────┼───────────┐ + │ │ │ + ┌──────▼──┐ ┌────▼───┐ ┌───▼────┐ + │ MySQL │ │ Redis │ │ ES │ + │ RDS │ │ │ │ │ + └─────────┘ └────────┘ └────────┘ +``` + +### 5.1 环境规划 + +| 环境 | 用途 | 配置 | +|------|------|------| +| 开发 (dev) | 本地开发 | 个人电脑 / Docker Compose | +| 测试 (staging) | 联调测试 | 阿里云 ECS 2C4G | +| 生产 (production) | 正式运营 | 阿里云 ECS 4C8G × 2 + RDS 2C4G | + +### 5.2 CI/CD 流程 + +``` +Git Push → GitHub Actions + ├── Lint & Type Check + ├── Unit Test + ├── Build + └── Deploy to 阿里云 + ├── 构建 Docker 镜像 + ├── Push 到阿里云 CR + └── 滚动更新 ECS/Pod +``` + +--- + +## 6. 性能与安全 + +### 6.1 性能目标 + +| 指标 | 目标 | +|------|------| +| API 响应时间 (P95) | < 200ms | +| 首屏加载时间 | < 1.5s | +| AI 对话首 Token 延迟 | < 1s | +| 并发用户 | 支持 1000+ 同时在线 | +| 系统可用性 | 99.9% | + +### 6.2 安全措施 + +- HTTPS 全站加密 +- API 限流(单用户 100次/分钟) +- SQL 注入防护(Prisma ORM 参数化查询) +- XSS/CSRF 防护 +- 密码 bcrypt 加密 +- 敏感信息脱敏 +- 定期安全扫描 + 渗透测试 + +--- + +## 7. 技术债务与演进路线 + +| 阶段 | 任务 | +|------|------| +| MVP | 单体应用快速验证 | +| V2 | 服务化拆分 | +| V3 | AI 网关独立部署 | +| V4 | 引入 K8s 容器编排 | +| V5 | 多数据中心容灾 | diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..b60b791 --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,10 @@ +node_modules +dist +.next +.env +.env.local +*.log +.git +.gitignore +.DS_Store +coverage diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 0000000..3eec15e --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL=http://localhost:4000 diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..aaa9103 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,2 @@ +test-results/ +playwright-report/ diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..5448c9e --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,33 @@ +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +# Production stage +FROM node:20-alpine + +WORKDIR /app + +RUN apk add --no-cache tini + +COPY --from=builder /app/.next ./.next +COPY --from=builder /app/public ./public +COPY --from=builder /app/package*.json ./ +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/next.config*.js ./ + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +EXPOSE 3000 + +USER node + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["npm", "run", "start"] diff --git a/frontend/e2e/admin-pages.spec.ts b/frontend/e2e/admin-pages.spec.ts new file mode 100644 index 0000000..4f8bfde --- /dev/null +++ b/frontend/e2e/admin-pages.spec.ts @@ -0,0 +1,55 @@ +import { test, expect } from '@playwright/test'; + +test.describe('后台管理页面', () => { + const adminPages = [ + '/admin', + '/admin/login', + '/admin/users', + '/admin/courses', + '/admin/prompts', + '/admin/contents', + '/admin/tools', + '/admin/orders', + '/admin/comments', + '/admin/enterprise', + ]; + + for (const path of adminPages) { + test.describe(`${path}`, () => { + test.beforeEach(async ({ page }) => { + await page.goto(path); + }); + + test('页面能正常加载', async ({ page }) => { + await expect(page.locator('body')).toBeVisible(); + await expect(page.locator('body')).not.toHaveText(/500/); + await expect(page.locator('body')).not.toHaveText(/Application Error/); + await expect(page.locator('body')).not.toHaveText(/Cannot read properties/); + }); + + test('页面有内容展示', async ({ page }) => { + const anyHeading = page.locator('h1, h2, h3, h4, .text-2xl, .text-3xl'); + const headingCount = await anyHeading.count(); + const bodyText = await page.locator('body').textContent() || ''; + expect(headingCount > 0 || bodyText.length > 50).toBeTruthy(); + }); + }); + } + + test.describe('管理后台编辑页面', () => { + const editPages = [ + '/admin/courses/new', + '/admin/prompts/new', + '/admin/contents/new', + '/admin/tools/new', + ]; + + for (const path of editPages) { + test(`${path} 渲染正常`, async ({ page }) => { + await page.goto(path); + await expect(page.locator('body')).toBeVisible(); + await expect(page.locator('body')).not.toHaveText(/500/); + }); + } + }); +}); diff --git a/frontend/e2e/dark-mode.spec.ts b/frontend/e2e/dark-mode.spec.ts new file mode 100644 index 0000000..6f3013b --- /dev/null +++ b/frontend/e2e/dark-mode.spec.ts @@ -0,0 +1,20 @@ +import { test, expect } from '@playwright/test'; + +test.describe('暗黑模式切换', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/'); + }); + + test('主题切换按钮存在', async ({ page }) => { + const toggleBtn = page.locator('button').filter({ has: page.locator('svg') }).first(); + await expect(toggleBtn).toBeVisible(); + }); + + test('点击主题切换按钮无错误', async ({ page }) => { + const toggleBtn = page.locator('button').filter({ has: page.locator('svg') }).first(); + await expect(toggleBtn).toBeEnabled(); + await toggleBtn.click(); + await page.waitForTimeout(500); + await expect(page.locator('html')).toBeAttached(); + }); +}); diff --git a/frontend/e2e/functional-pages.spec.ts b/frontend/e2e/functional-pages.spec.ts new file mode 100644 index 0000000..0ba2b4f --- /dev/null +++ b/frontend/e2e/functional-pages.spec.ts @@ -0,0 +1,119 @@ +import { test, expect } from '@playwright/test'; + +test.describe('功能页面', () => { + test.describe('沙盒 (/sandbox)', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/sandbox'); + }); + + test('页面渲染正常', async ({ page }) => { + await expect(page.locator('h1')).toBeVisible(); + }); + + test('模型选择器存在', async ({ page }) => { + const select = page.locator('select'); + const count = await select.count(); + expect(count).toBeGreaterThanOrEqual(1); + }); + + test('消息输入框存在', async ({ page }) => { + await expect(page.locator('textarea, input[type="text"]').first()).toBeVisible(); + }); + + test('发送按钮存在', async ({ page }) => { + await expect(page.getByText('发送').first()).toBeVisible(); + }); + + test('初始欢迎消息展示', async ({ page }) => { + await expect(page.getByText(/你好!我是宇之然 AI 助手/)).toBeVisible(); + }); + + test('对比实验室链接存在', async ({ page }) => { + const compareLink = page.getByText('对比实验室').or(page.getByText('模型对比')); + const count = await page.getByText('对比实验室').count(); + if (count > 0) { + const link = page.getByText('对比实验室').first(); + await expect(link).toBeVisible(); + const href = await link.getAttribute('href'); + if (href) { + await expect(link).toHaveAttribute('href', /\/sandbox\/compare|\/compare/); + } + } + }); + }); + + test.describe('对比实验室 (/sandbox/compare)', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/sandbox/compare'); + }); + + test('页面渲染正常', async ({ page }) => { + await expect(page.locator('h1')).toBeVisible(); + }); + }); + + test.describe('提示词工坊 (/prompts/workshop)', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/prompts/workshop'); + }); + + test('页面渲染正常', async ({ page }) => { + await expect(page.locator('h1')).toBeVisible(); + }); + }); + + test.describe('搜索 (/search)', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/search'); + }); + + test('搜索输入框存在', async ({ page }) => { + await expect(page.locator('input[type="text"], input[name="q"]').first()).toBeVisible(); + }); + + test('搜索按钮存在', async ({ page }) => { + await expect(page.getByText('搜索').first()).toBeVisible(); + }); + }); + + test.describe('发现页及子页', () => { + test('/discover 渲染', async ({ page }) => { + await page.goto('/discover'); + await expect(page.locator('h1')).toBeVisible(); + const dailyLink = page.getByText('每日精选').first(); + if (await dailyLink.isVisible()) { + await expect(dailyLink).toHaveAttribute('href', '/discover/daily'); + } + }); + + test('/discover/daily 渲染', async ({ page }) => { + await page.goto('/discover/daily'); + await expect(page.locator('h1')).toBeVisible(); + }); + + test('/discover/hot 渲染', async ({ page }) => { + await page.goto('/discover/hot'); + await expect(page.locator('h1')).toBeVisible(); + }); + + test('/discover/tools 渲染', async ({ page }) => { + await page.goto('/discover/tools'); + await expect(page.locator('h1')).toBeVisible(); + }); + }); + + test.describe('认证页 (/auth)', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/auth'); + }); + + test('登录表单可见', async ({ page }) => { + await expect(page.getByText('登录').first()).toBeVisible(); + }); + + test('注册表单可切换', async ({ page }) => { + await page.goto('/auth?tab=register'); + await expect(page.getByText('注册').first()).toBeVisible(); + }); + }); +}); diff --git a/frontend/e2e/homepage.spec.ts b/frontend/e2e/homepage.spec.ts new file mode 100644 index 0000000..39857f6 --- /dev/null +++ b/frontend/e2e/homepage.spec.ts @@ -0,0 +1,67 @@ +import { test, expect } from '@playwright/test'; + +test.describe('首页 (/)', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/'); + }); + + test('页面标题正确', async ({ page }) => { + await expect(page).toHaveTitle(/宇之然 AI/); + }); + + test('Hero 区域渲染', async ({ page }) => { + await expect(page.getByText('免费 AI 知识社区')).toBeVisible(); + await expect(page.getByText('让每个人').first()).toBeVisible(); + await expect(page.getByText('都能用好 AI').first()).toBeVisible(); + await expect(page.getByText('宇之然 AI 是面向大众的 AI 工具与知识社区')).toBeVisible(); + }); + + test('Hero 按钮存在并指向正确链接', async ({ page }) => { + const startBtn = page.getByText('开始探索').first(); + await expect(startBtn).toBeVisible(); + await expect(startBtn).toHaveAttribute('href', '/courses'); + + const registerBtn = page.getByText('免费注册').first(); + await expect(registerBtn).toBeVisible(); + await expect(registerBtn).toHaveAttribute('href', '/auth?tab=register'); + }); + + test('统计数据区域', async ({ page }) => { + await expect(page.getByText('50+').first()).toBeVisible(); + await expect(page.getByText('200+').first()).toBeVisible(); + await expect(page.getByText('30+').first()).toBeVisible(); + await expect(page.getByText('10,000+').first()).toBeVisible(); + }); + + test('特性区域', async ({ page }) => { + await expect(page.getByText('为什么选择宇之然?')).toBeVisible(); + await expect(page.getByText('分领域指南').first()).toBeVisible(); + await expect(page.getByText('AI 沙盒实战').first()).toBeVisible(); + await expect(page.getByText('提示词库').first()).toBeVisible(); + await expect(page.getByText('持续更新').first()).toBeVisible(); + }); + + test('热门专题区域', async ({ page }) => { + await expect(page.getByText('热门专题')).toBeVisible(); + await expect(page.getByText('AI 通识:零基础入门')).toBeVisible(); + await expect(page.getByText('提示词工程从入门到精通')).toBeVisible(); + await expect(page.getByText('用 AI 提升 10 倍办公效率')).toBeVisible(); + }); + + test('AI 沙盒预览区域', async ({ page }) => { + await expect(page.getByText('AI 沙盒').first()).toBeVisible(); + await expect(page.getByText('在线体验 AI 对话,边学边练')).toBeVisible(); + const sandboxLink = page.getByText('打开沙盒').first(); + await expect(sandboxLink).toHaveAttribute('href', '/sandbox'); + }); + + test('CTA 区域', async ({ page }) => { + await expect(page.getByText('准备好开启 AI 之旅了吗?')).toBeVisible(); + await expect(page.getByText('立即注册,免费探索所有内容')).toBeVisible(); + }); + + test('点击 Hero 开始探索进入课程页', async ({ page }) => { + await page.getByText('开始探索').first().click(); + await expect(page).toHaveURL(/\/courses/); + }); +}); diff --git a/frontend/e2e/listing-pages.spec.ts b/frontend/e2e/listing-pages.spec.ts new file mode 100644 index 0000000..f45354c --- /dev/null +++ b/frontend/e2e/listing-pages.spec.ts @@ -0,0 +1,42 @@ +import { test, expect } from '@playwright/test'; + +test.describe('列表页面', () => { + const listingPages = [ + { path: '/courses', title: '专题', skeleton: true }, + { path: '/prompts', title: '提示词', skeleton: true }, + { path: '/community', title: '社区', skeleton: true }, + { path: '/tools', title: 'AI 工具', skeleton: true }, + { path: '/contents', title: '文章', skeleton: true }, + { path: '/models', title: '模型', skeleton: false }, + { path: '/circles', title: '圈子', skeleton: false }, + { path: '/discover', title: '发现', skeleton: false }, + { path: '/dashboard', title: '控制台', skeleton: true }, + ]; + + for (const { path, title, skeleton } of listingPages) { + test.describe(`${path}`, () => { + test.beforeEach(async ({ page }) => { + await page.goto(path); + }); + + test('页面标题元素存在', async ({ page }) => { + const anyHeading = page.locator('h1, h2, h3, h4, [class*="text-2xl"], [class*="text-3xl"]'); + const count = await anyHeading.count(); + expect(count).toBeGreaterThanOrEqual(1); + }); + + test('页面能正常加载', async ({ page }) => { + await expect(page.locator('body')).not.toHaveText(/500/); + await expect(page.locator('body')).not.toHaveText(/Application Error/); + }); + + if (skeleton) { + test('加载骨架屏显示', async ({ page }) => { + const skeletons = page.locator('[class*="animate-pulse"], [class*="skeleton"]'); + const count = await skeletons.count(); + expect(count).toBeGreaterThanOrEqual(1); + }); + } + }); + } +}); diff --git a/frontend/e2e/navigation.spec.ts b/frontend/e2e/navigation.spec.ts new file mode 100644 index 0000000..4ca0234 --- /dev/null +++ b/frontend/e2e/navigation.spec.ts @@ -0,0 +1,112 @@ +import { test, expect } from '@playwright/test'; + +test.describe('导航与页脚', () => { + test.describe('Header 导航', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/'); + }); + + test('品牌名称可见', async ({ page }) => { + await expect(page.getByText('宇之然').first()).toBeVisible(); + }); + + test('主导航链接都可见', async ({ page }) => { + const navLinks = ['首页', '专题', '沙盒', '模型', '提示词', '文章', 'AI 工具', '社区']; + for (const link of navLinks) { + const el = page.getByRole('link', { name: link, exact: true }); + const count = await el.count(); + if (count > 1) { + await expect(el.first()).toBeVisible(); + } else if (count === 1) { + await expect(el).toBeVisible(); + } + } + }); + + test('搜索框可见', async ({ page }) => { + const searchInput = page.locator('input[placeholder="搜索..."]'); + await expect(searchInput).toBeVisible(); + }); + + test('主题切换按钮可见', async ({ page }) => { + const themeToggle = page.locator('button').filter({ has: page.locator('svg') }).first(); + await expect(themeToggle).toBeVisible(); + }); + + test('登录/注册按钮可见', async ({ page }) => { + await expect(page.getByText('登录').first()).toBeVisible(); + await expect(page.getByText('注册').first()).toBeVisible(); + }); + + test('点击导航链接可跳转', async ({ page }) => { + const navMap = [ + { label: '专题', url: '/courses' }, + { label: '沙盒', url: '/sandbox' }, + { label: '模型', url: '/models' }, + { label: '提示词', url: '/prompts' }, + { label: 'AI 工具', url: '/tools' }, + { label: '社区', url: '/community' }, + { label: '文章', url: '/contents' }, + ]; + for (const { label, url } of navMap) { + await page.getByRole('link', { name: label }).first().click(); + await expect(page).toHaveURL(new RegExp(url)); + await page.goBack(); + } + }); + }); + + test.describe('Footer 页脚', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/'); + }); + + test('品牌信息展示', async ({ page }) => { + await expect(page.getByText('让每个人都能用好 AI').first()).toBeVisible(); + const footerHeading = page.locator('footer h3'); + await expect(footerHeading).toContainText('宇之然 AI'); + }); + + test('导航链接', async ({ page }) => { + await expect(page.getByText('专题').last()).toBeVisible(); + await expect(page.getByText('提示词库').last()).toBeVisible(); + await expect(page.getByText('AI 工具').last()).toBeVisible(); + }); + + test('关于链接', async ({ page }) => { + await expect(page.getByText('关于我们')).toBeVisible(); + await expect(page.getByText('隐私政策')).toBeVisible(); + await expect(page.getByText('服务协议').first()).toBeVisible(); + await expect(page.getByText('AI 服务协议')).toBeVisible(); + }); + + test('联系方式', async ({ page }) => { + await expect(page.getByText('contact@yuzhiran.com').first()).toBeVisible(); + const footerInfo = page.locator('footer li, footer p').filter({ hasText: '北京宇之然科技中心' }); + await expect(footerInfo.first()).toBeVisible(); + }); + + test('ICP 备案号链接', async ({ page }) => { + const icpEl = page.locator('footer a').filter({ hasText: /ICP备案|ICP 备案/ }); + await expect(icpEl).toBeVisible(); + await expect(icpEl).toHaveAttribute('href', 'https://beian.miit.gov.cn/'); + }); + + test('Footer 链接点击跳转正确', async ({ page }) => { + const footerLinks: [string, RegExp][] = [ + ['专题', /\/courses/], + ['关于我们', /\/about/], + ['隐私政策', /\/privacy/], + ['服务协议', /\/terms/], + ['AI 服务协议', /\/ai-agreement/], + ]; + for (const [text, urlPattern] of footerLinks) { + const link = page.locator('footer a').filter({ hasText: text }); + await expect(link.first()).toBeVisible(); + await link.first().click(); + await expect(page).toHaveURL(urlPattern); + await page.goBack(); + } + }); + }); +}); diff --git a/frontend/e2e/not-found.spec.ts b/frontend/e2e/not-found.spec.ts new file mode 100644 index 0000000..99b3f3d --- /dev/null +++ b/frontend/e2e/not-found.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from '@playwright/test'; + +test.describe('404 页面', () => { + test('访问不存在页面显示 404', async ({ page }) => { + await page.goto('/this-page-does-not-exist-12345'); + + await expect(page.locator('body')).toBeVisible(); + + const has404 = page.getByText('404').first(); + const hasNotFound = page.getByText(/找不到|不存在|页面/i).first(); + const is404 = await has404.isVisible().catch(() => false); + const isNotFound = await hasNotFound.isVisible().catch(() => false); + + expect(is404 || isNotFound).toBe(true); + }); +}); diff --git a/frontend/e2e/static-pages.spec.ts b/frontend/e2e/static-pages.spec.ts new file mode 100644 index 0000000..1017e18 --- /dev/null +++ b/frontend/e2e/static-pages.spec.ts @@ -0,0 +1,41 @@ +import { test, expect } from '@playwright/test'; + +test.describe('静态页面', () => { + const pages = [ + { path: '/about', title: '关于宇之然', checks: ['我们的使命', '北京宇之然科技中心'] }, + { path: '/privacy', title: '隐私政策', checks: ['隐私政策'] }, + { path: '/terms', title: '服务协议', checks: ['服务协议'] }, + { path: '/ai-agreement', title: 'AI 服务协议', checks: ['AI 服务协议'] }, + ]; + + for (const { path, title, checks } of pages) { + test.describe(`${path}`, () => { + test.beforeEach(async ({ page }) => { + await page.goto(path); + }); + + test('页面标题正确', async ({ page }) => { + await expect(page).toHaveTitle(new RegExp(title)); + }); + + test('页面标题元素存在', async ({ page }) => { + const h1 = page.locator('h1'); + await expect(h1).toContainText(title); + }); + + for (const check of checks) { + test(`包含 "${check}" 内容`, async ({ page }) => { + const el = page.getByText(check, { exact: true }); + const count = await el.count(); + if (count > 1) { + await expect(el.first()).toBeVisible(); + } else if (count === 0) { + await expect(page.locator('main, article, section').filter({ hasText: check })).toBeVisible(); + } else { + await expect(el).toBeVisible(); + } + }); + } + }); + } +}); diff --git a/frontend/e2e/user-pages.spec.ts b/frontend/e2e/user-pages.spec.ts new file mode 100644 index 0000000..1f27041 --- /dev/null +++ b/frontend/e2e/user-pages.spec.ts @@ -0,0 +1,32 @@ +import { test, expect } from '@playwright/test'; + +test.describe('用户相关页面', () => { + const userPages = [ + { path: '/my', title: '我的' }, + { path: '/my/learning', title: '学习进度' }, + { path: '/my/favorites', title: '收藏夹' }, + { path: '/my/member', title: '会员中心' }, + { path: '/my/settings', title: '设置' }, + { path: '/my/dashboard', title: '数据看板' }, + { path: '/notifications', title: '通知' }, + ]; + + for (const { path, title } of userPages) { + test.describe(`${path}`, () => { + test.beforeEach(async ({ page }) => { + await page.goto(path); + }); + + test('页面标题元素存在', async ({ page }) => { + const anyHeading = page.locator('h1, h2, h3, h4, [class*="text-2xl"], [class*="text-3xl"]'); + const count = await anyHeading.count(); + expect(count).toBeGreaterThanOrEqual(1); + }); + + test('无错误展示', async ({ page }) => { + await expect(page.locator('body')).not.toHaveText(/500/); + await expect(page.locator('body')).not.toHaveText(/Application Error/); + }); + }); + } +}); diff --git a/frontend/next-env.d.ts b/frontend/next-env.d.ts new file mode 100644 index 0000000..40c3d68 --- /dev/null +++ b/frontend/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/frontend/next.config.js b/frontend/next.config.js new file mode 100644 index 0000000..bb2ec14 --- /dev/null +++ b/frontend/next.config.js @@ -0,0 +1,13 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + output: 'export', + images: { unoptimized: true }, + typescript: { ignoreBuildErrors: true }, + env: { + NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL || 'https://api.yuzhiran.com', + NEXT_PUBLIC_SITE_URL: 'https://yuzhiran.com', + NEXT_PUBLIC_SITE_NAME: '宇之然 AI', + }, +}; + +module.exports = nextConfig; diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..9d123c2 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,5755 @@ +{ + "name": "@yuzhiran/frontend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@yuzhiran/frontend", + "version": "1.0.0", + "license": "UNLICENSED", + "dependencies": { + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-progress": "^1.1.8", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toast": "^1.2.15", + "@radix-ui/react-tooltip": "^1.2.8", + "@types/node": "^25.6.2", + "autoprefixer": "^10.5.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "framer-motion": "^12.38.0", + "lucide-react": "^1.14.0", + "next": "^14.2.35", + "next-themes": "^0.4.6", + "postcss": "^8.5.14", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "sonner": "^2.0.7", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^3.4.19", + "typescript": "5.3" + }, + "devDependencies": { + "@playwright/test": "^1.60.0", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "jsdom": "^29.1.1", + "vitest": "^4.1.5" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.0.tgz", + "integrity": "sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz", + "integrity": "sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.2.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz", + "integrity": "sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", + "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.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==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@next/env": { + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.35.tgz", + "integrity": "sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.33.tgz", + "integrity": "sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.33.tgz", + "integrity": "sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.33.tgz", + "integrity": "sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.33.tgz", + "integrity": "sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.33.tgz", + "integrity": "sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.33.tgz", + "integrity": "sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.33.tgz", + "integrity": "sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.33.tgz", + "integrity": "sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.33.tgz", + "integrity": "sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "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==", + "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==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.128.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.128.0.tgz", + "integrity": "sha512-huv1Y/LzBJkBVHt3OlC7u0zHBW9qXf1FdD7sGmc1rXc2P1mTwHssYv7jyGx5KAACSCH+9B3Bhn6Z9luHRvf7pQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@playwright/test": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", + "devOptional": true, + "dependencies": { + "playwright": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", + "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz", + "integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", + "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", + "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-lIDyUAfD7U3+BWKzdxMbJcsYHuqXqmGz40aeRqvuAm3y5TkJSYTBW2RDrn65DJFPQqVjUAUqq5uz8urzQ8aBdQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-apJq2ktnGp27nSInMR5Vcj8kY6xJzDAvfdIFlpDcAK/w4cDO58qVoi1YQsES/SKiFNge/6e4CUzgjfHduYqWpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.18.tgz", + "integrity": "sha512-5Ofot8xbs+pxRHJqm9/9N/4sTQOvdrwEsmPE9pdLEEoAbdZtG6F2LMDfO1sp6ZAtXJuJV/21ew2srq3W8NXB5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.18.tgz", + "integrity": "sha512-7h8eeOTT1eyqJyx64BFCnWZpNm486hGWt2sqeLLgDxA0xI1oGZ9H7gK1S85uNGmBhkdPwa/6reTxfFFKvIsebw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.18.tgz", + "integrity": "sha512-eRcm/HVt9U/JFu5RKAEKwGQYtDCKWLiaH6wOnsSEp6NMBb/3Os8LgHZlNyzMpFVNmiiMFlfb2zEnebfzJrHFmg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-SOrT/cT4ukTmgnrEz/Hg3m7LBnuCLW9psDeMKrimRWY4I8DmnO7Lco8W2vtqPmMkbVu8iJ+g4GFLVLLOVjJ9DQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.18.tgz", + "integrity": "sha512-QWjdxN1HJCpBTAcZ5N5F7wju3gVPzRzSpmGzx7na0c/1qpN9CFil+xt+l9lV/1M6/gqHSNXCiqPfwhVJPeLnug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-ugCOyj7a4d9h3q9B+wXmf6g3a68UsjGh6dob5DHevHGMwDUbhsYNbSPxJsENcIttJZ9jv7qGM2UesLw5jqIhdg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-kKWRhbsotpXkGbcd5dllUWg5gEXcDAa8u5YnP9AV5DYNbvJHGzzuwv7dpmhc8NqKMJldl0a+x76IHbspEpEmdA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-uCo8ElcCIAMyYAZyuIZ81oFkhTSIllNvUCHCAlbhlN4ji3uC28h7IIdlXyIvGO7HsuqnV9p3rD/bpH7XhIyhRw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.18.tgz", + "integrity": "sha512-XNOQZtuE6yUIvx4rwGemwh8kpL1xvU41FXy/s9K7T/3JVcqGzo3NfKM2HrbrGgfPYGFW42f07Wk++aOC6B9NWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-tSn/kzrfa7tNOXr7sEacDBN4YsIqTyLqh45IO0nHDwtpKIDNDJr+VFojt+4klSpChxB29JLyduSsE0MKEwa65A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.18.tgz", + "integrity": "sha512-+J9YGmc+czgqlhYmwun3S3O0FIZhsH8ep2456xwjAdIOmuJxM7xz4P4PtrxU+Bz17a/5bqPA8o3HAAoX0teUdg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.18.tgz", + "integrity": "sha512-zsu47DgU0FQzSwi6sU9dZoEdUv7pc1AptSEz/Z8HBg54sV0Pbs3N0+CrIbTsgiu6EyoaNN9CHboqbLaz9lhOyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.18.tgz", + "integrity": "sha512-7H+3yqGgmnlDTRRhw/xpYY9J1kf4GC681nVc4GqKhExZTDrVVrV2tsOR9kso0fvgBdcTCcQShx4SLLoHgaLwhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.18.tgz", + "integrity": "sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "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": "25.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz", + "integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/expect": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", + "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", + "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.5", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", + "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", + "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.5", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", + "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", + "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", + "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.5", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "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", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.27", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.27.tgz", + "integrity": "sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/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==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.352", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.352.tgz", + "integrity": "sha512-9wHk8x6dyuimoe18EdiDPWKExNdxYqo4fn4FwOVVper6RxT3cmpBwBkWWfSOCYJjQdIco/nPhJhNLmn4Ufg1Yg==", + "license": "ISC" + }, + "node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "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==", + "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==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz", + "integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.38.0", + "motion-utils": "^12.36.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "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==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/lucide-react": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.14.0.tgz", + "integrity": "sha512-+1mdWcfSJVUsaTIjN9zoezmUhfXo5l0vP7ekBMPo3jcS/aIkxHnXqAPsByszMZx/Y8oQBRJxJx5xg+RH3urzxA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "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/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "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==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/motion-dom": { + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", + "integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.36.0" + } + }, + "node_modules/motion-utils": { + "version": "12.36.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz", + "integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "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/next": { + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.35.tgz", + "integrity": "sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==", + "license": "MIT", + "dependencies": { + "@next/env": "14.2.35", + "@swc/helpers": "0.5.5", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.2.33", + "@next/swc-darwin-x64": "14.2.33", + "@next/swc-linux-arm64-gnu": "14.2.33", + "@next/swc-linux-arm64-musl": "14.2.33", + "@next/swc-linux-x64-gnu": "14.2.33", + "@next/swc-linux-x64-musl": "14.2.33", + "@next/swc-win32-arm64-msvc": "14.2.33", + "@next/swc-win32-ia32-msvc": "14.2.33", + "@next/swc-win32-x64-msvc": "14.2.33" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "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.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-releases": { + "version": "2.0.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", + "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "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/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "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==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/playwright": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "devOptional": true, + "dependencies": { + "playwright-core": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "devOptional": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "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.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "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==", + "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/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/rolldown": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.18.tgz", + "integrity": "sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.128.0", + "@rolldown/pluginutils": "1.0.0-rc.18" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.18", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.18", + "@rolldown/binding-darwin-x64": "1.0.0-rc.18", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.18", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.18", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.18", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.18", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.18", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.18", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.18", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.18" + } + }, + "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==", + "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/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "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/sonner": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", + "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwind-merge": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "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/tinyexec": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", + "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.0.30", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.30.tgz", + "integrity": "sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.30" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.30", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.30.tgz", + "integrity": "sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-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/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vite": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.11.tgz", + "integrity": "sha512-Jz1mxtUBR5xTT65VOdJZUUeoyLtqljmFkiUXhPTLZka3RDc9vpi/xXkyrnsdRcm2lIi3l3GPMnAidTsEGIj3Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.14", + "rolldown": "1.0.0-rc.18", + "tinyglobby": "^0.2.16" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", + "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.5", + "@vitest/browser-preview": "4.1.5", + "@vitest/browser-webdriverio": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/ui": "4.1.5", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "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/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..545ad60 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,67 @@ +{ + "name": "@yuzhiran/frontend", + "version": "1.0.0", + "description": "宇之然 AI - 官网前端", + "private": true, + "scripts": { + "predev": "rm -rf .next", + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "test": "vitest run", + "test:watch": "vitest", + "test:e2e": "npx playwright test", + "test:e2e:ui": "npx playwright test --ui", + "test:e2e:headed": "npx playwright test --headed", + "test:e2e:report": "npx playwright show-report" + }, + "keywords": [ + "yuzhiran", + "ai", + "learning", + "platform" + ], + "author": "北京宇之然科技中心", + "license": "UNLICENSED", + "dependencies": { + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-progress": "^1.1.8", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toast": "^1.2.15", + "@radix-ui/react-tooltip": "^1.2.8", + "@types/node": "^25.6.2", + "autoprefixer": "^10.5.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "framer-motion": "^12.38.0", + "lucide-react": "^1.14.0", + "next": "^14.2.35", + "next-themes": "^0.4.6", + "postcss": "^8.5.14", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "sonner": "^2.0.7", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^3.4.19", + "typescript": "5.3" + }, + "devDependencies": { + "@playwright/test": "^1.60.0", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "jsdom": "^29.1.1", + "vitest": "^4.1.5" + } +} diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 0000000..0e280c1 --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,23 @@ +import { defineConfig, devices } from '@playwright/test'; + +const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: [['list'], ['html', { open: 'never' }]], + use: { + baseURL: BASE_URL, + trace: 'on-first-retry', + screenshot: 'only-on-failure', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'], locale: 'zh-CN' }, + }, + ], +}); diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 0000000..12a703d --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000..431d0f6 Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/public/favicon.png b/frontend/public/favicon.png new file mode 100644 index 0000000..d070f92 Binary files /dev/null and b/frontend/public/favicon.png differ diff --git a/frontend/public/icon.svg b/frontend/public/icon.svg new file mode 100644 index 0000000..0911c5c --- /dev/null +++ b/frontend/public/icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/app/__tests__/home.test.tsx b/frontend/src/app/__tests__/home.test.tsx new file mode 100644 index 0000000..44b3e64 --- /dev/null +++ b/frontend/src/app/__tests__/home.test.tsx @@ -0,0 +1,77 @@ +import { describe, it, expect } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import HomePage from '@/app/page'; + +describe('HomePage', () => { + it('should render hero section', () => { + render(); + const heading = screen.getByRole('heading', { level: 1 }); + expect(heading.textContent).toMatch(/让/); + expect(heading.textContent).toMatch(/每个人/); + expect(heading.textContent).toMatch(/都能用好 AI/); + expect(screen.getByText(/免费 AI 知识社区/)).toBeInTheDocument(); + }); + + it('should render feature section title', () => { + render(); + expect(screen.getByText('为什么选择宇之然?')).toBeInTheDocument(); + }); + + it('should render all four features', () => { + render(); + expect(screen.getByText('分领域指南')).toBeInTheDocument(); + expect(screen.getByText('AI 沙盒实战')).toBeInTheDocument(); + expect(screen.getByText('提示词库')).toBeInTheDocument(); + expect(screen.getByText('持续更新')).toBeInTheDocument(); + }); + + it('should render stats section', () => { + render(); + expect(screen.getByText('50+')).toBeInTheDocument(); + expect(screen.getByText('200+')).toBeInTheDocument(); + expect(screen.getByText('30+')).toBeInTheDocument(); + expect(screen.getByText('10,000+')).toBeInTheDocument(); + }); + + it('should render course preview section', () => { + render(); + expect(screen.getByText('热门专题')).toBeInTheDocument(); + expect(screen.getByText('AI 通识:零基础入门')).toBeInTheDocument(); + expect(screen.getByText('提示词工程从入门到精通')).toBeInTheDocument(); + expect(screen.getByText('用 AI 提升 10 倍办公效率')).toBeInTheDocument(); + }); + + it('should render sandbox preview section', () => { + render(); + expect(screen.getByText('AI 沙盒')).toBeInTheDocument(); + expect(screen.getByText('在线体验 AI 对话,边学边练')).toBeInTheDocument(); + }); + + it('should render CTA section', () => { + render(); + expect(screen.getByText('准备好开启 AI 之旅了吗?')).toBeInTheDocument(); + expect(screen.getByText('立即注册,免费探索所有内容')).toBeInTheDocument(); + }); + + it('should have CTA buttons with correct links', () => { + render(); + const startLearning = screen.getByText('开始探索').closest('a'); + expect(startLearning).toHaveAttribute('href', '/courses'); + + const registerBtn = screen.getAllByText('免费注册'); + expect(registerBtn.length).toBeGreaterThanOrEqual(1); + }); + + it('should render course descriptions', () => { + render(); + expect(screen.getByText(/面向零基础用户/)).toBeInTheDocument(); + expect(screen.getByText(/系统学习提示词编写技巧/)).toBeInTheDocument(); + expect(screen.getByText(/学习使用 AI 工具/)).toBeInTheDocument(); + }); + + it('should render sandbox with mock chat interface', () => { + render(); + expect(screen.getByText(/你好!我是宇之然 AI 助手/)).toBeInTheDocument(); + expect(screen.getByText(/正在输入/)).toBeInTheDocument(); + }); +}); diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx new file mode 100644 index 0000000..3f2c28e --- /dev/null +++ b/frontend/src/app/about/page.tsx @@ -0,0 +1,47 @@ +import Link from 'next/link'; +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: '关于宇之然', + description: '关于宇之然 AI 学习与实践平台', +}; + +export default function AboutPage() { + return ( +
+

关于宇之然

+ +
+

我们的使命

+

+ 宇之然 AI 致力于让每个人都能用好 AI。我们相信 AI 不应只是技术人员的专属工具,而是每个人都可以掌握和运用的生产力助手。 +

+
+ +
+

北京宇之然科技中心

+

+ 北京宇之然科技中心是一家专注于 AI 技术普及与应用的科技企业,位于北京市大兴区。我们致力于搭建 AI 技术与大众用户之间的桥梁。 +

+
+ +
+

合规文件

+
    +
  • 隐私政策
  • +
  • 服务协议
  • +
  • AI 服务协议
  • +
+
+ +
+

联系方式

+

+ 邮箱:contact@yuzhiran.com
+ 北京宇之然科技中心
+ 北京市大兴区 +

+
+
+ ); +} diff --git a/frontend/src/app/admin/comments/page.tsx b/frontend/src/app/admin/comments/page.tsx new file mode 100644 index 0000000..cba1b70 --- /dev/null +++ b/frontend/src/app/admin/comments/page.tsx @@ -0,0 +1,134 @@ +'use client'; + +import { useEffect, useState, useCallback } from 'react'; +import { Skeleton } from '@/components/ui/skeleton'; + +interface PendingComment { + id: number; + content: string; + status: string; + createdAt: string; + user: { id: number; nickname: string; avatar: string | null }; + post: { id: number; title: string }; +} + +export default function AdminCommentsPage() { + const [comments, setComments] = useState([]); + const [loading, setLoading] = useState(true); + const [tab, setTab] = useState<'pending' | 'approved' | 'rejected'>('pending'); + + const base = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000/api/v1'; + function headers() { + const t = localStorage.getItem('adminToken'); + return { 'Content-Type': 'application/json', ...(t ? { Authorization: `Bearer ${t}` } : {}) }; + } + + const load = useCallback(async () => { + setLoading(true); + try { + const url = tab === 'pending' + ? '/admin/comments/pending' + : tab === 'approved' + ? '/admin/comments?status=PUBLISHED' + : '/admin/comments?status=REJECTED'; + const res = await fetch(`${base}${url}`, { headers: headers() }); + if (res.ok) { + const data = await res.json(); + setComments(data.items || []); + } + } catch (e) { console.error(e) } + setLoading(false); + }, [tab, base]); + + useEffect(() => { load(); }, [load]); + + async function approve(id: number) { + try { + const res = await fetch(`${base}/admin/comments/${id}/approve`, { + method: 'PUT', headers: headers(), + }); + if (res.ok) setComments(prev => prev.filter(c => c.id !== id)); + } catch (e) { console.error(e) } + } + + async function reject(id: number) { + const reason = prompt('请输入拒绝原因:'); + if (!reason) return; + try { + const res = await fetch(`${base}/admin/comments/${id}/reject`, { + method: 'PUT', headers: headers(), body: JSON.stringify({ reason }), + }); + if (res.ok) setComments(prev => prev.filter(c => c.id !== id)); + } catch (e) { console.error(e) } + } + + return ( + <> +
+

评论审核

+
+
+
+ {(['pending', 'approved', 'rejected'] as const).map(t => ( + + ))} +
+ + {loading ? ( +
+ {[1,2,3].map(i => ( +
+ + + +
+ ))} +
+ ) : comments.length === 0 ? ( +
+

{tab === 'pending' ? '✅' : '📝'}

+

{tab === 'pending' ? '暂无待审核评论' : tab === 'approved' ? '暂无已通过评论' : '暂无已拒绝评论'}

+
+ ) : ( +
+ {comments.map(c => ( +
+
+
+ {c.user.nickname?.[0] || 'U'} +
+ {c.user.nickname || '用户'} + · {new Date(c.createdAt).toLocaleString('zh-CN')} +
+

{c.content}

+
+ + 来源: {c.post.title} + + {tab === 'pending' && ( +
+ + +
+ )} +
+
+ ))} +
+ )} +
+ + ); +} diff --git a/frontend/src/app/admin/contents/[id]/edit-content.tsx b/frontend/src/app/admin/contents/[id]/edit-content.tsx new file mode 100644 index 0000000..9a5ec34 --- /dev/null +++ b/frontend/src/app/admin/contents/[id]/edit-content.tsx @@ -0,0 +1,103 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useParams, useRouter } from 'next/navigation'; +import Link from 'next/link'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Card } from '@/components/ui/card'; +import { Skeleton } from '@/components/ui/skeleton'; + +export default function EditContentPage() { + const params = useParams(); + const router = useRouter(); + const [form, setForm] = useState({ title: '', summary: '', content: '', cover: '', contentType: 'article' }); + const [loading, setLoading] = useState(true); + const [submitting, setSubmitting] = useState(false); + + useEffect(() => { loadContent(); }, [params.id]); + + const base = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'; + function token() { return localStorage.getItem('adminToken'); } + function headers() { + const t = token(); + return { 'Content-Type': 'application/json', ...(t ? { Authorization: `Bearer ${t}` } : {}) }; + } + + async function loadContent() { + try { + const res = await fetch(`${base}/api/v1/contents/${params.id}`, { headers: headers() }); + if (res.ok) { + const data = await res.json(); + setForm({ title: data.title || '', summary: data.summary || '', content: data.content || '', cover: data.cover || '', contentType: data.contentType || 'article' }); + } + } catch {} + setLoading(false); + } + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + if (!form.title.trim() || !form.content.trim()) return; + setSubmitting(true); + try { + const res = await fetch(`${base}/api/v1/contents/${params.id}`, { + method: 'PUT', headers: headers(), body: JSON.stringify(form), + }); + if (res.ok) router.push('/admin/contents'); + } catch {} + setSubmitting(false); + } + + if (loading) return ( +
+ + +
+ ); + + return ( + <> +
+

编辑内容

+
+
+ +
+
+ + setForm(f => ({ ...f, title: e.target.value }))} required /> +
+
+ + setForm(f => ({ ...f, summary: e.target.value }))} /> +
+
+ +