From aa2416c5d614f4cd55361329c7144d235312058a Mon Sep 17 00:00:00 2001 From: liangweihao <734499798@qq.com> Date: Tue, 8 Jul 2025 00:52:10 +0800 Subject: [PATCH] first commit --- .gitignore | 139 + ARCHITECTURE.md | 288 + INTEGRATION_README.md | 152 + README.md | 262 + backend/Dockerfile | 38 + backend/README.md | 347 + backend/package.json | 45 + backend/prisma/schema.prisma | 99 + backend/prisma/seed.ts | 153 + backend/src/config/database.ts | 34 + backend/src/controllers/accountController.ts | 545 ++ backend/src/controllers/adminController.ts | 222 + backend/src/controllers/auditLogController.ts | 57 + backend/src/controllers/authController.ts | 387 + backend/src/controllers/userController.ts | 365 + backend/src/index.ts | 105 + backend/src/middleware/adminMiddleware.ts | 19 + backend/src/middleware/auth.ts | 82 + backend/src/middleware/authMiddleware.ts | 72 + backend/src/middleware/errorHandler.ts | 45 + backend/src/middleware/notFoundHandler.ts | 9 + backend/src/middleware/validateRequest.ts | 16 + backend/src/middleware/validation.ts | 17 + backend/src/routes/accounts.ts | 38 + backend/src/routes/admin.ts | 37 + backend/src/routes/auth.ts | 52 + backend/src/routes/users.ts | 23 + backend/src/utils/audit.ts | 41 + backend/src/utils/logger.ts | 26 + backend/tsconfig.json | 30 + docker-compose.yml | 44 + env.example | 68 + frontend/Dockerfile | 35 + frontend/README.md | 108 + frontend/index.html | 17 + frontend/package.json | 50 + frontend/postcss.config.js | 6 + frontend/src/App.vue | 15 + frontend/src/assets/ChatGPT.png | Bin 0 -> 15180 bytes frontend/src/assets/claude.png | Bin 0 -> 54846 bytes frontend/src/assets/grok.png | Bin 0 -> 10570 bytes frontend/src/components/icons/index.ts | 35 + frontend/src/config/websites.ts | 62 + frontend/src/env.d.ts | 11 + frontend/src/main.ts | 44 + frontend/src/router/index.ts | 105 + frontend/src/stores/admin.ts | 248 + frontend/src/stores/auth.ts | 247 + frontend/src/style.css | 39 + frontend/src/types/index.ts | 119 + frontend/src/types/vue.d.ts | 13 + frontend/src/utils/api.ts | 294 + frontend/src/utils/auth.ts | 96 + frontend/src/views/Admin.vue | 472 + frontend/src/views/AdminAccounts.vue | 422 + frontend/src/views/AdminLogin.vue | 208 + frontend/src/views/AdminMonitor.vue | 38 + frontend/src/views/AdminPermissions.vue | 388 + frontend/src/views/AdminUsers.vue | 400 + frontend/src/views/Dashboard.vue | 243 + frontend/src/views/Home.vue | 401 + frontend/src/views/NotFound.vue | 43 + frontend/src/views/Test.vue | 212 + frontend/tailwind.config.js | 65 + frontend/tsconfig.json | 36 + frontend/tsconfig.node.json | 10 + frontend/vite.config.ts | 44 + package-lock.json | 8186 +++++++++++++++++ package.json | 59 + 69 files changed, 16628 insertions(+) create mode 100644 .gitignore create mode 100644 ARCHITECTURE.md create mode 100644 INTEGRATION_README.md create mode 100644 README.md create mode 100644 backend/Dockerfile create mode 100644 backend/README.md create mode 100644 backend/package.json create mode 100644 backend/prisma/schema.prisma create mode 100644 backend/prisma/seed.ts create mode 100644 backend/src/config/database.ts create mode 100644 backend/src/controllers/accountController.ts create mode 100644 backend/src/controllers/adminController.ts create mode 100644 backend/src/controllers/auditLogController.ts create mode 100644 backend/src/controllers/authController.ts create mode 100644 backend/src/controllers/userController.ts create mode 100644 backend/src/index.ts create mode 100644 backend/src/middleware/adminMiddleware.ts create mode 100644 backend/src/middleware/auth.ts create mode 100644 backend/src/middleware/authMiddleware.ts create mode 100644 backend/src/middleware/errorHandler.ts create mode 100644 backend/src/middleware/notFoundHandler.ts create mode 100644 backend/src/middleware/validateRequest.ts create mode 100644 backend/src/middleware/validation.ts create mode 100644 backend/src/routes/accounts.ts create mode 100644 backend/src/routes/admin.ts create mode 100644 backend/src/routes/auth.ts create mode 100644 backend/src/routes/users.ts create mode 100644 backend/src/utils/audit.ts create mode 100644 backend/src/utils/logger.ts create mode 100644 backend/tsconfig.json create mode 100644 docker-compose.yml create mode 100644 env.example create mode 100644 frontend/Dockerfile create mode 100644 frontend/README.md create mode 100644 frontend/index.html create mode 100644 frontend/package.json create mode 100644 frontend/postcss.config.js create mode 100644 frontend/src/App.vue create mode 100644 frontend/src/assets/ChatGPT.png create mode 100644 frontend/src/assets/claude.png create mode 100644 frontend/src/assets/grok.png create mode 100644 frontend/src/components/icons/index.ts create mode 100644 frontend/src/config/websites.ts create mode 100644 frontend/src/env.d.ts create mode 100644 frontend/src/main.ts create mode 100644 frontend/src/router/index.ts create mode 100644 frontend/src/stores/admin.ts create mode 100644 frontend/src/stores/auth.ts create mode 100644 frontend/src/style.css create mode 100644 frontend/src/types/index.ts create mode 100644 frontend/src/types/vue.d.ts create mode 100644 frontend/src/utils/api.ts create mode 100644 frontend/src/utils/auth.ts create mode 100644 frontend/src/views/Admin.vue create mode 100644 frontend/src/views/AdminAccounts.vue create mode 100644 frontend/src/views/AdminLogin.vue create mode 100644 frontend/src/views/AdminMonitor.vue create mode 100644 frontend/src/views/AdminPermissions.vue create mode 100644 frontend/src/views/AdminUsers.vue create mode 100644 frontend/src/views/Dashboard.vue create mode 100644 frontend/src/views/Home.vue create mode 100644 frontend/src/views/NotFound.vue create mode 100644 frontend/src/views/Test.vue create mode 100644 frontend/tailwind.config.js create mode 100644 frontend/tsconfig.json create mode 100644 frontend/tsconfig.node.json create mode 100644 frontend/vite.config.ts create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..636a19e --- /dev/null +++ b/.gitignore @@ -0,0 +1,139 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Production builds +dist/ +build/ +.next/ +out/ + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Logs +logs/ +*.log + +# Runtime data +pids/ +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Docker +.dockerignore + +# Database +*.sqlite +*.db + +# Uploads +uploads/ +public/uploads/ + +# SSL certificates +ssl/ +*.pem +*.key +*.crt + +# Backup files +backups/ +*.backup + +# Temporary files +tmp/ +temp/ + +# Prisma +prisma/migrations/ +!prisma/migrations/.gitkeep + +# TypeScript +*.tsbuildinfo + +# Testing +coverage/ +.nyc_output/ + +# Monitoring +monitoring/data/ \ No newline at end of file diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..343a9d0 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,288 @@ +# Pandora 系统架构设计 + +## 整体架构 + +Pandora 采用现代化的微服务架构,前后端分离,支持容器化部署。 + +### 技术栈 + +**前端**: Vue 3 + TypeScript + Tailwind CSS + Vite +**后端**: Node.js + Express.js + TypeScript + Prisma +**数据库**: PostgreSQL + Redis +**部署**: Docker + Docker Compose + Nginx + +### 核心功能模块 + +1. **用户认证系统** - 多路径登录、二步验证 +2. **权限管理系统** - 基于角色的访问控制 +3. **账号管理系统** - 网站账号token存储和分配 +4. **后台管理系统** - 用户和权限管理界面 + +### 安全特性 + +- JWT身份验证 +- 密码加密存储 +- 二步验证(TOTP/邮箱) +- API限流保护 +- 审计日志记录 + +### 部署架构 + +- 开发环境: Docker Compose +- 生产环境: 支持负载均衡和监控 +- 数据库: PostgreSQL主从复制 +- 缓存: Redis集群 + +## 数据库设计 + +### 核心表结构 + +- **users**: 用户信息 +- **paths**: 登录路径 +- **user_paths**: 用户路径权限 +- **website_accounts**: 网站账号 +- **account_assignments**: 账号分配 +- **sessions**: 用户会话 +- **audit_logs**: 审计日志 + +## API设计 + +RESTful API设计,支持用户管理、权限管理、账号管理等核心功能。 + +## 监控和日志 + +- 健康检查端点 +- 性能监控 +- 错误追踪 +- 访问日志 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 用户层 │ +├─────────────────────────────────────────────────────────────┤ +│ Domain A (path1.com) │ Domain B (path2.com) │ Domain C │ +└─────────────────────────────────────────────────────────────┘ + │ + ┌─────────────────┐ + │ Nginx Proxy │ + │ (Load Bal.) │ + └─────────────────┘ + │ + ┌─────────────────┐ + │ Frontend │ + │ (React SPA) │ + └─────────────────┘ + │ + ┌─────────────────┐ + │ Backend API │ + │ (Express.js) │ + └─────────────────┘ + │ + ┌────────────────────┼────────────────────┐ + │ │ │ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ PostgreSQL │ │ Redis │ │ File Storage │ +│ (Main DB) │ │ (Cache/Session)│ │ (Uploads) │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ +``` + +## 技术栈选择 + +### 前端技术栈 +- **React 18**: 现代化的前端框架,支持并发特性 +- **TypeScript**: 类型安全,提高开发效率和代码质量 +- **Vite**: 快速的构建工具,支持热重载 +- **Tailwind CSS**: 实用优先的CSS框架,快速构建UI +- **React Router**: 客户端路由管理 +- **React Query**: 数据获取和缓存管理 +- **Zustand**: 轻量级状态管理 +- **React Hook Form**: 表单处理 +- **React Hot Toast**: 通知组件 + +### 后端技术栈 +- **Node.js**: JavaScript运行时 +- **Express.js**: 轻量级Web框架 +- **TypeScript**: 类型安全 +- **Prisma**: 现代化数据库ORM +- **PostgreSQL**: 关系型数据库 +- **Redis**: 缓存和会话存储 +- **JWT**: 身份验证 +- **bcrypt**: 密码加密 +- **nodemailer**: 邮件发送 +- **speakeasy**: TOTP生成 + +### 基础设施 +- **Docker**: 容器化部署 +- **Docker Compose**: 多服务编排 +- **Nginx**: 反向代理和负载均衡 +- **Let's Encrypt**: SSL证书 + +## 安全架构 + +### 认证机制 +1. **多因素认证**: 支持邮箱验证码和TOTP +2. **JWT Token**: 无状态的身份验证 +3. **会话管理**: Redis存储会话信息 +4. **密码安全**: bcrypt加密,支持盐值 + +### 权限控制 +1. **基于角色的访问控制(RBAC)**: 用户、管理员、超级管理员 +2. **路径权限**: 用户只能访问被授权的路径 +3. **账号权限**: 用户只能访问被分配的账号 +4. **API权限**: 基于角色的API访问控制 + +### 数据安全 +1. **敏感数据加密**: 使用AES加密存储token +2. **SQL注入防护**: 使用Prisma ORM +3. **XSS防护**: 输入验证和输出转义 +4. **CSRF防护**: Token验证 +5. **限流保护**: API访问频率限制 + +## API设计 + +### RESTful API +``` +认证相关: +POST /api/auth/register - 用户注册 +POST /api/auth/login - 用户登录 +POST /api/auth/logout - 用户登出 +POST /api/auth/verify-email - 邮箱验证 +POST /api/auth/verify-totp - TOTP验证 + +用户管理: +GET /api/users - 获取用户列表 +GET /api/users/:id - 获取用户详情 +PUT /api/users/:id - 更新用户信息 +DELETE /api/users/:id - 删除用户 + +路径管理: +GET /api/paths - 获取路径列表 +GET /api/paths/:id - 获取路径详情 +POST /api/paths - 创建路径 +PUT /api/paths/:id - 更新路径 +DELETE /api/paths/:id - 删除路径 + +账号管理: +GET /api/accounts - 获取账号列表 +GET /api/accounts/:id - 获取账号详情 +POST /api/accounts - 创建账号 +PUT /api/accounts/:id - 更新账号 +DELETE /api/accounts/:id - 删除账号 + +权限管理: +GET /api/permissions - 获取权限列表 +POST /api/permissions - 分配权限 +DELETE /api/permissions/:id - 撤销权限 +``` + +### GraphQL API (可选) +```graphql +type Query { + users: [User!]! + user(id: ID!): User + paths: [Path!]! + accounts: [Account!]! +} + +type Mutation { + createUser(input: CreateUserInput!): User! + updateUser(id: ID!, input: UpdateUserInput!): User! + assignPermission(input: AssignPermissionInput!): Permission! +} +``` + +## 部署架构 + +### 开发环境 +```yaml +services: + postgres: PostgreSQL 数据库 + redis: Redis 缓存 + backend: Express.js API 服务 + frontend: React 开发服务器 + nginx: 反向代理 +``` + +### 生产环境 +```yaml +services: + postgres: PostgreSQL 数据库 (主从复制) + redis: Redis 集群 + backend: Express.js API 服务 (负载均衡) + frontend: Nginx 静态文件服务 + nginx: 反向代理和SSL终止 + prometheus: 监控服务 + grafana: 监控面板 +``` + +## 监控和日志 + +### 应用监控 +- **健康检查**: 每个服务都有健康检查端点 +- **性能监控**: 使用Prometheus收集指标 +- **错误追踪**: 集成错误监控服务 +- **日志聚合**: 集中化日志管理 + +### 安全监控 +- **访问日志**: 记录所有API访问 +- **审计日志**: 记录敏感操作 +- **异常检测**: 检测异常访问模式 +- **实时告警**: 安全事件实时通知 + +## 扩展性设计 + +### 水平扩展 +- **无状态设计**: 后端服务无状态,支持水平扩展 +- **数据库分片**: 支持数据库水平分片 +- **缓存分层**: 多级缓存策略 +- **CDN集成**: 静态资源CDN加速 + +### 功能扩展 +- **插件系统**: 支持功能插件扩展 +- **API版本控制**: 支持API版本管理 +- **多租户**: 支持多租户架构 +- **国际化**: 支持多语言 + +## 性能优化 + +### 前端优化 +- **代码分割**: 按路由分割代码 +- **懒加载**: 组件和图片懒加载 +- **缓存策略**: 静态资源缓存 +- **预加载**: 关键资源预加载 + +### 后端优化 +- **数据库索引**: 优化查询性能 +- **连接池**: 数据库连接池管理 +- **缓存策略**: Redis缓存热点数据 +- **异步处理**: 非关键操作异步处理 + +## 故障恢复 + +### 高可用性 +- **服务冗余**: 关键服务多实例部署 +- **数据库备份**: 定期数据库备份 +- **故障转移**: 自动故障转移机制 +- **灾难恢复**: 完整的灾难恢复计划 + +### 数据保护 +- **数据备份**: 定期数据备份 +- **版本控制**: 数据版本管理 +- **加密存储**: 敏感数据加密 +- **访问控制**: 严格的数据访问控制 + +## 开发流程 + +### 代码管理 +- **Git工作流**: 基于Git的版本控制 +- **代码审查**: 强制代码审查 +- **自动化测试**: 单元测试和集成测试 +- **CI/CD**: 持续集成和部署 + +### 质量保证 +- **代码规范**: ESLint和Prettier +- **类型检查**: TypeScript严格模式 +- **测试覆盖**: 高测试覆盖率 +- **安全扫描**: 定期安全扫描 + +这个架构设计确保了系统的安全性、可扩展性和可维护性,为Pandora网站账号共享系统提供了坚实的基础。 \ No newline at end of file diff --git a/INTEGRATION_README.md b/INTEGRATION_README.md new file mode 100644 index 0000000..599ac28 --- /dev/null +++ b/INTEGRATION_README.md @@ -0,0 +1,152 @@ +# Pandora 前后端集成说明 + +## 🚀 快速启动 + +### 1. 启动后端服务 + +```bash +cd backend +npm install +npm run dev +``` + +后端服务将在 `http://localhost:3001` 启动 + +### 2. 启动前端服务 + +```bash +cd frontend +npm install +npm run dev +``` + +前端服务将在 `http://localhost:3000` 启动 + +## 🔧 配置说明 + +### 后端配置 + +后端使用 SQLite 数据库,无需额外配置。主要配置项在 `backend/.env` 文件中: + +- `DATABASE_URL`: SQLite 数据库路径 +- `JWT_SECRET`: JWT 密钥 +- `PORT`: 服务端口 (默认 3001) + +### 前端配置 + +前端 API 基础 URL 配置在 `frontend/src/utils/api.ts` 中: + +```typescript +const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3001/api' +``` + +## 🧪 测试集成 + +### 1. API 测试页面 + +访问 `http://localhost:3000/test` 可以测试各种 API 功能: + +- 获取路径列表 +- 用户注册 +- 用户登录 +- 获取用户信息 + +### 2. 功能测试 + +1. **用户注册**: 访问首页,切换到注册模式,填写信息并注册 +2. **用户登录**: 使用注册的邮箱和密码登录 +3. **路径权限**: 登录后查看仪表板中的路径权限 +4. **账号管理**: 查看分配的网站账号 + +## 📋 已实现的功能 + +### 后端 API + +- ✅ 用户注册 (`POST /api/auth/register`) +- ✅ 用户登录 (`POST /api/auth/login`) +- ✅ 邮箱验证 (`POST /api/auth/verify-email`) +- ✅ 密码重置 (`POST /api/auth/forgot-password`, `POST /api/auth/reset-password`) +- ✅ TOTP 二步验证 (`POST /api/auth/verify-totp`) +- ✅ 用户信息管理 (`GET /api/auth/profile`, `PUT /api/auth/profile`) +- ✅ 路径权限管理 (`GET /api/paths`, `GET /api/paths/user`) +- ✅ 账号管理 (`GET /api/accounts/user`) +- ✅ 管理员功能 (`/api/admin/*`) + +### 前端功能 + +- ✅ 用户认证状态管理 (Pinia Store) +- ✅ API 服务层 (Axios) +- ✅ 路由守卫 +- ✅ 登录/注册界面 +- ✅ 用户仪表板 +- ✅ 路径权限显示 +- ✅ 账号列表显示 +- ✅ Toast 通知 +- ✅ 响应式设计 + +## 🔐 认证流程 + +1. **注册**: 用户填写信息 → 后端创建用户 → 发送验证邮件 +2. **登录**: 用户输入邮箱密码 → 后端验证 → 返回 JWT Token +3. **权限验证**: 前端请求携带 Token → 后端验证权限 → 返回数据 +4. **路径选择**: 用户选择登录路径 → 验证路径权限 → 进入系统 + +## 🛠️ 开发工具 + +### 后端开发 + +```bash +# 数据库迁移 +npm run db:migrate + +# 生成 Prisma 客户端 +npm run db:generate + +# 查看数据库 +npm run db:studio +``` + +### 前端开发 + +```bash +# 代码检查 +npm run lint + +# 类型检查 +npm run type-check + +# 构建生产版本 +npm run build +``` + +## 🐛 常见问题 + +### 1. CORS 错误 + +确保后端 CORS 配置正确,允许前端域名访问。 + +### 2. 数据库连接错误 + +检查 SQLite 数据库文件是否存在,确保有写入权限。 + +### 3. API 请求失败 + +检查后端服务是否正常运行,API 地址是否正确。 + +### 4. 认证失败 + +检查 JWT Token 是否正确传递,Token 是否过期。 + +## 📝 下一步开发 + +1. **完善管理后台**: 实现用户管理、权限管理、账号管理界面 +2. **添加更多安全功能**: API 限流、IP 白名单、审计日志 +3. **优化用户体验**: 添加加载状态、错误处理、表单验证 +4. **性能优化**: 数据库查询优化、前端代码分割、缓存策略 +5. **测试覆盖**: 单元测试、集成测试、端到端测试 + +## 🔗 相关文档 + +- [后端 API 文档](./backend/README.md) +- [前端开发文档](./frontend/README.md) +- [数据库设计文档](./TODO.md) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d35b7d2 --- /dev/null +++ b/README.md @@ -0,0 +1,262 @@ +# Pandora - 网站账号共享系统 + +## 项目简介 + +Pandora 是一个现代化的网站账号共享管理系统,允许用户通过不同的域名路径访问共享的网站账号。系统提供了完整的用户管理、权限控制和账号token管理功能。 + +## 核心功能 + +### 🏠 用户界面 +- **Claude风格首页**: 现代化的AI助手风格界面设计 +- **多路径登录**: 支持三个不同的登录路径,每个路径对应独立域名 +- **响应式设计**: 适配各种设备尺寸 + +### 🔐 认证系统 +- **多路径登录**: 用户可选择不同的登录路径 +- **二步验证**: 支持邮箱验证码和TOTP验证 +- **权限控制**: 基于角色的访问控制 + +### 👥 用户管理 +- **用户注册/登录**: 完整的用户认证流程 +- **权限分配**: 管理员可控制用户访问权限 +- **路径权限**: 用户只能看到有权限的登录路径 + +### 🔑 账号管理 +- **Token存储**: 安全存储不同网站的账号token +- **账号分配**: 将网站账号分配给指定用户 +- **访问控制**: 未分配的账号用户无法访问 + +### 🛠️ 后台管理 +- **用户管理**: 查看、编辑、删除用户 +- **权限管理**: 分配和撤销用户权限 +- **账号管理**: 管理网站账号和token +- **系统监控**: 访问日志和系统状态 + +## 技术架构 + +### 前端技术栈 +- **Vue 3**: 现代化的前端框架 +- **TypeScript**: 类型安全的JavaScript +- **Tailwind CSS**: 实用优先的CSS框架 +- **Vue Router**: 客户端路由 +- **Pinia**: 状态管理 +- **VueUse**: 组合式工具库 +- **VeeValidate**: 表单验证 +- **Vue Toastification**: 通知组件 + +### 后端技术栈 +- **Node.js**: JavaScript运行时 +- **Express.js**: Web应用框架 +- **TypeScript**: 类型安全 +- **Prisma**: 数据库ORM +- **PostgreSQL**: 主数据库 +- **Redis**: 缓存和会话存储 +- **JWT**: 身份验证 +- **bcrypt**: 密码加密 +- **nodemailer**: 邮件发送 +- **speakeasy**: TOTP生成 + +### 基础设施 +- **Docker**: 容器化部署 +- **Docker Compose**: 多服务编排 +- **Nginx**: 反向代理和负载均衡 +- **Let's Encrypt**: SSL证书 + +## 系统架构 + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Domain A │ │ Domain B │ │ Domain C │ +│ (path1.com) │ │ (path2.com) │ │ (path3.com) │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ │ │ + └───────────────────────┼───────────────────────┘ + │ + ┌─────────────────┐ + │ Nginx Proxy │ + │ (Load Bal.) │ + └─────────────────┘ + │ + ┌─────────────────┐ + │ Frontend │ + │ (Vue App) │ + └─────────────────┘ + │ + ┌─────────────────┐ + │ Backend API │ + │ (Express.js) │ + └─────────────────┘ + │ + ┌───────────────────────┼───────────────────────┐ + │ │ │ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ PostgreSQL │ │ Redis │ │ File Storage │ +│ (Main DB) │ │ (Cache/Session)│ │ (Uploads) │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ +``` + +## 数据库设计 + +### 核心表结构 +- **users**: 用户信息表 +- **user_paths**: 用户路径权限表 +- **website_accounts**: 网站账号表 +- **account_assignments**: 账号分配表 +- **sessions**: 用户会话表 +- **audit_logs**: 审计日志表 + +## 快速开始 + +### 环境要求 +- Docker 20.10+ +- Docker Compose 2.0+ +- 至少 2GB 可用内存 + +### 安装步骤 + +1. **克隆项目** +```bash +git clone https://github.com/your-username/pandora.git +cd pandora +``` + +2. **配置环境变量** +```bash +cp env.example .env +# 编辑 .env 文件,配置必要的环境变量 +``` + +3. **启动服务** +```bash +docker-compose up -d +``` + +4. **初始化数据库** +```bash +docker-compose exec backend npm run db:migrate +docker-compose exec backend npm run db:seed +``` + +5. **访问应用** +- 前端: http://localhost:3000 +- 管理后台: http://localhost:3000/admin +- API文档: http://localhost:3000/api/docs + +## 开发指南 + +### 本地开发 +```bash +# 安装依赖 +npm install + +# 启动开发服务器 +npm run dev + +# 运行测试 +npm test + +# 构建生产版本 +npm run build +``` + +### 代码规范 +- 使用 ESLint 和 Prettier 进行代码格式化 +- 遵循 TypeScript 严格模式 +- 使用 Conventional Commits 规范 + +## 部署 + +### 生产环境部署 +```bash +# 构建生产镜像 +docker-compose -f docker-compose.prod.yml build + +# 启动生产服务 +docker-compose -f docker-compose.prod.yml up -d +``` + +### 环境变量配置 +生产环境需要配置以下环境变量: +- `DATABASE_URL`: PostgreSQL连接字符串 +- `REDIS_URL`: Redis连接字符串 +- `JWT_SECRET`: JWT密钥 +- `SMTP_CONFIG`: 邮件服务器配置 +- `DOMAIN_CONFIG`: 域名配置 + +## 安全特性 + +- **密码加密**: 使用bcrypt进行密码哈希 +- **JWT认证**: 安全的token认证机制 +- **二步验证**: 支持邮箱和TOTP验证 +- **权限控制**: 基于角色的访问控制 +- **审计日志**: 完整的操作日志记录 +- **HTTPS**: 强制HTTPS连接 +- **CORS**: 跨域资源共享控制 + +## 贡献指南 + +1. Fork 项目 +2. 创建功能分支 (`git checkout -b feature/AmazingFeature`) +3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 打开 Pull Request + +## 许可证 + +本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。 + +## 支持 + +如果您遇到问题或有建议,请: +1. 查看 [FAQ](docs/FAQ.md) +2. 搜索 [Issues](https://github.com/your-username/pandora/issues) +3. 创建新的 Issue + +## 更新日志 + +查看 [CHANGELOG.md](CHANGELOG.md) 了解版本更新历史。 + +## 用户激活功能 + +### 功能说明 +- 新注册的用户默认为禁用状态(`isActive: false`) +- 用户需要等待管理员激活账户后才能登录 +- 管理员可以在用户管理页面激活/禁用用户账户 + +### 修改内容 + +#### 后端修改 +1. **注册控制器** (`backend/src/controllers/authController.ts`) + - 新注册用户默认为禁用状态 + - 返回明确的激活提示信息 + +2. **登录控制器** (`backend/src/controllers/authController.ts`) + - 检查用户是否激活 + - 被禁用用户登录时返回明确错误信息 + +3. **用户管理控制器** (`backend/src/controllers/userController.ts`) + - 管理员创建用户时默认为禁用状态 + - 支持管理员激活/禁用用户 + +#### 前端修改 +1. **登录页面** (`frontend/src/views/Home.vue`) + - 注册成功后显示激活提示 + - 登录失败时区分账户禁用和其他错误 + +2. **管理员用户管理** (`frontend/src/views/AdminUsers.vue`) + - 显示用户激活状态 + - 支持管理员编辑用户激活状态 + +3. **API调用** (`frontend/src/utils/api.ts`) + - 修复登录API使用username字段 + - 移除不需要的email字段 + +4. **类型定义** (`frontend/src/types/index.ts`) + - 更新用户类型定义 + - 移除email相关字段 + +### 使用流程 +1. 用户注册 → 账户默认为禁用状态 +2. 管理员在用户管理页面查看新注册用户 +3. 管理员激活用户账户 +4. 用户可以使用账户登录系统 \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..8c9878d --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,38 @@ +FROM node:18-alpine + +# 设置工作目录 +WORKDIR /app + +# 安装系统依赖 +RUN apk add --no-cache \ + python3 \ + make \ + g++ \ + curl + +# 复制 package.json 和 package-lock.json +COPY package*.json ./ + +# 安装依赖 +RUN npm ci --only=production && npm cache clean --force + +# 复制源代码 +COPY . . + +# 创建非root用户 +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nodejs -u 1001 + +# 更改文件所有权 +RUN chown -R nodejs:nodejs /app +USER nodejs + +# 暴露端口 +EXPOSE 3001 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3001/health || exit 1 + +# 启动命令 +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..124b785 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,347 @@ +# Pandora 后端 API + +这是 Pandora 项目的后端 API 服务,提供完整的用户认证系统和权限管理功能。 + +## 🚀 功能特性 + +### 用户认证系统 +- ✅ 用户注册和登录 +- ✅ JWT 令牌认证 +- ✅ 邮箱验证 +- ✅ 密码重置 +- ✅ TOTP 二步验证 +- ✅ 会话管理 +- ✅ 密码加密 (bcrypt) + +### 权限管理系统 +- ✅ 基于角色的权限控制 +- ✅ 路径权限验证 +- ✅ 用户权限分配 +- ✅ 权限审计日志 + +### 账号管理系统 +- ✅ 网站账号管理 +- ✅ 账号分配和撤销 +- ✅ 账号使用统计 +- ✅ 多用户共享控制 + +### 安全特性 +- ✅ API 限流 +- ✅ CORS 配置 +- ✅ 安全头部 (Helmet) +- ✅ 输入验证 +- ✅ 错误处理 +- ✅ 审计日志 + +## 📋 技术栈 + +- **运行时**: Node.js + TypeScript +- **框架**: Express.js +- **数据库**: PostgreSQL + Prisma ORM +- **缓存**: Redis +- **认证**: JWT + bcrypt +- **二步验证**: TOTP (Google Authenticator) +- **邮件**: Nodemailer +- **日志**: Winston +- **验证**: express-validator + +## 🛠️ 安装和设置 + +### 1. 安装依赖 + +```bash +cd backend +npm install +``` + +### 2. 环境配置 + +复制环境变量文件: + +```bash +cp env.example .env +``` + +编辑 `.env` 文件,配置以下变量: + +```env +# 数据库配置 +DATABASE_URL="postgresql://username:password@localhost:5432/pandora" + +# JWT 配置 +JWT_SECRET="your-super-secret-jwt-key-here" +JWT_EXPIRES_IN="7d" + +# 邮件配置 (用于邮箱验证和密码重置) +SMTP_HOST="smtp.gmail.com" +SMTP_PORT=587 +SMTP_USER="your-email@gmail.com" +SMTP_PASS="your-app-password" +EMAIL_FROM="noreply@pandora.com" + +# Redis 配置 +REDIS_URL="redis://localhost:6379" + +# 服务器配置 +PORT=3001 +NODE_ENV="development" + +# 安全配置 +BCRYPT_ROUNDS=12 +RATE_LIMIT_WINDOW_MS=900000 +RATE_LIMIT_MAX_REQUESTS=100 + +# TOTP 配置 +TOTP_ISSUER="Pandora" +TOTP_LABEL="Pandora Authentication" +``` + +### 3. 数据库设置 + +```bash +# 生成 Prisma 客户端 +npm run db:generate + +# 运行数据库迁移 +npm run db:migrate + +# 初始化测试数据 +npm run db:seed +``` + +### 4. 启动服务 + +```bash +# 开发模式 +npm run dev + +# 生产模式 +npm run build +npm start +``` + +## 📚 API 文档 + +### 认证相关 API + +#### 用户注册 +```http +POST /api/auth/register +Content-Type: application/json + +{ + "email": "user@example.com", + "username": "username", + "password": "password123", + "firstName": "张", + "lastName": "三" +} +``` + +#### 用户登录 +```http +POST /api/auth/login +Content-Type: application/json + +{ + "email": "user@example.com", + "password": "password123" +} +``` + +#### 邮箱验证 +```http +POST /api/auth/verify-email +Content-Type: application/json + +{ + "token": "verification-token" +} +``` + +#### 设置 TOTP +```http +POST /api/auth/setup-totp +Authorization: Bearer +``` + +#### 验证 TOTP +```http +POST /api/auth/verify-totp +Authorization: Bearer +Content-Type: application/json + +{ + "token": "123456" +} +``` + +#### 获取当前用户信息 +```http +GET /api/auth/me +Authorization: Bearer +``` + +### 用户管理 API + +#### 获取所有用户 (管理员) +```http +GET /api/users +Authorization: Bearer +``` + +#### 获取用户详情 +```http +GET /api/users/:id +Authorization: Bearer +``` + +#### 更新用户信息 +```http +PUT /api/users/:id +Authorization: Bearer +Content-Type: application/json + +{ + "firstName": "新名字", + "lastName": "新姓氏" +} +``` + +### 账号管理 API + +#### 获取用户账号 +```http +GET /api/accounts/user/assigned +Authorization: Bearer +``` + +#### 创建账号 (管理员) +```http +POST /api/accounts +Authorization: Bearer +Content-Type: application/json + +{ + "website": "claude.ai", + "accountName": "claude_pro_1", + "token": "sk-ant-api03-xxx", + "maxUsers": 3 +} +``` + +## 🔐 安全说明 + +### 密码安全 +- 使用 bcrypt 进行密码哈希,默认 12 轮加密 +- 密码最小长度 8 位 +- 支持密码重置功能 + +### 会话管理 +- JWT 令牌有效期 7 天 +- 支持令牌刷新 +- 会话存储在数据库中,支持强制登出 + +### 二步验证 +- 支持 TOTP (Google Authenticator) +- 提供 10 个备用码 +- 可选择性启用 + +### API 安全 +- 所有敏感 API 需要认证 +- 管理员 API 需要管理员权限 +- 实现 API 限流防止滥用 +- 输入验证和清理 + +## 🧪 测试账户 + +运行 `npm run db:seed` 后会创建以下测试账户: + +### 管理员账户 +- 邮箱: `admin@pandora.com` +- 密码: `admin123` +- 权限: 所有账号 + +### 测试用户账户 +- 邮箱: `user@pandora.com` +- 密码: `user123` +- 权限: claude.ai 和 openai.com 账号 + +## 📝 开发说明 + +### 项目结构 +``` +src/ +├── config/ # 配置文件 +│ ├── database.ts # 数据库连接 +│ └── redis.ts # Redis 连接 +├── controllers/ # 控制器 +│ ├── authController.ts +│ ├── userController.ts +│ └── accountController.ts +├── middleware/ # 中间件 +│ ├── authMiddleware.ts +│ ├── adminMiddleware.ts +│ ├── validateRequest.ts +│ ├── errorHandler.ts +│ └── notFoundHandler.ts +├── routes/ # 路由 +│ ├── auth.ts +│ ├── users.ts +│ └── accounts.ts +├── utils/ # 工具函数 +│ └── logger.ts +└── index.ts # 入口文件 +``` + +### 数据库模型 +- `User`: 用户信息 +- `WebsiteAccount`: 网站账号 +- `AccountAssignment`: 账号分配 +- `Session`: 用户会话 +- `AuditLog`: 审计日志 + +### 开发命令 +```bash +# 开发模式 +npm run dev + +# 构建 +npm run build + +# 数据库操作 +npm run db:generate # 生成 Prisma 客户端 +npm run db:migrate # 运行迁移 +npm run db:push # 推送 schema 到数据库 +npm run db:studio # 打开 Prisma Studio +npm run db:seed # 初始化测试数据 +``` + +## 🚨 注意事项 + +1. **环境变量**: 确保所有必需的环境变量都已正确配置 +2. **数据库**: 确保 PostgreSQL 数据库正在运行 +3. **Redis**: 确保 Redis 服务正在运行 +4. **邮件服务**: 如果使用邮箱验证功能,需要配置有效的 SMTP 服务 +5. **JWT 密钥**: 生产环境请使用强随机密钥 +6. **HTTPS**: 生产环境建议使用 HTTPS + +## 📞 支持 + +如有问题,请查看: +1. 日志文件 (`logs/` 目录) +2. 数据库连接状态 +3. Redis 连接状态 +4. 环境变量配置 + +## 🔄 更新日志 + +### v1.0.0 +- ✅ 完整的用户认证系统 +- ✅ JWT 令牌认证 +- ✅ 邮箱验证功能 +- ✅ TOTP 二步验证 +- ✅ 权限管理系统 +- ✅ 账号管理系统 +- ✅ 审计日志 +- ✅ API 限流和安全防护 \ No newline at end of file diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..7eafc4f --- /dev/null +++ b/backend/package.json @@ -0,0 +1,45 @@ +{ + "name": "pandora-backend", + "version": "1.0.0", + "description": "Pandora Backend API", + "main": "dist/index.js", + "scripts": { + "dev": "nodemon src/index.ts", + "build": "tsc", + "start": "node dist/index.js", + "db:generate": "prisma generate", + "db:push": "prisma db push", + "db:migrate": "prisma migrate dev", + "db:studio": "prisma studio", + "db:seed": "ts-node prisma/seed.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@prisma/client": "^5.7.1", + "bcryptjs": "^2.4.3", + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "express-async-errors": "^3.1.1", + "express-rate-limit": "^7.1.5", + "express-validator": "^7.0.1", + "helmet": "^7.1.0", + "jsonwebtoken": "^9.0.2", + "nodemailer": "^6.9.7", + "winston": "^3.11.0" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.6", + "@types/cors": "^2.8.17", + "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.5", + "@types/node": "^20.10.5", + "@types/nodemailer": "^6.4.14", + "nodemon": "^3.0.2", + "prisma": "^5.7.1", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + } +} diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma new file mode 100644 index 0000000..289fbd8 --- /dev/null +++ b/backend/prisma/schema.prisma @@ -0,0 +1,99 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "sqlite" + url = env("DATABASE_URL") +} + +model User { + id String @id @default(cuid()) + username String @unique + password String + firstName String? + lastName String? + isActive Boolean @default(true) + isAdmin Boolean @default(false) + lastLoginAt DateTime? + loginAttempts Int @default(0) + lockedUntil DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + sessions Session[] + auditLogs AuditLog[] + accountAssignments AccountAssignment[] + + @@map("users") +} + +model WebsiteAccount { + id String @id @default(cuid()) + website String + accountName String + token String + isActive Boolean @default(true) + maxUsers Int @default(1) + currentUsers Int @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + accountAssignments AccountAssignment[] + + @@unique([website, accountName]) + @@map("website_accounts") +} + +model AccountAssignment { + id String @id @default(cuid()) + userId String + accountId String + assignedAt DateTime @default(now()) + expiresAt DateTime? + isActive Boolean @default(true) + + // Relations + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + account WebsiteAccount @relation(fields: [accountId], references: [id], onDelete: Cascade) + + @@unique([userId, accountId]) + @@map("account_assignments") +} + +model Session { + id String @id @default(cuid()) + userId String + token String @unique + ipAddress String? + userAgent String? + expiresAt DateTime + createdAt DateTime @default(now()) + + // Relations + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("sessions") +} + +model AuditLog { + id String @id @default(cuid()) + userId String? + action String + resource String? + resourceId String? + details String? // JSON string + ipAddress String? + userAgent String? + createdAt DateTime @default(now()) + + // Relations + user User? @relation(fields: [userId], references: [id], onDelete: SetNull) + + @@map("audit_logs") +} \ No newline at end of file diff --git a/backend/prisma/seed.ts b/backend/prisma/seed.ts new file mode 100644 index 0000000..3b0895c --- /dev/null +++ b/backend/prisma/seed.ts @@ -0,0 +1,153 @@ +import { PrismaClient } from '@prisma/client'; +import bcrypt from 'bcryptjs'; + +const prisma = new PrismaClient(); + +async function main() { + console.log('开始初始化数据库...'); + + // 创建管理员用户 + const adminPassword = await bcrypt.hash('admin123', 12); + const admin = await prisma.user.upsert({ + where: { email: 'admin@pandora.com' }, + update: {}, + create: { + email: 'admin@pandora.com', + username: 'admin', + password: adminPassword, + firstName: '管理员', + lastName: '系统', + isAdmin: true, + isActive: true, + emailVerified: true, + }, + }); + + // 创建测试用户 + const userPassword = await bcrypt.hash('user123', 12); + const user = await prisma.user.upsert({ + where: { email: 'user@pandora.com' }, + update: {}, + create: { + email: 'user@pandora.com', + username: 'testuser', + password: userPassword, + firstName: '测试', + lastName: '用户', + isAdmin: false, + isActive: true, + emailVerified: true, + }, + }); + + // 创建网站账号 + const accounts = [ + { + website: 'claude.ai', + accountName: 'claude_pro_1', + token: 'sk-ant-api03-xxx-claude-pro-1', + maxUsers: 3, + currentUsers: 0, + }, + { + website: 'openai.com', + accountName: 'gpt4_plus_1', + token: 'sk-xxx-gpt4-plus-1', + maxUsers: 2, + currentUsers: 0, + }, + { + website: 'gemini.google.com', + accountName: 'gemini_pro_1', + token: 'AIzaSyCxxx-gemini-pro-1', + maxUsers: 1, + currentUsers: 0, + }, + ]; + + for (const accountData of accounts) { + await prisma.websiteAccount.upsert({ + where: { + website_accountName: { + website: accountData.website, + accountName: accountData.accountName, + } + }, + update: {}, + create: accountData, + }); + } + + // 为管理员分配所有账号 + const allAccounts = await prisma.websiteAccount.findMany(); + for (const account of allAccounts) { + await prisma.accountAssignment.upsert({ + where: { + userId_accountId: { + userId: admin.id, + accountId: account.id, + } + }, + update: {}, + create: { + userId: admin.id, + accountId: account.id, + isActive: true, + }, + }); + } + + // 为用户分配部分账号 + const userAccounts = await prisma.websiteAccount.findMany({ + where: { + website: { + in: ['claude.ai', 'openai.com'] + } + } + }); + + for (const account of userAccounts) { + await prisma.accountAssignment.upsert({ + where: { + userId_accountId: { + userId: user.id, + accountId: account.id, + } + }, + update: {}, + create: { + userId: user.id, + accountId: account.id, + isActive: true, + }, + }); + } + + // 更新账号当前用户数 + for (const account of allAccounts) { + const userCount = await prisma.accountAssignment.count({ + where: { + accountId: account.id, + isActive: true, + } + }); + + await prisma.websiteAccount.update({ + where: { id: account.id }, + data: { currentUsers: userCount } + }); + } + + console.log('数据库初始化完成!'); + console.log('管理员账户:', admin.email, '密码: admin123'); + console.log('测试用户账户:', user.email, '密码: user123'); +} + +main() + .catch((e) => { + console.error('数据库初始化失败:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); \ No newline at end of file diff --git a/backend/src/config/database.ts b/backend/src/config/database.ts new file mode 100644 index 0000000..fb9f2af --- /dev/null +++ b/backend/src/config/database.ts @@ -0,0 +1,34 @@ +import { PrismaClient } from '@prisma/client'; +import { logger } from '../utils/logger'; + +declare global { + var prisma: PrismaClient | undefined; +} + +export const prisma = globalThis.prisma || new PrismaClient({ + log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'], +}); + +if (process.env.NODE_ENV !== 'production') { + globalThis.prisma = prisma; +} + +export async function connectDatabase() { + try { + await prisma.$connect(); + logger.info('Database connected successfully'); + } catch (error) { + logger.error('Database connection failed:', error); + throw error; + } +} + +export async function disconnectDatabase() { + try { + await prisma.$disconnect(); + logger.info('Database disconnected successfully'); + } catch (error) { + logger.error('Database disconnection failed:', error); + throw error; + } +} \ No newline at end of file diff --git a/backend/src/controllers/accountController.ts b/backend/src/controllers/accountController.ts new file mode 100644 index 0000000..18e4cfa --- /dev/null +++ b/backend/src/controllers/accountController.ts @@ -0,0 +1,545 @@ +import { Request, Response } from 'express'; +import { prisma } from '../config/database'; +import { AuthRequest } from '../middleware/authMiddleware'; + +export const accountController = { + // 获取所有账号 (管理员) + async getAllAccounts(req: Request, res: Response) { + const accounts = await prisma.websiteAccount.findMany({ + include: { + accountAssignments: { + include: { + user: { + select: { + id: true, + username: true, + } + } + } + } + } + }); + + return res.json({ + accounts: accounts.map((account: any) => ({ + id: account.id, + website: account.website, + username: account.accountName, + token: account.token, + isActive: account.isActive, + createdAt: account.createdAt, + updatedAt: account.updatedAt, + assignedUsers: account.accountAssignments.map((aa: any) => aa.user) + })) + }); + }, + + // 根据ID获取账号 (管理员) + async getAccountById(req: Request, res: Response) { + const { id } = req.params; + + if (!id) { + return res.status(400).json({ error: '账号ID是必需的' }); + } + + const account = await prisma.websiteAccount.findUnique({ + where: { id }, + include: { + accountAssignments: { + include: { + user: { + select: { + id: true, + username: true, + firstName: true, + lastName: true, + } + } + } + } + } + }); + + if (!account) { + return res.status(404).json({ error: '账号不存在' }); + } + + return res.json({ + account: { + id: account.id, + website: account.website, + username: account.accountName, + token: account.token, + isActive: account.isActive, + createdAt: account.createdAt, + updatedAt: account.updatedAt, + assignedUsers: account.accountAssignments.map((aa: any) => aa.user) + } + }); + }, + + // 创建新账号 (管理员) + async createAccount(req: Request, res: Response) { + const { website, accountName, token, isActive, maxUsers } = req.body; + + if (!website || !accountName || !token) { + return res.status(400).json({ error: '网站、账号名称和token是必需的' }); + } + + // 检查账号是否已存在 + const existingAccount = await prisma.websiteAccount.findFirst({ + where: { + website, + accountName + } + }); + + if (existingAccount) { + return res.status(400).json({ error: '账号已存在' }); + } + + const account = await prisma.websiteAccount.create({ + data: { + website, + accountName, + token, + isActive: isActive !== undefined ? isActive : true, + maxUsers: maxUsers || 1, + currentUsers: 0, + } + }); + + return res.status(201).json({ + message: '账号创建成功', + account: { + id: account.id, + website: account.website, + username: account.accountName, + token: account.token, + isActive: account.isActive, + createdAt: account.createdAt, + updatedAt: account.updatedAt + } + }); + }, + + // 更新账号 (管理员) + async updateAccount(req: Request, res: Response) { + const { id } = req.params; + const { website, accountName, token, maxUsers, isActive } = req.body; + + if (!id) { + return res.status(400).json({ error: '账号ID是必需的' }); + } + + const account = await prisma.websiteAccount.findUnique({ + where: { id } + }); + + if (!account) { + return res.status(404).json({ error: '账号不存在' }); + } + + // 检查是否与其他账号重复(排除当前账号) + if (website && accountName) { + const existingAccount = await prisma.websiteAccount.findFirst({ + where: { + website, + accountName, + id: { not: id } + } + }); + + if (existingAccount) { + return res.status(400).json({ error: '该网站和账号名称组合已存在' }); + } + } + + const updatedAccount = await prisma.websiteAccount.update({ + where: { id }, + data: { + website, + accountName, + token, + maxUsers, + isActive, + } + }); + + return res.json({ + message: '账号更新成功', + account: { + id: updatedAccount.id, + website: updatedAccount.website, + username: updatedAccount.accountName, + token: updatedAccount.token, + isActive: updatedAccount.isActive, + createdAt: updatedAccount.createdAt, + updatedAt: updatedAccount.updatedAt + } + }); + }, + + // 删除账号 (管理员) + async deleteAccount(req: Request, res: Response) { + const { id } = req.params; + + if (!id) { + return res.status(400).json({ error: '账号ID是必需的' }); + } + + const account = await prisma.websiteAccount.findUnique({ + where: { id } + }); + + if (!account) { + return res.status(404).json({ error: '账号不存在' }); + } + + // 删除账号相关的所有分配 + await prisma.$transaction([ + prisma.accountAssignment.deleteMany({ where: { accountId: id } }), + prisma.websiteAccount.delete({ where: { id } }) + ]); + + return res.json({ message: '账号删除成功' }); + }, + + // 获取用户的已分配账号 + async getUserAccounts(req: AuthRequest, res: Response) { + if (!req.user) { + return res.status(401).json({ error: '未授权' }); + } + + const assignments = await prisma.accountAssignment.findMany({ + where: { + userId: req.user.id, + isActive: true, + OR: [ + { expiresAt: null }, + { expiresAt: { gt: new Date() } } + ] + }, + include: { + account: { + select: { + id: true, + website: true, + accountName: true, + token: true, + isActive: true, + createdAt: true, + updatedAt: true, + } + } + } + }); + + return res.json({ + accounts: assignments.map((aa: any) => ({ + id: aa.account.id, + website: aa.account.website, + username: aa.account.accountName, + token: aa.account.token, + isActive: aa.account.isActive, + createdAt: aa.account.createdAt, + updatedAt: aa.account.updatedAt, + assignedAt: aa.assignedAt, + expiresAt: aa.expiresAt, + })) + }); + }, + + // 分配账号给用户 (管理员) + async assignAccount(req: Request, res: Response) { + const { id } = req.params; + const { userId, expiresAt } = req.body; + + if (!id || !userId) { + return res.status(400).json({ error: '账号ID和用户ID都是必需的' }); + } + + // 检查账号是否存在 + const account = await prisma.websiteAccount.findUnique({ + where: { id } + }); + + if (!account) { + return res.status(404).json({ error: '账号不存在' }); + } + + // 检查用户是否存在 + const user = await prisma.user.findUnique({ + where: { id: userId } + }); + + if (!user) { + return res.status(404).json({ error: '用户不存在' }); + } + + // 检查账号是否已满 + if (account.currentUsers >= account.maxUsers) { + return res.status(400).json({ error: '账号已达到最大用户数' }); + } + + // 检查是否已经分配 + const existingAssignment = await prisma.accountAssignment.findFirst({ + where: { + userId, + accountId: id, + isActive: true + } + }); + + if (existingAssignment) { + return res.status(400).json({ error: '用户已分配此账号' }); + } + + // 创建分配 + const assignment = await prisma.accountAssignment.create({ + data: { + userId, + accountId: id, + expiresAt: expiresAt ? new Date(expiresAt) : null, + isActive: true, + } + }); + + // 更新账号当前用户数 + await prisma.websiteAccount.update({ + where: { id }, + data: { + currentUsers: { + increment: 1 + } + } + }); + + return res.json({ + message: '账号分配成功', + assignment + }); + }, + + // 取消账号分配 (管理员) + async unassignAccount(req: Request, res: Response) { + const { id, userId } = req.params; + + if (!id || !userId) { + return res.status(400).json({ error: '账号ID和用户ID都是必需的' }); + } + + const assignment = await prisma.accountAssignment.findFirst({ + where: { + userId, + accountId: id, + isActive: true + } + }); + + if (!assignment) { + return res.status(404).json({ error: '分配不存在' }); + } + + // 删除分配 + await prisma.accountAssignment.delete({ + where: { id: assignment.id } + }); + + // 更新账号当前用户数 + await prisma.websiteAccount.update({ + where: { id }, + data: { + currentUsers: { + decrement: 1 + } + } + }); + + return res.json({ message: '账号分配已取消' }); + }, + + // 网站登录 + async loginToWebsite(req: Request, res: Response) { + const { accountId } = req.params; + const { userId } = req.body; + + if (!accountId || !userId) { + return res.status(400).json({ error: '账号ID和用户ID是必需的' }); + } + + try { + // 获取账号信息 + const account = await prisma.websiteAccount.findUnique({ + where: { id: accountId } + }); + + if (!account) { + return res.status(404).json({ error: '账号不存在' }); + } + + // 检查用户是否有权限访问该账号 + console.log('检查用户权限:', { accountId, userId }); + + const assignment = await prisma.accountAssignment.findFirst({ + where: { + accountId, + userId, + isActive: true, + OR: [ + { expiresAt: null }, + { expiresAt: { gt: new Date() } } + ] + } + }); + + console.log('权限检查结果:', { + assignment: assignment ? 'found' : 'not found', + accountId, + userId, + currentTime: new Date() + }); + + if (!assignment) { + // 获取更多调试信息 + const allAssignments = await prisma.accountAssignment.findMany({ + where: { accountId, userId } + }); + console.log('该用户的所有分配记录:', allAssignments); + + return res.status(403).json({ error: '您没有权限访问该账号' }); + } + + let loginUrl = ''; + + // 根据网站类型处理登录 + switch (account.website) { + case 'claude': + loginUrl = await handleClaudeLogin(account.token, userId); + break; + case 'chatgpt': + loginUrl = await handleChatGPTLogin(account.token, userId); + break; + case 'grok': + loginUrl = await handleGrokLogin(account.token, userId); + break; + default: + return res.status(400).json({ error: '不支持的网站类型' }); + } + + return res.json({ + success: true, + loginUrl, + website: account.website, + accountName: account.accountName + }); + + } catch (error) { + console.error('网站登录失败:', error); + return res.status(500).json({ error: '登录失败,请稍后重试' }); + } + } +}; + +// Claude 登录处理 +async function handleClaudeLogin(token: string, userName: string): Promise { + try { + const baseUrl = process.env.CLAUDE_TARGET_URL || 'https://chat.micar9.com:8443'; + console.log('Claude登录处理:', { token, userName }); + // 第一步:获取oauth token + const oauthResponse = await fetch(`${baseUrl}/manage-api/auth/oauth_token`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + session_key: token, + unique_name: userName + }) + }); + + if (!oauthResponse.ok) { + throw new Error(`OAuth token 请求失败: ${oauthResponse.status}`); + } + + const oauthData = await oauthResponse.json() as { login_url?: string }; + + if (!oauthData.login_url) { + throw new Error('未获取到登录URL'); + } + + return oauthData.login_url; + } catch (error) { + console.error('Claude登录处理失败:', error); + throw error; + } +} + +// ChatGPT 登录处理 +async function handleChatGPTLogin(token: string, userName: string): Promise { + try { + const baseUrl = process.env.CLAUDE_TARGET_URL || 'http://127.0.0.1:8181'; + + const response = await fetch(`${baseUrl}/api/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.ADMIN_PASSWORD || 'admin'}` + }, + body: JSON.stringify({ + access_token: token, + user_name: userName, + isolated_session: true, + limits: [] + }) + }); + + if (!response.ok) { + throw new Error(`ChatGPT登录请求失败: ${response.status}`); + } + + const data = await response.json() as { login_url?: string }; + + if (!data.login_url) { + throw new Error('未获取到登录URL'); + } + + return data.login_url; + } catch (error) { + console.error('ChatGPT登录处理失败:', error); + throw error; + } +} + +// Grok 登录处理 +async function handleGrokLogin(token: string, userName: string): Promise { + try { + const baseUrl = process.env.CLAUDE_TARGET_URL || 'https://grok-mirror.micar9.com:8443'; + + const response = await fetch(`${baseUrl}/api/login-v2`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + user_name: userName, + sso_token: token + }) + }); + + if (!response.ok) { + throw new Error(`Grok登录请求失败: ${response.status}`); + } + + const data = await response.json() as { login_url?: string }; + + if (!data.login_url) { + throw new Error('未获取到登录URL'); + } + + return data.login_url; + } catch (error) { + console.error('Grok登录处理失败:', error); + throw error; + } +} \ No newline at end of file diff --git a/backend/src/controllers/adminController.ts b/backend/src/controllers/adminController.ts new file mode 100644 index 0000000..16048a4 --- /dev/null +++ b/backend/src/controllers/adminController.ts @@ -0,0 +1,222 @@ +import { Request, Response } from 'express'; +import bcrypt from 'bcryptjs'; +import jwt from 'jsonwebtoken'; +import { prisma } from '../config/database'; +import { logger } from '../utils/logger'; +import { createAuditLog } from '../utils/audit'; + +export const adminController = { + // 管理员登录 + async login(req: Request, res: Response): Promise { + try { + const { username, password } = req.body; + + // 验证管理员凭据 + const admin = await prisma.user.findFirst({ + where: { + username, + isAdmin: true + } + }); + + if (!admin) { + // 记录管理员登录失败审计日志 + await createAuditLog({ + userId: null, + action: 'ADMIN_LOGIN_FAILED', + resource: 'ADMIN', + details: JSON.stringify({ username, reason: '管理员不存在' }), + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null + }); + + res.status(401).json({ + success: false, + message: '管理员凭据无效' + }); + return; + } + + // 验证密码 + const isValidPassword = await bcrypt.compare(password, admin.password); + if (!isValidPassword) { + // 记录管理员登录失败审计日志 + await createAuditLog({ + userId: admin.id, + action: 'ADMIN_LOGIN_FAILED', + resource: 'ADMIN', + details: JSON.stringify({ username, reason: '密码错误' }), + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null + }); + + res.status(401).json({ + success: false, + message: '管理员凭据无效' + }); + return; + } + + // 生成JWT token + const token = jwt.sign( + { + userId: admin.id, + username: admin.username, + role: admin.isAdmin ? 'admin' : 'user' + }, + process.env.JWT_SECRET!, + { expiresIn: '24h' } + ); + + // 创建审计日志 + await createAuditLog({ + userId: admin.id, + action: 'ADMIN_LOGIN', + resource: 'ADMIN', + details: { username: admin.username }, + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null + }); + + res.json({ + success: true, + message: '管理员登录成功', + token, + admin: { + id: admin.id, + username: admin.username, + role: admin.isAdmin ? 'admin' : 'user' + } + }); + } catch (error) { + logger.error('Admin login error:', error); + res.status(500).json({ + success: false, + message: '服务器内部错误' + }); + } + }, + + // 获取统计数据 + async getStats(req: Request, res: Response): Promise { + try { + // 获取用户总数 + const totalUsers = await prisma.user.count({ + where: { isAdmin: false } + }); + + // 获取账号总数 + const totalAccounts = await prisma.websiteAccount.count(); + + // 获取今日访问数(基于会话) + const today = new Date(); + today.setHours(0, 0, 0, 0); + const todayVisits = await prisma.session.count({ + where: { + createdAt: { + gte: today + } + } + }); + + // 获取系统告警数(基于审计日志中的错误) + const alerts = await prisma.auditLog.count({ + where: { + action: { contains: 'ERROR' }, + createdAt: { + gte: new Date(Date.now() - 24 * 60 * 60 * 1000) // 最近24小时 + } + } + }); + + console.log('统计数据:', { totalUsers, totalAccounts, todayVisits, alerts }); + + res.json({ + success: true, + data: { + totalUsers, + totalAccounts, + todayVisits, + alerts + } + }); + } catch (error) { + logger.error('Get stats error:', error); + res.status(500).json({ + success: false, + message: '获取统计数据失败' + }); + } + }, + + // 获取最近活动 + async getRecentActivities(req: Request, res: Response): Promise { + try { + const activities = await prisma.auditLog.findMany({ + take: 10, + orderBy: { + createdAt: 'desc' + }, + include: { + user: { + select: { + id: true, + username: true + } + } + } + }); + + const formattedActivities = activities.map((activity: any) => { + let description = ''; + + if (activity.action === 'USER_LOGIN_FAILED' || activity.action === 'ADMIN_LOGIN_FAILED') { + // 解析失败原因 + let reason = '登录失败'; + let username = '未知用户'; + + if (activity.details) { + try { + const details = JSON.parse(activity.details); + reason = details.reason || '登录失败'; + username = details.username || '未知用户'; + } catch (e) { + console.error('解析活动详情失败:', e); + } + } + + description = `${username} ${reason}`; + } else if (activity.user) { + description = `${activity.user.username} ${activity.action}`; + } else { + description = `系统 ${activity.action}`; + } + + return { + id: activity.id, + description, + time: activity.createdAt, + details: activity.details, + ipAddress: activity.ipAddress, + userAgent: activity.userAgent, + action: activity.action + }; + }); + + console.log('最近活动:', formattedActivities); + + res.json({ + success: true, + data: { + activities: formattedActivities + } + }); + } catch (error) { + logger.error('Get recent activities error:', error); + res.status(500).json({ + success: false, + message: '获取最近活动失败' + }); + } + } +}; \ No newline at end of file diff --git a/backend/src/controllers/auditLogController.ts b/backend/src/controllers/auditLogController.ts new file mode 100644 index 0000000..2750551 --- /dev/null +++ b/backend/src/controllers/auditLogController.ts @@ -0,0 +1,57 @@ +import { Request, Response } from 'express'; +import { prisma } from '../config/database'; +import { logger } from '../utils/logger'; + +export const auditLogController = { + // 获取审计日志 + async getAuditLogs(req: Request, res: Response): Promise { + try { + const { page = 1, limit = 10, userId, action, resource } = req.query; + const skip = (Number(page) - 1) * Number(limit); + + const where: any = {}; + if (userId) where.userId = String(userId); + if (action) where.action = { contains: String(action) }; + if (resource) where.resource = { contains: String(resource) }; + + const [logs, total] = await Promise.all([ + prisma.auditLog.findMany({ + where, + skip, + take: Number(limit), + orderBy: { + createdAt: 'desc' + }, + include: { + user: { + select: { + id: true, + username: true + } + } + } + }), + prisma.auditLog.count({ where }) + ]); + + res.json({ + success: true, + data: { + logs, + pagination: { + page: Number(page), + limit: Number(limit), + total, + totalPages: Math.ceil(total / Number(limit)) + } + } + }); + } catch (error) { + logger.error('Get audit logs error:', error); + res.status(500).json({ + success: false, + message: '获取审计日志失败' + }); + } + } +}; \ No newline at end of file diff --git a/backend/src/controllers/authController.ts b/backend/src/controllers/authController.ts new file mode 100644 index 0000000..9b1c4d4 --- /dev/null +++ b/backend/src/controllers/authController.ts @@ -0,0 +1,387 @@ +import { Request, Response } from 'express'; +import bcrypt from 'bcryptjs'; +import jwt from 'jsonwebtoken'; +import { prisma } from '../config/database'; +import { logger } from '../utils/logger'; +import { AuthRequest } from '../middleware/authMiddleware'; +import type { Secret, SignOptions } from 'jsonwebtoken'; + +// Generate JWT token +function generateToken(userId: string): string { + const secret = process.env.JWT_SECRET; + if (!secret) { + throw new Error('JWT_SECRET is not configured'); + } + const expiresIn = process.env.JWT_EXPIRES_IN || '7d'; + return jwt.sign( + { userId }, + secret, + { expiresIn: expiresIn as any } + ); +} + +// Create session +async function createSession(userId: string, token: string, req: Request) { + console.log('创建session:', { userId, token: token.substring(0, 20) + '...' }) + + const session = await prisma.session.create({ + data: { + userId, + token, + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null, + expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days + }, + }); + + console.log('Session创建成功:', { + sessionId: session.id, + expiresAt: session.expiresAt, + currentTime: new Date() + }) + + return session; +} + +export const authController = { + // 用户注册 + async register(req: Request, res: Response) { + const { username, password, confirmPassword, firstName, lastName } = req.body; + + // 验证密码确认 + if (password !== confirmPassword) { + return res.status(400).json({ + error: '密码和确认密码不匹配' + }); + } + + // Check if user already exists + const existingUser = await prisma.user.findUnique({ + where: { username } + }); + + if (existingUser) { + return res.status(400).json({ + error: '用户名已存在' + }); + } + + // Hash password + const hashedPassword = await bcrypt.hash(password, parseInt(process.env.BCRYPT_ROUNDS || '12')); + + // Create user with isActive set to false by default + const user = await prisma.user.create({ + data: { + username, + password: hashedPassword, + firstName, + lastName, + isActive: false, // 新注册用户默认为禁用状态 + }, + }); + + // Create audit log + await prisma.auditLog.create({ + data: { + userId: user.id, + action: 'USER_REGISTERED', + resource: 'user', + resourceId: user.id, + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null, + } + }); + + return res.status(201).json({ + message: '注册成功,请等待管理员激活您的账户', + user: { + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + isAdmin: user.isAdmin, + isActive: user.isActive, + } + }); + }, + + // 用户登录 + async login(req: Request, res: Response) { + const { username, password } = req.body; + + // Find user + const user = await prisma.user.findUnique({ + where: { username } + }); + + if (!user) { + // 记录登录失败审计日志 + await prisma.auditLog.create({ + data: { + userId: null, + action: 'USER_LOGIN_FAILED', + resource: 'user', + resourceId: null, + details: JSON.stringify({ username, reason: '用户不存在' }), + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null, + } + }); + return res.status(401).json({ error: '用户不存在' }); + } + + // Check if user is active + if (!user.isActive) { + // 记录登录失败审计日志 + await prisma.auditLog.create({ + data: { + userId: user.id, + action: 'USER_LOGIN_FAILED', + resource: 'user', + resourceId: user.id, + details: JSON.stringify({ username, reason: '账户已被禁用' }), + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null, + } + }); + return res.status(401).json({ error: '账户已被禁用,请联系管理员激活' }); + } + + // Verify password + const isValidPassword = await bcrypt.compare(password, user.password); + if (!isValidPassword) { + // 增加登录失败次数 + const loginAttempts = (user.loginAttempts || 0) + 1; + const updateData: any = { loginAttempts }; + let userDisabled = false; + + // 如果失败次数达到5次,禁用账户 + if (loginAttempts >= 5) { + updateData.isActive = false; + userDisabled = true; + } + + await prisma.user.update({ + where: { id: user.id }, + data: updateData + }); + + // 记录登录失败审计日志 + await prisma.auditLog.create({ + data: { + userId: user.id, + action: 'USER_LOGIN_FAILED', + resource: 'user', + resourceId: user.id, + details: JSON.stringify({ + username, + reason: userDisabled ? '密码错误且账户已被禁用' : '密码错误', + loginAttempts, + isDisabled: userDisabled + }), + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null, + } + }); + + if (userDisabled) { + return res.status(401).json({ error: '登录失败次数过多,账户已被禁用,请联系管理员' }); + } + return res.status(401).json({ + error: '用户名或密码错误', + remainingAttempts: 5 - loginAttempts + }); + } + + // 登录成功,重置登录失败次数和锁定时间 + await prisma.user.update({ + where: { id: user.id }, + data: { + loginAttempts: 0, + lockedUntil: null + } + }); + + // Generate token + const token = generateToken(user.id); + + // Delete existing sessions for this user (optional - for single session per user) + await prisma.session.deleteMany({ + where: { userId: user.id } + }); + + // Create session + await createSession(user.id, token, req); + + // Update last login + await prisma.user.update({ + where: { id: user.id }, + data: { lastLoginAt: new Date() } + }); + + // Create audit log + await prisma.auditLog.create({ + data: { + userId: user.id, + action: 'USER_LOGIN', + resource: 'user', + resourceId: user.id, + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null, + } + }); + + return res.json({ + message: '登录成功', + token, + user: { + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + isAdmin: user.isAdmin, + } + }); + }, + + // 用户登出 + async logout(req: AuthRequest, res: Response) { + const token = req.headers.authorization?.substring(7); + + if (token) { + // Delete session + await prisma.session.deleteMany({ + where: { token } + }); + } + + // Create audit log + if (req.user) { + await prisma.auditLog.create({ + data: { + userId: req.user.id, + action: 'USER_LOGOUT', + resource: 'user', + resourceId: req.user.id, + ipAddress: req.ip ?? null, + userAgent: req.get('User-Agent') ?? null, + } + }); + } + + res.json({ message: '登出成功' }); + }, + + // 获取当前用户信息 + async getCurrentUser(req: AuthRequest, res: Response) { + if (!req.user) { + return res.status(401).json({ error: '未授权' }); + } + + const user = await prisma.user.findUnique({ + where: { id: req.user.id }, + select: { + id: true, + username: true, + firstName: true, + lastName: true, + isAdmin: true, + isActive: true, + lastLoginAt: true, + createdAt: true, + updatedAt: true, + } + }); + + if (!user) { + return res.status(404).json({ error: '用户不存在' }); + } + + return res.json({ + user: user + }); + }, + + // 刷新token + async refreshToken(req: Request, res: Response) { + const { refreshToken } = req.body; + + if (!refreshToken) { + return res.status(400).json({ error: '刷新令牌是必需的' }); + } + + try { + const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET!) as any; + + const session = await prisma.session.findFirst({ + where: { + token: refreshToken, + expiresAt: { + gt: new Date() + } + }, + include: { + user: { + select: { + id: true, + username: true, + isAdmin: true, + isActive: true + } + } + } + }); + + if (!session || !session.user || !session.user.isActive) { + return res.status(401).json({ error: '无效的刷新令牌' }); + } + + // Generate new token + const newToken = generateToken(session.user.id); + + // Update session + await prisma.session.update({ + where: { id: session.id }, + data: { + token: newToken, + expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), + } + }); + + return res.json({ + token: newToken, + user: session.user + }); + } catch (error) { + return res.status(401).json({ error: '无效的刷新令牌' }); + } + }, + + // 调试端点 - 检查用户session状态 + async debugSession(req: AuthRequest, res: Response) { + if (!req.user) { + return res.status(401).json({ error: '未授权' }); + } + + try { + const sessions = await prisma.session.findMany({ + where: { userId: req.user.id }, + orderBy: { createdAt: 'desc' } + }); + + return res.json({ + userId: req.user.id, + username: req.user.username, + sessions: sessions.map((s: any) => ({ + id: s.id, + token: s.token.substring(0, 20) + '...', + expiresAt: s.expiresAt, + createdAt: s.createdAt, + isExpired: s.expiresAt < new Date() + })) + }); + } catch (error) { + return res.status(500).json({ error: '获取session信息失败' }); + } + } +}; \ No newline at end of file diff --git a/backend/src/controllers/userController.ts b/backend/src/controllers/userController.ts new file mode 100644 index 0000000..7fa7fc5 --- /dev/null +++ b/backend/src/controllers/userController.ts @@ -0,0 +1,365 @@ +import { Request, Response } from 'express'; +import { prisma } from '../config/database'; +import { AuthRequest } from '../middleware/auth'; +import bcrypt from 'bcryptjs'; + +export const userController = { + // 获取所有用户 (管理员) + async getAllUsers(req: Request, res: Response) { + const { page = 1, limit = 10, search = '', role = '' } = req.query; + + const pageNum = parseInt(page as string) || 1; + const limitNum = parseInt(limit as string) || 10; + const skip = (pageNum - 1) * limitNum; + + // 构建查询条件 + const where: any = {}; + + if (search) { + where.OR = [ + { username: { contains: search as string, mode: 'insensitive' } }, + { firstName: { contains: search as string, mode: 'insensitive' } }, + { lastName: { contains: search as string, mode: 'insensitive' } } + ]; + } + + if (role) { + if (role === 'admin') { + where.isAdmin = true; + } else if (role === 'user') { + where.isAdmin = false; + } + } + + // 获取总数 + const total = await prisma.user.count({ where }); + + // 获取用户列表 + const users = await prisma.user.findMany({ + where, + select: { + id: true, + username: true, + firstName: true, + lastName: true, + isAdmin: true, + isActive: true, + totpEnabled: true, + lastLoginAt: true, + createdAt: true, + accountAssignments: { + select: { + accountId: true + } + } + }, + skip, + take: limitNum, + orderBy: { createdAt: 'desc' } + }); + + // 计算分页信息 + const totalPages = Math.ceil(total / limitNum); + + return res.json({ + users: users.map((user: any) => ({ + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + role: user.isAdmin ? 'admin' : 'user', + isAdmin: user.isAdmin, + isActive: user.isActive, + totpEnabled: user.totpEnabled, + lastLoginAt: user.lastLoginAt, + createdAt: user.createdAt, + accounts: user.accountAssignments.map((assignment: any) => assignment.accountId) + })), + pagination: { + page: pageNum, + limit: limitNum, + total, + totalPages + } + }); + }, + + // 根据ID获取用户信息 + async getUserById(req: AuthRequest, res: Response) { + const { id } = req.params; + + if (!id) { + return res.status(400).json({ error: '用户ID是必需的' }); + } + + // 检查权限:只能查看自己的信息或管理员可以查看所有 + if (req.user?.id !== id && req.user?.role !== 'admin') { + return res.status(403).json({ error: '权限不足' }); + } + + const user = await prisma.user.findUnique({ + where: { id }, + select: { + id: true, + username: true, + firstName: true, + lastName: true, + isAdmin: true, + isActive: true, + totpEnabled: true, + lastLoginAt: true, + createdAt: true, + } + }); + + if (!user) { + return res.status(404).json({ error: '用户不存在' }); + } + + return res.json({ + user: { + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + isAdmin: user.isAdmin, + isActive: user.isActive, + totpEnabled: user.totpEnabled, + lastLoginAt: user.lastLoginAt, + createdAt: user.createdAt + } + }); + }, + + // 更新用户信息 + async updateUser(req: AuthRequest, res: Response) { + const { id } = req.params; + const { username, role, firstName, lastName, isActive, loginAttempts } = req.body; + + console.log('收到更新请求:', req.body); + + if (!id) { + return res.status(400).json({ error: '用户ID是必需的' }); + } + + // 检查权限:只能更新自己的信息或管理员可以更新所有 + if (req.user?.id !== id && req.user?.role !== 'admin') { + return res.status(403).json({ error: '权限不足' }); + } + + // 构建更新数据 + const updateData: any = {}; + + // 只有管理员可以修改这些字段 + if (req.user?.role === 'admin') { + if (username !== undefined) updateData.username = username; + if (role !== undefined) updateData.isAdmin = role === 'admin'; + if (typeof isActive === 'boolean') updateData.isActive = isActive; + } + + // 普通用户可以修改这些字段 + if (firstName !== undefined) updateData.firstName = firstName; + if (lastName !== undefined) updateData.lastName = lastName; + + // 新增:处理密码修改 + if (req.body.password && typeof req.body.password === 'string' && req.body.password.trim() !== '') { + console.log('正在处理密码更新'); + const hashedPassword = await bcrypt.hash(req.body.password, 12); + updateData.password = hashedPassword; + console.log('密码已加密'); + } + updateData.loginAttempts = 0 + console.log('最终更新数据:', updateData); + + // 检查用户名是否已存在(排除当前用户) + if (username) { + const existingUser = await prisma.user.findFirst({ + where: { + username, + id: { not: id } + } + }); + + if (existingUser) { + return res.status(400).json({ error: '用户名已存在' }); + } + } + + const user = await prisma.user.update({ + where: { id }, + data: updateData, + select: { + id: true, + username: true, + firstName: true, + lastName: true, + isAdmin: true, + isActive: true, + totpEnabled: true, + lastLoginAt: true, + createdAt: true, + password: true, + loginAttempts: true + } + }); + + return res.json({ + user: { + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + isAdmin: user.isAdmin, + isActive: user.isActive, + totpEnabled: user.totpEnabled, + lastLoginAt: user.lastLoginAt, + createdAt: user.createdAt, + password: user.password, + loginAttempts: loginAttempts + } + }); + }, + + // 更新用户账号权限 + async updateUserAccounts(req: AuthRequest, res: Response) { + const { id } = req.params; + const { accountIds } = req.body; + + if (!id) { + return res.status(400).json({ error: '用户ID是必需的' }); + } + + if (!Array.isArray(accountIds)) { + return res.status(400).json({ error: 'accountIds必须是数组' }); + } + + // 检查用户是否存在 + const user = await prisma.user.findUnique({ + where: { id } + }); + + if (!user) { + return res.status(404).json({ error: '用户不存在' }); + } + + // 检查所有账号是否存在 + const accounts = await prisma.websiteAccount.findMany({ + where: { + id: { in: accountIds } + } + }); + + if (accounts.length !== accountIds.length) { + return res.status(400).json({ error: '部分账号不存在' }); + } + + // 使用事务来确保数据一致性 + await prisma.$transaction(async (tx) => { + // 删除用户现有的所有账号分配 + await tx.accountAssignment.deleteMany({ + where: { userId: id } + }); + + // 创建新的账号分配 + if (accountIds.length > 0) { + await tx.accountAssignment.createMany({ + data: accountIds.map(accountId => ({ + userId: id, + accountId: accountId, + isActive: true + })) + }); + } + }); + + return res.json({ + message: '用户账号权限更新成功', + accountIds + }); + }, + + // 删除用户 (管理员) + async deleteUser(req: Request, res: Response) { + const { id } = req.params; + + if (!id) { + return res.status(400).json({ error: '用户ID是必需的' }); + } + + const user = await prisma.user.findUnique({ + where: { id } + }); + + if (!user) { + return res.status(404).json({ error: '用户不存在' }); + } + + // 删除用户相关的所有数据 + await prisma.$transaction([ + prisma.session.deleteMany({ where: { userId: id } }), + prisma.accountAssignment.deleteMany({ where: { userId: id } }), + prisma.auditLog.deleteMany({ where: { userId: id } }), + prisma.user.delete({ where: { id } }) + ]); + + return res.json({ message: '用户删除成功' }); + }, + + // 创建用户 (管理员) + async createUser(req: Request, res: Response) { + const { username, password, role } = req.body; + + if (!username || !password) { + return res.status(400).json({ error: '用户名和密码是必需的' }); + } + + // 检查用户是否已存在 + const existingUser = await prisma.user.findUnique({ + where: { username } + }); + + if (existingUser) { + return res.status(400).json({ error: '用户名已存在' }); + } + + // 加密密码 + const hashedPassword = await bcrypt.hash(password, 12); + + // 创建用户,默认为禁用状态 + const user = await prisma.user.create({ + data: { + username, + password: hashedPassword, + isAdmin: role === 'admin', + isActive: false, // 新创建的用户默认为禁用状态 + }, + select: { + id: true, + username: true, + firstName: true, + lastName: true, + isAdmin: true, + isActive: true, + totpEnabled: true, + lastLoginAt: true, + createdAt: true, + } + }); + + return res.status(201).json({ + message: '用户创建成功,需要激活后才能登录', + user: { + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + role: user.isAdmin ? 'admin' : 'user', + isAdmin: user.isAdmin, + isActive: user.isActive, + totpEnabled: user.totpEnabled, + lastLoginAt: user.lastLoginAt, + createdAt: user.createdAt + } + }); + }, +}; \ No newline at end of file diff --git a/backend/src/index.ts b/backend/src/index.ts new file mode 100644 index 0000000..b6f9061 --- /dev/null +++ b/backend/src/index.ts @@ -0,0 +1,105 @@ +import 'express-async-errors'; +import express from 'express'; +import cors from 'cors'; +import helmet from 'helmet'; +import rateLimit from 'express-rate-limit'; +import dotenv from 'dotenv'; +import { logger } from './utils/logger'; +import { errorHandler } from './middleware/errorHandler'; +import { notFoundHandler } from './middleware/notFoundHandler'; +import authRoutes from './routes/auth'; +import userRoutes from './routes/users'; +import accountRoutes from './routes/accounts'; +import adminRoutes from './routes/admin'; +import { connectDatabase } from './config/database'; + +// Load environment variables +dotenv.config(); + +const app = express(); +const PORT = process.env.PORT || 3001; + +// 信任代理,确保正确获取客户端IP地址 +app.set('trust proxy', true); + +// Security middleware +app.use(helmet()); +app.use(cors({ + origin: process.env.NODE_ENV === 'production' + ? ['http://frontend:3000',"http://backend:3001"] + : ['http://localhost:3000', 'http://localhost:5173'], + credentials: true +})); + +// Rate limiting +const limiter = rateLimit({ + windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000'), // 15 minutes + max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100'), // limit each IP to 100 requests per windowMs + message: { + error: 'Too many requests from this IP, please try again later.' + } +}); +app.use('/api/', limiter); + +// Body parsing middleware +app.use(express.json({ limit: '10mb' })); +app.use(express.urlencoded({ extended: true })); + +// Request logging +app.use((req, res, next) => { + logger.info(`${req.method} ${req.path}`, { + ip: req.ip, + userAgent: req.get('User-Agent') + }); + next(); +}); + +// Health check endpoint +app.get('/health', (req, res) => { + res.json({ + status: 'OK', + timestamp: new Date().toISOString(), + uptime: process.uptime() + }); +}); + +// API routes +app.use('/api/auth', authRoutes); +app.use('/api/users', userRoutes); +app.use('/api/accounts', accountRoutes); +app.use('/api/admin', adminRoutes); + +// Error handling middleware +app.use(notFoundHandler); +app.use(errorHandler); + +// Start server +async function startServer() { + try { + // Connect to database + await connectDatabase(); + logger.info('Database connected successfully'); + + // Start server + app.listen(PORT, () => { + logger.info(`Server running on port ${PORT}`); + logger.info(`Environment: ${process.env.NODE_ENV}`); + }); + } catch (error) { + logger.error('Failed to start server:', error); + process.exit(1); + } +} + +// Handle graceful shutdown +process.on('SIGTERM', () => { + logger.info('SIGTERM received, shutting down gracefully'); + process.exit(0); +}); + +process.on('SIGINT', () => { + logger.info('SIGINT received, shutting down gracefully'); + process.exit(0); +}); + +startServer(); \ No newline at end of file diff --git a/backend/src/middleware/adminMiddleware.ts b/backend/src/middleware/adminMiddleware.ts new file mode 100644 index 0000000..d721da4 --- /dev/null +++ b/backend/src/middleware/adminMiddleware.ts @@ -0,0 +1,19 @@ +import { Response, NextFunction } from 'express'; +import { AuthRequest } from './authMiddleware'; +import { AppError } from './errorHandler'; + +export function adminMiddleware( + req: AuthRequest, + res: Response, + next: NextFunction +) { + if (!req.user) { + throw new AppError('Authentication required', 401); + } + + if (!req.user.isAdmin) { + throw new AppError('Admin privileges required', 403); + } + + next(); +} \ No newline at end of file diff --git a/backend/src/middleware/auth.ts b/backend/src/middleware/auth.ts new file mode 100644 index 0000000..2103869 --- /dev/null +++ b/backend/src/middleware/auth.ts @@ -0,0 +1,82 @@ +import { Request, Response, NextFunction } from 'express'; +import jwt from 'jsonwebtoken'; +import { prisma } from '../config/database'; + +export interface AuthRequest extends Request { + user?: { + id: string; + username: string; + role: string; + }; +} + +// 验证JWT token +export const authenticateToken = async ( + req: AuthRequest, + res: Response, + next: NextFunction +): Promise => { + try { + const authHeader = req.headers.authorization; + + if (!authHeader || !authHeader.startsWith('Bearer ')) { + res.status(401).json({ + success: false, + message: '未提供认证token' + }); + return; + } + + const token = authHeader.substring(7); + const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any; + + // 检查用户是否存在 + const user = await prisma.user.findUnique({ + where: { id: decoded.userId } + }); + + if (!user || !user.isActive) { + res.status(401).json({ + success: false, + message: '用户不存在或已被禁用' + }); + return; + } + + req.user = { + id: user.id, + username: user.username, + role: user.isAdmin ? 'admin' : 'user' + }; + + next(); + } catch (error) { + res.status(401).json({ + success: false, + message: '无效的token' + }); + } +}; + +// 检查角色权限 +export const requireRole = (role: string) => { + return (req: AuthRequest, res: Response, next: NextFunction): void => { + if (!req.user) { + res.status(401).json({ + success: false, + message: '需要认证' + }); + return; + } + + if (req.user.role !== role) { + res.status(403).json({ + success: false, + message: '权限不足' + }); + return; + } + + next(); + }; +}; \ No newline at end of file diff --git a/backend/src/middleware/authMiddleware.ts b/backend/src/middleware/authMiddleware.ts new file mode 100644 index 0000000..0444f83 --- /dev/null +++ b/backend/src/middleware/authMiddleware.ts @@ -0,0 +1,72 @@ +import { Request, Response, NextFunction } from 'express'; +import jwt from 'jsonwebtoken'; +import { prisma } from '../config/database'; +import { AppError } from './errorHandler'; + +export interface AuthRequest extends Request { + user?: { + id: string; + username: string; + isAdmin: boolean; + }; +} + +export async function authMiddleware( + req: AuthRequest, + res: Response, + next: NextFunction +) { + try { + const authHeader = req.headers.authorization; + + if (!authHeader || !authHeader.startsWith('Bearer ')) { + throw new AppError('No token provided', 401); + } + + const token = authHeader.substring(7); + console.log('验证token:', { token: token.substring(0, 20) + '...' }) + + const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any; + console.log('JWT解码成功:', { userId: decoded.userId }) + + // Check if session exists and is valid + const session = await prisma.session.findFirst({ + where: { + token, + expiresAt: { + gt: new Date() + } + }, + include: { + user: { + select: { + id: true, + username: true, + isAdmin: true, + isActive: true + } + } + } + }); + + console.log('Session查询结果:', { + found: !!session, + expiresAt: session?.expiresAt, + currentTime: new Date(), + userActive: session?.user?.isActive + }) + + if (!session || !session.user || !session.user.isActive) { + throw new AppError('Invalid or expired token', 401); + } + + req.user = session.user; + next(); + } catch (error) { + if (error instanceof jwt.JsonWebTokenError) { + next(new AppError('Invalid token', 401)); + } else { + next(error); + } + } +} \ No newline at end of file diff --git a/backend/src/middleware/errorHandler.ts b/backend/src/middleware/errorHandler.ts new file mode 100644 index 0000000..0c02dd2 --- /dev/null +++ b/backend/src/middleware/errorHandler.ts @@ -0,0 +1,45 @@ +import { Request, Response, NextFunction } from 'express'; +import { logger } from '../utils/logger'; + +export class AppError extends Error { + public statusCode: number; + public isOperational: boolean; + + constructor(message: string, statusCode: number = 500) { + super(message); + this.statusCode = statusCode; + this.isOperational = true; + + Error.captureStackTrace(this, this.constructor); + } +} + +export function errorHandler( + error: AppError, + req: Request, + res: Response, + next: NextFunction +) { + const statusCode = error.statusCode || 500; + const message = error.message || 'Internal Server Error'; + + // Log error + logger.error('Error occurred:', { + error: error.message, + stack: error.stack, + url: req.url, + method: req.method, + ip: req.ip, + userAgent: req.get('User-Agent') + }); + + // Don't leak error details in production + const responseMessage = process.env.NODE_ENV === 'production' && statusCode === 500 + ? 'Internal Server Error' + : message; + + res.status(statusCode).json({ + error: responseMessage, + ...(process.env.NODE_ENV === 'development' && { stack: error.stack }) + }); +} \ No newline at end of file diff --git a/backend/src/middleware/notFoundHandler.ts b/backend/src/middleware/notFoundHandler.ts new file mode 100644 index 0000000..9f0deb1 --- /dev/null +++ b/backend/src/middleware/notFoundHandler.ts @@ -0,0 +1,9 @@ +import { Request, Response } from 'express'; + +export function notFoundHandler(req: Request, res: Response) { + res.status(404).json({ + error: 'Route not found', + path: req.path, + method: req.method + }); +} \ No newline at end of file diff --git a/backend/src/middleware/validateRequest.ts b/backend/src/middleware/validateRequest.ts new file mode 100644 index 0000000..8d773d5 --- /dev/null +++ b/backend/src/middleware/validateRequest.ts @@ -0,0 +1,16 @@ +import { Request, Response, NextFunction } from 'express'; +import { validationResult } from 'express-validator'; + +export function validateRequest(req: Request, res: Response, next: NextFunction): void { + const errors = validationResult(req); + + if (!errors.isEmpty()) { + res.status(400).json({ + error: 'Validation failed', + details: errors.array() + }); + return; + } + + next(); +} \ No newline at end of file diff --git a/backend/src/middleware/validation.ts b/backend/src/middleware/validation.ts new file mode 100644 index 0000000..6712759 --- /dev/null +++ b/backend/src/middleware/validation.ts @@ -0,0 +1,17 @@ +import { Request, Response, NextFunction } from 'express'; +import { validationResult } from 'express-validator'; + +export const validateRequest = (req: Request, res: Response, next: NextFunction): void => { + const errors = validationResult(req); + + if (!errors.isEmpty()) { + res.status(400).json({ + success: false, + message: '验证失败', + errors: errors.array() + }); + return; + } + + next(); +}; \ No newline at end of file diff --git a/backend/src/routes/accounts.ts b/backend/src/routes/accounts.ts new file mode 100644 index 0000000..e3b18d5 --- /dev/null +++ b/backend/src/routes/accounts.ts @@ -0,0 +1,38 @@ +import { Router } from 'express'; +import { accountController } from '../controllers/accountController'; +import { authMiddleware } from '../middleware/authMiddleware'; +import { adminMiddleware } from '../middleware/adminMiddleware'; + +const router = Router(); + +// All routes require authentication +router.use(authMiddleware); + +// Get all accounts (admin only) +router.get('/', adminMiddleware, accountController.getAllAccounts); + +// Get account by ID (admin only) +router.get('/:id', adminMiddleware, accountController.getAccountById); + +// Create new account (admin only) +router.post('/', adminMiddleware, accountController.createAccount); + +// Update account (admin only) +router.put('/:id', adminMiddleware, accountController.updateAccount); + +// Delete account (admin only) +router.delete('/:id', adminMiddleware, accountController.deleteAccount); + +// Get user's assigned accounts +router.get('/user/assigned', accountController.getUserAccounts); + +// Assign account to user (admin only) +router.post('/:id/assign', adminMiddleware, accountController.assignAccount); + +// Unassign account from user (admin only) +router.delete('/:id/assign/:userId', adminMiddleware, accountController.unassignAccount); + +// Login to website +router.post('/:accountId/login', accountController.loginToWebsite); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/admin.ts b/backend/src/routes/admin.ts new file mode 100644 index 0000000..a836ba5 --- /dev/null +++ b/backend/src/routes/admin.ts @@ -0,0 +1,37 @@ +import express from 'express'; +import { authenticateToken, requireRole } from '../middleware/auth'; +import { validateRequest } from '../middleware/validation'; +import { adminController } from '../controllers/adminController'; +import { userController } from '../controllers/userController'; +import { accountController } from '../controllers/accountController'; + +const router = express.Router(); + +// 管理员认证中间件 +const requireAdmin = requireRole('admin'); + +// 管理员登录 +router.post('/login', validateRequest, adminController.login); + +// 获取统计数据 +router.get('/stats', authenticateToken, requireAdmin, adminController.getStats); + +// 获取最近活动 +router.get('/activities', authenticateToken, requireAdmin, adminController.getRecentActivities); + +// 用户管理 +router.get('/users', authenticateToken, requireAdmin, userController.getAllUsers); +router.post('/users', authenticateToken, requireAdmin, validateRequest, userController.createUser); +router.get('/users/:id', authenticateToken, requireAdmin, userController.getUserById); +router.put('/users/:id', authenticateToken, requireAdmin, validateRequest, userController.updateUser); +router.put('/users/:id/accounts', authenticateToken, requireAdmin, validateRequest, userController.updateUserAccounts); +router.delete('/users/:id', authenticateToken, requireAdmin, userController.deleteUser); + +// 账号管理 +router.get('/accounts', authenticateToken, requireAdmin, accountController.getAllAccounts); +router.post('/accounts', authenticateToken, requireAdmin, validateRequest, accountController.createAccount); +router.get('/accounts/:id', authenticateToken, requireAdmin, accountController.getAccountById); +router.put('/accounts/:id', authenticateToken, requireAdmin, validateRequest, accountController.updateAccount); +router.delete('/accounts/:id', authenticateToken, requireAdmin, accountController.deleteAccount); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/auth.ts b/backend/src/routes/auth.ts new file mode 100644 index 0000000..ef54c58 --- /dev/null +++ b/backend/src/routes/auth.ts @@ -0,0 +1,52 @@ +import { Router } from 'express'; +import { body } from 'express-validator'; +import { validateRequest } from '../middleware/validateRequest'; +import { authController } from '../controllers/authController'; +import { authMiddleware } from '../middleware/authMiddleware'; + +const router = Router(); + +// Register +router.post('/register', [ + body('username').isLength({ min: 3, max: 30 }).matches(/^[a-zA-Z0-9_]+$/), + body('password').isLength({ min: 8 }), + body('confirmPassword').isLength({ min: 8 }).custom((value, { req }) => { + if (value !== req.body.password) { + throw new Error('密码和确认密码不匹配'); + } + return true; + }), + body('firstName').optional().isLength({ max: 50 }), + body('lastName').optional().isLength({ max: 50 }), + validateRequest +], authController.register); + +// Login +router.post('/login', [ + body('username').isLength({ min: 3, max: 30 }), + body('password').notEmpty(), + validateRequest +], authController.login); + +// Logout +router.post('/logout', authMiddleware, authController.logout); + +// Setup TOTP +router.post('/setup-totp', authMiddleware, authController.setupTOTP); + +// Verify TOTP +router.post('/verify-totp', [ + body('token').notEmpty(), + validateRequest +], authMiddleware, authController.verifyTOTP); + +// Get current user +router.get('/me', authMiddleware, authController.getCurrentUser); + +// Refresh token +router.post('/refresh', authController.refreshToken); + +// Debug session (for development) +router.get('/debug-session', authMiddleware, authController.debugSession); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/users.ts b/backend/src/routes/users.ts new file mode 100644 index 0000000..f670b25 --- /dev/null +++ b/backend/src/routes/users.ts @@ -0,0 +1,23 @@ +import { Router } from 'express'; +import { userController } from '../controllers/userController'; +import { authMiddleware } from '../middleware/authMiddleware'; +import { adminMiddleware } from '../middleware/adminMiddleware'; + +const router = Router(); + +// All routes require authentication +router.use(authMiddleware); + +// Get all users (admin only) +router.get('/', adminMiddleware, userController.getAllUsers); + +// Get user by ID (admin or self) +router.get('/:id', userController.getUserById); + +// Update user (admin or self) +router.put('/:id', userController.updateUser); + +// Delete user (admin only) +router.delete('/:id', adminMiddleware, userController.deleteUser); + +export default router; \ No newline at end of file diff --git a/backend/src/utils/audit.ts b/backend/src/utils/audit.ts new file mode 100644 index 0000000..a400b00 --- /dev/null +++ b/backend/src/utils/audit.ts @@ -0,0 +1,41 @@ +import { prisma } from '../config/database'; + +interface AuditLogData { + userId: string | null; + action: string; + resource: string; + resourceId?: string; + details?: any; + ipAddress?: string | null; + userAgent?: string | null; +} + +export const createAuditLog = async (data: AuditLogData) => { + try { + const auditData: any = { + userId: data.userId, + action: data.action, + resource: data.resource + }; + + // 只添加非undefined的字段 + if (data.resourceId !== undefined) { + auditData.resourceId = data.resourceId; + } + if (data.details !== undefined) { + auditData.details = data.details; + } + if (data.ipAddress !== undefined) { + auditData.ipAddress = data.ipAddress; + } + if (data.userAgent !== undefined) { + auditData.userAgent = data.userAgent; + } + + await prisma.auditLog.create({ + data: auditData + }); + } catch (error) { + console.error('Failed to create audit log:', error); + } +}; \ No newline at end of file diff --git a/backend/src/utils/logger.ts b/backend/src/utils/logger.ts new file mode 100644 index 0000000..d73b4c4 --- /dev/null +++ b/backend/src/utils/logger.ts @@ -0,0 +1,26 @@ +import winston from 'winston'; + +const logFormat = winston.format.combine( + winston.format.timestamp(), + winston.format.errors({ stack: true }), + winston.format.json() +); + +export const logger = winston.createLogger({ + level: process.env.NODE_ENV === 'production' ? 'info' : 'debug', + format: logFormat, + defaultMeta: { service: 'pandora-backend' }, + transports: [ + new winston.transports.File({ filename: 'logs/error.log', level: 'error' }), + new winston.transports.File({ filename: 'logs/combined.log' }), + ], +}); + +if (process.env.NODE_ENV !== 'production') { + logger.add(new winston.transports.Console({ + format: winston.format.combine( + winston.format.colorize(), + winston.format.simple() + ) + })); +} \ No newline at end of file diff --git a/backend/tsconfig.json b/backend/tsconfig.json new file mode 100644 index 0000000..bceeb40 --- /dev/null +++ b/backend/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "removeComments": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..edce753 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,44 @@ +version: '3.8' + +services: + # 后端 API 服务 + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: pandora_backend + volumes: + - sqlite_data:/app/prisma + ports: + - "3001:3001" + networks: + - pandora_network + restart: always + command: npm run start + + # 前端应用 + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + container_name: pandora_frontend + environment: + CLAUDE_TARGET_URL: https://claude.micar9.com:8443 + CHATGPT_TARGET_URL: https://gpt.micar9.com:8443 + GROK_TARGET_URL: https://grok-mirror.micar9.com:8443 + ports: + - "3000:3000" + depends_on: + - backend + networks: + - pandora_network + restart: always + command: npm run start + +volumes: + sqlite_data: + driver: local + +networks: + pandora_network: + driver: bridge \ No newline at end of file diff --git a/env.example b/env.example new file mode 100644 index 0000000..0f161aa --- /dev/null +++ b/env.example @@ -0,0 +1,68 @@ +# 数据库配置 +DATABASE_URL=postgresql://pandora_user:pandora_password@localhost:5432/pandora +POSTGRES_DB=pandora +POSTGRES_USER=pandora_user +POSTGRES_PASSWORD=your-secure-password + +# Redis配置 +REDIS_URL=redis://localhost:6379 +REDIS_PASSWORD=your-redis-password + +# JWT配置 +JWT_SECRET=your-super-secret-jwt-key-change-in-production +JWT_EXPIRES_IN=7d + +# 服务器配置 +PORT=3001 +NODE_ENV=development +CORS_ORIGIN=http://localhost:3000 + +# 邮件配置 +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_USER=your-email@gmail.com +SMTP_PASS=your-app-password +SMTP_FROM=Pandora + +# 前端配置 +VITE_API_URL=http://localhost:3001 +VITE_APP_NAME=Pandora + +# 域名配置 +DOMAIN_PATH1=path1.com +DOMAIN_PATH2=path2.com +DOMAIN_PATH3=path3.com + +# 聊天配置 - 网站代理目标地址 +CLAUDE_TARGET_URL=https://claude.ai +CHATGPT_TARGET_URL=https://chat.openai.com +GROK_TARGET_URL=https://grok.x.ai + +# 聊天配置 - 自定义User-Agent(可选) +CLAUDE_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 +CHATGPT_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 +GROK_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 + +# 聊天配置 - 超时和限制 +CHAT_TIMEOUT=10000 +CHAT_RATE_LIMIT=100 + +# 日志配置 +LOG_LEVEL=info + +# 监控配置 (可选) +GRAFANA_PASSWORD=admin + +# 安全配置 +BCRYPT_ROUNDS=12 +RATE_LIMIT_WINDOW=15m +RATE_LIMIT_MAX=100 + +# 文件上传配置 +UPLOAD_MAX_SIZE=10mb +UPLOAD_PATH=./uploads + +# 备份配置 +BACKUP_ENABLED=true +BACKUP_SCHEDULE=0 2 * * * +BACKUP_RETENTION_DAYS=30 \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..326724c --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,35 @@ +FROM node:18-alpine + +# 设置工作目录 +WORKDIR /app + +# 安装系统依赖 +RUN apk add --no-cache \ + curl + +# 复制 package.json 和 package-lock.json +COPY package*.json ./ + +# 安装依赖 +RUN npm ci + +# 复制源代码 +COPY . . + +# 创建非root用户 +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nodejs -u 1001 + +# 更改文件所有权 +RUN chown -R nodejs:nodejs /app +USER nodejs + +# 暴露端口 +EXPOSE 3000 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3000 || exit 1 + +# 启动命令 - 支持环境变量 +CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"] \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..a999aaf --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,108 @@ +# Pandora 前端应用 + +基于 Vue 3 + TypeScript + Vite 构建的现代化前端应用。 + +## 技术栈 + +- **Vue 3**: 现代化的前端框架 +- **TypeScript**: 类型安全的JavaScript +- **Vite**: 快速的构建工具 +- **Tailwind CSS**: 实用优先的CSS框架 +- **Vue Router**: 客户端路由 +- **Pinia**: 状态管理 +- **VueUse**: 组合式工具库 +- **VeeValidate**: 表单验证 +- **Vue Toastification**: 通知组件 + +## 项目结构 + +``` +src/ +├── components/ # 可复用组件 +├── views/ # 页面组件 +├── stores/ # Pinia状态管理 +├── utils/ # 工具函数 +├── types/ # TypeScript类型定义 +├── assets/ # 静态资源 +├── router/ # 路由配置 +├── App.vue # 根组件 +├── main.ts # 应用入口 +└── style.css # 全局样式 +``` + +## 开发指南 + +### 安装依赖 +```bash +npm install +``` + +### 启动开发服务器 +```bash +npm run dev +``` + +### 构建生产版本 +```bash +npm run build +``` + +### 代码检查 +```bash +npm run lint +``` + +### 运行测试 +```bash +npm test +``` + +## 主要功能 + +1. **Claude风格首页** - 现代化的AI助手风格界面,集成登录和注册功能 +2. **用户仪表板** - 显示可用账号和统计信息 +3. **管理后台** - 用户和权限管理界面 +4. **响应式设计** - 适配各种设备尺寸 +5. **深色模式** - 支持深色/浅色主题切换 + +## 组件说明 + +### 页面组件 +- `Home.vue` - 首页,包含登录和注册功能 +- `Dashboard.vue` - 用户仪表板 +- `Admin.vue` - 管理后台 +- `NotFound.vue` - 404页面 + +### 工具组件 +- `icons/` - SVG图标组件 +- 更多组件开发中... + +## 样式系统 + +使用 Tailwind CSS 构建,包含: +- 响应式设计 +- 深色模式支持 +- 自定义组件类 +- 动画效果 + +## 状态管理 + +使用 Pinia 进行状态管理,主要store: +- 用户认证状态 +- 应用配置 +- 主题设置 + +## 路由配置 + +- `/` - 首页(包含登录/注册功能) +- `/dashboard` - 用户仪表板 +- `/admin` - 管理后台 +- `/*` - 404页面 + +## 开发规范 + +- 使用 TypeScript 严格模式 +- 遵循 Vue 3 Composition API +- 使用 ESLint 和 Prettier +- 组件命名使用 PascalCase +- 文件命名使用 kebab-case \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..47c12da --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,17 @@ + + + + + + + Pandora - 网站账号共享系统 + + + + + + +
+ + + \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..6888f81 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,50 @@ +{ + "name": "pandora-frontend", + "version": "1.0.0", + "description": "Pandora 前端应用", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc && vite build", + "preview": "vite preview", + "test": "vitest", + "test:ui": "vitest --ui", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "dependencies": { + "vue": "^3.3.8", + "vue-router": "^4.2.5", + "pinia": "^2.1.7", + "@vueuse/core": "^10.4.1", + "vee-validate": "^4.10.5", + "vue-toastification": "^2.0.0-rc.5", + "axios": "^1.5.0", + "@headlessui/vue": "^1.7.16", + "@heroicons/vue": "^2.0.18", + "clsx": "^2.0.0", + "tailwind-merge": "^1.14.0" + }, + "devDependencies": { + "@types/node": "^20.6.3", + "@vitejs/plugin-vue": "^4.4.0", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^12.0.0", + "@vue/test-utils": "^2.4.2", + "autoprefixer": "^10.4.15", + "eslint": "^8.49.0", + "eslint-plugin-vue": "^9.17.0", + "jsdom": "^22.1.0", + "postcss": "^8.4.29", + "prettier": "^3.0.3", + "tailwindcss": "^3.3.3", + "typescript": "~5.2.0", + "vite": "^4.4.11", + "vitest": "^0.34.4", + "vue-tsc": "^1.8.15" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + } +} \ No newline at end of file diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 0000000..387612e --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/frontend/src/App.vue b/frontend/src/App.vue new file mode 100644 index 0000000..9728637 --- /dev/null +++ b/frontend/src/App.vue @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/assets/ChatGPT.png b/frontend/src/assets/ChatGPT.png new file mode 100644 index 0000000000000000000000000000000000000000..12c6130aee574daabeb6038ef51bdc4dbae567ce GIT binary patch literal 15180 zcmV-SJF~=zP){4fGNhwiU=~P0xK|(<~6;${dn5c-v(kdn0Az>jQ(jtB*2Ft@==gH$by+H zm;kVmNHPh;6T=x!@Hf}E%mpHemv%BqflL_yN&$qCpGs7u5CzFY0KSUfZ6k>oE^~?V zZ09&viIgdspvjPc65vY+WvE6)Dk2EN&xN0}lfWI$vzPts<|0;U%LGq`0hBN!C{Jw~ zQj{Dze`6BYIKeu0avZD7L{Rz$lz{A%r8RXZO`w5aXX84*vw_Y0EfX_glnwzUz?VEU zrUR7;!R(eln#g5-WHr0FovE~^D?kZ9O3{k;JV_R}|M4jHGK*ihkqN4F04M<#s?&jn z6mk<^N{!;#&w5sHE~8t4X&g|(k81R$DLK4gG0B`{4okU|kvUZw29z*Ul0I}sc+poR zbC8*=AWCKeDougOL@v6}j}rKJ-Qr@|#64(fCvv<50qv8cd}qGlghGR?BgV)tU(? zFNISuy%@*SX=K$VEL5XBe_5_rGXdp&Hl3vmpEB6%Mcse*w z@&f*8P)p54JuH@kmRM^hpu7Z5fxN<(luWZ;vjD16gg-1%)=WTo0h~g4lXnnle4k5G zp2L=_=^avDe&+>*@;-eD(D{dLBw^(`(ZrBI0(aBp{K-NfA%v2hEXsMEs$}ONudzLS z2WGq-P`Me+tGZkoPMJe*T2rD~>8OpEel}nkt7EXB> zPY0KbhGZgG&pLi5N{{0cCITo-6IxP%tS;@`Y5KBN+CZ4_CxAdg$cG>&!2}U_UxYH5 zIAV$B2G_VkG_fR-mMOxym_6!dw5yVKkYxeWl zIK(KX$?KlEm{zRGmg8(8n4-Feh_sR!3uS3aT}+l+mT32b%8LLc%yi=&f;7Gs&oTz^ ztMq8Tkrm4ge&Qm}5b6bLgg=F7!t-RcL|9_n3o5Sxlz?ZLL_Wu zV)ffD(a((^Het9l;1zcpgr|L}7Z-odRhfJvo-| z_>{xOx<0*N8w50FktWCBHC|`AO!7FGa?pkWlyy19#$9CNB%iW^SedQ?70Mi1X?Q_0 zoTZ+HlYneArw>&KByCYNYxsmyMy0@b98khU7iMVCKko1@(>z(=Ex?az45qPHYfX>i zQ~UWJTZ|EX9(Nm91fNqv`SBDM^NEb}=mjXkV8-xl8mtk#$3*f|lgpOV)|7MyC}E}p z{WPp%C$HhL*r&jfgKmtYJt3rR%1&JpEr04?&+K85Cvvlf>dKE_q&wR@lK?9qkU9*e zo`G6Z3Mr&umJj-*`rLYdo{gYV9 za4ySq0H^@w&{1&(v5ep=ch|CsKF|Hk<@F5>1X+Tp-xTw`7 zvw?wnaVe7r`BN3vkw@|I_4JT8-MT(s$})hqy3LA7mJUTowyiM`e1@ z#OV$-esm{_4~a?394a>(sjR4ue@lP&rKyOlJkL<7>EyUf;W*P+%M~N-Qvv=|qd$$E z7SFMK%y^lQb^+Ct#bi@@^ct<%xRvI#h8ct@m z-()!RUFD%3@{|i7`chZ%;ib%Whr2+SD8^96IDH`hrD)bNoP|=lC#&0vHPP}Ho485| zr!=ZSD)NWrylZg?H*+XqBA9#>rvdFKptw(+JZ# z^E4x9-0VM(`OdVdNJb5)+mGKNO){-Pw?_Ask8s@(jIbOgax18{&Gh;Ls&?Yj5Pn@%?O}gLvKq~Vx&B&#L82N)n^11;oizn$zC!I<% z?c8KJ;hgl=u9?D@R(wHWjhbL5eskt}=qmDrAC>4$Gji($)L)3w9q?gvq90G{q&3B} zjY(|vWKyz2(U&Y%6U#K7(C|_|MsUQL-Pesn2{R?=M+fri_L~WGV4a>8o(Sf7hUu0K zp3D)ZvWlDDKMq!y>BM+VZQNoR$}H_X%2%g*FKEXAO6lr(zra!bj!O7bmA1IdAH3`4}!`6UzzUQw`zcAO^9GQyu`6@TU%MQd{>bkmFp`?S7V|A03@+wD>UH zWIi)EnKr=m52TXBeEj)b!-aZ^f#MCV^^YzBN|?yY0D9}DHT_E|96|?wjxZtULLc46 zUB|MG$=FiC}v2I)x1S`a7-)JmE_@M$k+rt;xbK)UNLZN3Pj`CimU9`+S|)Q)ru{*$ zCmGFbW#v2<-NjBV;@v4g2@@sxoF;~L9XaJ}(yxFJnlXe5I;}5>{e-jLdx9!1+Iv6o zHE$@JP>m_iE<*t&e5u9fR5mzM;Q~&ny~2lzyhUT3<{Kn)mRT$?Hi6g8kV+I&sYZQe z9@RtaQxC&v29(G`7v86!;fXKTrE_p<#aN2y6jZs$eCBZ88~WtwN>>?A1;vhBX6jLh zv#LL>QNs{H4CYG;84f2q&Lw%(WP%fEWvS6^=Fyh-<(YH`C#0RtEJxLgR)l8i{!mRE zN@QawBXqKw961e~FwI2>Ln)}kUr%H|lh}aO(9}K?0R)o`f1(ohH9c!t@`Gq~)@L~a_=n$l#$hd3hH!W!|1 zyHfKc;u!OIPx1UK@C;jY29)rpA46P*Qxr+$Rsxjv?&E%Rbh)S8b(S)dW5xzmL@-Sl zMAiG;t;MKH4_1ol{NTKP%`XatZg8j$C9OYWks>TIAJ{ zLkS<+@qr7yky1FxLRNAH8_ycHLHWt=^t(2WF`hNj(1Leiq5v<`=aB_uK9puWt(hdY z7#}N?DPlFRP*&;TC#fhdNqqn%%skJhN`fkN;dO?EEaQx{fiSYLG|)-EeF~RZ$ZSp< ztTpAL83P;+YYgNCs<2i}<*?y1I?u6+l1fY^fJS_;A~hWTn1C8g(v zD^k9pTa1v%wh<8~|dnXJU6HhXZ1vC>u!l3oZ zB-Sh1)4^0zF&2Cs+^zn!bs}CL%St{ru3NtjzNRZIVkTz{Zm|f2 zm?{n#R8_N=6I4-pvMRxj!RPx}HL?~%oJdW($XLELe(sUe6wOA$*>7wriU^=4L#eMr zf=_mOQlD?dY(om%Z?RD^&|j9kE&+{>O_<5^Hr|c?#Q!Q3|JpQiKyu>rf&KgQ%lfFWE>BHhU?Y?400jI5)Sj1(xU;?bgV`BK2qE@qqoKcwOGDlELWs= zg6Rs2m}jibDNKaWiXK!qXbwy;ov6)P@eN0GytFqtNEHR}`%o4?N4}^>iM)cmNiK~h z_?LX)wONgSFoeAZYfV|G$uM2CrpF1t{Pd?Ov&B5UG%A@QHq%|H7N#H}Tz5j`34i)2 zC$isz(-&S0C)jN)oP>{fiis?ynW1pH2dcun$4a^hy%LFzD&}?+betUIo2t26l^&X^ z*y5PVmw0o|wXs2!FnZ97qHgS1>Puy&(o}@AUx$>J8{AYXf(>yTBKA#HQV-VD{w0xb z7?VCy__eFx1W}*YsOf>}d0FX5E#`}FT=u8MaFNnVhCwdjpmCHrl`U#Q6HR943O<&% zGbEgRsmu)KQ(q&TZgU!aQt9$Bg4OgBxn1(5$FpDQIWt8Zaba^Rmu`TDFoB(4c?X#R z!DJS9HJO(P)%0QlTj;?HjN}A*_`ZF3it#L>g$n_i6iz5+n3r(m_4obnHqnCTG%V!= zZ}N9W!;^sQv|#Y}T9J3%5OiHdff9|>A? zsQmQP5Nx^1NcPK&1||#j>8E+Jr;P~avxH-JV{$Tu(m6zObJHOl4)Xv=9HHk+)(m620C(fKggj%X|BOL{xjdCgIa$r?t#Meqz45whEx*R z!6Y^lo7y4E7_o}q=uBT-+BEu5j)}A-T>PSG*7r@t!v8E9041O{RW*paiQLRUU<#!T z11P649A)DyGx(OsM{{xs*TiIgpf89duE22^5|n7|3;OxZ-#;OFN^(BIFYEWD&# zhLpl=wr3RWN%&En5l#eEB3Z#yjyuj|k|`V)Z?RgZR@Wx7^9r^2N-R_y5Mm=<5l|L& zKs`lmFy1{t3Hs5AFpaz;mS32}4)r;IGC^$PkZ#TR%{`E?L} ze$=2G--~ee>y+s1=g3Ftd!NIgx$-A$=DYN6-3iD+T?T2Mhi>B>3z*FX=XOZiI4j;~ z9Rq2ki$;}=4%B3!n5|2bS(78f!T0~Sua0tU%XKEXa{{nOz?6j=45zL}t;x;}mNDa= zugO`GNn#HNsm@@XMy};!IIZ|fEaa+-j3CKT3cx)Mn=U8Adf70yHM_@jA~lLEO(z zvns|D6G(C-TLE$_3%n!zCetBr68U+P<#cn33uNOB`in4O;0om(*3h0&oJ9{V=tFs? zGoOay9xo16j84X@0jh#xBODv+xt8w06haqP^1joZLroOpGnUXwWHk;{5_z3)TJtrL zx+F9Q@gj@)Qj` znzBMn=csY*i)5Vmf!~}m9vAVuu!PozYE*V938yVzIoZ$s;j5rR$&SZ#n*}_l$U4t+Asv7z3w4>r44%_> z-tq(FPaWnkoo9uC#Z@wedm5Fy9646UCYdk3lvZ@@?@jB~EyDcIJanx=l?3+TuW1;O zi4b0*4)erp;|8Khh!a1skJb#LoEyqaFFVdLF=J6|7;NLuv^}Iku*$AD&?Xv#Bex7^zY5H)H6;GDF(|*g5C8Jk^&c6w~Ui zaV8A|syS^mSE@*sGM6Lwf+{kZBjODf(~H)ce#=4|YVadd#Q~#=IwT~C9UP(-12iYy zs0;q>j-!=kgkl2OWhaJZc#}4+4NmcVPiNlbz=JV58P86J(4DOsOUc7{i50vriVCw) zpD2;hY@{1QIEWFzjp3+@ksGF{%pD?uj6o?J;dQ$6i;S149h;T)bm3i%8kLy>yv1sI z8mdv*{XRWq9;GM-;}nL+H= z#Jx>~F_<+B5_yc9J0+3PETJ9maatGQcbVO4l3lH|^G>=3l$~>YKnGUH7|q8P#XQEsMgX_x1D zk9I84chZJb6Wk@5V@OY~%?(;AhDE>sapfKszJ;)(ZqaQJG>9Y|z5 zz3Iy~sY`HG#_%IO7{FdlULZ41Fo@L*6=8;IRM%NTd*0==lS#zSFpd&J;d4}VeDC){ z`D*~w-C#vWmdQK%MZBe5M)57}nLvcb08L58u*~q3m&<%f8|FBb?`fhMV;uL8GLsSM zZaDR0c~u&5Y!`Tk_AJ(@b!MS9bC^MSVO&}bGKIqo=2Z?jVfp#ck~c(J8=YCnNKw$x08JdL>B?d!vZ(y%L;J^TduBzX2D)KF zfbsPIDQPm+*wikGyu%7QGK!NL12jc>j}>$=G(cmM#~HvoYL0*hD3o_8Cm#C&YI?sv zerX&`b|hcYhOcC#d-4P&@+y;P#T1R5{`{!QOy*PH&_F#;?$ccibZtdJ$c5x0VHXY#~DdCR%vv*1ksGej1v_MbSEV713g%y(UoALC9ghu z#F|;r9gt12kilDNK7HgC=@Cm+#<7uC`Bk%3B^ba;-WG+7awkZeJWOAvXl#BG#B0

8imeWV%(*I&hxW#DZYYG_^W?*VgPBYgP?YuGs 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 UWNwh3K<+XV!Z literal 0 HcmV?d00001 diff --git a/frontend/src/assets/grok.png b/frontend/src/assets/grok.png new file mode 100644 index 0000000000000000000000000000000000000000..73ed533457a271eaa4cfa9e165631e62c20f6e7d GIT binary patch literal 10570 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 literal 0 HcmV?d00001 diff --git a/frontend/src/components/icons/index.ts b/frontend/src/components/icons/index.ts new file mode 100644 index 0000000..0a4f140 --- /dev/null +++ b/frontend/src/components/icons/index.ts @@ -0,0 +1,35 @@ +// 用户图标 +export const UserIcon = { + template: ` + + + + ` +} + +// 钥匙图标 +export const KeyIcon = { + template: ` + + + + ` +} + +// 盾牌图标 +export const ShieldIcon = { + template: ` + + + + ` +} + +// 图表图标 +export const ChartIcon = { + template: ` + + + + ` +} \ No newline at end of file diff --git a/frontend/src/config/websites.ts b/frontend/src/config/websites.ts new file mode 100644 index 0000000..17be843 --- /dev/null +++ b/frontend/src/config/websites.ts @@ -0,0 +1,62 @@ +// 网站URL配置 +// 支持通过Docker环境变量配置 + +export interface WebsiteConfig { + name: string + url: string + icon: string +} + +// 从环境变量获取URL,如果没有配置则使用默认值 +const getWebsiteUrls = () => { + // 检查是否在浏览器环境中 + if (typeof window !== 'undefined') { + // 在客户端,使用Vite定义的全局变量 + return { + claude: (window as any).__CLAUDE_URL__ || 'https://chat.micar9.com:8443', + chatgpt: (window as any).__CHATGPT_URL__ || 'https://chat.openai.com', + grok: (window as any).__GROK_URL__ || 'https://grok-mirror.micar9.com:8443' + } + } + + // 在服务端,使用环境变量 + return { + claude: process.env.CLAUDE_TARGET_URL || 'https://chat.micar9.com:8443', + chatgpt: process.env.CHATGPT_TARGET_URL || 'https://chat.openai.com', + grok: process.env.GROK_TARGET_URL || 'https://grok-mirror.micar9.com:8443' + } +} + +// 网站配置 +export const websiteConfigs: Record = { + claude: { + name: 'Claude', + url: getWebsiteUrls().claude, + icon: '/src/assets/claude.png' + }, + chatgpt: { + name: 'ChatGPT', + url: getWebsiteUrls().chatgpt, + icon: '/src/assets/ChatGPT.png' + }, + grok: { + name: 'Grok', + url: getWebsiteUrls().grok, + icon: '/src/assets/grok.png' + } +} + +// 获取网站URL的函数 +export const getWebsiteUrl = (site: string): string => { + return websiteConfigs[site]?.url || '' +} + +// 获取网站配置的函数 +export const getWebsiteConfig = (site: string): WebsiteConfig | null => { + return websiteConfigs[site] || null +} + +// 获取所有网站配置 +export const getAllWebsiteConfigs = (): WebsiteConfig[] => { + return Object.values(websiteConfigs) +} \ No newline at end of file diff --git a/frontend/src/env.d.ts b/frontend/src/env.d.ts new file mode 100644 index 0000000..e51ca5f --- /dev/null +++ b/frontend/src/env.d.ts @@ -0,0 +1,11 @@ +/// + +interface ImportMetaEnv { + readonly VITE_API_BASE_URL: string + readonly VITE_APP_TITLE: string + readonly VITE_APP_VERSION: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} \ No newline at end of file diff --git a/frontend/src/main.ts b/frontend/src/main.ts new file mode 100644 index 0000000..1aada55 --- /dev/null +++ b/frontend/src/main.ts @@ -0,0 +1,44 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import Toast from 'vue-toastification' +import 'vue-toastification/dist/index.css' + +import App from './App.vue' +import router from './router' +import './style.css' +import { useAuthStore } from './stores/auth' +import { useAdminStore } from './stores/admin' + +const app = createApp(App) + +// 配置 Pinia 状态管理 +const pinia = createPinia() +app.use(pinia) + +// 初始化认证状态 +const authStore = useAuthStore() +const adminStore = useAdminStore() + +authStore.initAuth() +adminStore.initAuth() + +// 配置路由 +app.use(router) + +// 配置 Toast 通知 +app.use(Toast, { + position: 'top-right', + timeout: 5000, + closeOnClick: true, + pauseOnFocusLoss: true, + pauseOnHover: true, + draggable: true, + draggablePercent: 0.6, + showCloseButtonOnHover: false, + hideProgressBar: false, + closeButton: 'button', + icon: true, + rtl: false, +}) + +app.mount('#app') \ No newline at end of file diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts new file mode 100644 index 0000000..3afacb2 --- /dev/null +++ b/frontend/src/router/index.ts @@ -0,0 +1,105 @@ +import { createRouter, createWebHistory } from 'vue-router' +import type { RouteRecordRaw } from 'vue-router' +import { useAuthStore } from '@/stores/auth' +import { useAdminStore } from '@/stores/admin' +import { adminAuth } from '@/utils/auth' +import { useToast } from 'vue-toastification' + +const routes: RouteRecordRaw[] = [ + { + path: '/', + name: 'Home', + component: () => import('@/views/Home.vue'), + meta: { title: '首页' } + }, + { + path: '/admin/login', + name: 'AdminLogin', + component: () => import('@/views/AdminLogin.vue'), + meta: { title: '管理员登录' } + }, + { + path: '/dashboard', + name: 'Dashboard', + component: () => import('@/views/Dashboard.vue'), + meta: { title: '仪表板', requiresAuth: true } + }, + { + path: '/admin', + name: 'Admin', + component: () => import('@/views/Admin.vue'), + meta: { title: '管理后台', requiresAdminAuth: true } + }, + { + path: '/admin/users', + name: 'AdminUsers', + component: () => import('@/views/AdminUsers.vue'), + meta: { title: '用户管理', requiresAdminAuth: true } + }, + { + path: '/admin/accounts', + name: 'AdminAccounts', + component: () => import('@/views/AdminAccounts.vue'), + meta: { title: '账号管理', requiresAdminAuth: true } + }, + { + path: '/admin/permissions', + name: 'AdminPermissions', + component: () => import('@/views/AdminPermissions.vue'), + meta: { title: '权限管理', requiresAdminAuth: true } + }, + { + path: '/admin/monitor', + name: 'AdminMonitor', + component: () => import('@/views/AdminMonitor.vue'), + meta: { title: '系统监控', requiresAdminAuth: true } + }, + { + path: '/test', + name: 'Test', + component: () => import('@/views/Test.vue'), + meta: { title: 'API测试' } + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: () => import('@/views/NotFound.vue'), + meta: { title: '页面未找到' } + } +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +// 路由守卫 +router.beforeEach((to: any, from: any, next: any) => { + // 设置页面标题 + document.title = `${to.meta.title} - Pandora` + + // 获取认证状态 + const authStore = useAuthStore() + const adminStore = useAdminStore() + const toast = useToast() + + // 检查是否需要用户认证 + if (to.meta.requiresAuth) { + if (!authStore.isLoggedIn) { + next('/') + return + } + } + + // 检查是否需要管理员认证 + if (to.meta.requiresAdminAuth) { + if (!adminAuth.isLoggedIn()) { + next('/admin/login') + return + } + } + + next() +}) + +export default router \ No newline at end of file diff --git a/frontend/src/stores/admin.ts b/frontend/src/stores/admin.ts new file mode 100644 index 0000000..85d0847 --- /dev/null +++ b/frontend/src/stores/admin.ts @@ -0,0 +1,248 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import { adminAPI } from '@/utils/api' +import { adminAuth } from '@/utils/auth' +import type { User, PaginatedResponse } from '@/types' + +export const useAdminStore = defineStore('admin', () => { + // 状态 + const admin = ref(null) + const token = ref(null) + const loading = ref(false) + const error = ref(null) + const users = ref([]) + const pagination = ref({ + page: 1, + limit: 10, + total: 0, + totalPages: 0 + }) + + // 计算属性 + const isLoggedIn = computed(() => !!token.value && !!admin.value) + + // 初始化认证状态 + const initAuth = () => { + const storedToken = adminAuth.getToken() + const storedAdmin = adminAuth.getAdminInfo() + + if (storedToken && storedAdmin) { + token.value = storedToken + admin.value = storedAdmin + } + } + + // 管理员登录 + const login = async (data: { username: string; password: string }) => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.login(data) + + // 保存认证信息 + token.value = response.token + admin.value = response.admin + adminAuth.setLogin(response.token, response.admin) + + return response + } catch (err: any) { + error.value = err.response?.data?.message || '登录失败' + throw err + } finally { + loading.value = false + } + } + + // 管理员登出 + const logout = async () => { + loading.value = true + error.value = null + + try { + // 清除本地状态 + token.value = null + admin.value = null + users.value = [] + adminAuth.logout() + } catch (err) { + console.warn('Admin logout failed:', err) + } finally { + loading.value = false + } + } + + // 获取用户列表 + const loadUsers = async (params?: { page?: number; limit?: number; search?: string }) => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.getUsers(params) + users.value = response.users + pagination.value = response.pagination + return response + } catch (err: any) { + error.value = err.response?.data?.message || '获取用户列表失败' + throw err + } finally { + loading.value = false + } + } + + // 创建用户 + const createUser = async (data: { + username: string + password: string + role: string + }) => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.createUser(data) + // 重新加载用户列表 + await loadUsers() + return response + } catch (err: any) { + error.value = err.response?.data?.message || '创建用户失败' + throw err + } finally { + loading.value = false + } + } + + // 更新用户 + const updateUser = async (userId: string, data: any) => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.updateUser(userId, data) + // 重新加载用户列表 + await loadUsers() + return response + } catch (err: any) { + error.value = err.response?.data?.message || '更新用户失败' + throw err + } finally { + loading.value = false + } + } + + // 更新用户账号权限 + const updateUserAccounts = async (userId: string, accountIds: string[]) => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.updateUserAccounts(userId, accountIds) + // 重新加载用户列表 + await loadUsers() + return response + } catch (err: any) { + error.value = err.response?.data?.message || '更新用户账号权限失败' + throw err + } finally { + loading.value = false + } + } + + // 删除用户 + const deleteUser = async (userId: string) => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.deleteUser(userId) + // 重新加载用户列表 + await loadUsers() + return response + } catch (err: any) { + error.value = err.response?.data?.message || '删除用户失败' + throw err + } finally { + loading.value = false + } + } + + // 获取统计数据 + const getStats = async () => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.getStats() + return response + } catch (err: any) { + error.value = err.response?.data?.message || '获取统计数据失败' + throw err + } finally { + loading.value = false + } + } + + // 获取最近活动 + const getRecentActivities = async () => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.getRecentActivities() + return response + } catch (err: any) { + error.value = err.response?.data?.message || '获取最近活动失败' + throw err + } finally { + loading.value = false + } + } + + // 获取账号列表 + const getAccounts = async (params?: { page?: number; limit?: number; search?: string; status?: string }) => { + loading.value = true + error.value = null + + try { + const response = await adminAPI.getAccounts(params) + return response + } catch (err: any) { + error.value = err.response?.data?.message || '获取账号列表失败' + throw err + } finally { + loading.value = false + } + } + + // 清除错误 + const clearError = () => { + error.value = null + } + + return { + // 状态 + admin, + token, + loading, + error, + users, + pagination, + + // 计算属性 + isLoggedIn, + + // 方法 + initAuth, + login, + logout, + loadUsers, + createUser, + updateUser, + updateUserAccounts, + deleteUser, + getStats, + getRecentActivities, + getAccounts, + clearError + } +}) \ No newline at end of file diff --git a/frontend/src/stores/auth.ts b/frontend/src/stores/auth.ts new file mode 100644 index 0000000..88bfa80 --- /dev/null +++ b/frontend/src/stores/auth.ts @@ -0,0 +1,247 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import { authAPI } from '@/utils/api' +import { userAuth } from '@/utils/auth' +import type { User } from '@/types' + +export const useAuthStore = defineStore('auth', () => { + // 状态 + const user = ref(null) + const token = ref(null) + const loading = ref(false) + const error = ref(null) + + // 计算属性 + const isLoggedIn = computed(() => !!token.value && !!user.value) + + // 初始化认证状态 + const initAuth = () => { + const storedToken = userAuth.getToken() + const storedUser = userAuth.getUserInfo() + + if (storedToken && storedUser) { + token.value = storedToken + user.value = storedUser + } else { + + } + } + + // 用户注册 + const register = async (data: { + username: string + password: string + confirmPassword: string + }) => { + loading.value = true + error.value = null + + try { + const response = await authAPI.register(data) + return response + } catch (err: any) { + error.value = err.response?.data?.message || '注册失败' + throw err + } finally { + loading.value = false + } + } + + // 用户登录 + const login = async (data: { + username: string + password: string + }) => { + loading.value = true + error.value = null + + try { + const response = await authAPI.login(data) + + // 保存认证信息 + token.value = response.token + user.value = response.user + userAuth.setLogin(response.token, response.user) + + return response + } catch (err: any) { + throw err + } finally { + loading.value = false + } + } + + // 邮箱验证 + const verifyEmail = async (token: string) => { + loading.value = true + error.value = null + + try { + const response = await authAPI.verifyEmail(token) + return response + } catch (err: any) { + error.value = err.response?.data?.message || '邮箱验证失败' + throw err + } finally { + loading.value = false + } + } + + // 重新发送验证邮件 + const resendVerification = async (email: string) => { + loading.value = true + error.value = null + + try { + const response = await authAPI.resendVerification(email) + return response + } catch (err: any) { + error.value = err.response?.data?.message || '发送验证邮件失败' + throw err + } finally { + loading.value = false + } + } + + // 忘记密码 + const forgotPassword = async (email: string) => { + loading.value = true + error.value = null + + try { + const response = await authAPI.forgotPassword(email) + return response + } catch (err: any) { + error.value = err.response?.data?.message || '发送重置邮件失败' + throw err + } finally { + loading.value = false + } + } + + // 重置密码 + const resetPassword = async (data: { + token: string + password: string + }) => { + loading.value = true + error.value = null + + try { + const response = await authAPI.resetPassword(data) + return response + } catch (err: any) { + error.value = err.response?.data?.message || '重置密码失败' + throw err + } finally { + loading.value = false + } + } + + // 设置TOTP + const setupTOTP = async () => { + loading.value = true + error.value = null + + try { + const response = await authAPI.setupTOTP() + return response + } catch (err: any) { + error.value = err.response?.data?.message || '设置二步验证失败' + throw err + } finally { + loading.value = false + } + } + + // 验证TOTP + const verifyTOTP = async (totpToken: string) => { + loading.value = true + error.value = null + + try { + const response = await authAPI.verifyTOTP(totpToken) + + // 更新用户信息 + if (user.value && token.value) { + user.value.totpEnabled = true + userAuth.setLogin(token.value, user.value) + } + + return response + } catch (err: any) { + error.value = err.response?.data?.message || '验证失败' + throw err + } finally { + loading.value = false + } + } + + // 获取用户信息 + const getProfile = async () => { + loading.value = true + error.value = null + + try { + const response = await authAPI.getProfile() + user.value = response.user + if (token.value) { + userAuth.setLogin(token.value, response.user) + } + return response + } catch (err: any) { + error.value = err.response?.data?.message || '获取用户信息失败' + throw err + } finally { + loading.value = false + } + } + + // 用户登出 + const logout = async () => { + loading.value = true + error.value = null + + try { + await authAPI.logout() + } catch (err: any) { + console.error('登出API调用失败:', err) + } finally { + // 清除本地状态 + token.value = null + user.value = null + userAuth.logout() + loading.value = false + } + } + + // 清除错误 + const clearError = () => { + error.value = null + } + + return { + // 状态 + user, + token, + loading, + error, + + // 计算属性 + isLoggedIn, + + // 方法 + initAuth, + register, + login, + verifyEmail, + resendVerification, + forgotPassword, + resetPassword, + setupTOTP, + verifyTOTP, + getProfile, + logout, + clearError + } +}) \ No newline at end of file diff --git a/frontend/src/style.css b/frontend/src/style.css new file mode 100644 index 0000000..0f8c4bd --- /dev/null +++ b/frontend/src/style.css @@ -0,0 +1,39 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + html { + font-family: 'Inter', system-ui, sans-serif; + } + + body { + @apply antialiased; + } +} + +@layer components { + .btn { + @apply inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors duration-200; + } + + .btn-primary { + @apply btn bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500; + } + + .btn-secondary { + @apply btn bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500; + } + + .btn-outline { + @apply btn border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-primary-500; + } + + .input { + @apply block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm; + } + + .card { + @apply bg-white dark:bg-gray-800 shadow rounded-lg; + } +} \ No newline at end of file diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts new file mode 100644 index 0000000..7a58738 --- /dev/null +++ b/frontend/src/types/index.ts @@ -0,0 +1,119 @@ +// 用户相关类型 +export interface User { + id: string + username: string + role: string + isActive: boolean + emailVerified?: boolean + totpEnabled: boolean + createdAt: string + updatedAt: string +} + +// 网站账号相关类型 +export interface WebsiteAccount { + id: string + website: string + username: string + token?: string + isActive: boolean + createdAt: string + updatedAt: string + assignedUsers?: User[] +} + +// 账号分配相关类型 +export interface AccountAssignment { + id: string + userId: string + accountId: string + assignedAt: string + expiresAt?: string + isActive: boolean + account: WebsiteAccount + user: User +} + +// 会话相关类型 +export interface Session { + id: string + userId: string + token: string + expiresAt: string + createdAt: string + user: User +} + +// 审计日志相关类型 +export interface AuditLog { + id: string + userId: string + action: string + resource: string + resourceId?: string + details?: any + ipAddress?: string + userAgent?: string + createdAt: string + user: User +} + +// API响应类型 +export interface ApiResponse { + success: boolean + message: string + data?: T + error?: string +} + +// 分页响应类型 +export interface PaginatedResponse { + data: T[] + pagination: { + page: number + limit: number + total: number + totalPages: number + } +} + +// 认证相关类型 +export interface LoginRequest { + username: string + password: string +} + +export interface RegisterRequest { + username: string + password: string + confirmPassword: string +} + +export interface LoginResponse { + token: string + user: User +} + +export interface RegisterResponse { + message: string + user: User +} + +// 表单验证类型 +export interface ValidationError { + field: string + message: string +} + +// 主题类型 +export type Theme = 'light' | 'dark' | 'system' + +// 通知类型 +export interface Notification { + id: string + type: 'success' | 'error' | 'warning' | 'info' + title: string + message: string + duration?: number + createdAt: string +} \ No newline at end of file diff --git a/frontend/src/types/vue.d.ts b/frontend/src/types/vue.d.ts new file mode 100644 index 0000000..4bcb8c4 --- /dev/null +++ b/frontend/src/types/vue.d.ts @@ -0,0 +1,13 @@ +declare module '*.vue' { + import type { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} + +declare module 'vue-router' { + interface RouteMeta { + title?: string + requiresAuth?: boolean + requiresAdmin?: boolean + } +} \ No newline at end of file diff --git a/frontend/src/utils/api.ts b/frontend/src/utils/api.ts new file mode 100644 index 0000000..eceff11 --- /dev/null +++ b/frontend/src/utils/api.ts @@ -0,0 +1,294 @@ +import axios, { AxiosInstance, AxiosResponse } from 'axios' +import { userAuth, adminAuth } from './auth' + +// API基础配置 +const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api' + +// 创建axios实例 +const api: AxiosInstance = axios.create({ + baseURL: API_BASE_URL, + timeout: 10000, + headers: { + 'Content-Type': 'application/json' + } +}) + +// 请求拦截器 - 添加认证token +api.interceptors.request.use( + (config) => { + // 优先使用管理员token,如果没有则使用用户token + let token = adminAuth.getToken() + if (!token) { + token = userAuth.getToken() + } + + if (token) { + config.headers.Authorization = `Bearer ${token}` + } else { + + } + return config + }, + (error) => { + return Promise.reject(error) + } +) + +// 响应拦截器 - 处理认证错误 +api.interceptors.response.use( + (response: AxiosResponse) => { + return response + }, + (error) => { + if (error.response?.status === 401) { + // Token过期或无效,清除所有认证状态 + userAuth.logout() + adminAuth.logout() + + // 自动重定向到登录页面(如果不是已经在登录页面) + if (window.location.pathname !== '/' && window.location.pathname !== '/login') { + window.location.href = '/' + } + } + return Promise.reject(error) + } +) + +// 用户认证API +export const authAPI = { + // 用户注册 + async register(data: { + username: string + password: string + confirmPassword: string + }) { + // 只发送后端需要的字段 + const requestData = { + username: data.username, + password: data.password, + confirmPassword: data.confirmPassword + } + + const response = await api.post('/auth/register', requestData) + return response.data + }, + + // 用户登录 + async login(data: { + username: string + password: string + }) { + try { + const response = await api.post('/auth/login', data) + return response.data + } catch (error: any) { + throw error + } + }, + + // 邮箱验证 + async verifyEmail(token: string) { + const response = await api.post('/auth/verify-email', { token }) + return response.data + }, + + // 重新发送验证邮件 + async resendVerification(email: string) { + const response = await api.post('/auth/resend-verification', { email }) + return response.data + }, + + // 忘记密码 + async forgotPassword(email: string) { + const response = await api.post('/auth/forgot-password', { email }) + return response.data + }, + + // 重置密码 + async resetPassword(data: { + token: string + password: string + }) { + const response = await api.post('/auth/reset-password', data) + return response.data + }, + + // 设置TOTP + async setupTOTP() { + const response = await api.post('/auth/setup-totp') + return response.data + }, + + // 验证TOTP + async verifyTOTP(token: string) { + const response = await api.post('/auth/verify-totp', { token }) + return response.data + }, + + // 获取用户信息 + async getProfile() { + const response = await api.get('/auth/me') + return response.data + }, + + // 更新用户信息 + async updateProfile(data: { + username?: string + email?: string + currentPassword?: string + newPassword?: string + }) { + const response = await api.put('/auth/profile', data) + return response.data + }, + + // 用户登出 + async logout() { + const response = await api.post('/auth/logout') + return response.data + }, + + // 获取TOTP二维码 + async getTOTPQRCode() { + const response = await api.get('/auth/totp/qr-code') + return response.data + }, + + // 启用TOTP + async enableTOTP(token: string) { + const response = await api.post('/auth/totp/enable', { token }) + return response.data + }, + + // 禁用TOTP + async disableTOTP(password: string) { + const response = await api.post('/auth/totp/disable', { password }) + return response.data + } +} + +// 账号管理API +export const accountAPI = { + // 获取用户可用账号 + async getUserAccounts() { + const response = await api.get('/accounts/user/assigned') + return response.data + }, + + // 获取账号详情 + async getAccountDetails(accountId: string) { + const response = await api.get(`/accounts/${accountId}`) + return response.data + }, + + // 登录到网站 + async loginToWebsite(accountId: string, userId: string) { + const response = await api.post(`/accounts/${accountId}/login`, { userId }) + return response.data + } +} + +// 管理员API +export const adminAPI = { + // 管理员登录 + async login(data: { username: string; password: string }) { + const response = await api.post('/admin/login', data) + return response.data + }, + + // 获取用户列表 + async getUsers(params?: { page?: number; limit?: number; search?: string }) { + const response = await api.get('/admin/users', { params }) + return response.data + }, + + // 创建用户 + async createUser(data: { + username: string + password: string + role: string + }) { + const response = await api.post('/admin/users', data) + return response.data + }, + + // 更新用户 + async updateUser(userId: string, data: any) { + const response = await api.put(`/admin/users/${userId}`, data) + return response.data + }, + + // 更新用户账号权限 + async updateUserAccounts(userId: string, accountIds: string[]) { + const response = await api.put(`/admin/users/${userId}/accounts`, { accountIds }) + return response.data + }, + + // 删除用户 + async deleteUser(userId: string) { + const response = await api.delete(`/admin/users/${userId}`) + return response.data + }, + + // 获取统计数据 + async getStats() { + console.log('发送获取统计数据请求...') + const response = await api.get('/admin/stats') + console.log('统计数据API响应:', response.data) + return response.data + }, + + // 获取最近活动 + async getRecentActivities() { + console.log('发送获取最近活动请求...') + const response = await api.get('/admin/activities') + console.log('最近活动API响应:', response.data) + return response.data + }, + + // 获取账号列表 + async getAccounts(params?: { page?: number; limit?: number; search?: string; status?: string }) { + const response = await api.get('/admin/accounts', { params }) + return response.data + }, + + // 创建账号 + async createAccount(data: { + website: string + username: string + token?: string + isActive: boolean + }) { + const requestData = { + website: data.website, + accountName: data.username, + token: data.token, + isActive: data.isActive + } + const response = await api.post('/admin/accounts', requestData) + return response.data + }, + + // 更新账号 + async updateAccount(accountId: string, data: any) { + const response = await api.put(`/admin/accounts/${accountId}`, data) + return response.data + }, + + // 删除账号 + async deleteAccount(accountId: string) { + const response = await api.delete(`/admin/accounts/${accountId}`) + return response.data + } +} + +// 路径API +export const pathAPI = { + // 获取路径 + async getPaths() { + const response = await api.get('/paths') + return response.data + } +} + +export default api \ No newline at end of file diff --git a/frontend/src/utils/auth.ts b/frontend/src/utils/auth.ts new file mode 100644 index 0000000..abdd8b6 --- /dev/null +++ b/frontend/src/utils/auth.ts @@ -0,0 +1,96 @@ +// 认证工具函数 + +// 用户认证相关 +export const userAuth = { + // 检查用户是否已登录 + isLoggedIn(): boolean { + return !!localStorage.getItem('userToken') + }, + + // 获取用户token + getToken(): string | null { + return localStorage.getItem('userToken') + }, + + // 获取用户信息 + getUserInfo(): any { + const userInfo = localStorage.getItem('userInfo') + return userInfo ? JSON.parse(userInfo) : null + }, + + // 设置用户登录状态 + setLogin(token: string, userInfo: any): void { + localStorage.setItem('userToken', token) + localStorage.setItem('userInfo', JSON.stringify(userInfo)) + }, + + // 清除用户登录状态 + logout(): void { + localStorage.removeItem('userToken') + localStorage.removeItem('userInfo') + } +} + +// 管理员认证相关 +export const adminAuth = { + // 检查管理员是否已登录 + isLoggedIn(): boolean { + return !!localStorage.getItem('adminToken') + }, + + // 获取管理员token + getToken(): string | null { + return localStorage.getItem('adminToken') + }, + + // 获取管理员信息 + getAdminInfo(): any { + try { + const adminInfo = localStorage.getItem('adminUser') + return adminInfo ? JSON.parse(adminInfo) : null + } catch (error) { + console.error('解析管理员信息失败:', error) + // 清除可能损坏的数据 + localStorage.removeItem('adminUser') + return null + } + }, + + // 设置管理员登录状态 + setLogin(token: string, adminInfo: any): void { + try { + if (!token || !adminInfo) { + console.error('设置管理员登录状态失败:token 或 adminInfo 为空') + return + } + + if (!adminInfo.username) { + console.error('设置管理员登录状态失败:adminInfo 缺少 username 字段') + return + } + + localStorage.setItem('adminToken', token) + localStorage.setItem('adminUser', JSON.stringify(adminInfo)) + console.log('管理员登录状态设置成功:', { token, adminInfo }) + } catch (error) { + console.error('设置管理员登录状态失败:', error) + } + }, + + // 清除管理员登录状态 + logout(): void { + localStorage.removeItem('adminToken') + localStorage.removeItem('adminUser') + } +} + +// 验证管理员凭据 +export const validateAdminCredentials = (username: string, password: string): boolean => { + // 这里可以扩展为从API验证 + const validCredentials = { + username: 'admin', + password: 'admin123' + } + + return username === validCredentials.username && password === validCredentials.password +} \ No newline at end of file diff --git a/frontend/src/views/Admin.vue b/frontend/src/views/Admin.vue new file mode 100644 index 0000000..a22e79f --- /dev/null +++ b/frontend/src/views/Admin.vue @@ -0,0 +1,472 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/AdminAccounts.vue b/frontend/src/views/AdminAccounts.vue new file mode 100644 index 0000000..3daceaa --- /dev/null +++ b/frontend/src/views/AdminAccounts.vue @@ -0,0 +1,422 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/AdminLogin.vue b/frontend/src/views/AdminLogin.vue new file mode 100644 index 0000000..1a04d0f --- /dev/null +++ b/frontend/src/views/AdminLogin.vue @@ -0,0 +1,208 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/AdminMonitor.vue b/frontend/src/views/AdminMonitor.vue new file mode 100644 index 0000000..9000ca1 --- /dev/null +++ b/frontend/src/views/AdminMonitor.vue @@ -0,0 +1,38 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/AdminPermissions.vue b/frontend/src/views/AdminPermissions.vue new file mode 100644 index 0000000..4ab7e53 --- /dev/null +++ b/frontend/src/views/AdminPermissions.vue @@ -0,0 +1,388 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/AdminUsers.vue b/frontend/src/views/AdminUsers.vue new file mode 100644 index 0000000..8c18881 --- /dev/null +++ b/frontend/src/views/AdminUsers.vue @@ -0,0 +1,400 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/Dashboard.vue b/frontend/src/views/Dashboard.vue new file mode 100644 index 0000000..172bf5f --- /dev/null +++ b/frontend/src/views/Dashboard.vue @@ -0,0 +1,243 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home.vue new file mode 100644 index 0000000..cae3d6d --- /dev/null +++ b/frontend/src/views/Home.vue @@ -0,0 +1,401 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/views/NotFound.vue b/frontend/src/views/NotFound.vue new file mode 100644 index 0000000..3db0186 --- /dev/null +++ b/frontend/src/views/NotFound.vue @@ -0,0 +1,43 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/Test.vue b/frontend/src/views/Test.vue new file mode 100644 index 0000000..8c16496 --- /dev/null +++ b/frontend/src/views/Test.vue @@ -0,0 +1,212 @@ + + + \ No newline at end of file diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js new file mode 100644 index 0000000..0c094f2 --- /dev/null +++ b/frontend/tailwind.config.js @@ -0,0 +1,65 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{vue,js,ts,jsx,tsx}", + ], + theme: { + extend: { + colors: { + primary: { + 50: '#eff6ff', + 100: '#dbeafe', + 200: '#bfdbfe', + 300: '#93c5fd', + 400: '#60a5fa', + 500: '#3b82f6', + 600: '#2563eb', + 700: '#1d4ed8', + 800: '#1e40af', + 900: '#1e3a8a', + 950: '#172554', + }, + gray: { + 50: '#f9fafb', + 100: '#f3f4f6', + 200: '#e5e7eb', + 300: '#d1d5db', + 400: '#9ca3af', + 500: '#6b7280', + 600: '#4b5563', + 700: '#374151', + 800: '#1f2937', + 900: '#111827', + 950: '#030712', + }, + }, + fontFamily: { + sans: ['Inter', 'system-ui', 'sans-serif'], + }, + animation: { + 'fade-in': 'fadeIn 0.5s ease-in-out', + 'slide-up': 'slideUp 0.3s ease-out', + 'bounce-in': 'bounceIn 0.6s ease-out', + }, + keyframes: { + fadeIn: { + '0%': { opacity: '0' }, + '100%': { opacity: '1' }, + }, + slideUp: { + '0%': { transform: 'translateY(10px)', opacity: '0' }, + '100%': { transform: 'translateY(0)', opacity: '1' }, + }, + bounceIn: { + '0%': { transform: 'scale(0.3)', opacity: '0' }, + '50%': { transform: 'scale(1.05)' }, + '70%': { transform: 'scale(0.9)' }, + '100%': { transform: 'scale(1)', opacity: '1' }, + }, + }, + }, + }, + plugins: [], + darkMode: 'class', +} \ No newline at end of file diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..498a5f4 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + /* Path mapping */ + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue" + ], + "references": [{ "path": "./tsconfig.node.json" }] +} \ No newline at end of file diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 0000000..862dfb2 --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} \ No newline at end of file diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..fb85a28 --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,44 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { resolve } from 'path' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': resolve(__dirname, 'src'), + }, + }, + define: { + // 定义环境变量,使其在客户端可用 + VITE_API_URL: JSON.stringify(process.env.VITE_API_URL || 'http://localhost:3001'), + VITE_APP_NAME: JSON.stringify(process.env.VITE_APP_NAME || 'Pandora'), + VITE_CLAUDE_TARGET_URL: JSON.stringify(process.env.CLAUDE_TARGET_URL || 'https://claude.ai'), + VITE_CHATGPT_TARGET_URL: JSON.stringify(process.env.CHATGPT_TARGET_URL || 'https://chat.openai.com'), + VITE_GROK_TARGET_URL: JSON.stringify(process.env.GROK_TARGET_URL || 'https://grok.x.ai'), + }, + server: { + port: 3000, + host: '0.0.0.0', + proxy: { + '/api': { + target: 'http://localhost:3001', + changeOrigin: true, + secure: false, + }, + }, + }, + build: { + outDir: 'dist', + sourcemap: true, + rollupOptions: { + output: { + manualChunks: { + vendor: ['vue', 'vue-router', 'pinia'], + ui: ['@headlessui/vue', '@heroicons/vue'], + }, + }, + }, + }, +}) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..bc9edd0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8186 @@ +{ + "name": "pandora", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pandora", + "version": "1.0.0", + "license": "MIT", + "workspaces": [ + "frontend", + "backend" + ], + "devDependencies": { + "concurrently": "^8.2.2", + "prettier": "^3.1.0" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + } + }, + "backend": { + "name": "pandora-backend", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@prisma/client": "^5.7.1", + "@types/http-proxy-middleware": "^0.19.3", + "bcryptjs": "^2.4.3", + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "express-async-errors": "^3.1.1", + "express-rate-limit": "^7.1.5", + "express-validator": "^7.0.1", + "helmet": "^7.1.0", + "http-proxy-middleware": "^3.0.5", + "jsonwebtoken": "^9.0.2", + "nodemailer": "^6.9.7", + "qrcode": "^1.5.3", + "redis": "^4.6.11", + "speakeasy": "^2.0.0", + "winston": "^3.11.0" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.6", + "@types/cors": "^2.8.17", + "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.5", + "@types/node": "^20.10.5", + "@types/nodemailer": "^6.4.14", + "@types/qrcode": "^1.5.5", + "@types/speakeasy": "^2.0.10", + "nodemon": "^3.0.2", + "prisma": "^5.7.1", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + } + }, + "backend/node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "frontend": { + "name": "pandora-frontend", + "version": "1.0.0", + "dependencies": { + "@headlessui/vue": "^1.7.16", + "@heroicons/vue": "^2.0.18", + "@vueuse/core": "^10.4.1", + "axios": "^1.5.0", + "clsx": "^2.0.0", + "pinia": "^2.1.7", + "tailwind-merge": "^1.14.0", + "vee-validate": "^4.10.5", + "vue": "^3.3.8", + "vue-router": "^4.2.5", + "vue-toastification": "^2.0.0-rc.5" + }, + "devDependencies": { + "@types/node": "^20.6.3", + "@vitejs/plugin-vue": "^4.4.0", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^12.0.0", + "@vue/test-utils": "^2.4.2", + "autoprefixer": "^10.4.15", + "eslint": "^8.49.0", + "eslint-plugin-vue": "^9.17.0", + "jsdom": "^22.1.0", + "postcss": "^8.4.29", + "prettier": "^3.0.3", + "tailwindcss": "^3.3.3", + "typescript": "~5.2.0", + "vite": "^4.4.11", + "vitest": "^0.34.4", + "vue-tsc": "^1.8.15" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", + "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "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/@cspotcode/source-map-support/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/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@headlessui/vue": { + "version": "1.7.23", + "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.23.tgz", + "integrity": "sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==", + "license": "MIT", + "dependencies": { + "@tanstack/vue-virtual": "^3.0.0-beta.60" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@heroicons/vue": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/vue/-/vue-2.2.0.tgz", + "integrity": "sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw==", + "license": "MIT", + "peerDependencies": { + "vue": ">= 3" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@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.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz", + "integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==", + "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==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.22.0.tgz", + "integrity": "sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.22.0", + "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", + "@prisma/fetch-engine": "5.22.0", + "@prisma/get-platform": "5.22.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz", + "integrity": "sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz", + "integrity": "sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.22.0", + "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", + "@prisma/get-platform": "5.22.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.22.0.tgz", + "integrity": "sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.22.0" + } + }, + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", + "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", + "license": "MIT", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz", + "integrity": "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/vue-virtual": { + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.12.tgz", + "integrity": "sha512-vhF7kEU9EXWXh+HdAwKJ2m3xaOnTTmgcdXcF2pim8g4GvI7eRrk2YRuV5nUlZnd/NbCIX4/Ja2OZu5EjJL06Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.13.12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "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/@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/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai-subset": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.6.tgz", + "integrity": "sha512-m8lERkkQj+uek18hXOZuec3W/fCRTrU4hrnXjH3qhHy96ytuPaPiWGgu7sJb7tZxZonO75vYAjCvpe/e4VUwRw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/chai": "<5.2.0" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", + "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "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/http-proxy": { + "version": "1.17.16", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", + "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-proxy-middleware": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz", + "integrity": "sha512-lnBTx6HCOUeIJMLbI/LaL5EmdKLhczJY5oeXZpX/cXE4rRqb3RmV7VcMpiEfYkmTjipv3h7IAyIINe4plEv7cA==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/http-proxy": "*", + "@types/node": "*" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.4.tgz", + "integrity": "sha512-OP+We5WV8Xnbuvw0zC2m4qfB/BJvjyCwtNjhHdJxV1639SGSKrLmJkc3fMnp2Qy8nJyHp8RO6umxELN/dS1/EA==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/nodemailer": { + "version": "6.4.17", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.17.tgz", + "integrity": "sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qrcode": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz", + "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "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/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/speakeasy": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/speakeasy/-/speakeasy-2.0.10.tgz", + "integrity": "sha512-QVRlDW5r4yl7p7xkNIbAIC/JtyOcClDIIdKfuG7PWdDT1MmyhtXSANsildohy0K+Lmvf/9RUtLbNLMacvrVwxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz", + "integrity": "sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.0.0 || ^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vitest/expect": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", + "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", + "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "0.34.6", + "p-limit": "^4.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", + "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", + "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^2.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", + "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "diff-sequences": "^29.4.3", + "loupe": "^2.3.6", + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@volar/language-core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", + "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "1.11.1" + } + }, + "node_modules/@volar/source-map": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", + "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "muggle-string": "^0.3.1" + } + }, + "node_modules/@volar/typescript": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", + "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "1.11.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.17.tgz", + "integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@vue/shared": "3.5.17", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz", + "integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz", + "integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@vue/compiler-core": "3.5.17", + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.17", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz", + "integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz", + "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.7", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz", + "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==", + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/eslint-config-prettier": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-8.0.0.tgz", + "integrity": "sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^5.0.0" + }, + "peerDependencies": { + "eslint": ">= 8.0.0", + "prettier": ">= 3.0.0" + } + }, + "node_modules/@vue/eslint-config-typescript": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-12.0.0.tgz", + "integrity": "sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "vue-eslint-parser": "^9.3.1" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0", + "eslint-plugin-vue": "^9.0.0", + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", + "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~1.11.1", + "@volar/source-map": "~1.11.1", + "@vue/compiler-dom": "^3.3.0", + "@vue/shared": "^3.3.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "muggle-string": "^0.3.1", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.17.tgz", + "integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.17.tgz", + "integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz", + "integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.17", + "@vue/runtime-core": "3.5.17", + "@vue/shared": "3.5.17", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.17.tgz", + "integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17" + }, + "peerDependencies": { + "vue": "3.5.17" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.17.tgz", + "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==", + "license": "MIT" + }, + "node_modules/@vue/test-utils": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz", + "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-beautify": "^1.14.9", + "vue-component-type-helpers": "^2.0.0" + } + }, + "node_modules/@vueuse/core": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz", + "integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.11.1", + "@vueuse/shared": "10.11.1", + "vue-demi": ">=0.14.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz", + "integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz", + "integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==", + "license": "MIT", + "dependencies": { + "vue-demi": ">=0.14.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "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/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "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==", + "dev": true, + "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==", + "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==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "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/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "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.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "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/axios": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", + "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "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/base32.js": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.0.1.tgz", + "integrity": "sha512-EGHIRiegFa62/SsA1J+Xs2tIzludPdzM064N9wjbiEgHnGnJ1V0WEpA4pEwCYT5nDvZk3ubf0shqaCS7k6xeUQ==", + "license": "MIT" + }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/birpc": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.4.0.tgz", + "integrity": "sha512-5IdNxTyhXHv2UlgnPHQ0h+5ypVmkrYHzL8QT+DwFZ//2N/oNV8Ch+BCRmTJ3x6/z9Axo/cXYBc9eprsUVK/Jsg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/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/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/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/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "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": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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/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/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001726", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz", + "integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==", + "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/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/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/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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/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/cliui/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/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/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/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "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": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true, + "license": "MIT" + }, + "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/concurrently": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "date-fns": "^2.30.0", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "spawn-command": "0.0.2", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/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/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/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/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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.179", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.179.tgz", + "integrity": "sha512-UWKi/EbBopgfFsc5k61wFpV7WrnnSlSzW/e2XcBmS6qKYTivZlLtoll5/rdqRTxGglGHkmkW0j0pFNJG10EUIQ==", + "dev": true, + "license": "ISC" + }, + "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/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "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/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=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-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.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz", + "integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", + "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "vue-eslint-parser": "^9.4.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-async-errors": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz", + "integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==", + "license": "ISC", + "peerDependencies": { + "express": "^4.16.2" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express-validator": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.2.1.tgz", + "integrity": "sha512-CjNE6aakfpuwGaHQZ3m8ltCG2Qvivd7RHtVMS/6nVxOM7xVGqr4bhflsm4+N5FP5zI7Zxp+Hae+9RE+o8e3ZOQ==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "validator": "~13.12.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express/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/express/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/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-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/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/finalhandler/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/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "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/form-data": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "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/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/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/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/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-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-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/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "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/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/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.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/helmet": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", + "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz", + "integrity": "sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "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.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "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-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/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-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.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/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "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/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/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==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-beautify": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "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": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "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": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/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/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "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.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/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/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "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/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": "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/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "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==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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/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/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/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/muggle-string": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", + "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemailer": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz", + "integrity": "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "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/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", + "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "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/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "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/pandora-backend": { + "resolved": "backend", + "link": true + }, + "node_modules/pandora-frontend": { + "resolved": "frontend", + "link": true + }, + "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/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "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/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "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==", + "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-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "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/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "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.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", + "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "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-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "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==", + "dev": true, + "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.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prisma": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.22.0.tgz", + "integrity": "sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/engines": "5.22.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "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/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/qrcode/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==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/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==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/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==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qrcode/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==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/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": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "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/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redis": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", + "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", + "license": "MIT", + "workspaces": [ + "./packages/*" + ], + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.1", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.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==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "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/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/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/rollup": { + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "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/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/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/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/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/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/send/node_modules/debug/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/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "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/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "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/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "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-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/spawn-command": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", + "dev": true + }, + "node_modules/speakeasy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/speakeasy/-/speakeasy-2.0.0.tgz", + "integrity": "sha512-lW2A2s5LKi8rwu77ewisuUOtlCydF/hmQSOJjpTqTj1gZLkNgTaYnyvfxy2WBr4T/h+9c4g8HIITfj83OkFQFw==", + "license": "MIT", + "dependencies": { + "base32.js": "0.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "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/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-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/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/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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/strip-literal": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", + "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/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/superjson": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", + "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=16" + } + }, + "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/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==", + "dev": true, + "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/synckit": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz", + "integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.4" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/tailwind-merge": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz", + "integrity": "sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "dev": true, + "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.6", + "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", + "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/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "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==", + "dev": true, + "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/tinypool": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", + "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "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/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/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==", + "dev": true, + "license": "Apache-2.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/ts-node/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/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.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/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "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/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.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/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/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "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/vee-validate": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.15.1.tgz", + "integrity": "sha512-DkFsiTwEKau8VIxyZBGdO6tOudD+QoUBPuHj3e6QFqmbfCRj1ArmYWue9lEp6jLSWBIw4XPlDLjFIZNLdRAMSg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^7.5.2", + "type-fest": "^4.8.3" + }, + "peerDependencies": { + "vue": "^3.4.26" + } + }, + "node_modules/vee-validate/node_modules/@vue/devtools-api": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.7.tgz", + "integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.7" + } + }, + "node_modules/vee-validate/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vite": { + "version": "4.5.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", + "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", + "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.4.0", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", + "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^4.3.5", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.34.6", + "@vitest/runner": "0.34.6", + "@vitest/snapshot": "0.34.6", + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "acorn": "^8.9.0", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.10", + "debug": "^4.3.4", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.3.3", + "strip-literal": "^1.0.1", + "tinybench": "^2.5.0", + "tinypool": "^0.7.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", + "vite-node": "0.34.6", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@vitest/browser": "*", + "@vitest/ui": "*", + "happy-dom": "*", + "jsdom": "*", + "playwright": "*", + "safaridriver": "*", + "webdriverio": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "playwright": { + "optional": true + }, + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.17.tgz", + "integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-sfc": "3.5.17", + "@vue/runtime-dom": "3.5.17", + "@vue/server-renderer": "3.5.17", + "@vue/shared": "3.5.17" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-component-type-helpers": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.12.tgz", + "integrity": "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", + "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-toastification": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-2.0.0-rc.5.tgz", + "integrity": "sha512-q73e5jy6gucEO/U+P48hqX+/qyXDozAGmaGgLFm5tXX4wJBcVsnGp4e/iJqlm9xzHETYOilUuwOUje2Qg1JdwA==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.0.2" + } + }, + "node_modules/vue-tsc": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", + "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "~1.11.1", + "@vue/language-core": "1.8.27", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "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/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "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/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "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/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/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "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/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "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" + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "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/yargs/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/yargs/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/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" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9fa930d --- /dev/null +++ b/package.json @@ -0,0 +1,59 @@ +{ + "name": "pandora", + "version": "1.0.0", + "description": "网站账号共享系统", + "private": true, + "workspaces": [ + "frontend", + "backend" + ], + "scripts": { + "dev": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"", + "dev:backend": "cd backend && npm run dev", + "dev:frontend": "cd frontend && npm run dev", + "build": "npm run build:backend && npm run build:frontend", + "build:backend": "cd backend && npm run build", + "build:frontend": "cd frontend && npm run build", + "test": "npm run test:backend && npm run test:frontend", + "test:backend": "cd backend && npm test", + "test:frontend": "cd frontend && npm test", + "lint": "npm run lint:backend && npm run lint:frontend", + "lint:backend": "cd backend && npm run lint", + "lint:frontend": "cd frontend && npm run lint", + "format": "prettier --write \"**/*.{js,jsx,ts,tsx,vue,json,md}\"", + "docker:build": "docker-compose build", + "docker:up": "docker-compose up -d", + "docker:down": "docker-compose down", + "docker:logs": "docker-compose logs -f", + "docker:prod": "docker-compose -f docker-compose.prod.yml up -d", + "db:migrate": "cd backend && npm run db:migrate", + "db:seed": "cd backend && npm run db:seed", + "db:reset": "cd backend && npm run db:reset" + }, + "devDependencies": { + "concurrently": "^8.2.2", + "prettier": "^3.1.0" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "keywords": [ + "account-sharing", + "user-management", + "authentication", + "vue", + "express", + "typescript" + ], + "author": "Your Name", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/your-username/pandora.git" + }, + "bugs": { + "url": "https://github.com/your-username/pandora/issues" + }, + "homepage": "https://github.com/your-username/pandora#readme" +} \ No newline at end of file