From 296e1c63e575efee1302cab3eb37245290db8bee Mon Sep 17 00:00:00 2001 From: m0_37981569 Date: Fri, 1 May 2026 22:00:00 +0800 Subject: [PATCH 01/20] refactor: restructure project to use reactpress-cli for API management, remove server directory, and update configurations --- .env | 9 +- .reactpress/config.json | 12 + .reactpress/docker-compose.yml | 27 + TODO.md | 317 ++ docker-compose.prod.yml | 28 +- package.json | 22 +- pnpm-lock.yaml | 4734 +---------------- pnpm-workspace.yaml | 2 +- scripts/bundled-server-path.js | 4 + scripts/docker-dev.js | 4 +- scripts/install.sh | 102 +- scripts/reactpress-cli.js | 142 +- scripts/reactpress-dev.js | 2 + scripts/reactpress-publish.js | 10 +- scripts/reactpress.js | 90 - server/.eslintrc.js | 25 - server/Dockerfile | 38 - server/LICENSE | 21 - server/README.md | 371 +- server/bin/reactpress-server.js | 218 +- server/ecosystem.config.js | 7 +- server/nest-cli.json | 4 - server/package.json | 139 +- server/public/favicon.png | Bin 33057 -> 0 bytes server/public/index.html | 439 -- server/public/swagger/custom.css | 11 - server/scripts/dev.js | 60 + server/scripts/generate-swagger.js | 9 + server/src/app.module.ts | 82 - server/src/filters/http-exception.filter.ts | 28 - server/src/generate-swagger.ts | 95 - .../src/interceptors/transform.interceptor.ts | 33 - server/src/logger/index.ts | 47 - server/src/main.ts | 346 -- .../src/modules/article/article.controller.ts | 178 - server/src/modules/article/article.entity.ts | 103 - server/src/modules/article/article.module.ts | 18 - server/src/modules/article/article.service.ts | 398 -- server/src/modules/article/article.util.ts | 4 - server/src/modules/auth/auth.controller.ts | 45 - server/src/modules/auth/auth.module.ts | 30 - server/src/modules/auth/auth.service.ts | 119 - server/src/modules/auth/jwt-auth.guard.ts | 18 - server/src/modules/auth/jwt.strategy.ts | 25 - server/src/modules/auth/roles.guard.ts | 34 - .../modules/category/category.controller.ts | 66 - .../src/modules/category/category.entity.ts | 42 - .../src/modules/category/category.module.ts | 15 - .../src/modules/category/category.service.ts | 104 - .../src/modules/comment/comment.controller.ts | 74 - server/src/modules/comment/comment.entity.ts | 73 - server/src/modules/comment/comment.module.ts | 18 - server/src/modules/comment/comment.service.ts | 189 - server/src/modules/comment/html.ts | 641 --- server/src/modules/file/file.controller.ts | 61 - server/src/modules/file/file.entity.ts | 37 - server/src/modules/file/file.module.ts | 15 - server/src/modules/file/file.service.ts | 113 - .../src/modules/install/install.controller.ts | 20 - server/src/modules/install/install.module.ts | 14 - server/src/modules/install/install.service.ts | 53 - .../modules/knowledge/knowledge.controller.ts | 110 - .../src/modules/knowledge/knowledge.entity.ts | 77 - .../src/modules/knowledge/knowledge.module.ts | 15 - .../modules/knowledge/knowledge.service.ts | 168 - server/src/modules/page/page.controller.ts | 87 - server/src/modules/page/page.entity.ts | 65 - server/src/modules/page/page.module.ts | 15 - server/src/modules/page/page.service.ts | 112 - .../src/modules/search/search.controller.ts | 43 - server/src/modules/search/search.entity.ts | 37 - server/src/modules/search/search.module.ts | 15 - server/src/modules/search/search.service.ts | 74 - .../src/modules/setting/setting.constant.ts | 29 - .../src/modules/setting/setting.controller.ts | 57 - server/src/modules/setting/setting.entity.ts | 109 - server/src/modules/setting/setting.module.ts | 16 - server/src/modules/setting/setting.service.ts | 116 - server/src/modules/smtp/mail.util.ts | 31 - server/src/modules/smtp/smtp.controller.ts | 45 - server/src/modules/smtp/smtp.entity.ts | 37 - server/src/modules/smtp/smtp.module.ts | 16 - server/src/modules/smtp/smtp.service.ts | 69 - server/src/modules/tag/tag.controller.ts | 75 - server/src/modules/tag/tag.entity.ts | 41 - server/src/modules/tag/tag.module.ts | 15 - server/src/modules/tag/tag.service.ts | 122 - server/src/modules/user/user.controller.ts | 105 - server/src/modules/user/user.entity.ts | 76 - server/src/modules/user/user.module.ts | 16 - server/src/modules/user/user.service.ts | 201 - server/src/modules/view/view.controller.ts | 66 - server/src/modules/view/view.entity.ts | 60 - server/src/modules/view/view.module.ts | 15 - server/src/modules/view/view.service.ts | 86 - server/src/starter.ts | 103 - server/src/utils/date.util.ts | 11 - server/src/utils/ip.util.ts | 25 - server/src/utils/markdown.util.ts | 46 - server/src/utils/oss.util.ts | 59 - server/src/utils/oss/aliyun-oss-client.ts | 27 - server/src/utils/oss/oss-client.ts | 10 - server/src/utils/ua.util.ts | 36 - server/src/utils/uniqueid.util.ts | 5 - server/src/utils/upload.util.ts | 34 - server/src/utils/user.util.ts | 16 - server/tsconfig.build.json | 4 - server/tsconfig.json | 21 - server/tslint.json | 18 - toolkit/scripts/generate-api-types.js | 2 +- toolkit/scripts/generate-api.js | 3 +- toolkit/scripts/generate-swagger.js | 39 +- toolkit/scripts/resolve-swagger-input.js | 11 + 113 files changed, 918 insertions(+), 11758 deletions(-) create mode 100644 .reactpress/config.json create mode 100644 .reactpress/docker-compose.yml create mode 100644 TODO.md create mode 100644 scripts/bundled-server-path.js delete mode 100755 scripts/reactpress.js delete mode 100644 server/.eslintrc.js delete mode 100644 server/Dockerfile delete mode 100644 server/LICENSE mode change 100755 => 100644 server/bin/reactpress-server.js delete mode 100644 server/nest-cli.json delete mode 100644 server/public/favicon.png delete mode 100644 server/public/index.html delete mode 100644 server/public/swagger/custom.css create mode 100644 server/scripts/dev.js create mode 100644 server/scripts/generate-swagger.js delete mode 100644 server/src/app.module.ts delete mode 100644 server/src/filters/http-exception.filter.ts delete mode 100644 server/src/generate-swagger.ts delete mode 100644 server/src/interceptors/transform.interceptor.ts delete mode 100644 server/src/logger/index.ts delete mode 100644 server/src/main.ts delete mode 100644 server/src/modules/article/article.controller.ts delete mode 100644 server/src/modules/article/article.entity.ts delete mode 100644 server/src/modules/article/article.module.ts delete mode 100644 server/src/modules/article/article.service.ts delete mode 100644 server/src/modules/article/article.util.ts delete mode 100644 server/src/modules/auth/auth.controller.ts delete mode 100644 server/src/modules/auth/auth.module.ts delete mode 100644 server/src/modules/auth/auth.service.ts delete mode 100644 server/src/modules/auth/jwt-auth.guard.ts delete mode 100644 server/src/modules/auth/jwt.strategy.ts delete mode 100644 server/src/modules/auth/roles.guard.ts delete mode 100644 server/src/modules/category/category.controller.ts delete mode 100644 server/src/modules/category/category.entity.ts delete mode 100644 server/src/modules/category/category.module.ts delete mode 100644 server/src/modules/category/category.service.ts delete mode 100644 server/src/modules/comment/comment.controller.ts delete mode 100644 server/src/modules/comment/comment.entity.ts delete mode 100644 server/src/modules/comment/comment.module.ts delete mode 100644 server/src/modules/comment/comment.service.ts delete mode 100644 server/src/modules/comment/html.ts delete mode 100644 server/src/modules/file/file.controller.ts delete mode 100644 server/src/modules/file/file.entity.ts delete mode 100644 server/src/modules/file/file.module.ts delete mode 100644 server/src/modules/file/file.service.ts delete mode 100644 server/src/modules/install/install.controller.ts delete mode 100644 server/src/modules/install/install.module.ts delete mode 100644 server/src/modules/install/install.service.ts delete mode 100644 server/src/modules/knowledge/knowledge.controller.ts delete mode 100644 server/src/modules/knowledge/knowledge.entity.ts delete mode 100644 server/src/modules/knowledge/knowledge.module.ts delete mode 100644 server/src/modules/knowledge/knowledge.service.ts delete mode 100644 server/src/modules/page/page.controller.ts delete mode 100644 server/src/modules/page/page.entity.ts delete mode 100644 server/src/modules/page/page.module.ts delete mode 100644 server/src/modules/page/page.service.ts delete mode 100644 server/src/modules/search/search.controller.ts delete mode 100644 server/src/modules/search/search.entity.ts delete mode 100644 server/src/modules/search/search.module.ts delete mode 100644 server/src/modules/search/search.service.ts delete mode 100644 server/src/modules/setting/setting.constant.ts delete mode 100644 server/src/modules/setting/setting.controller.ts delete mode 100644 server/src/modules/setting/setting.entity.ts delete mode 100644 server/src/modules/setting/setting.module.ts delete mode 100644 server/src/modules/setting/setting.service.ts delete mode 100644 server/src/modules/smtp/mail.util.ts delete mode 100644 server/src/modules/smtp/smtp.controller.ts delete mode 100644 server/src/modules/smtp/smtp.entity.ts delete mode 100644 server/src/modules/smtp/smtp.module.ts delete mode 100644 server/src/modules/smtp/smtp.service.ts delete mode 100644 server/src/modules/tag/tag.controller.ts delete mode 100644 server/src/modules/tag/tag.entity.ts delete mode 100644 server/src/modules/tag/tag.module.ts delete mode 100644 server/src/modules/tag/tag.service.ts delete mode 100644 server/src/modules/user/user.controller.ts delete mode 100644 server/src/modules/user/user.entity.ts delete mode 100644 server/src/modules/user/user.module.ts delete mode 100644 server/src/modules/user/user.service.ts delete mode 100644 server/src/modules/view/view.controller.ts delete mode 100644 server/src/modules/view/view.entity.ts delete mode 100644 server/src/modules/view/view.module.ts delete mode 100644 server/src/modules/view/view.service.ts delete mode 100644 server/src/starter.ts delete mode 100644 server/src/utils/date.util.ts delete mode 100644 server/src/utils/ip.util.ts delete mode 100644 server/src/utils/markdown.util.ts delete mode 100644 server/src/utils/oss.util.ts delete mode 100644 server/src/utils/oss/aliyun-oss-client.ts delete mode 100644 server/src/utils/oss/oss-client.ts delete mode 100644 server/src/utils/ua.util.ts delete mode 100644 server/src/utils/uniqueid.util.ts delete mode 100644 server/src/utils/upload.util.ts delete mode 100644 server/src/utils/user.util.ts delete mode 100644 server/tsconfig.build.json delete mode 100644 server/tsconfig.json delete mode 100644 server/tslint.json create mode 100644 toolkit/scripts/resolve-swagger-input.js diff --git a/.env b/.env index 0a433c5..f9118cf 100644 --- a/.env +++ b/.env @@ -1,12 +1,9 @@ -# Database Config +# ReactPress — managed by reactpress-cli DB_HOST=127.0.0.1 DB_PORT=3306 DB_USER=reactpress DB_PASSWD=reactpress DB_DATABASE=reactpress - -# Client Config CLIENT_SITE_URL=http://localhost:3001 - -# Server Config -SERVER_SITE_URL=http://localhost:3002 \ No newline at end of file +SERVER_SITE_URL=http://localhost:3002 +SERVER_PORT=3002 diff --git a/.reactpress/config.json b/.reactpress/config.json new file mode 100644 index 0000000..7144102 --- /dev/null +++ b/.reactpress/config.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "database": { + "mode": "embedded-docker", + "containerName": "reactpress_cli_db" + }, + "server": { + "port": 3002, + "clientUrl": "http://localhost:3001", + "serverUrl": "http://localhost:3002" + } +} diff --git a/.reactpress/docker-compose.yml b/.reactpress/docker-compose.yml new file mode 100644 index 0000000..4755498 --- /dev/null +++ b/.reactpress/docker-compose.yml @@ -0,0 +1,27 @@ +services: + db: + image: mysql:8.0 + container_name: reactpress_cli_db + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-reactpress_root} + MYSQL_DATABASE: ${DB_DATABASE:-reactpress} + MYSQL_USER: ${DB_USER:-reactpress} + MYSQL_PASSWORD: ${DB_PASSWD:-reactpress} + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --default-authentication-plugin=mysql_native_password + volumes: + - reactpress_cli_db_data:/var/lib/mysql + ports: + - "${DB_PORT:-3306}:3306" + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-reactpress_root}"] + interval: 5s + timeout: 5s + retries: 12 + start_period: 20s + +volumes: + reactpress_cli_db_data: diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..14de78d --- /dev/null +++ b/TODO.md @@ -0,0 +1,317 @@ +# easy-blog-publish 重构 TODO + +> 目标:参考 [reactpress-cli](https://github.com/fecommunity/reactpress-cli) 简化仓库架构;后端运行时依赖 `@fecommunity/reactpress-cli`,本仓库聚焦 client / toolkit / 文档与模板。 +> 状态说明:`[ ]` 未开始 · `[~]` 进行中 · `[x]` 已完成 + +--- + +## 一、现状与问题清单 + +### 1.1 与 reactpress-cli 的定位差异 + +| 维度 | 当前仓库(easy-blog-publish) | 参考工程(reactpress-cli) | +|------|------------------------------|----------------------------| +| 目标 | 全栈 CMS(client + server + docs + templates) | CLI + 内置 server/toolkit,零配置跑通 | +| npm 发布 | 6+ 包(root / server / client / toolkit / 2 模板) | 单包 `@fecommunity/reactpress-cli` | +| CLI | 多入口薄封装 + 各包自带 bin | TypeScript CLI(init/start/stop/restart/status/config)+ Vitest | +| 初始化 | Server `main.ts` 内嵌 Web 安装向导 | `init` + `config.default.json` + Docker MySQL | +| 内置资源 | 各包独立发布 | `sync-bundled-assets` 将 server/toolkit 打进 CLI 包 | + +**结论**:业务代码可保留;**发布与运维层过重、入口分散**,应向「单 CLI 管生命周期 + 本仓管前端」收敛。 + +--- + +### 1.2 CLI / 脚本层 + +- [ ] **多入口重复**:`scripts/reactpress-cli.js` 与 `scripts/reactpress.js` 逻辑重复;`reactpress.js` 未挂到 `package.json` bin,且引用不存在的 `scripts/reactpress-server.js`(死代码)。 +- [ ] **脚本与实现不一致**:根 `package.json` 中 `build:packages` 指向 `reactpress-cli.js --build`,但 `--build` / `--publish` 实际在 `reactpress-publish.js`(约 944 行),`pnpm build:packages` 可能无效。 +- [ ] **根包职责模糊**:`@fecommunity/reactpress` 的 `files` 仅含 scripts/bin,却与 server/client 独立发包并存,用户心智成本高。 +- [ ] **发布脚本过重**:`reactpress-publish.js` 单文件承担哈希缓存、多包交互发布、GitHub Release 等;参考工程已拆为 `prepare-publish.mjs`、`publish-cli.mjs`、`verify-npm-pack.mjs` 等。 + +--- + +### 1.3 发布与版本 + +- [ ] **版本号不同步**(示例,以仓库当时为准): + - root: `2.0.0-beta-4-beta.1` + - client: `1.0.0-beta.32` + - server: `1.0.0-beta.16` + - toolkit / 模板: `1.0.0-beta.4` +- [ ] **workspace 范围过大**:`docs`、`templates/*` 纳入 pnpm workspace,日常 dev / 安装 / CI 与「仅发 CLI+前端」路径纠缠。 +- [ ] **多包发布维护成本高**:`@fecommunity/reactpress-server` 与本仓 server 源码重复(与 reactpress-cli 的 `packages/server/src` 已对齐)。 + +--- + +### 1.4 配置与路径 + +- [ ] **`REACTPRESS_ORIGINAL_CWD` 多处维护**:`reactpress-dev.js`、`docker-dev.js`、`server/bin`、`client/bin`、`server/main.ts`、`toolkit/config/env.ts` 等,根因是 npx 全局安装时 cwd 与包内路径不一致。 +- [ ] **toolkit 启动时强依赖 `.env`**:`toolkit/src/config/env.ts` 在模块加载时 `parseEnv()`,多路径猜测 `.env`,失败即抛错,对 monorepo / 仅 server 场景偏脆。 +- [ ] **配置格式不统一**:Web 安装向导写 `.env`;reactpress-cli 使用 `.reactpress/config.json` + `syncEnvFromConfig` 写 `.env`。 + +--- + +### 1.5 安装 / 初始化双轨 + +- [ ] **Server `main.ts`**:无 `.env` 时启动 Express 安装向导(WordPress 式 Web UI)。 +- [ ] **reactpress-cli**:`init` + 默认配置 + Docker MySQL + `start`。 +- [ ] 用户可能混用两套路径,后续难以只保留一条。 + +--- + +### 1.6 工程债与运维 + +- [ ] **`@nestjs/cli` 写在 server `dependencies`**,应属 devDependencies,膨胀生产安装体积。 +- [ ] **技术栈偏旧**:NestJS 6、Next 12、TS ~4.1、Node `>=16.5`;reactpress-cli 要求 Node `>=18`、CLI 为 TS 5 + ESM。 +- [ ] **`server/src/main.ts` 职责过重**:安装向导、端口探测、Express 路由与 Nest 启动混在一起。 +- [ ] **`scripts/install.sh` 约 578 行**:与 CLI `init` 能力重叠,且假设存在 `server/package.json`。 +- [ ] **文档与实现不一致**:文档写 Next.js 14,client 仍为 Next 12;README 多包 `npx` 与统一 CLI 叙事并存。 + +--- + +### 1.7 代码对齐事实(迁移前提) + +- [x] **已验证**:`easy-blog-publish/server/src` 与 `reactpress-cli/packages/server/src` **当前完全一致**(`diff -rq` 无差异)。 + → **删除本仓 server、依赖 CLI 内置 server 在技术上可行**;后续 server 变更需在 reactpress-cli 仓库维护。 + +--- + +## 二、目标架构(依赖 reactpress-cli) + +```mermaid +flowchart LR + subgraph repo [easy-blog-publish] + C[client Next.js] + T[toolkit 建议保留] + D[docs / templates] + end + subgraph ext [@fecommunity/reactpress-cli] + CLI[CLI 命令] + S[内置 server/dist] + DB[(MySQL Docker / 外部)] + end + C -->|HTTP /api| S + T --> C + CLI --> S + CLI --> DB + repo -->|.env + .reactpress/config.json| CLI +``` + +| 角色 | 职责 | +|------|------| +| reactpress-cli | `init` / `start` / `stop` / `restart` / `status` / `config`;内置 Nest server + 运行时 toolkit | +| 本仓库 | client 产品与定制;toolkit 源码与 Swagger 生成(推荐保留);文档与模板 | + +--- + +## 三、技术方案 + +### 3.1 方案总览 + +| 方案 | 说明 | 推荐度 | +|------|------|--------| +| **主方案** | 移除 `server/`,dev/prod 用 `reactpress-cli` 起 API;本仓保留 client + toolkit | ⭐ 推荐 | +| 备选 A | 仅修 P0 脚本问题,暂不删 server | 短期止血 | +| 备选 B | 本仓并进 reactpress-cli monorepo | 职责混杂,不推荐 | +| 备选 C | server 改为 git submodule 指向 reactpress-cli | 运维复杂,仅在不发 npm CLI 时考虑 | + +--- + +### 3.2 移除 server 后的依赖策略 + +**根目录 `package.json`(devDependencies):** + +```json +"@fecommunity/reactpress-cli": "^0.1.0" +``` + +**本地联调 reactpress-cli 源码:** + +```json +"@fecommunity/reactpress-cli": "link:../reactpress-cli/packages/cli" +``` + +或:`pnpm link --global`(见 reactpress-cli README)。 + +**开发脚本示例:** + +```json +{ + "dev": "concurrently -n api,web -c blue,green \"pnpm exec reactpress-cli start\" \"pnpm run dev:client\"", + "dev:client": "pnpm run --dir ./client dev", + "dev:api": "pnpm exec reactpress-cli start" +} +``` + +**一次性初始化(仓库根):** + +```bash +pnpm exec reactpress-cli init . +# 或 force 覆盖:pnpm exec reactpress-cli init . --force +``` + +默认端口建议与现网一致:client `3001`,server `3002`(在 `.reactpress/config.json` 调整)。 + +--- + +### 3.3 toolkit 处理(三选一) + +| 选项 | 做法 | 适用 | +|------|------|------| +| **A(推荐)** | **保留 `toolkit/`**,client/templates 继续 `workspace:*` | 仍会改 API、需 `swagger-typescript-api` 重新 generate | +| B | 删除 toolkit,client 依赖 npm `@fecommunity/reactpress-toolkit` | 不再改 API 类型,版本跟 CLI/npm 走 | +| C | toolkit 薄封装 re-export CLI 包内路径 | 路径脆弱,不推荐 | + +reactpress-cli 内 toolkit 仅有 `dist`、无 `src`;本仓 toolkit 含生成脚本,**删 server 时建议仍保留 toolkit**。 + +--- + +### 3.4 配置统一 + +| 项 | 迁移后 | +|----|--------| +| 项目元数据 | `.reactpress/config.json`(CLI 管理) | +| 运行时 env | 根目录 `.env`(由 CLI `syncEnvFromConfig` 生成/更新) | +| client API 地址 | 继续读 `SERVER_SITE_URL` / `SERVER_API_URL`,默认 `http://localhost:3002/api` | +| 废弃 | 依赖 server `main.ts` Web 安装向导作为唯一初始化方式 | + +**env 关键字段(与 CLI 模板一致):** + +- `DB_*`、`CLIENT_SITE_URL`、`SERVER_SITE_URL`、`SERVER_PORT`、`SERVER_API_PREFIX` + +--- + +### 3.5 待删除 / 待修改清单 + +**删除:** + +- [ ] 目录 `server/`(含 `bin`、`Dockerfile`、`ecosystem.config.js`) +- [ ] `pnpm-workspace.yaml` 中的 `server` +- [ ] 根 `package.json`:`reactpress-server` bin、`dev:server`、`build:server`、`pm2:server`、`start:server` +- [ ] `scripts/reactpress-cli.js`(或改为仅文档说明,不再 spawn 本地 server) +- [ ] `scripts/reactpress.js`(死代码) +- [ ] 发布流程中的 `@fecommunity/reactpress-server` 包项 + +**修改:** + +- [ ] 根 `package.json`:增加 `@fecommunity/reactpress-cli`;重写 `dev` / `build` / `release` +- [ ] `scripts/reactpress-publish.js`:移除 server 包逻辑,或拆分为小脚本对齐 reactpress-cli +- [ ] `scripts/reactpress-dev.js`:改为调 CLI + client,或合并进根 `dev` +- [ ] `scripts/install.sh`:去掉 server 构建/镜像假设,改为 CLI 起 API + client 镜像 +- [ ] `server/Dockerfile` 相关文档与 compose:改为 CLI 镜像或 API 侧车方案 +- [ ] README / docs:安装改为 `reactpress-cli init` + `start`;删除 `npx @fecommunity/reactpress-server` 主推 + +**保留(首期):** + +- [ ] `client/` +- [ ] `toolkit/`(方案 A) +- [ ] `docs/`、`templates/`(可二期移出 workspace) + +--- + +### 3.6 P0 止血(不删 server 也可先做) + +- [ ] 修正 `build:packages` → `node scripts/reactpress-publish.js --build` +- [ ] 修正 `release` → `node scripts/reactpress-publish.js --publish`(若尚未正确) +- [ ] 删除 `scripts/reactpress.js` 或修复并明确是否挂 bin +- [ ] 统一 `reactpress-publish.js` 帮助文案中的脚本名 + +--- + +## 四、可行性评估 + +| 维度 | 评估 | 说明 | +|------|------|------| +| API 兼容 | ✅ 高 | server 源码与 CLI 内置一致 | +| client 改造量 | ✅ 低 | 仍连 `localhost:3002/api`,env 名不变 | +| 初始化体验 | ⚠️ 中 | 从 Web 向导改为 CLI `init`,需更新文档 | +| 发版耦合 | ⚠️ 中 | server 修复需先进 reactpress-cli 并发 npm | +| CLI 成熟度 | ⚠️ 中 | 当前 CLI `0.1.0`,需确认 npm 可用或 workspace link | +| 生产 Docker | ⚠️ 中 | `install.sh` / compose 需重新设计 | +| toolkit | ✅ 高 | 建议保留本仓 toolkit,与 CLI bundled 版本定期对齐 | + +**不适合删 server 的情况:** + +- 计划在本仓库长期独立 fork 后端(大量 Nest 定制),且不愿回流 reactpress-cli。 + +--- + +## 五、风险与缓解 + +| 风险 | 缓解 | +|------|------| +| 两仓库 server 漂移 | 约定 server 仅以 reactpress-cli 为源码;本仓 CI 可加「API 冒烟」对 CLI 版本 | +| CLI 未发布 / 版本过旧 | dev 用 `link:../reactpress-cli`;CI 锁定 CLI 版本号 | +| 安装文档过时 | 迁移时同步 README-zh_CN、deploy 文档 | +| `install.sh` 失效 | 分阶段:先文档化 CLI 流程,再改 shell | +| 首次无 Web 向导 | `init` 后文档说明访问 `http://localhost:3001/admin` | + +--- + +## 六、落地计划(分阶段) + +### Phase 0 — 止血(0.5~1 天) + +- [ ] 修复 `build:packages` / `release` 脚本指向 +- [ ] 删除或修复 `scripts/reactpress.js` +- [ ] 在 README 注明当前脚本问题与临时正确命令 + +### Phase 1 — 验证 CLI 联调(1~2 天) + +- [ ] 根目录执行 `reactpress-cli init`(端口 3001/3002) +- [ ] `reactpress-cli start` + `pnpm dev:client` 跑通登录、文章列表、管理后台 +- [ ] 确认 `.env` 字段满足 client / toolkit 读取 +- [ ] 决定 CLI 依赖方式:**npm 正式版** vs **`link:../reactpress-cli`** + +### Phase 2 — 删除 server(1~2 天) + +- [ ] 从 workspace 移除 `server` +- [ ] 删除 `server/` 目录 +- [ ] 更新根 `package.json` scripts / bin +- [ ] 更新 `reactpress-dev.js` 或合并为根 `dev` +- [ ] 精简 `reactpress-publish.js`(去掉 server 包) + +### Phase 3 — 工程与文档(2~3 天) + +- [ ] 更新 `install.sh`、Docker、compose(如仍需要生产一键装) +- [ ] README / docs:安装、部署、环境变量以 CLI 为准 +- [ ] 统一 Node `>=18` engines(与 CLI 对齐) +- [ ] (可选)`docs`、`templates` 移出 workspace +- [ ] (可选)`@nestjs/cli` 等仅存在于 reactpress-cli 侧,本仓不再关心 + +### Phase 4 — 发布与长期(持续) + +- [ ] 本仓 npm 发布范围收敛为:`@fecommunity/reactpress-client`(+ 可选 toolkit / 模板) +- [ ] 建立 toolkit API 与 CLI bundled toolkit 版本对齐检查(发版前 diff dist 或跑 e2e) +- [ ] 评估是否将 toolkit 改为纯 npm 依赖(方案 B) + +--- + +## 七、验收标准 + +- [ ] 克隆仓库后:`pnpm install` → `reactpress-cli init` → `pnpm dev` 可访问前台与管理端 +- [ ] 仓库内无 `server/` 目录,无 `@fecommunity/reactpress-server` 发包配置 +- [ ] `pnpm build:packages` / `pnpm release`(若保留)指向正确且可执行 +- [ ] CI(若有)不依赖本仓 server 构建 +- [ ] 文档无 `npx @fecommunity/reactpress-server` 作为推荐路径 + +--- + +## 八、待决策项 + +- [ ] CLI 依赖:**npm `@fecommunity/reactpress-cli@^x`** 还是 **monorepo link 本地路径** +- [ ] toolkit:**保留 workspace(A)** 还是 **改 npm 依赖(B)** +- [ ] `docs` / `templates`:是否移出 pnpm workspace +- [ ] 是否继续发布根包 `@fecommunity/reactpress`,或改名为纯 client 元包 +- [ ] 生产环境:CLI 进容器 vs API 独立部署 + 仅容器化 client + +--- + +## 九、参考链接 + +- reactpress-cli 仓库:`/Users/xiu/Documents/my-code/reactpress-cli`(或 GitHub `fecommunity/reactpress-cli`) +- 用户项目结构:`.env` + `.reactpress/config.json` + `docker-compose.yml`(由 `init` 生成) +- 默认 API:`http://localhost:3002/api` · 默认前台:`http://localhost:3001` + +--- + +*文档生成自架构评审与「依赖 reactpress-cli、移除 server」方案讨论,随实施进度更新 checkbox。* diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 7e8f1e1..1d3f19b 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -19,27 +19,8 @@ services: networks: - reactpress-network - server: - build: - context: . - dockerfile: server/Dockerfile - container_name: reactpress_server - restart: always - depends_on: - - db - environment: - - NODE_ENV=production - # 从.env文件读取环境变量,使用默认值 - - DB_HOST=${DB_HOST:-db} - - DB_PORT=${DB_PORT:-3306} - - DB_USER=${DB_USER:-reactpress} - - DB_PASSWD=${DB_PASSWD:-reactpress} - - DB_DATABASE=${DB_DATABASE:-reactpress} - - SERVER_SITE_URL=${SERVER_SITE_URL:-http://localhost:3002} - ports: - - "3002:3002" - networks: - - reactpress-network + # API 由宿主机上的 @fecommunity/reactpress-cli 提供(pnpm exec reactpress-cli start) + # nginx 通过 host.docker.internal:3002 转发 /api client: build: @@ -47,8 +28,6 @@ services: dockerfile: client/Dockerfile container_name: reactpress_client restart: always - depends_on: - - server environment: - NODE_ENV=production # 从.env文件读取环境变量,使用默认值 @@ -66,7 +45,8 @@ services: - "8080:80" depends_on: - client - - server + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf networks: diff --git a/package.json b/package.json index 0563d93..f84bfc0 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,11 @@ "clean": "pnpm clean:node_modules && pnpm clean:dist", "clean:node_modules": "npx rimraf ./node_modules ./**/node_modules", "clean:dist": "npx rimraf ./dist ./**/dist", + "init": "pnpm exec reactpress-cli init .", + "init:force": "pnpm exec reactpress-cli init . --force", "dev": "node ./scripts/reactpress-dev.js", "dev:server": "pnpm run --dir ./server dev", + "dev:api": "pnpm run dev:server", "dev:client": "pnpm run --dir ./client dev", "dev:docs": "pnpm run --dir ./docs dev", "docker:dev": "node ./scripts/docker-dev.js", @@ -39,22 +42,27 @@ "docker:dev:status": "node ./scripts/docker-dev.js status", "docker:dev:logs": "node ./scripts/docker-dev.js logs", "build": "pnpm build:toolkit && pnpm build:server && pnpm build:client", - "build:packages": "node scripts/reactpress-cli.js --build", + "build:packages": "node scripts/reactpress-publish.js --build", "build:toolkit": "pnpm run --dir ./toolkit build", "build:server": "pnpm run --dir ./server build", "build:client": "pnpm run --dir ./client build", "build:docs": "pnpm run --dir ./docs build", "deploy:docs": "pnpm run --dir ./docs deploy:surge", "deploy": "sh scripts/deploy.sh", - "start": "concurrently 'pnpm:start:*'", + "start": "concurrently -n api,web -c blue,green \"pnpm run start:server\" \"pnpm run start:client\"", "start:server": "pnpm run --dir ./server start", + "start:api": "pnpm run start:server", "start:client": "pnpm run --dir ./client start", + "stop": "pnpm exec reactpress-cli stop", + "restart": "pnpm exec reactpress-cli restart", + "status": "pnpm exec reactpress-cli status", "pm2": "pnpm run pm2:server && pnpm run pm2:client", "pm2:server": "pnpm run --dir ./server pm2", + "pm2:api": "pnpm run pm2:server", "pm2:client": "pnpm run --dir ./client pm2", "lint": "concurrently 'pnpm:lint:*'", "lint:client": "eslint --fix './client/**/*.{ts,tsx,js,jsx}'", - "lint:server": "eslint --fix './server/./**/*.{ts,js}'", + "lint:server": "node -e \"console.log('server: no local TS sources (see @fecommunity/reactpress-cli)')\"", "format": "concurrently 'pnpm:format:*'", "format:js": "prettier --write --parser typescript './**/*.{ts,tsx,js,jsx}'", "prepare": "husky", @@ -77,9 +85,10 @@ "rimraf": "^3.0.2" }, "engines": { - "node": ">=16.5.0" + "node": ">=18.0.0" }, "devDependencies": { + "@fecommunity/reactpress-cli": "^0.1.0", "husky": "^7.0.4", "lint-staged": "^12.4.1", "prettier": "^2.3.2", @@ -90,12 +99,9 @@ "./client/**/*.{ts,tsx,js,jsx}": [ "eslint --fix" ], - "./server/src/**/*.{ts,js}": [ - "eslint --fix" - ], "./config/**/*.{ts,tsx,js,jsx}": [ "eslint --fix" ] }, "packageManager": "pnpm@10.12.1+sha512.f0dda8580f0ee9481c5c79a1d927b9164f2c478e90992ad268bbb2465a736984391d6333d2c327913578b2804af33474ca554ba29c04a8b13060a717675ae3ac" -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 869ea12..3bdd7ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,6 +45,9 @@ importers: specifier: ^3.0.2 version: 3.0.2 devDependencies: + '@fecommunity/reactpress-cli': + specifier: ^0.1.0 + version: 0.1.0(@types/node@24.5.2) husky: specifier: ^7.0.4 version: 7.0.4 @@ -299,220 +302,9 @@ importers: server: dependencies: - '@fecommunity/reactpress-toolkit': - specifier: workspace:* - version: link:../toolkit - '@nestjs/cli': - specifier: ^6.9.0 - version: 6.14.2(eslint@8.57.1) - '@nestjs/common': - specifier: ^6.7.2 - version: 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nestjs/config': - specifier: ^0.6.3 - version: 0.6.3(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nestjs/core': - specifier: ^6.7.2 - version: 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nestjs/jwt': - specifier: ^6.1.1 - version: 6.1.2(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)) - '@nestjs/passport': - specifier: ^6.1.1 - version: 6.2.0(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(passport@0.4.1) - '@nestjs/platform-express': - specifier: ^6.11.5 - version: 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)) - '@nestjs/swagger': - specifier: ^4.8.2 - version: 4.8.2(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))(class-transformer@0.2.3)(class-validator@0.13.2)(reflect-metadata@0.1.14)(swagger-ui-express@4.6.3(express@4.21.2)) - '@types/express-serve-static-core': - specifier: ^4.19.5 - version: 4.19.5 - ali-oss: - specifier: ^6.5.1 - version: 6.21.0 - axios: - specifier: ^0.23.0 - version: 0.23.0 - bcryptjs: - specifier: ^2.4.3 - version: 2.4.3 - body-parser: - specifier: ^1.19.0 - version: 1.20.3 - chalk: - specifier: ^4.1.2 - version: 4.1.2 - class-transformer: - specifier: ^0.2.3 - version: 0.2.3 - commander: - specifier: ^9.4.1 - version: 9.5.0 - compression: - specifier: ^1.7.4 - version: 1.7.4 - cross-env: - specifier: ^7.0.3 - version: 7.0.3 - date-fns: - specifier: ^2.17.0 - version: 2.30.0 - deepmerge: - specifier: ^4.2.2 - version: 4.3.1 - dotenv: - specifier: ^8.2.0 - version: 8.6.0 - express: - specifier: ^4.18.2 - version: 4.21.2 - express-rate-limit: - specifier: ^5.0.0 - version: 5.5.1 - fs-extra: - specifier: ^10.0.0 - version: 10.1.0 - helmet: - specifier: ^3.21.2 - version: 3.23.3 - highlight.js: - specifier: ^9.18.0 - version: 9.18.5 - inquirer: - specifier: ^8.2.4 - version: 8.2.7(@types/node@12.20.55) - lodash: - specifier: ^4.17.21 - version: 4.17.21 - log4js: - specifier: ^6.1.0 - version: 6.9.1 - marked: - specifier: ^0.8.0 - version: 0.8.2 - mysql2: - specifier: ^3.12.0 - version: 3.12.0 - node-ip2region: - specifier: ^1.0.2 - version: 1.0.2 - nodemailer: - specifier: ^6.4.2 - version: 6.9.15 - nuid: - specifier: ^1.1.0 - version: 1.1.6 - open: - specifier: ^8.2.1 - version: 8.4.2 - passport: - specifier: ^0.4.1 - version: 0.4.1 - passport-jwt: - specifier: ^4.0.0 - version: 4.0.1 - pm2: - specifier: ^5.2.0 - version: 5.4.3 - reflect-metadata: - specifier: ^0.1.13 - version: 0.1.14 - rimraf: - specifier: ^3.0.0 - version: 3.0.2 - rxjs: - specifier: ^6.5.3 - version: 6.6.7 - segment: - specifier: ^0.1.3 - version: 0.1.3 - swagger-themes: - specifier: ^1.4.3 - version: 1.4.3 - swagger-ui-express: - specifier: ^4.1.6 - version: 4.6.3(express@4.21.2) - typeorm: - specifier: ^0.2.45 - version: 0.2.45(mysql2@3.12.0) - ua-parser-js: - specifier: ^0.7.28 - version: 0.7.39 - devDependencies: - '@nestjs/schematics': - specifier: ^6.7.0 - version: 6.9.4(typescript@4.1.6) - '@nestjs/testing': - specifier: ^6.7.1 - version: 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)) - '@nestjs/typeorm': - specifier: ^6.3.4 - version: 6.3.4(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))(reflect-metadata@0.1.14)(rxjs@6.6.7)(typeorm@0.2.45(mysql2@3.12.0)) - '@types/express': - specifier: 4.17.18 - version: 4.17.18 - '@types/jest': - specifier: ^24.0.18 - version: 24.9.1 - '@types/node': - specifier: ^12.7.5 - version: 12.20.55 - '@types/supertest': - specifier: ^2.0.8 - version: 2.0.16 - '@typescript-eslint/eslint-plugin': - specifier: ^5.21.0 - version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1)(typescript@4.1.6) - '@typescript-eslint/parser': - specifier: ^5.21.0 - version: 5.62.0(eslint@8.57.1)(typescript@4.1.6) - eslint: - specifier: ^8.15.0 - version: 8.57.1 - eslint-config-prettier: - specifier: ^8.5.0 - version: 8.10.0(eslint@8.57.1) - eslint-plugin-import: - specifier: ^2.26.0 - version: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1) - eslint-plugin-prettier: - specifier: ^4.0.0 - version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@1.19.1) - eslint-plugin-simple-import-sort: - specifier: ^7.0.0 - version: 7.0.0(eslint@8.57.1) - jest: - specifier: ^24.9.0 - version: 24.9.0 - next-transpile-modules: - specifier: ^6.3.0 - version: 6.4.1 - prettier: - specifier: ^1.18.2 - version: 1.19.1 - supertest: - specifier: ^4.0.2 - version: 4.0.2 - ts-jest: - specifier: ^24.1.0 - version: 24.3.0(jest@24.9.0) - ts-loader: - specifier: ^6.1.1 - version: 6.2.2(typescript@4.1.6) - ts-node: - specifier: ^8.4.1 - version: 8.10.2(typescript@4.1.6) - tsconfig-paths: - specifier: ^3.9.0 - version: 3.15.0 - tslint: - specifier: ^5.20.0 - version: 5.20.1(typescript@4.1.6) - typescript: - specifier: ~4.1.6 - version: 4.1.6 + '@fecommunity/reactpress-cli': + specifier: ^0.1.0 + version: 0.1.0(@types/node@24.5.2) templates/hello-world: dependencies: @@ -524,7 +316,7 @@ importers: version: 10.1.0 next: specifier: ^12.3.4 - version: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3) + version: 12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3) react: specifier: 17.0.2 version: 17.0.2 @@ -549,7 +341,7 @@ importers: version: link:../../toolkit next: specifier: ^12.3.4 - version: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3) + version: 12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3) react: specifier: 17.0.2 version: 17.0.2 @@ -697,19 +489,6 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@angular-devkit/core@7.3.8': - resolution: {integrity: sha512-3X9uzaZXFpm5o2TSzhD6wEOtVU32CgeytKjD1Scxj+uMMVo48SWLlKiFh312T+smI9ko7tOT8VqxglwYkWosgg==} - engines: {node: '>= 8.9.0', npm: '>= 5.5.1'} - - '@angular-devkit/schematics-cli@0.13.8': - resolution: {integrity: sha512-PnVetGOLqONNhKcUfJoCRUJU8BSpcTZpWwQS6YywyNrvyVXtnUi/dgMTQkS8fva3XC/5Ij3Mj7yrfTHaG7M7bw==} - engines: {node: '>= 8.9.0', npm: '>= 5.5.1'} - hasBin: true - - '@angular-devkit/schematics@7.3.8': - resolution: {integrity: sha512-mvaKoORZIaW/h0VNZ3IQWP0qThRCZRX6869FNlzV0jlW0mhn07XbiIGHCGGSCDRxS7qJ0VbuIVnKXntF+iDeWw==} - engines: {node: '>= 8.9.0', npm: '>= 5.5.1'} - '@ant-design/colors@6.0.0': resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==} @@ -2499,18 +2278,10 @@ packages: resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@9.36.0': resolution: {integrity: sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2526,6 +2297,11 @@ packages: '@exodus/schemasafe@1.3.0': resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} + '@fecommunity/reactpress-cli@0.1.0': + resolution: {integrity: sha512-pfujpBCamo5BA18II7WtitawmZofR7xs+THgILC2taH3Go4Nslf5zvWgjfBSNu1+YxYVLk6d8k+KFdL0nQ1Abw==} + engines: {node: '>=18'} + hasBin: true + '@formatjs/ecma402-abstract@1.11.4': resolution: {integrity: sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==} @@ -2555,11 +2331,6 @@ packages: resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - '@humanwhocodes/config-array@0.9.5': resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} engines: {node: '>=10.10.0'} @@ -2573,10 +2344,6 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} deprecated: Use @eslint/object-schema instead - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead - '@humanwhocodes/retry@0.4.3': resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} @@ -2707,90 +2474,6 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@nestjs/cli@6.14.2': - resolution: {integrity: sha512-Bv6ZoziyuXrCmeWMf4rcEjN84O4RmZtQugscFm0k2nOWVfW79eltqMJlpj6h9IutLLC52Je/SOw0XTiDGOukyg==} - engines: {node: '>= 8.9.0', npm: '>= 5.5.1'} - hasBin: true - - '@nestjs/common@6.11.11': - resolution: {integrity: sha512-K4wuK/V2M82AsoudtY0UYV+M1nYDSSb10t8AkMwFiP+AWMuxCJNtE8qLc9jUe2aTKMbhBiQUfsbZFmg/MRinPg==} - peerDependencies: - reflect-metadata: ^0.1.12 - rxjs: ^6.0.0 - - '@nestjs/config@0.6.3': - resolution: {integrity: sha512-JxvvUpmH0/WOrTB+zh8dEkxSUQXhB7V3d/qeQXyCnMiEFjaq89+fNFztpWjz4DlOfdS4/eYTzIEy9PH2uGnfzA==} - peerDependencies: - '@nestjs/common': ^6.10.0 || ^7.0.0 - reflect-metadata: ^0.1.12 - rxjs: ^6.0.0 - - '@nestjs/core@6.11.11': - resolution: {integrity: sha512-ewUy2rjiRWi6SziI5gXZnlat7PfnVklL3tusnU1qqtUm74cPY1Zre+zDCJ27P/+B7sFJHbkFfpi0qQP2pQv9jQ==} - peerDependencies: - '@nestjs/common': ^6.0.0 - reflect-metadata: ^0.1.12 - rxjs: ^6.0.0 - - '@nestjs/jwt@6.1.2': - resolution: {integrity: sha512-+qfcAeAuZiwGRj5WqmDCtzhlY109l2e6QJR4K2ANu1UJskxxaD9O7QS8SGegzpfTaIL01NAF8BWNxwy5ps6Lzg==} - peerDependencies: - '@nestjs/common': ^6.0.0 - - '@nestjs/mapped-types@0.4.1': - resolution: {integrity: sha512-JXrw2LMangSU3vnaXWXVX47GRG1FbbNh4aVBbidDjxT3zlghsoNQY6qyWtT001MCl8lJGo8I6i6+DurBRRxl/Q==} - peerDependencies: - '@nestjs/common': ^7.0.8 - class-transformer: ^0.2.0 || ^0.3.0 || ^0.4.0 - class-validator: ^0.11.1 || ^0.12.0 || ^0.13.0 - reflect-metadata: ^0.1.12 - - '@nestjs/passport@6.2.0': - resolution: {integrity: sha512-Wy8FeSCNxbfTKRe/mJk0w5hSLsqoNMehg6DUQOoDug+6Uaq+QLEy6wvGPUJbVqGKpJwFHGgUoWp2ag05zh4zpA==} - peerDependencies: - '@nestjs/common': ^6.0.0 - passport: ^0.4.0 - - '@nestjs/platform-express@6.11.11': - resolution: {integrity: sha512-4h3F3hDhNlO5+Ruy6eS+lSL2yIz5r4hF/BB3QkZVOuRdfji9n0gZAIR7tuSLTizqYxaHYRZ7dBv+PscQS/7ztQ==} - peerDependencies: - '@nestjs/common': ^6.0.0 - '@nestjs/core': ^6.0.0 - - '@nestjs/schematics@6.9.4': - resolution: {integrity: sha512-tZoLDboqXQT+DcWUFTJyDsOIg9Qt6ilXYWWbrbbEPCP2+UKjfsqZPsEnG31DOj0IbovFS5g+Mbn3IanVsEcIsQ==} - peerDependencies: - typescript: ^3.4.5 - - '@nestjs/swagger@4.8.2': - resolution: {integrity: sha512-RSUwcVxrzXF7/b/IZ5lXnYHJ6jIGS9wWRTJKIt1kIaCNWT+0wRfTlAyhQkzs2g35/PTXJEcdIwwY7mBO/bwHzw==} - peerDependencies: - '@nestjs/common': ^6.8.0 || ^7.0.0 - '@nestjs/core': ^6.8.0 || ^7.0.0 - fastify-swagger: '*' - reflect-metadata: ^0.1.12 - swagger-ui-express: '*' - peerDependenciesMeta: - fastify-swagger: - optional: true - swagger-ui-express: - optional: true - - '@nestjs/testing@6.11.11': - resolution: {integrity: sha512-Mqu4IWZhnLdIFfVfueAFFCm3jPfQoWg+YmDLBsFS2kpab3az5gsRCZQv9R9CCHGa1hHKYWqM1lMcz1IQc70kww==} - peerDependencies: - '@nestjs/common': ^6.0.0 - '@nestjs/core': ^6.0.0 - - '@nestjs/typeorm@6.3.4': - resolution: {integrity: sha512-qMUHaTMo+U5WOlMfL0ogNm8C2T/Kej/v+NnjSixx/UmtluLvTbNYuZUfbHI9ePCmtCXDV0lMRvIAi+U5LCjsbA==} - peerDependencies: - '@nestjs/common': ^6.7.0 - '@nestjs/core': ^6.7.0 - reflect-metadata: ^0.1.12 - rxjs: ^6.0.0 - typeorm: ^0.2.7 - '@next/env@12.3.4': resolution: {integrity: sha512-H/69Lc5Q02dq3o+dxxy5O/oNxFsZpdL6WREtOOtOM1B/weonIwDXkekr1KV5DPVPr12IHFPrMrcJQ6bgPMfn7A==} @@ -2887,25 +2570,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nuxtjs/opencollective@0.2.2': - resolution: {integrity: sha512-69gFVDs7mJfNjv9Zs5DFVD+pvBW+k1TaHSOqUWqAyTTfLcKI/EMYQgvEvziRd+zAFtUOoye6MfWh0qvinGISPw==} - engines: {node: '>=8.0.0', npm: '>=5.0.0'} - hasBin: true - - '@pm2/agent@2.0.4': - resolution: {integrity: sha512-n7WYvvTJhHLS2oBb1PjOtgLpMhgImOq8sXkPBw6smeg9LJBWZjiEgPKOpR8mn9UJZsB5P3W4V/MyvNnp31LKeA==} - - '@pm2/io@6.0.1': - resolution: {integrity: sha512-KiA+shC6sULQAr9mGZ1pg+6KVW9MF8NpG99x26Lf/082/Qy8qsTCtnJy+HQReW1A9Rdf0C/404cz0RZGZro+IA==} - engines: {node: '>=6.0'} - - '@pm2/js-api@0.8.0': - resolution: {integrity: sha512-nmWzrA/BQZik3VBz+npRcNIu01kdBhWL0mxKmP1ciF/gTcujPTQqt027N9fc1pK9ERM8RipFhymw7RcmCyOEYA==} - engines: {node: '>=4.0'} - - '@pm2/pm2-version-check@1.0.4': - resolution: {integrity: sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==} - '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} @@ -3185,10 +2849,6 @@ packages: '@rushstack/eslint-patch@1.10.4': resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} - '@schematics/schematics@0.13.8': - resolution: {integrity: sha512-7Bqw2DzCbt7EkR0IYDEUXJ6WQjE90NqSMFqK0Lylps0WswJfjUq5axJduz5LwbmrIDhWdDhXMtI4QimUBm4Qsw==} - engines: {node: '>= 8.9.0', npm: '>= 5.5.1'} - '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -3224,9 +2884,6 @@ packages: '@slorber/remark-comment@1.0.0': resolution: {integrity: sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==} - '@sqltools/formatter@1.2.5': - resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} - '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} @@ -3338,9 +2995,6 @@ packages: '@types/react-dom': optional: true - '@tootallnate/quickjs-emscripten@0.23.0': - resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -3348,10 +3002,6 @@ packages: '@types/acorn@4.0.6': resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} - '@types/anymatch@3.0.0': - resolution: {integrity: sha512-qLChUo6yhpQ9k905NwL74GU7TxH+9UODwwQ6ICNI+O6EDMExqH/Cv9NsbmcZ7yC/rRXJ/AHCzfgjsFRY5fKjYw==} - deprecated: This is a stub types definition. anymatch provides its own type definitions, so you do not need this installed. - '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -3379,9 +3029,6 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/cookiejar@2.1.5': - resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} - '@types/debounce@1.2.4': resolution: {integrity: sha512-jBqiORIzKDOToaF63Fm//haOCHuwQuLa2202RK4MozpA6lh93eCBc+/8+wZn5OzjJt3ySdc+74SXWXB55Ewtyw==} @@ -3457,18 +3104,12 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/jsonwebtoken@8.3.7': - resolution: {integrity: sha512-B5SSifLkjB0ns7VXpOOtOUlynE78/hKcY8G8pOAhkLJZinwofIBYqz555nRj2W9iDWZqFhK5R+7NZDaRmKWAoQ==} - '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} '@types/mdx@2.0.13': resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} - '@types/methods@1.1.4': - resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} - '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -3484,9 +3125,6 @@ packages: '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} - '@types/node@12.20.55': - resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@17.0.22': resolution: {integrity: sha512-8FwbVoG4fy+ykY86XCAclKZDORttqE5/s7dyWZKLXTdv3vRy5HozBEinG5IqhvPXXzIZEcTVbuHlQEI6iuwcmw==} @@ -3559,45 +3197,24 @@ packages: '@types/sockjs@0.3.36': resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} - '@types/source-list-map@0.1.6': - resolution: {integrity: sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==} - '@types/stack-utils@1.0.1': resolution: {integrity: sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - '@types/superagent@8.1.9': - resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} - - '@types/supertest@2.0.16': - resolution: {integrity: sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==} - '@types/swagger-schema-official@2.0.22': resolution: {integrity: sha512-7yQiX6MWSFSvc/1wW5smJMZTZ4fHOd+hqLr3qr/HONDxHEa2bnYAsOcGBOEqFIjd4yetwMOdEDdeW+udRAQnHA==} - '@types/tapable@2.2.7': - resolution: {integrity: sha512-D6QzACV9vNX3r8HQQNTOnpG+Bv1rko+yEA82wKs3O9CQ5+XW7HI7TED17/UE7+5dIxyxZIWTxKbsBeF6uKFCwA==} - '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@types/uglify-js@3.17.5': - resolution: {integrity: sha512-TU+fZFBTBcXj/GpDpDaBmgWk/gn96kMZ+uocaFUlV2f8a6WdMzzI44QBCmGcCiYR0Y6ZlNRiyUyKKt5nl/lbzQ==} - '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/webpack-sources@3.2.3': - resolution: {integrity: sha512-4nZOdMwSPHZ4pTEZzSp0AsTM4K7Qmu40UKW4tJDiOVs20UzYF9l+qUe4s0ftfN0pin06n+5cWWDJXH+sbhAiDw==} - - '@types/webpack@4.41.5': - resolution: {integrity: sha512-693JfV/83UZxpQY8vutDSwkDjNujy2327UrFqQciJWXh761B/aUIZIM5N05IRIZ17WwsG8VfUSE3edwXvkehiQ==} - '@types/webxr@0.5.20': resolution: {integrity: sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==} @@ -3616,9 +3233,6 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@types/zen-observable@0.8.3': - resolution: {integrity: sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==} - '@typescript-eslint/eslint-plugin@5.62.0': resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3691,102 +3305,48 @@ packages: '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - '@webassemblyjs/ast@1.8.5': - resolution: {integrity: sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==} - '@webassemblyjs/floating-point-hex-parser@1.13.2': resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - '@webassemblyjs/floating-point-hex-parser@1.8.5': - resolution: {integrity: sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==} - '@webassemblyjs/helper-api-error@1.13.2': resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} - '@webassemblyjs/helper-api-error@1.8.5': - resolution: {integrity: sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==} - '@webassemblyjs/helper-buffer@1.14.1': resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} - '@webassemblyjs/helper-buffer@1.8.5': - resolution: {integrity: sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==} - - '@webassemblyjs/helper-code-frame@1.8.5': - resolution: {integrity: sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==} - - '@webassemblyjs/helper-fsm@1.8.5': - resolution: {integrity: sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==} - - '@webassemblyjs/helper-module-context@1.8.5': - resolution: {integrity: sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==} - '@webassemblyjs/helper-numbers@1.13.2': resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} '@webassemblyjs/helper-wasm-bytecode@1.13.2': resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} - '@webassemblyjs/helper-wasm-bytecode@1.8.5': - resolution: {integrity: sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==} - '@webassemblyjs/helper-wasm-section@1.14.1': resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} - '@webassemblyjs/helper-wasm-section@1.8.5': - resolution: {integrity: sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==} - '@webassemblyjs/ieee754@1.13.2': resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} - '@webassemblyjs/ieee754@1.8.5': - resolution: {integrity: sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==} - '@webassemblyjs/leb128@1.13.2': resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} - '@webassemblyjs/leb128@1.8.5': - resolution: {integrity: sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==} - '@webassemblyjs/utf8@1.13.2': resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - '@webassemblyjs/utf8@1.8.5': - resolution: {integrity: sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==} - '@webassemblyjs/wasm-edit@1.14.1': resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - '@webassemblyjs/wasm-edit@1.8.5': - resolution: {integrity: sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==} - '@webassemblyjs/wasm-gen@1.14.1': resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - '@webassemblyjs/wasm-gen@1.8.5': - resolution: {integrity: sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==} - '@webassemblyjs/wasm-opt@1.14.1': resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - '@webassemblyjs/wasm-opt@1.8.5': - resolution: {integrity: sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==} - '@webassemblyjs/wasm-parser@1.14.1': resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} - '@webassemblyjs/wasm-parser@1.8.5': - resolution: {integrity: sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==} - - '@webassemblyjs/wast-parser@1.8.5': - resolution: {integrity: sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==} - '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - '@webassemblyjs/wast-printer@1.8.5': - resolution: {integrity: sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==} - '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -3864,23 +3424,10 @@ packages: resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} engines: {node: '>= 10.0.0'} - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - agentkeepalive@3.5.3: - resolution: {integrity: sha512-yqXL+k5rr8+ZRpOAntkaaRgWgE5o8ESAj5DyRmVTCSoZxXmqemb9Dd7T4i5UzwuERdLAJUy6XzR9zFVuf0kzkw==} - engines: {node: '>= 4.0.0'} - aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} - ajv-errors@1.0.1: - resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==} - peerDependencies: - ajv: '>=5.0.0' - ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -3902,9 +3449,6 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@6.9.1: - resolution: {integrity: sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==} - ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} @@ -3917,16 +3461,6 @@ packages: resolution: {integrity: sha512-iNC6BGvipaalFfDfDnXUje8GUlW5asj0cTMsZJwO/0rhsyLx1L7GZFAY8wW+eQ6AM4Yge2p5GSE5hrBlfSD90Q==} engines: {node: '>= 14.0.0'} - ali-oss@6.21.0: - resolution: {integrity: sha512-dRvKWO/GJEa6dlsCnvmgHIbU5+yE/SmZsE4kZRGNU7Uotr9uIkQWGqv4szLTxRSxWv3YgL+BZgt+swIgitYGjA==} - engines: {node: '>=8'} - - amp-message@0.1.2: - resolution: {integrity: sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg==} - - amp@0.3.1: - resolution: {integrity: sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw==} - anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} @@ -3953,10 +3487,6 @@ packages: engines: {'0': node >= 0.8.0} hasBin: true - ansi-regex@2.1.1: - resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} - engines: {node: '>=0.10.0'} - ansi-regex@3.0.1: resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} engines: {node: '>=4'} @@ -3973,10 +3503,6 @@ packages: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - ansi-styles@2.2.1: - resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} - engines: {node: '>=0.10.0'} - ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -3999,9 +3525,6 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - anymatch@2.0.0: resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} @@ -4009,22 +3532,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - app-root-path@3.1.0: - resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} - engines: {node: '>= 6.0.0'} - appdirsjs@1.2.7: resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} - append-field@1.0.0: - resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - - aproba@1.2.0: - resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} - - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -4124,9 +3634,6 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - asn1.js@4.10.1: - resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} - asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} @@ -4134,9 +3641,6 @@ packages: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} - assert@1.5.1: - resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==} - assign-symbols@1.0.0: resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} engines: {node: '>=0.10.0'} @@ -4144,10 +3648,6 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - ast-types@0.13.4: - resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} - engines: {node: '>=4'} - ast-types@0.15.2: resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} engines: {node: '>=4'} @@ -4164,18 +3664,12 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true - async-each@1.0.6: - resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} - async-limiter@1.0.1: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} async-validator@1.11.5: resolution: {integrity: sha512-XNtCsMAeAH1pdLMEg1z8/Bb3a8cdCbui9QbJATRFHHHW5kT6+NPI3zSVQUXgikTFITzsg+kYY5NTWhM2Orwt9w==} - async@2.6.4: - resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} - async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} @@ -4216,10 +3710,6 @@ packages: resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} engines: {node: '>=4'} - axios@0.19.2: - resolution: {integrity: sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==} - deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410 - axios@0.23.0: resolution: {integrity: sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==} @@ -4230,9 +3720,6 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} - babel-code-frame@6.26.0: - resolution: {integrity: sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==} - babel-core@7.0.0-bridge.0: resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: @@ -4314,26 +3801,15 @@ packages: resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} engines: {node: '>=0.10.0'} - basic-ftp@5.0.5: - resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} - engines: {node: '>=10.0.0'} - batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - bcryptjs@2.4.3: - resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} - big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - binary-extensions@1.13.1: - resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} - engines: {node: '>=0.10.0'} - binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -4344,27 +3820,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - blessed@0.1.81: - resolution: {integrity: sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==} - engines: {node: '>= 0.8.0'} - hasBin: true - - bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - - bn.js@4.12.0: - resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - - bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - - bodec@0.1.0: - resolution: {integrity: sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==} - - body-parser@1.19.0: - resolution: {integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==} - engines: {node: '>= 0.8'} - body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -4379,12 +3834,6 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - bowser@1.9.4: - resolution: {integrity: sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==} - - bowser@2.9.0: - resolution: {integrity: sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==} - boxen@6.2.1: resolution: {integrity: sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -4407,34 +3856,12 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - browser-process-hrtime@1.0.0: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} browser-resolve@1.11.3: resolution: {integrity: sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==} - browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - - browserify-cipher@1.0.1: - resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} - - browserify-des@1.0.2: - resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} - - browserify-rsa@4.1.0: - resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} - - browserify-sign@4.2.3: - resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} - engines: {node: '>= 0.12'} - - browserify-zlib@0.2.0: - resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} - browserslist@4.23.3: resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -4452,54 +3879,27 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - - buffer@4.9.2: - resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} - buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - builtin-modules@1.1.1: - resolution: {integrity: sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==} - engines: {node: '>=0.10.0'} - builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} - builtin-status-codes@3.0.0: - resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} - - busboy@0.2.14: - resolution: {integrity: sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==} - engines: {node: '>=0.8.0'} - bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} - bytes@3.1.0: - resolution: {integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==} - engines: {node: '>= 0.8'} - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - cacache@12.0.4: - resolution: {integrity: sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==} - cache-base@1.0.1: resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} engines: {node: '>=0.10.0'} @@ -4566,9 +3966,6 @@ packages: resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} engines: {node: '>=14.16'} - camelize@1.0.0: - resolution: {integrity: sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==} - caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} @@ -4585,18 +3982,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - chalk@1.1.3: - resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} - engines: {node: '>=0.10.0'} - chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} - chalk@3.0.0: - resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} - engines: {node: '>=8'} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -4621,15 +4010,9 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} - chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - chardet@2.1.0: resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} - charm@0.1.2: - resolution: {integrity: sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ==} - cheerio-select@2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} @@ -4637,12 +4020,6 @@ packages: resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} engines: {node: '>= 6'} - chokidar@2.0.4: - resolution: {integrity: sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==} - - chokidar@2.1.8: - resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -4651,9 +4028,6 @@ packages: resolution: {integrity: sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==} engines: {node: '>= 14.16.0'} - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - chrome-launcher@0.15.2: resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} engines: {node: '>=12.13.0'} @@ -4673,19 +4047,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} - - class-transformer@0.2.3: - resolution: {integrity: sha512-qsP+0xoavpOlJHuYsQJsN58HXSl8Jvveo+T37rEvCEeRfMWoytAyR0Ua/YsFgpM6AZYZ/og2PJwArwzJl1aXtQ==} - class-utils@0.3.6: resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} engines: {node: '>=0.10.0'} - class-validator@0.13.2: - resolution: {integrity: sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==} - classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -4707,38 +4072,22 @@ packages: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} - cli-color@2.0.0: - resolution: {integrity: sha512-a0VZ8LeraW0jTuCkuAGMNufareGHhyZU9z8OGsW0gXd1hZGi1SRuNRXdbGkraBBKnhyUhyebFWnRbp+dIn0f0A==} - - cli-cursor@2.1.0: - resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} - engines: {node: '>=4'} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} - cli-highlight@2.1.11: - resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} - engines: {node: '>=8.0.0', npm: '>=5.0.0'} - hasBin: true + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-table3@0.5.1: - resolution: {integrity: sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==} - engines: {node: '>=6'} - cli-table3@0.6.5: resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} - cli-tableau@2.0.1: - resolution: {integrity: sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==} - engines: {node: '>=8.10.0'} - cli-truncate@2.1.0: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} @@ -4747,9 +4096,6 @@ packages: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - cli-width@2.2.1: - resolution: {integrity: sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==} - cli-width@3.0.0: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} @@ -4815,10 +4161,6 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - combine-promises@1.2.0: resolution: {integrity: sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==} engines: {node: '>=10'} @@ -4837,16 +4179,13 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} - commander@2.15.1: - resolution: {integrity: sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==} + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - commander@5.1.0: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} @@ -4899,10 +4238,6 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concat-stream@1.6.2: - resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} - engines: {'0': node >= 0.8} - concurrently@7.6.0: resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==} engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} @@ -4923,27 +4258,14 @@ packages: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} - consola@2.15.3: - resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} - consola@3.4.0: resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} engines: {node: ^14.18.0 || >=16.10.0} - console-browserify@1.2.0: - resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} - - constants-browserify@1.0.0: - resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} - content-disposition@0.5.2: resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} engines: {node: '>= 0.6'} - content-disposition@0.5.3: - resolution: {integrity: sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==} - engines: {node: '>= 0.6'} - content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -4952,10 +4274,6 @@ packages: resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} engines: {node: '>= 0.6'} - content-security-policy-builder@2.1.0: - resolution: {integrity: sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==} - engines: {node: '>=4.0.0'} - content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -5040,24 +4358,13 @@ packages: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} - cookie@0.4.0: - resolution: {integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==} - engines: {node: '>= 0.6'} - cookie@0.7.1: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} - cookiejar@2.1.4: - resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} - copy-anything@2.0.6: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} - copy-concurrently@1.0.5: - resolution: {integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==} - deprecated: This package is no longer supported. - copy-descriptor@0.1.1: resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} engines: {node: '>=0.10.0'} @@ -5069,19 +4376,12 @@ packages: copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} - copy-to@2.0.1: - resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==} - copy-webpack-plugin@11.0.0: resolution: {integrity: sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==} engines: {node: '>= 14.15.0'} peerDependencies: webpack: ^5.1.0 - copyfiles@2.2.0: - resolution: {integrity: sha512-iJbHJI+8OKqsq+4JF0rqgRkZzo++jqO6Wf4FUU1JM41cJF6JcY5968XyF4tm3Kkm7ZOMrqlljdm8N9oyY5raGw==} - hasBin: true - core-js-compat@3.38.1: resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==} @@ -5108,10 +4408,6 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - cosmiconfig@5.2.1: resolution: {integrity: sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==} engines: {node: '>=4'} @@ -5142,21 +4438,9 @@ packages: typescript: optional: true - create-ecdh@4.0.4: - resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} - - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - - create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - create-react-class@15.7.0: resolution: {integrity: sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==} - croner@4.1.97: - resolution: {integrity: sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==} - cross-env@7.0.3: resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} @@ -5174,9 +4458,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crypto-browserify@3.12.0: - resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} - crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} @@ -5315,19 +4596,9 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - culvert@0.1.2: - resolution: {integrity: sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==} - cxs@6.2.0: resolution: {integrity: sha512-RGatb1BUwVMBzV8DRo9Kapc55bdGfAxMcukVk+ZzE3Ts8xaTve0GVz730kBDxjhEBU2LK+RPuAcjZb00Q3O24w==} - cyclist@1.0.2: - resolution: {integrity: sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==} - - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} - damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -5339,17 +4610,10 @@ packages: resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} engines: {node: '>=0.10'} - dasherize@2.0.0: - resolution: {integrity: sha512-APql/TZ6FdLEpf2z7/X2a2zyqK8juYtqaSVqxw9mYoQ64CXkfU15AeLh8pUszT8+fnYjgm6t0aIYpWKJbnLkuA==} - data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} - data-uri-to-buffer@6.0.2: - resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} - engines: {node: '>= 14'} - data-urls@1.1.0: resolution: {integrity: sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==} @@ -5369,22 +4633,12 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} - date-format@4.0.14: - resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} - engines: {node: '>=4.0'} - - dateformat@2.2.0: - resolution: {integrity: sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==} - dateformat@3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dayjs@1.8.36: - resolution: {integrity: sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==} - debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -5396,14 +4650,6 @@ packages: supports-color: optional: true - debug@3.1.0: - resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -5468,10 +4714,6 @@ packages: resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==} engines: {node: '>= 10'} - default-user-agent@1.0.0: - resolution: {integrity: sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==} - engines: {node: '>= 0.10.0'} - defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -5503,10 +4745,6 @@ packages: resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} engines: {node: '>=0.10.0'} - degenerator@5.0.1: - resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} - engines: {node: '>= 14'} - del@4.1.1: resolution: {integrity: sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==} engines: {node: '>=6'} @@ -5538,12 +4776,6 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - des.js@1.1.0: - resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - - destroy@1.0.4: - resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==} - destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -5568,10 +4800,6 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - dicer@0.2.5: - resolution: {integrity: sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==} - engines: {node: '>=0.8.0'} - didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -5579,17 +4807,6 @@ packages: resolution: {integrity: sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==} engines: {node: '>= 6'} - diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - - diffie-hellman@5.0.3: - resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} - - digest-header@1.1.0: - resolution: {integrity: sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg==} - engines: {node: '>= 8.0.0'} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -5633,10 +4850,6 @@ packages: dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - domain-browser@1.2.0: - resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==} - engines: {node: '>=0.4', npm: '>=1.2'} - domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} @@ -5658,10 +4871,6 @@ packages: domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - dont-sniff-mimetype@1.1.0: - resolution: {integrity: sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug==} - engines: {node: '>=4.0.0'} - dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} @@ -5673,17 +4882,14 @@ packages: resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} engines: {node: '>=10'} - dotenv-expand@5.1.0: - resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} dotenv@17.2.3: resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} engines: {node: '>=12'} - dotenv@8.2.0: - resolution: {integrity: sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==} - engines: {node: '>=8'} - dotenv@8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} @@ -5701,18 +4907,12 @@ packages: duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - duplexify@3.7.1: - resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} ecc-jsbn@0.1.2: resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} - ecdsa-sig-formatter@1.0.11: - resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - echarts-for-react@3.0.2: resolution: {integrity: sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==} peerDependencies: @@ -5736,8 +4936,8 @@ packages: electron-to-chromium@1.5.27: resolution: {integrity: sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==} - elliptic@6.5.7: - resolution: {integrity: sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} emoji-regex@7.0.3: resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} @@ -5772,14 +4972,6 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - end-or-error@1.0.1: - resolution: {integrity: sha512-OclLMSug+k2A0JKuf494im25ANRBVW8qsjmwbgX7lQ8P82H21PQ1PWkoYwb9y5yMBS69BPlwtzdIFClo3+7kOQ==} - engines: {node: '>= 0.11.14'} - - enhanced-resolve@4.5.0: - resolution: {integrity: sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==} - engines: {node: '>=6.9.0'} - enhanced-resolve@5.17.1: resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} @@ -5870,23 +5062,9 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} - engines: {node: '>=0.10'} - - es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} - - es6-weak-map@2.0.3: - resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} - esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -5925,11 +5103,6 @@ packages: engines: {node: '>=4.0'} hasBin: true - escodegen@2.1.0: - resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} - engines: {node: '>=6.0'} - hasBin: true - eslint-config-next@12.1.0: resolution: {integrity: sha512-tBhuUgoDITcdcM7xFvensi9I5WTI4dnvH4ETGRg1U8ZKpXrZsWQFdOKIDzR3RLP5HR3xXrLviaMM4c3zVoE/pA==} peerDependencies: @@ -6021,10 +5194,6 @@ packages: peerDependencies: eslint: '>=5.0.0' - eslint-scope@4.0.3: - resolution: {integrity: sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==} - engines: {node: '>=4.0.0'} - eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -6061,12 +5230,6 @@ packages: deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - eslint@9.36.0: resolution: {integrity: sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -6077,10 +5240,6 @@ packages: jiti: optional: true - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} - espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -6153,22 +5312,10 @@ packages: resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} engines: {node: '>= 0.8'} - event-emitter@0.3.5: - resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} - event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} - eventemitter2@0.4.14: - resolution: {integrity: sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==} - - eventemitter2@5.0.1: - resolution: {integrity: sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==} - - eventemitter2@6.4.9: - resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} - eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -6176,9 +5323,6 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - exec-sh@0.3.6: resolution: {integrity: sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==} @@ -6205,13 +5349,6 @@ packages: exponential-backoff@3.1.1: resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} - express-rate-limit@5.5.1: - resolution: {integrity: sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==} - - express@4.17.1: - resolution: {integrity: sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==} - engines: {node: '>= 0.10.0'} - express@4.21.2: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} @@ -6220,9 +5357,6 @@ packages: resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} engines: {node: '>= 18'} - ext@1.7.0: - resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} - extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -6234,24 +5368,14 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - extglob@2.0.4: resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} engines: {node: '>=0.10.0'} - extrareqp2@1.0.0: - resolution: {integrity: sha512-Gum0g1QYb6wpPJCVypWP3bbIuaibcFiJcpuPM10YSXp/tzqi84x9PJageob+eN4xVRIOto4wjSGNLyMD54D2xA==} - extsprintf@1.3.0: resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} engines: {'0': node >=0.6.0} - fast-deep-equal@2.0.1: - resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -6262,12 +5386,6 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} - fast-json-patch@3.1.1: - resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==} - - fast-json-stable-stringify@2.0.0: - resolution: {integrity: sha512-eIgZvM9C3P05kg0qxfqaVU6Tma4QedCPIByQOcemV0vju8ot3cS2DpHi4m2G2JvbSMI152rjfLX0p1pkSdyPlQ==} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -6300,13 +5418,6 @@ packages: fbjs@0.8.18: resolution: {integrity: sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==} - fclone@1.0.11: - resolution: {integrity: sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw==} - - feature-policy@0.3.0: - resolution: {integrity: sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==} - engines: {node: '>=4.0.0'} - feed@4.2.2: resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==} engines: {node: '>=0.4.0'} @@ -6315,14 +5426,6 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} - figgy-pudding@3.5.2: - resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} - deprecated: This module is no longer supported. - - figures@2.0.0: - resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} - engines: {node: '>=4'} - figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -6425,9 +5528,6 @@ packages: resolution: {integrity: sha512-WHRizzSrWFTcKo7cVcbP3wzZVhzsoYxoWqbnH4z+JXGqrjVmnsld6kBZWVlB200PwD5ur8r+HV3KUDxv3cHhOQ==} engines: {node: '>=0.4.0'} - flush-write-stream@1.1.1: - resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} - follow-redirects@1.15.9: resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} @@ -6437,10 +5537,6 @@ packages: debug: optional: true - follow-redirects@1.5.10: - resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==} - engines: {node: '>=4.0'} - for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -6451,20 +5547,6 @@ packages: forever-agent@0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - fork-ts-checker-webpack-plugin@4.0.3: - resolution: {integrity: sha512-5hGeMYKg817Hp6rvdc2EOS/T/Cq0JW9LLJDZtVUPlNIojIuP7YbOAdrHEk4Irw1097YQUr56kWIiYhqNPzfNzQ==} - engines: {node: '>=6.11.5', yarn: '>=1.0.0'} - peerDependencies: - eslint: '>= 6' - typescript: '>= 2.7' - vue-template-compiler: '*' - webpack: '>= 4' - peerDependenciesMeta: - eslint: - optional: true - vue-template-compiler: - optional: true - fork-ts-checker-webpack-plugin@6.5.3: resolution: {integrity: sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==} engines: {node: '>=10', yarn: '>=1.0.0'} @@ -6487,14 +5569,6 @@ packages: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} - form-data@2.5.1: - resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} - engines: {node: '>= 0.12'} - - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - form-data@4.0.4: resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} @@ -6507,13 +5581,6 @@ packages: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} - formidable@1.2.6: - resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==} - deprecated: 'Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau' - - formstream@1.5.1: - resolution: {integrity: sha512-q7ORzFqotpwn3Y/GBK2lK7PjtZZwJHz9QE9Phv8zb5IrL9ftGLyi2zjGURON3voK8TaZ+mqJKERYN4lrHYTkUQ==} - forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -6533,9 +5600,6 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} - from2@2.3.0: - resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} - fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -6555,10 +5619,6 @@ packages: fs-monkey@1.0.6: resolution: {integrity: sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==} - fs-write-stream-atomic@1.0.10: - resolution: {integrity: sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==} - deprecated: This package is no longer supported. - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -6597,6 +5657,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -6617,9 +5681,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-ready@1.0.0: - resolution: {integrity: sha512-mFXCZPJIlcYcth+N8267+mghfYN9h3EhsDa6JSnbA3Wrhh/XFpuowviFcsDeYZtKspQyWyJqfs4O6P8CHeTwzw==} - get-stream@4.1.0: resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} engines: {node: '>=6'} @@ -6632,10 +5693,6 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - get-uri@6.0.5: - resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} - engines: {node: '>= 14'} - get-value@2.0.6: resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} engines: {node: '>=0.10.0'} @@ -6643,14 +5700,6 @@ packages: getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} - git-node-fs@1.0.0: - resolution: {integrity: sha512-bLQypt14llVXBg0S0u8q8HmU7g9p3ysH+NvVlae5vILuUvs759665HvmR5+wb04KjHyjFcDRxdYb4kyNnluMUQ==} - peerDependencies: - js-git: ^0.7.8 - peerDependenciesMeta: - js-git: - optional: true - git-raw-commits@3.0.0: resolution: {integrity: sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==} engines: {node: '>=14'} @@ -6665,9 +5714,6 @@ packages: engines: {node: '>=14'} hasBin: true - git-sha1@0.1.2: - resolution: {integrity: sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg==} - gitconfiglocal@1.0.0: resolution: {integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==} @@ -6677,9 +5723,6 @@ packages: github-slugger@1.5.0: resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} - glob-parent@3.1.0: - resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -6791,10 +5834,6 @@ packages: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} - has-ansi@2.0.0: - resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} - engines: {node: '>=0.10.0'} - has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -6845,17 +5884,6 @@ packages: resolution: {integrity: sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hash-base@3.0.4: - resolution: {integrity: sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==} - engines: {node: '>=4'} - - hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} - - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -6888,18 +5916,6 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - helmet-crossdomain@0.4.0: - resolution: {integrity: sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==} - engines: {node: '>=4.0.0'} - - helmet-csp@2.10.0: - resolution: {integrity: sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w==} - engines: {node: '>=4.0.0'} - - helmet@3.23.3: - resolution: {integrity: sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA==} - engines: {node: '>=4.0.0'} - hermes-estree@0.22.0: resolution: {integrity: sha512-FLBt5X9OfA8BERUdc6aZS36Xz3rRuB0Y/mfocSADWEJfomc1xfene33GdyAmtTkKTBXTN/EgAy+rjTKkkZJHlw==} @@ -6912,13 +5928,6 @@ packages: hermes-parser@0.23.1: resolution: {integrity: sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==} - hide-powered-by@1.1.0: - resolution: {integrity: sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==} - engines: {node: '>=4.0.0'} - - highlight.js@10.7.3: - resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - highlight.js@9.18.5: resolution: {integrity: sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==} deprecated: Support has ended for 9.x series. Upgrade to @latest @@ -6926,9 +5935,6 @@ packages: history@4.10.1: resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==} - hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} @@ -6942,13 +5948,6 @@ packages: hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} - hpkp@2.0.0: - resolution: {integrity: sha512-TaZpC6cO/k3DFsjfzz1LnOobbVSq+J+7WpJxrVtN4L+8+BPQj8iBDRB2Dx49613N+e7/+ZSQ9ra+xZm7Blf4wg==} - - hsts@2.2.0: - resolution: {integrity: sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==} - engines: {node: '>=4.0.0'} - html-encoding-sniffer@1.0.2: resolution: {integrity: sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==} @@ -7003,14 +6002,6 @@ packages: resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} engines: {node: '>= 0.6'} - http-errors@1.7.2: - resolution: {integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==} - engines: {node: '>= 0.6'} - - http-errors@1.7.3: - resolution: {integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==} - engines: {node: '>= 0.6'} - http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -7018,10 +6009,6 @@ packages: http-parser-js@0.5.9: resolution: {integrity: sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==} - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - http-proxy-middleware@2.0.7: resolution: {integrity: sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==} engines: {node: '>=12.0.0'} @@ -7046,20 +6033,10 @@ packages: resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} engines: {node: '>=10.19.0'} - https-browserify@1.0.0: - resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - husky@7.0.4: resolution: {integrity: sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==} engines: {node: '>=12'} @@ -7077,6 +6054,10 @@ packages: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + icss-utils@5.1.0: resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} @@ -7089,9 +6070,6 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - iferr@0.1.5: - resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -7141,9 +6119,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - infer-owner@1.0.4: - resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} - infima@0.2.0-alpha.45: resolution: {integrity: sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==} engines: {node: '>=12'} @@ -7168,14 +6143,6 @@ packages: inline-style-parser@0.2.4: resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} - inquirer@6.2.1: - resolution: {integrity: sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==} - engines: {node: '>=6.0.0'} - - inquirer@7.0.4: - resolution: {integrity: sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==} - engines: {node: '>=6.0.0'} - inquirer@8.2.7: resolution: {integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==} engines: {node: '>=12.0.0'} @@ -7194,10 +6161,6 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ip-address@10.0.1: - resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} - engines: {node: '>= 12'} - ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -7234,10 +6197,6 @@ packages: is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - is-binary-path@1.0.1: - resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} - engines: {node: '>=0.10.0'} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -7261,9 +6220,6 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true - is-class-hotfix@0.0.6: - resolution: {integrity: sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==} - is-core-module@2.15.1: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} @@ -7335,10 +6291,6 @@ packages: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} - is-glob@3.1.0: - resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} - engines: {node: '>=0.10.0'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -7354,6 +6306,10 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -7421,9 +6377,6 @@ packages: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} - is-promise@2.2.2: - resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -7470,9 +6423,6 @@ packages: resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==} engines: {node: '>=0.10.0'} - is-type-of@1.4.0: - resolution: {integrity: sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==} - is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} @@ -7484,6 +6434,14 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -7560,10 +6518,6 @@ packages: resolution: {integrity: sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==} engines: {node: '>=6'} - iterare@1.2.0: - resolution: {integrity: sha512-RxMV9p/UzdK0Iplnd8mVgRvNdXlsTOiuDrqMRnDi3wIhbT+JP4xDquAX9ay13R3CH72NBzQ91KWe0+C168QAyQ==} - engines: {node: '>=6'} - iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} @@ -7740,15 +6694,6 @@ packages: joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} - js-base64@2.6.4: - resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==} - - js-git@0.7.8: - resolution: {integrity: sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA==} - - js-tokens@3.0.2: - resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -7847,31 +6792,14 @@ packages: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} - jsonwebtoken@8.5.1: - resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==} - engines: {node: '>=4', npm: '>=1.4.28'} - - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} - engines: {node: '>=12', npm: '>=6'} - jsprim@1.4.2: resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} engines: {node: '>=0.6.0'} - jstoxml@2.2.9: - resolution: {integrity: sha512-OYWlK0j+roh+eyaMROlNbS5cd5R25Y+IUpdl7cNdB8HNrkgwQzIS7L9MegxOiWNBj9dQhA/yAxiMwCC5mwNoBw==} - jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} - jwa@1.4.1: - resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} - - jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -7912,10 +6840,6 @@ packages: launch-editor@2.10.0: resolution: {integrity: sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==} - lazy@1.0.11: - resolution: {integrity: sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==} - engines: {node: '>=0.2.0'} - left-pad@1.3.0: resolution: {integrity: sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==} deprecated: use String.prototype.padStart() @@ -7948,9 +6872,6 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libphonenumber-js@1.11.8: - resolution: {integrity: sha512-0fv/YKpJBAgXKy0kaS3fnqoUVN8901vUYAKIGD/MWZaDfhJt1nZjPL3ZzdZBt/G8G8Hw2J1xOIrXWdNHFHPAvg==} - lighthouse-logger@1.4.2: resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} @@ -7983,18 +6904,10 @@ packages: resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} engines: {node: '>=4'} - loader-runner@2.4.0: - resolution: {integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==} - engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} - loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} - loader-utils@1.4.2: - resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} - engines: {node: '>=4.0.0'} - loader-utils@2.0.4: resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} engines: {node: '>=8.9.0'} @@ -8032,55 +6945,21 @@ packages: lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. - - lodash.has@4.5.2: - resolution: {integrity: sha512-rnYUdIo6xRCJnQmbVFEwcxF144erlD+M3YcJUVesflU9paQaE8p+fJDcIQrlMYbxoANFL+AB9hZrzSBBk5PL+g==} - - lodash.includes@4.3.0: - resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} - - lodash.isboolean@3.0.3: - resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - - lodash.isinteger@4.0.4: - resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} - lodash.ismatch@4.4.0: resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} - lodash.isnumber@3.0.3: - resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} - - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - - lodash.isstring@4.0.1: - resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.once@4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - - lodash.set@4.3.2: - resolution: {integrity: sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==} - lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} lodash.throttle@4.1.1: resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} - lodash.toarray@4.4.0: - resolution: {integrity: sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==} - lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} @@ -8090,22 +6969,18 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - log-symbols@3.0.0: - resolution: {integrity: sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==} - engines: {node: '>=8'} - log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + log-update@4.0.0: resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} engines: {node: '>=10'} - log4js@6.9.1: - resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==} - engines: {node: '>=8.0'} - logkitty@0.7.1: resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} hasBin: true @@ -8113,6 +6988,9 @@ packages: long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -8138,21 +7016,18 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} - lru-queue@0.1.0: - resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} - lru.min@1.1.1: resolution: {integrity: sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==} engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + lru.min@1.1.4: + resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true - macos-release@2.5.1: - resolution: {integrity: sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==} - engines: {node: '>=6'} - magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} @@ -8170,9 +7045,6 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - mamacro@0.0.3: - resolution: {integrity: sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==} - map-cache@0.2.2: resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} engines: {node: '>=0.10.0'} @@ -8199,11 +7071,6 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - marked@0.8.2: - resolution: {integrity: sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==} - engines: {node: '>= 8.16.2'} - hasBin: true - marky@1.2.5: resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} @@ -8211,9 +7078,6 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - mdast-util-directive@3.1.0: resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} @@ -8289,24 +7153,10 @@ packages: memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - memoizee@0.4.17: - resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} - engines: {node: '>=0.12'} - - memory-fs@0.4.1: - resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} - - memory-fs@0.5.0: - resolution: {integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==} - engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} - meow@8.1.2: resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} engines: {node: '>=10'} - merge-descriptors@1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} - merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -8383,9 +7233,6 @@ packages: engines: {node: '>=18'} hasBin: true - microevent.ts@0.1.1: - resolution: {integrity: sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==} - micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -8517,10 +7364,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - miller-rabin@4.0.1: - resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} - hasBin: true - mime-db@1.33.0: resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} engines: {node: '>= 0.6'} @@ -8559,14 +7402,14 @@ packages: engines: {node: '>=4.0.0'} hasBin: true - mimic-fn@1.2.0: - resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} - engines: {node: '>=4'} - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} @@ -8588,9 +7431,6 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -8602,16 +7442,9 @@ packages: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} engines: {node: '>= 6'} - minimist@1.2.0: - resolution: {integrity: sha512-7Wl+Jz+IGWuSdgsQEJ4JunV0si/iMhg42MnQQG6h1R6TNeVenp4U9x5CC5v/gYqz/fENLQITAWXidNtVL0NNbw==} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - mississippi@3.0.0: - resolution: {integrity: sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==} - engines: {node: '>=4.0.0'} - mixin-deep@1.3.2: resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} engines: {node: '>=0.10.0'} @@ -8629,16 +7462,9 @@ packages: resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} engines: {node: '>=0.10.0'} - module-details-from-path@1.0.4: - resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} - monaco-editor@0.52.0: resolution: {integrity: sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==} - move-concurrently@1.0.1: - resolution: {integrity: sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==} - deprecated: This package is no longer supported. - mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -8646,24 +7472,13 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.1: - resolution: {integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - multer@1.4.2: - resolution: {integrity: sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==} - engines: {node: '>= 0.10.0'} - deprecated: Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10. - multicast-dns@7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} hasBin: true - mute-stream@0.0.7: - resolution: {integrity: sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==} - mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} @@ -8671,13 +7486,20 @@ packages: resolution: {integrity: sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==} engines: {node: '>= 8.0'} - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + mysql2@3.22.3: + resolution: {integrity: sha512-uWWxvZSRvRhtBdh2CdcuK83YcOfPdmEeEYB069bAmPnV93QApDGVPuvCQOLjlh7tYHEWdgQPrn6kosDxHBVLkA==} + engines: {node: '>= 8.0'} + peerDependencies: + '@types/node': '>= 8' named-placeholders@1.1.3: resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} engines: {node: '>=12.0.0'} + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} + nan@2.20.0: resolution: {integrity: sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==} @@ -8701,11 +7523,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - needle@2.4.0: - resolution: {integrity: sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==} - engines: {node: '>= 4.4.x'} - hasBin: true - needle@3.3.1: resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} engines: {node: '>= 4.4.x'} @@ -8722,10 +7539,6 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - netmask@2.0.2: - resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} - engines: {node: '>= 0.4.0'} - next-compose-plugins@2.2.1: resolution: {integrity: sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg==} @@ -8764,12 +7577,6 @@ packages: peerDependencies: next: '*' - next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - - next-transpile-modules@6.4.1: - resolution: {integrity: sha512-trUMkm+bkjMci7mXSOQkF3apEY18K6YuaeG4mkLwiQtDdsmdVXzopNyZGc2nJq8OwHYDgJr1QlsBQuQb/2vXlw==} - next-with-less@2.0.5: resolution: {integrity: sha512-1MJDcgFOPucFPCMXV7rTqcWiLI2nLSBi8bA6msvkiNLhYyZMXaFl4MkyYf7eOEUUEtA/c5eD0grPhbcDkrKqPQ==} peerDependencies: @@ -8801,10 +7608,6 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - nocache@2.1.0: - resolution: {integrity: sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==} - engines: {node: '>=4.0.0'} - nocache@3.0.4: resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} engines: {node: '>=12.0.0'} @@ -8821,9 +7624,6 @@ packages: engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead - node-emoji@1.10.0: - resolution: {integrity: sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==} - node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -8855,20 +7655,9 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - node-hex@1.0.1: - resolution: {integrity: sha512-iwpZdvW6Umz12ICmu9IYPRxg0tOLGmU3Tq2tKetejCj3oZd7b2nUXwP3a7QA5M9glWy8wlPS1G3RwM/CdsUbdQ==} - engines: {node: '>=8.0.0'} - node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-ip2region@1.0.2: - resolution: {integrity: sha512-tH/A46cbCSeE+G0w8cwPeQDV3EdVp5D900VLgDbjhC4bH7SKVPBOarpjH1He6QvWFBOam48lIroKTAyVUPC3CA==} - engines: {node: '>=6.0.0'} - - node-libs-browser@2.2.1: - resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==} - node-notifier@5.4.5: resolution: {integrity: sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==} @@ -8885,13 +7674,6 @@ packages: resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} engines: {node: '>=0.12.0'} - nodemailer@6.9.15: - resolution: {integrity: sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ==} - engines: {node: '>=6.0.0'} - - noms@0.0.0: - resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} - normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -8926,17 +7708,9 @@ packages: nprogress@0.2.0: resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} - nssocket@0.6.0: - resolution: {integrity: sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==} - engines: {node: '>= 0.10.x'} - nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nuid@1.1.6: - resolution: {integrity: sha512-Eb3CPCupYscP1/S1FQcO5nxtu6l/F3k0MQ69h7f5osnsemVk5pkc8/5AyalVT+NCfra9M71U8POqF6EZa6IHvg==} - engines: {node: '>= 8.16.0'} - null-loader@4.0.1: resolution: {integrity: sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==} engines: {node: '>= 10.13.0'} @@ -8980,10 +7754,6 @@ packages: resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} engines: {node: '>=0.10.0'} - object-hash@2.0.3: - resolution: {integrity: sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==} - engines: {node: '>= 6'} - object-inspect@1.13.2: resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} @@ -9056,14 +7826,14 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - onetime@2.0.1: - resolution: {integrity: sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==} - engines: {node: '>=4'} - onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + open@6.4.0: resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} engines: {node: '>=8'} @@ -9080,9 +7850,6 @@ packages: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true - optional@0.1.4: - resolution: {integrity: sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==} - optionator@0.8.3: resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} engines: {node: '>= 0.8.0'} @@ -9091,34 +7858,13 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - ora@4.0.3: - resolution: {integrity: sha512-fnDebVFyz309A73cqCipVL1fBZewq4vwgSHfxh43vVy31mbyoQ8sCH3Oeaog/owYOs/lLlGVPCISQonTneg6Pg==} - engines: {node: '>=8'} - ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} - os-browserify@0.3.0: - resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} - - os-name@1.0.3: - resolution: {integrity: sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==} - engines: {node: '>=0.10.0'} - hasBin: true - - os-name@3.1.0: - resolution: {integrity: sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==} - engines: {node: '>=6'} - - os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - - osx-release@1.1.0: - resolution: {integrity: sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==} - engines: {node: '>=0.10.0'} - hasBin: true + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} p-cancelable@3.0.0: resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} @@ -9192,27 +7938,10 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - pac-proxy-agent@7.2.0: - resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} - engines: {node: '>= 14'} - - pac-resolver@7.0.1: - resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} - engines: {node: '>= 14'} - package-json@8.1.1: resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} engines: {node: '>=14.16'} - pako@0.2.9: - resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} - - pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - - parallel-transform@1.2.0: - resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==} - param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -9220,10 +7949,6 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-asn1@5.1.7: - resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} - engines: {node: '>= 0.10'} - parse-entities@4.0.2: resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} @@ -9242,21 +7967,12 @@ packages: parse-numeric-range@1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} - parse5-htmlparser2-tree-adapter@6.0.1: - resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} - parse5-htmlparser2-tree-adapter@7.1.0: resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} parse5@4.0.0: resolution: {integrity: sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==} - parse5@5.1.1: - resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} - - parse5@6.0.1: - resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - parse5@7.2.1: resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} @@ -9271,23 +7987,6 @@ packages: resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} engines: {node: '>=0.10.0'} - passport-jwt@4.0.1: - resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==} - - passport-strategy@1.0.0: - resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==} - engines: {node: '>= 0.4.0'} - - passport@0.4.1: - resolution: {integrity: sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==} - engines: {node: '>= 0.4.0'} - - path-browserify@0.0.1: - resolution: {integrity: sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==} - - path-dirname@1.0.2: - resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} - path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -9321,18 +8020,12 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - path-to-regexp@0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - path-to-regexp@1.9.0: resolution: {integrity: sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==} path-to-regexp@2.4.0: resolution: {integrity: sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==} - path-to-regexp@3.2.0: - resolution: {integrity: sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==} - path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} @@ -9347,16 +8040,6 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pause-stream@0.0.11: - resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} - - pause@0.0.1: - resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} - - pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} - performance-now@0.2.0: resolution: {integrity: sha512-YHk5ez1hmMR5LOkb9iJkLKqoBlL7WD5M8ljC75ZfzXriuBIVNuecaXuU7e+hOwyqf24Wxhh7Vxgt7Hnw9288Tg==} @@ -9375,14 +8058,6 @@ packages: engines: {node: '>=0.10'} hasBin: true - pidusage@2.0.21: - resolution: {integrity: sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==} - engines: {node: '>=8'} - - pidusage@3.0.2: - resolution: {integrity: sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==} - engines: {node: '>=10'} - pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -9423,32 +8098,6 @@ packages: resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} engines: {node: '>=8'} - platform@1.3.6: - resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} - - pm2-axon-rpc@0.7.1: - resolution: {integrity: sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw==} - engines: {node: '>=5'} - - pm2-axon@4.0.1: - resolution: {integrity: sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg==} - engines: {node: '>=5'} - - pm2-deploy@1.0.2: - resolution: {integrity: sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==} - engines: {node: '>=4.0.0'} - - pm2-multimeter@0.1.2: - resolution: {integrity: sha512-S+wT6XfyKfd7SJIBqRgOctGxaBzUOmVQzTAS+cg04TsEUObJVreha7lvCfX8zzGVr871XwCSnHUU7DQQ5xEsfA==} - - pm2-sysmonit@1.2.8: - resolution: {integrity: sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==} - - pm2@5.4.3: - resolution: {integrity: sha512-4/I1htIHzZk1Y67UgOCo4F1cJtas1kSds31N8zN0PybO230id1nigyjGuGFzUnGmUFPmrJ0On22fO1ChFlp7VQ==} - engines: {node: '>=12.0.0'} - hasBin: true - pn@1.1.0: resolution: {integrity: sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==} @@ -9870,11 +8519,6 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} - prettier@1.19.1: - resolution: {integrity: sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==} - engines: {node: '>=4'} - hasBin: true - prettier@2.7.1: resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} engines: {node: '>=10.13.0'} @@ -9924,27 +8568,12 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - - promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true - promise@7.3.1: resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} promise@8.3.0: resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} - promptly@2.2.0: - resolution: {integrity: sha512-aC9j+BZsRSSzEsXBNBwDnAxujdx19HycZoKgRgzWnS8eOHg1asuf9heuLprfbe739zY3IdUQx+Egv6Jn135WHA==} - prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -9965,10 +8594,6 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - proxy-agent@6.3.1: - resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==} - engines: {node: '>= 14'} - proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -9978,21 +8603,9 @@ packages: psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - public-encrypt@4.0.3: - resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} - - pump@2.0.1: - resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} - pump@3.0.2: resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - pumpify@1.5.1: - resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} - - punycode@1.4.1: - resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -10017,14 +8630,6 @@ packages: resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} engines: {node: '>=0.6'} - qs@6.7.0: - resolution: {integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==} - engines: {node: '>=0.6'} - - querystring-es3@0.2.1: - resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} - engines: {node: '>=0.4.x'} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -10045,9 +8650,6 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - randomfill@1.0.4: - resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} - range-parser@1.2.0: resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} engines: {node: '>= 0.6'} @@ -10056,10 +8658,6 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - raw-body@2.4.0: - resolution: {integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==} - engines: {node: '>= 0.8'} - raw-body@2.5.2: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} @@ -10537,16 +9135,6 @@ packages: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} engines: {node: '>=8'} - read@1.0.7: - resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} - engines: {node: '>=0.8'} - - readable-stream@1.0.34: - resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} - - readable-stream@1.1.14: - resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -10554,10 +9142,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readdirp@2.2.1: - resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} - engines: {node: '>=0.10'} - readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -10604,13 +9188,6 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} - referrer-policy@1.2.0: - resolution: {integrity: sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==} - engines: {node: '>=4.0.0'} - - reflect-metadata@0.1.14: - resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} - reflect.getprototypeof@1.0.6: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} @@ -10751,10 +9328,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-in-the-middle@5.2.0: - resolution: {integrity: sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==} - engines: {node: '>=6'} - require-like@0.1.2: resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} @@ -10804,14 +9377,14 @@ packages: resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} engines: {node: '>=14.16'} - restore-cursor@2.0.0: - resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} - engines: {node: '>=4'} - restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + ret@0.1.15: resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} engines: {node: '>=0.12'} @@ -10837,19 +9410,11 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@3.0.1: - resolution: {integrity: sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - rollup-plugin-terser@7.0.2: resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser @@ -10881,20 +9446,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - run-queue@1.0.3: - resolution: {integrity: sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==} - - run-series@1.1.9: - resolution: {integrity: sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==} - - rxjs@6.3.3: - resolution: {integrity: sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==} - engines: {npm: '>=2.0.0'} - - rxjs@6.6.7: - resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} - engines: {npm: '>=2.0.0'} - rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} @@ -10972,10 +9523,6 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} - schema-utils@1.0.0: - resolution: {integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==} - engines: {node: '>= 4'} - schema-utils@2.7.0: resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==} engines: {node: '>= 8.9.0'} @@ -10995,9 +9542,6 @@ packages: scroll-into-view-if-needed@3.1.0: resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} - sdk-base@2.0.1: - resolution: {integrity: sha512-eeG26wRwhtwYuKGCDM3LixCaxY27Pa/5lK4rLKhQa7HBjJ3U3Y+f81MMZQRsDw/8SC2Dao/83yJTXJ8aULuN8Q==} - search-insights@2.17.3: resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} @@ -11005,10 +9549,6 @@ packages: resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} engines: {node: '>=4'} - segment@0.1.3: - resolution: {integrity: sha512-4Kjk38q0ykMIK5a+uo2MjTM2EECJaLLQOkdptceiYHTFZU/iciWXiFiGTG8Or/cfO2RqjlLw/s6rqijxAFSKFQ==} - engines: {node: '>= 0.4.0'} - select-hose@2.0.0: resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} @@ -11028,20 +9568,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true - send@0.17.1: - resolution: {integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==} - engines: {node: '>= 0.8.0'} - send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} @@ -11070,10 +9601,6 @@ packages: resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} engines: {node: '>= 0.8.0'} - serve-static@1.14.1: - resolution: {integrity: sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==} - engines: {node: '>= 0.8.0'} - serve-static@1.16.2: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} @@ -11103,16 +9630,9 @@ packages: setprototypeof@1.1.0: resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} - setprototypeof@1.1.1: - resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true - shallow-clone@3.0.1: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} @@ -11147,9 +9667,6 @@ packages: shellwords@0.1.1: resolution: {integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==} - shimmer@1.2.1: - resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} - should-equal@2.0.0: resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==} @@ -11195,6 +9712,10 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + sirv@2.0.4: resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} engines: {node: '>= 10'} @@ -11242,10 +9763,6 @@ packages: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} @@ -11264,14 +9781,6 @@ packages: sockjs@0.3.24: resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} - socks-proxy-agent@8.0.5: - resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} - engines: {node: '>= 14'} - - socks@2.8.7: - resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - sort-css-media-queries@2.2.0: resolution: {integrity: sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==} engines: {node: '>= 6.3.0'} @@ -11302,10 +9811,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.3: - resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==} - engines: {node: '>= 8'} - source-map@0.7.4: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} @@ -11357,8 +9862,9 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - sprintf-js@1.1.2: - resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} + sql-escaper@1.3.3: + resolution: {integrity: sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==} + engines: {bun: '>=1.0.0', deno: '>=2.0.0', node: '>=12.0.0'} sqlstring@2.3.3: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} @@ -11373,9 +9879,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - ssri@6.0.2: - resolution: {integrity: sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==} - stack-utils@1.0.5: resolution: {integrity: sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==} engines: {node: '>=8'} @@ -11409,6 +9912,10 @@ packages: std-env@3.8.1: resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + stealthy-require@1.1.1: resolution: {integrity: sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==} engines: {node: '>=0.10.0'} @@ -11417,33 +9924,6 @@ packages: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} - stream-browserify@2.0.2: - resolution: {integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==} - - stream-each@1.2.3: - resolution: {integrity: sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==} - - stream-http@2.8.2: - resolution: {integrity: sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==} - - stream-http@2.8.3: - resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==} - - stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} - - stream-wormhole@1.1.0: - resolution: {integrity: sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==} - engines: {node: '>=4.0.0'} - - streamroller@3.1.5: - resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} - engines: {node: '>=8.0'} - - streamsearch@0.1.2: - resolution: {integrity: sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==} - engines: {node: '>=0.8.0'} - string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -11455,10 +9935,6 @@ packages: resolution: {integrity: sha512-Qka42GGrS8Mm3SZ+7cH8UXiIWI867/b/Z/feQSpQx/rbfB8UGknGEZVaUQMOUVj+soY6NpWAxily63HI1OckVQ==} engines: {node: '>=4'} - string-width@2.1.1: - resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} - engines: {node: '>=4'} - string-width@3.1.0: resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} engines: {node: '>=6'} @@ -11471,6 +9947,10 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + string.prototype.includes@2.0.0: resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} @@ -11492,9 +9972,6 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} - string_decoder@0.10.31: - resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} - string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -11508,10 +9985,6 @@ packages: resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} engines: {node: '>=4'} - strip-ansi@3.0.1: - resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} - engines: {node: '>=0.10.0'} - strip-ansi@4.0.0: resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} engines: {node: '>=4'} @@ -11595,20 +10068,6 @@ packages: resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - superagent@3.8.3: - resolution: {integrity: sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==} - engines: {node: '>= 4.0'} - deprecated: Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net - - supertest@4.0.2: - resolution: {integrity: sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ==} - engines: {node: '>=6.0.0'} - deprecated: Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net - - supports-color@2.0.0: - resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} - engines: {node: '>=0.8.0'} - supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -11649,22 +10108,10 @@ packages: swagger-schema-official@2.0.0-bab6bed: resolution: {integrity: sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==} - swagger-themes@1.4.3: - resolution: {integrity: sha512-1G0CqJC1IBbNxkAOyJoREd9hfwXH1R6+3GOFxLhQho2w2i+AbaJqkF4mTJhkce4yhaEMUXvv4KKu1YO/qpe6nQ==} - swagger-typescript-api@12.0.4: resolution: {integrity: sha512-04ZxlJzu3g15TupfPhS0Yk0jzV/MM23WU4uuOl2vSi4yHrxEwnkIsoBkP084ec61q4vr2FHcI3DKxC+Mt1u10Q==} hasBin: true - swagger-ui-dist@5.17.14: - resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==} - - swagger-ui-express@4.6.3: - resolution: {integrity: sha512-CDje4PndhTD2HkgyKH3pab+LKspDeB/NhPN2OF1j+piYIamQqBYwAXWESOT1Yju2xFg51bRW9sUng2WxDjzArw==} - engines: {node: '>= v0.10.32'} - peerDependencies: - express: '>=4.0.0 || >=5.0.0-beta' - swagger2openapi@7.0.8: resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==} hasBin: true @@ -11674,19 +10121,9 @@ packages: peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 - symbol-observable@1.2.0: - resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} - engines: {node: '>=0.10.0'} - symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - systeminformation@5.27.10: - resolution: {integrity: sha512-jkeOerLSwLZqJrPHCYltlKHu0PisdepIuS4GwjFFtgQUG/5AQPVZekkECuULqdP0cgrrIHW8Nl8J7WQXo5ypEg==} - engines: {node: '>=8.0.0'} - os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] - hasBin: true - tapable@1.1.3: resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} engines: {node: '>=6'} @@ -11711,12 +10148,6 @@ packages: resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==} engines: {node: '>=10'} - terser-webpack-plugin@1.4.6: - resolution: {integrity: sha512-2lBVf/VMVIddjSn3GqbT90GvIJ/eYXJkt8cTzU7NbjKqK8fwv18Ftr4PlbF46b/e88743iZFL5Dtr/rC4hjIeA==} - engines: {node: '>= 6.9.0'} - peerDependencies: - webpack: ^4.0.0 - terser-webpack-plugin@5.3.10: resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -11749,11 +10180,6 @@ packages: uglify-js: optional: true - terser@4.8.1: - resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==} - engines: {node: '>=6.0.0'} - hasBin: true - terser@5.33.0: resolution: {integrity: sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==} engines: {node: '>=10'} @@ -11770,13 +10196,6 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - three@0.168.0: resolution: {integrity: sha512-6m6jXtDwMJEK/GGMbAOTSAmxNdzKvvBzgd7q8bE/7Tr6m7PaBh5kKLrN7faWtlglXbzj7sVba48Idwx+NRsZXw==} @@ -11799,30 +10218,15 @@ packages: thunky@1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} - timers-browserify@2.0.12: - resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} - engines: {node: '>=0.6.0'} - - timers-ext@0.1.8: - resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} - engines: {node: '>=0.12'} - tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} tiny-warning@1.0.3: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - to-arraybuffer@1.0.1: - resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} - to-object-path@0.3.0: resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} engines: {node: '>=0.10.0'} @@ -11842,10 +10246,6 @@ packages: toggle-selection@1.0.6: resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} - toidentifier@1.0.0: - resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==} - engines: {node: '>=0.6'} - toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -11885,80 +10285,33 @@ packages: peerDependencies: jest: '>=24 <25' - ts-loader@6.2.2: - resolution: {integrity: sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ==} - engines: {node: '>=8.6'} - peerDependencies: - typescript: '*' - - ts-node@8.10.2: - resolution: {integrity: sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==} - engines: {node: '>=6.0.0'} - hasBin: true - peerDependencies: - typescript: '>=2.7' - - tsconfig-paths-webpack-plugin@3.2.0: - resolution: {integrity: sha512-S/gOOPOkV8rIL4LurZ1vUdYCVgo15iX9ZMJ6wx6w2OgcpT/G4wMyHB6WM+xheSqGMrWKuxFul+aXpCju3wmj/g==} - tsconfig-paths-webpack-plugin@3.5.2: resolution: {integrity: sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==} tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - tsconfig-paths@3.9.0: - resolution: {integrity: sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==} - - tslib@1.11.1: - resolution: {integrity: sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==} - tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@1.9.3: - resolution: {integrity: sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==} - tslib@2.3.0: resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} tslib@2.7.0: resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - tslint@5.20.1: - resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} - engines: {node: '>=4.8.0'} - hasBin: true - peerDependencies: - typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev' - - tsutils@2.29.0: - resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} - peerDependencies: - typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' - tsutils@3.21.0: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - tty-browserify@0.0.0: - resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==} - tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - tv4@1.3.0: - resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==} - engines: {node: '>= 0.8.0'} - tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - tx2@1.0.5: - resolution: {integrity: sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==} - type-check@0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} engines: {node: '>= 0.8.0'} @@ -12015,9 +10368,6 @@ packages: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} - type@2.7.3: - resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} - typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -12037,65 +10387,6 @@ packages: typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - - typeorm@0.2.45: - resolution: {integrity: sha512-c0rCO8VMJ3ER7JQ73xfk0zDnVv0WDjpsP6Q1m6CVKul7DB9iVdWLRjPzc8v2eaeBuomsbZ2+gTaYr8k1gm3bYA==} - hasBin: true - peerDependencies: - '@sap/hana-client': ^2.11.14 - better-sqlite3: ^7.1.2 - hdb-pool: ^0.1.6 - ioredis: ^4.28.3 - mongodb: ^3.6.0 - mssql: ^6.3.1 - mysql2: ^2.2.5 - oracledb: ^5.1.0 - pg: ^8.5.1 - pg-native: ^3.0.0 - pg-query-stream: ^4.0.0 - redis: ^3.1.1 - sql.js: ^1.4.0 - sqlite3: ^5.0.2 - typeorm-aurora-data-api-driver: ^2.0.0 - peerDependenciesMeta: - '@sap/hana-client': - optional: true - better-sqlite3: - optional: true - hdb-pool: - optional: true - ioredis: - optional: true - mongodb: - optional: true - mssql: - optional: true - mysql2: - optional: true - oracledb: - optional: true - pg: - optional: true - pg-native: - optional: true - pg-query-stream: - optional: true - redis: - optional: true - sql.js: - optional: true - sqlite3: - optional: true - typeorm-aurora-data-api-driver: - optional: true - - typescript@3.9.10: - resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==} - engines: {node: '>=4.2.0'} - hasBin: true - typescript@4.1.6: resolution: {integrity: sha512-pxnwLxeb/Z5SP80JDRzVjh58KsM6jZHRAOtTpS7sXLS4ogXNKC9ANxHHZqLLeVHZN35jCtI4JdmLLbLiC1kBow==} engines: {node: '>=4.2.0'} @@ -12131,10 +10422,6 @@ packages: undici-types@7.12.0: resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==} - unescape@1.0.1: - resolution: {integrity: sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==} - engines: {node: '>=0.10.0'} - unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -12162,12 +10449,6 @@ packages: resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} engines: {node: '>=0.10.0'} - unique-filename@1.1.1: - resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} - - unique-slug@2.0.2: - resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} - unique-string@2.0.0: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} @@ -12247,19 +10528,6 @@ packages: file-loader: optional: true - url@0.11.4: - resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} - engines: {node: '>= 0.4'} - - urllib@2.44.0: - resolution: {integrity: sha512-zRCJqdfYllRDA9bXUtx+vccyRqtJPKsw85f44zH7zPD28PIvjMqIgw9VwoTLV7xTBWZsbebUFVHU5ghQcWku2A==} - engines: {node: '>= 0.10.0'} - peerDependencies: - proxy-agent: ^5.0.0 - peerDependenciesMeta: - proxy-agent: - optional: true - use-intl@1.5.1: resolution: {integrity: sha512-GVqDf8NjeAxCrHGi3ZiofCmqUyX9gRnC9WNhwl5XLPLZ8b5g2zycGlRP1KxmKvQMu7l3asXZM7ALnj+Ls764iw==} engines: {node: '>=10'} @@ -12286,12 +10554,6 @@ packages: util.promisify@1.1.2: resolution: {integrity: sha512-PBdZ03m1kBnQ5cjjO0ZvJMJS+QsbyIcFwi4hY4U76OQsCO9JrOYjbCFgIF76ccFg9xnJo7ZHPkqyj1GqmdS7MA==} - util@0.10.4: - resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} - - util@0.11.1: - resolution: {integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==} - utila@0.4.0: resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} @@ -12299,10 +10561,6 @@ packages: resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} engines: {node: '>= 4'} - utility@1.18.0: - resolution: {integrity: sha512-PYxZDA+6QtvRvm//++aGdmKG/cI07jNwbROz0Ql+VzFV1+Z0Dy55NI4zZ7RHc9KKpBePNFwoErqIuqQv/cjiTA==} - engines: {node: '>= 0.12.0'} - utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -12312,14 +10570,6 @@ packages: deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. hasBin: true - uuid@7.0.1: - resolution: {integrity: sha512-yqjRXZzSJm9Dbl84H2VDHpM3zMjzSJQ+hn6C4zqd5ilW+7P4ZmLEEqwho9LjP+tGuZlF4xrHQXT0h9QZUS/pWA==} - hasBin: true - - uuid@7.0.3: - resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} - hasBin: true - uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -12330,10 +10580,6 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - validator@13.12.0: - resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} - engines: {node: '>= 0.10'} - value-equal@1.0.1: resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==} @@ -12357,16 +10603,9 @@ packages: viewerjs@1.11.6: resolution: {integrity: sha512-TlhdSp2oEOLFXvEp4psKaeTjR5zBjTRcM/sHUN8PkV1UWuY8HKC8n7GaVdW5Xqnwdr/F1OmzLik1QwDjI4w/nw==} - vizion@2.2.1: - resolution: {integrity: sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==} - engines: {node: '>=4.0'} - vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} - vm-browserify@1.1.2: - resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} - w3c-hr-time@1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} deprecated: Use your platform's native performance.now() and performance.timeOrigin. @@ -12377,12 +10616,6 @@ packages: warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} - watchpack-chokidar2@2.0.1: - resolution: {integrity: sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==} - - watchpack@1.7.5: - resolution: {integrity: sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==} - watchpack@2.4.2: resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} engines: {node: '>=10.13.0'} @@ -12438,9 +10671,6 @@ packages: resolution: {integrity: sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==} engines: {node: '>=18.0.0'} - webpack-node-externals@1.7.2: - resolution: {integrity: sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==} - webpack-sources@1.4.3: resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==} @@ -12448,19 +10678,6 @@ packages: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} - webpack@4.41.5: - resolution: {integrity: sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw==} - engines: {node: '>=6.11.5'} - hasBin: true - peerDependencies: - webpack-cli: '*' - webpack-command: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - webpack-command: - optional: true - webpack@5.98.0: resolution: {integrity: sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==} engines: {node: '>=10.13.0'} @@ -12537,14 +10754,6 @@ packages: wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} - win-release@1.1.1: - resolution: {integrity: sha512-iCRnKVvGxOQdsKhcQId2PXV1vV3J/sDPXKA4Oe9+Eti2nb2ESEsYHRYls/UjoUW3bIc5ZDO8dTH50A/5iVN+bw==} - engines: {node: '>=0.10.0'} - - windows-release@3.3.3: - resolution: {integrity: sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==} - engines: {node: '>=6'} - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -12609,12 +10818,6 @@ packages: workbox-window@6.6.0: resolution: {integrity: sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==} - worker-farm@1.7.0: - resolution: {integrity: sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==} - - worker-rpc@0.1.1: - resolution: {integrity: sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==} - wrap-ansi@5.1.0: resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} engines: {node: '>=6'} @@ -12689,10 +10892,6 @@ packages: utf-8-validate: optional: true - x-xss-protection@1.3.0: - resolution: {integrity: sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==} - engines: {node: '>=4.0.0'} - xdg-basedir@5.1.0: resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} engines: {node: '>=12'} @@ -12704,21 +10903,9 @@ packages: xml-name-validator@3.0.0: resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} - xml2js@0.4.23: - resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} - engines: {node: '>=4.0.0'} - - xml2js@0.6.2: - resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} - engines: {node: '>=4.0.0'} - xml@1.0.1: resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} - xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -12784,10 +10971,6 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -12799,12 +10982,6 @@ packages: zdog@1.1.3: resolution: {integrity: sha512-raRj6r0gPzopFm5XWBJZr/NuV4EEnT4iE+U3dp5FV5pCb588Gmm3zLIp/j9yqqcMiHH8VNQlerLTgOqL7krh6w==} - zen-observable-ts@1.1.0: - resolution: {integrity: sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==} - - zen-observable@0.8.15: - resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==} - zrender@5.6.1: resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==} @@ -12936,35 +11113,6 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@angular-devkit/core@7.3.8': - dependencies: - ajv: 6.9.1 - chokidar: 2.0.4 - fast-json-stable-stringify: 2.0.0 - rxjs: 6.3.3 - source-map: 0.7.3 - transitivePeerDependencies: - - supports-color - - '@angular-devkit/schematics-cli@0.13.8': - dependencies: - '@angular-devkit/core': 7.3.8 - '@angular-devkit/schematics': 7.3.8 - '@schematics/schematics': 0.13.8 - inquirer: 6.2.1 - minimist: 1.2.0 - rxjs: 6.3.3 - symbol-observable: 1.2.0 - transitivePeerDependencies: - - supports-color - - '@angular-devkit/schematics@7.3.8': - dependencies: - '@angular-devkit/core': 7.3.8 - rxjs: 6.3.3 - transitivePeerDependencies: - - supports-color - '@ant-design/colors@6.0.0': dependencies: '@ctrl/tinycolor': 3.6.1 @@ -16398,11 +14546,6 @@ snapshots: eslint: 8.11.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.0(eslint@9.36.0(jiti@1.21.7))': dependencies: eslint: 9.36.0(jiti@1.21.7) @@ -16440,20 +14583,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.4.3 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 @@ -16468,8 +14597,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} - '@eslint/js@9.36.0': {} '@eslint/object-schema@2.1.6': {} @@ -16481,6 +14608,18 @@ snapshots: '@exodus/schemasafe@1.3.0': {} + '@fecommunity/reactpress-cli@0.1.0(@types/node@24.5.2)': + dependencies: + chalk: 5.4.1 + commander: 13.1.0 + cross-spawn: 7.0.6 + dotenv: 16.6.1 + fs-extra: 11.3.0 + mysql2: 3.22.3(@types/node@24.5.2) + ora: 8.2.0 + transitivePeerDependencies: + - '@types/node' + '@formatjs/ecma402-abstract@1.11.4': dependencies: '@formatjs/intl-localematcher': 0.2.25 @@ -16518,14 +14657,6 @@ snapshots: '@humanfs/core': 0.19.1 '@humanwhocodes/retry': 0.4.3 - '@humanwhocodes/config-array@0.13.0': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - '@humanwhocodes/config-array@0.9.5': dependencies: '@humanwhocodes/object-schema': 1.2.1 @@ -16538,19 +14669,10 @@ snapshots: '@humanwhocodes/object-schema@1.2.1': {} - '@humanwhocodes/object-schema@2.0.3': {} - '@humanwhocodes/retry@0.4.3': {} '@hutson/parse-repository-url@3.0.2': {} - '@inquirer/external-editor@1.0.2(@types/node@12.20.55)': - dependencies: - chardet: 2.1.0 - iconv-lite: 0.7.0 - optionalDependencies: - '@types/node': 12.20.55 - '@inquirer/external-editor@1.0.2(@types/node@24.5.2)': dependencies: chardet: 2.1.0 @@ -16809,152 +14931,6 @@ snapshots: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - '@nestjs/cli@6.14.2(eslint@8.57.1)': - dependencies: - '@angular-devkit/core': 7.3.8 - '@angular-devkit/schematics': 7.3.8 - '@angular-devkit/schematics-cli': 0.13.8 - '@nestjs/schematics': 6.9.4(typescript@3.9.10) - '@types/webpack': 4.41.5 - chalk: 2.4.2 - cli-table3: 0.5.1 - commander: 4.1.1 - copyfiles: 2.2.0 - fork-ts-checker-webpack-plugin: 4.0.3(eslint@8.57.1)(typescript@3.9.10)(webpack@4.41.5) - inquirer: 7.0.4 - node-emoji: 1.10.0 - ora: 4.0.3 - os-name: 3.1.0 - rimraf: 3.0.1 - tree-kill: 1.2.2 - tsconfig-paths: 3.9.0 - tsconfig-paths-webpack-plugin: 3.2.0 - typescript: 3.9.10 - webpack: 4.41.5 - webpack-node-externals: 1.7.2 - transitivePeerDependencies: - - eslint - - supports-color - - vue-template-compiler - - webpack-cli - - webpack-command - - '@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)': - dependencies: - axios: 0.19.2 - cli-color: 2.0.0 - reflect-metadata: 0.1.14 - rxjs: 6.6.7 - tslib: 1.11.1 - uuid: 7.0.1 - transitivePeerDependencies: - - supports-color - - '@nestjs/config@0.6.3(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(reflect-metadata@0.1.14)(rxjs@6.6.7)': - dependencies: - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - dotenv: 8.2.0 - dotenv-expand: 5.1.0 - lodash.get: 4.4.2 - lodash.has: 4.5.2 - lodash.set: 4.3.2 - reflect-metadata: 0.1.14 - rxjs: 6.6.7 - uuid: 8.3.2 - - '@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)': - dependencies: - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nuxtjs/opencollective': 0.2.2(encoding@0.1.13) - fast-safe-stringify: 2.0.7 - iterare: 1.2.0 - object-hash: 2.0.3 - path-to-regexp: 3.2.0 - reflect-metadata: 0.1.14 - rxjs: 6.6.7 - tslib: 1.11.1 - uuid: 7.0.1 - transitivePeerDependencies: - - encoding - - '@nestjs/jwt@6.1.2(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))': - dependencies: - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@types/jsonwebtoken': 8.3.7 - jsonwebtoken: 8.5.1 - - '@nestjs/mapped-types@0.4.1(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(class-transformer@0.2.3)(class-validator@0.13.2)(reflect-metadata@0.1.14)': - dependencies: - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - class-transformer: 0.2.3 - class-validator: 0.13.2 - reflect-metadata: 0.1.14 - - '@nestjs/passport@6.2.0(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(passport@0.4.1)': - dependencies: - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - passport: 0.4.1 - - '@nestjs/platform-express@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))': - dependencies: - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nestjs/core': 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7) - body-parser: 1.19.0 - cors: 2.8.5 - express: 4.17.1 - multer: 1.4.2 - tslib: 1.11.1 - transitivePeerDependencies: - - supports-color - - '@nestjs/schematics@6.9.4(typescript@3.9.10)': - dependencies: - '@angular-devkit/core': 7.3.8 - '@angular-devkit/schematics': 7.3.8 - fs-extra: 8.1.0 - typescript: 3.9.10 - transitivePeerDependencies: - - supports-color - - '@nestjs/schematics@6.9.4(typescript@4.1.6)': - dependencies: - '@angular-devkit/core': 7.3.8 - '@angular-devkit/schematics': 7.3.8 - fs-extra: 8.1.0 - typescript: 4.1.6 - transitivePeerDependencies: - - supports-color - - '@nestjs/swagger@4.8.2(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))(class-transformer@0.2.3)(class-validator@0.13.2)(reflect-metadata@0.1.14)(swagger-ui-express@4.6.3(express@4.21.2))': - dependencies: - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nestjs/core': 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nestjs/mapped-types': 0.4.1(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(class-transformer@0.2.3)(class-validator@0.13.2)(reflect-metadata@0.1.14) - lodash: 4.17.21 - path-to-regexp: 3.2.0 - reflect-metadata: 0.1.14 - optionalDependencies: - swagger-ui-express: 4.6.3(express@4.21.2) - transitivePeerDependencies: - - class-transformer - - class-validator - - '@nestjs/testing@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))': - dependencies: - optional: 0.1.4 - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nestjs/core': 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7) - tslib: 1.11.1 - - '@nestjs/typeorm@6.3.4(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))(reflect-metadata@0.1.14)(rxjs@6.6.7)(typeorm@0.2.45(mysql2@3.12.0))': - dependencies: - '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7) - '@nestjs/core': 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7) - reflect-metadata: 0.1.14 - rxjs: 6.6.7 - typeorm: 0.2.45(mysql2@3.12.0) - uuid: 7.0.3 - '@next/env@12.3.4': {} '@next/eslint-plugin-next@12.1.0': @@ -17012,65 +14988,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@nuxtjs/opencollective@0.2.2(encoding@0.1.13)': - dependencies: - chalk: 2.4.2 - consola: 2.15.3 - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - '@pm2/agent@2.0.4': - dependencies: - async: 3.2.6 - chalk: 3.0.0 - dayjs: 1.8.36 - debug: 4.3.7(supports-color@9.4.0) - eventemitter2: 5.0.1 - fast-json-patch: 3.1.1 - fclone: 1.0.11 - nssocket: 0.6.0 - pm2-axon: 4.0.1 - pm2-axon-rpc: 0.7.1 - proxy-agent: 6.3.1 - semver: 7.5.4 - ws: 7.5.10 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@pm2/io@6.0.1': - dependencies: - async: 2.6.4 - debug: 4.3.7(supports-color@9.4.0) - eventemitter2: 6.4.9 - require-in-the-middle: 5.2.0 - semver: 7.5.4 - shimmer: 1.2.1 - signal-exit: 3.0.7 - tslib: 1.9.3 - transitivePeerDependencies: - - supports-color - - '@pm2/js-api@0.8.0': - dependencies: - async: 2.6.4 - debug: 4.3.7(supports-color@9.4.0) - eventemitter2: 6.4.9 - extrareqp2: 1.0.0(debug@4.3.7) - ws: 7.5.10 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@pm2/pm2-version-check@1.0.4': - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - '@pnpm/config.env-replace@1.1.0': {} '@pnpm/network.ca-file@1.0.2': @@ -17550,13 +15467,6 @@ snapshots: '@rushstack/eslint-patch@1.10.4': {} - '@schematics/schematics@0.13.8': - dependencies: - '@angular-devkit/core': 7.3.8 - '@angular-devkit/schematics': 7.3.8 - transitivePeerDependencies: - - supports-color - '@sideway/address@4.1.5': dependencies: '@hapi/hoek': 9.3.0 @@ -17595,8 +15505,6 @@ snapshots: micromark-util-character: 1.2.0 micromark-util-symbol: 1.1.0 - '@sqltools/formatter@1.2.5': {} - '@surma/rollup-plugin-off-main-thread@2.2.3': dependencies: ejs: 3.1.10 @@ -17734,18 +15642,12 @@ snapshots: optionalDependencies: '@types/react': 17.0.42 - '@tootallnate/quickjs-emscripten@0.23.0': {} - '@trysound/sax@0.2.0': {} '@types/acorn@4.0.6': dependencies: '@types/estree': 1.0.6 - '@types/anymatch@3.0.0': - dependencies: - anymatch: 3.1.3 - '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -17787,8 +15689,6 @@ snapshots: dependencies: '@types/node': 17.0.22 - '@types/cookiejar@2.1.5': {} - '@types/debounce@1.2.4': {} '@types/debug@4.1.12': @@ -17877,18 +15777,12 @@ snapshots: '@types/json5@0.0.29': {} - '@types/jsonwebtoken@8.3.7': - dependencies: - '@types/node': 17.0.22 - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 '@types/mdx@2.0.13': {} - '@types/methods@1.1.4': {} - '@types/mime@1.3.5': {} '@types/minimatch@5.1.2': {} @@ -17901,14 +15795,11 @@ snapshots: dependencies: '@types/node': 17.0.22 - '@types/node@12.20.55': {} - '@types/node@17.0.22': {} '@types/node@24.5.2': dependencies: undici-types: 7.12.0 - optional: true '@types/normalize-package-data@2.4.4': {} @@ -17990,54 +15881,18 @@ snapshots: dependencies: '@types/node': 17.0.22 - '@types/source-list-map@0.1.6': {} - '@types/stack-utils@1.0.1': {} '@types/stack-utils@2.0.3': {} - '@types/superagent@8.1.9': - dependencies: - '@types/cookiejar': 2.1.5 - '@types/methods': 1.1.4 - '@types/node': 17.0.22 - form-data: 4.0.0 - - '@types/supertest@2.0.16': - dependencies: - '@types/superagent': 8.1.9 - '@types/swagger-schema-official@2.0.22': {} - '@types/tapable@2.2.7': - dependencies: - tapable: 2.2.1 - '@types/trusted-types@2.0.7': {} - '@types/uglify-js@3.17.5': - dependencies: - source-map: 0.6.1 - '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} - '@types/webpack-sources@3.2.3': - dependencies: - '@types/node': 17.0.22 - '@types/source-list-map': 0.1.6 - source-map: 0.7.4 - - '@types/webpack@4.41.5': - dependencies: - '@types/anymatch': 3.0.0 - '@types/node': 17.0.22 - '@types/tapable': 2.2.7 - '@types/uglify-js': 3.17.5 - '@types/webpack-sources': 3.2.3 - source-map: 0.6.1 - '@types/webxr@0.5.20': {} '@types/ws@8.5.14': @@ -18058,8 +15913,6 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@types/zen-observable@0.8.3': {} - '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint@8.11.0)(typescript@4.6.2)': dependencies: '@eslint-community/regexpp': 4.11.1 @@ -18079,25 +15932,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1)(typescript@4.1.6)': - dependencies: - '@eslint-community/regexpp': 4.11.1 - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.1.6) - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@4.1.6) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.1.6) - debug: 4.3.7(supports-color@9.4.0) - eslint: 8.57.1 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare-lite: 1.4.0 - semver: 7.6.3 - tsutils: 3.21.0(typescript@4.1.6) - optionalDependencies: - typescript: 4.1.6 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2)': dependencies: '@typescript-eslint/scope-manager': 5.62.0 @@ -18110,18 +15944,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6)': - dependencies: - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.1.6) - debug: 4.3.7(supports-color@9.4.0) - eslint: 8.57.1 - optionalDependencies: - typescript: 4.1.6 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/scope-manager@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 @@ -18139,34 +15961,8 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@4.1.6)': - dependencies: - '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.1.6) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.1.6) - debug: 4.4.3 - eslint: 8.57.1 - tsutils: 3.21.0(typescript@4.1.6) - optionalDependencies: - typescript: 4.1.6 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/typescript-estree@5.62.0(typescript@4.1.6)': - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.4.3 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.6.3 - tsutils: 3.21.0(typescript@4.1.6) - optionalDependencies: - typescript: 4.1.6 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@5.62.0(typescript@4.6.2)': dependencies: '@typescript-eslint/types': 5.62.0 @@ -18196,21 +15992,6 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@4.1.6)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.1.6) - eslint: 8.57.1 - eslint-scope: 5.1.1 - semver: 7.6.3 - transitivePeerDependencies: - - supports-color - - typescript - '@typescript-eslint/visitor-keys@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 @@ -18229,35 +16010,12 @@ snapshots: '@webassemblyjs/helper-numbers': 1.13.2 '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ast@1.8.5': - dependencies: - '@webassemblyjs/helper-module-context': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/wast-parser': 1.8.5 - '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - '@webassemblyjs/floating-point-hex-parser@1.8.5': {} - '@webassemblyjs/helper-api-error@1.13.2': {} - '@webassemblyjs/helper-api-error@1.8.5': {} - '@webassemblyjs/helper-buffer@1.14.1': {} - '@webassemblyjs/helper-buffer@1.8.5': {} - - '@webassemblyjs/helper-code-frame@1.8.5': - dependencies: - '@webassemblyjs/wast-printer': 1.8.5 - - '@webassemblyjs/helper-fsm@1.8.5': {} - - '@webassemblyjs/helper-module-context@1.8.5': - dependencies: - '@webassemblyjs/ast': 1.8.5 - mamacro: 0.0.3 - '@webassemblyjs/helper-numbers@1.13.2': dependencies: '@webassemblyjs/floating-point-hex-parser': 1.13.2 @@ -18266,8 +16024,6 @@ snapshots: '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - '@webassemblyjs/helper-wasm-bytecode@1.8.5': {} - '@webassemblyjs/helper-wasm-section@1.14.1': dependencies: '@webassemblyjs/ast': 1.14.1 @@ -18275,33 +16031,16 @@ snapshots: '@webassemblyjs/helper-wasm-bytecode': 1.13.2 '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/helper-wasm-section@1.8.5': - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-buffer': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/wasm-gen': 1.8.5 - '@webassemblyjs/ieee754@1.13.2': dependencies: '@xtuc/ieee754': 1.2.0 - '@webassemblyjs/ieee754@1.8.5': - dependencies: - '@xtuc/ieee754': 1.2.0 - '@webassemblyjs/leb128@1.13.2': dependencies: '@xtuc/long': 4.2.2 - '@webassemblyjs/leb128@1.8.5': - dependencies: - '@xtuc/long': 4.2.2 - '@webassemblyjs/utf8@1.13.2': {} - '@webassemblyjs/utf8@1.8.5': {} - '@webassemblyjs/wasm-edit@1.14.1': dependencies: '@webassemblyjs/ast': 1.14.1 @@ -18313,17 +16052,6 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 '@webassemblyjs/wast-printer': 1.14.1 - '@webassemblyjs/wasm-edit@1.8.5': - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-buffer': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/helper-wasm-section': 1.8.5 - '@webassemblyjs/wasm-gen': 1.8.5 - '@webassemblyjs/wasm-opt': 1.8.5 - '@webassemblyjs/wasm-parser': 1.8.5 - '@webassemblyjs/wast-printer': 1.8.5 - '@webassemblyjs/wasm-gen@1.14.1': dependencies: '@webassemblyjs/ast': 1.14.1 @@ -18332,14 +16060,6 @@ snapshots: '@webassemblyjs/leb128': 1.13.2 '@webassemblyjs/utf8': 1.13.2 - '@webassemblyjs/wasm-gen@1.8.5': - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/ieee754': 1.8.5 - '@webassemblyjs/leb128': 1.8.5 - '@webassemblyjs/utf8': 1.8.5 - '@webassemblyjs/wasm-opt@1.14.1': dependencies: '@webassemblyjs/ast': 1.14.1 @@ -18347,13 +16067,6 @@ snapshots: '@webassemblyjs/wasm-gen': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wasm-opt@1.8.5': - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-buffer': 1.8.5 - '@webassemblyjs/wasm-gen': 1.8.5 - '@webassemblyjs/wasm-parser': 1.8.5 - '@webassemblyjs/wasm-parser@1.14.1': dependencies: '@webassemblyjs/ast': 1.14.1 @@ -18363,35 +16076,11 @@ snapshots: '@webassemblyjs/leb128': 1.13.2 '@webassemblyjs/utf8': 1.13.2 - '@webassemblyjs/wasm-parser@1.8.5': - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-api-error': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/ieee754': 1.8.5 - '@webassemblyjs/leb128': 1.8.5 - '@webassemblyjs/utf8': 1.8.5 - - '@webassemblyjs/wast-parser@1.8.5': - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/floating-point-hex-parser': 1.8.5 - '@webassemblyjs/helper-api-error': 1.8.5 - '@webassemblyjs/helper-code-frame': 1.8.5 - '@webassemblyjs/helper-fsm': 1.8.5 - '@xtuc/long': 4.2.2 - '@webassemblyjs/wast-printer@1.14.1': dependencies: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - '@webassemblyjs/wast-printer@1.8.5': - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/wast-parser': 1.8.5 - '@xtuc/long': 4.2.2 - '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -18458,21 +16147,11 @@ snapshots: address@1.2.2: {} - agent-base@7.1.4: {} - - agentkeepalive@3.5.3: - dependencies: - humanize-ms: 1.2.1 - aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 - ajv-errors@1.0.1(ajv@6.12.6): - dependencies: - ajv: 6.12.6 - ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -18493,13 +16172,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@6.9.1: - dependencies: - fast-deep-equal: 2.0.1 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 @@ -18528,50 +16200,14 @@ snapshots: '@algolia/requester-fetch': 5.20.3 '@algolia/requester-node-http': 5.20.3 - ali-oss@6.21.0: - dependencies: - address: 1.2.2 - agentkeepalive: 3.5.3 - bowser: 1.9.4 - copy-to: 2.0.1 - dateformat: 2.2.0 - debug: 4.3.7(supports-color@9.4.0) - destroy: 1.2.0 - end-or-error: 1.0.1 - get-ready: 1.0.0 - humanize-ms: 1.2.1 - is-type-of: 1.4.0 - js-base64: 2.6.4 - jstoxml: 2.2.9 - lodash: 4.17.21 - merge-descriptors: 1.0.3 - mime: 2.6.0 - platform: 1.3.6 - pump: 3.0.2 - qs: 6.13.0 - sdk-base: 2.0.1 - stream-http: 2.8.2 - stream-wormhole: 1.1.0 - urllib: 2.44.0 - utility: 1.18.0 - xml2js: 0.6.2 - transitivePeerDependencies: - - proxy-agent - - supports-color - - amp-message@0.1.2: - dependencies: - amp: 0.3.1 - - amp@0.3.1: {} - anser@1.4.10: {} ansi-align@3.0.1: dependencies: string-width: 4.2.3 - ansi-colors@4.1.3: {} + ansi-colors@4.1.3: + optional: true ansi-escapes@3.2.0: {} @@ -18587,8 +16223,6 @@ snapshots: ansi-html-community@0.0.8: {} - ansi-regex@2.1.1: {} - ansi-regex@3.0.1: {} ansi-regex@4.1.1: {} @@ -18597,8 +16231,6 @@ snapshots: ansi-regex@6.0.1: {} - ansi-styles@2.2.1: {} - ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 @@ -18669,8 +16301,6 @@ snapshots: - luxon - moment - any-promise@1.3.0: {} - anymatch@2.0.0: dependencies: micromatch: 3.1.10 @@ -18683,16 +16313,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - app-root-path@3.1.0: {} - appdirsjs@1.2.7: {} - append-field@1.0.0: {} - - aproba@1.2.0: {} - - arg@4.1.3: {} - arg@5.0.2: {} argparse@1.0.10: @@ -18812,31 +16434,16 @@ snapshots: asap@2.0.6: {} - asn1.js@4.10.1: - dependencies: - bn.js: 4.12.0 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - asn1@0.2.6: dependencies: safer-buffer: 2.1.2 assert-plus@1.0.0: {} - assert@1.5.1: - dependencies: - object.assign: 4.1.5 - util: 0.10.4 - assign-symbols@1.0.0: {} ast-types-flow@0.0.8: {} - ast-types@0.13.4: - dependencies: - tslib: 2.7.0 - ast-types@0.15.2: dependencies: tslib: 2.7.0 @@ -18847,16 +16454,10 @@ snapshots: astring@1.9.0: {} - async-each@1.0.6: {} - async-limiter@1.0.1: {} async-validator@1.11.5: {} - async@2.6.4: - dependencies: - lodash: 4.17.21 - async@3.2.6: {} asynckit@0.4.0: {} @@ -18887,21 +16488,15 @@ snapshots: axe-core@4.10.0: {} - axios@0.19.2: - dependencies: - follow-redirects: 1.5.10 - transitivePeerDependencies: - - supports-color - axios@0.23.0: dependencies: - follow-redirects: 1.15.9(debug@4.3.7) + follow-redirects: 1.15.9 transitivePeerDependencies: - debug axios@1.12.2: dependencies: - follow-redirects: 1.15.9(debug@4.3.7) + follow-redirects: 1.15.9 form-data: 4.0.4 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -18909,12 +16504,6 @@ snapshots: axobject-query@4.1.0: {} - babel-code-frame@6.26.0: - dependencies: - chalk: 1.1.3 - esutils: 2.0.3 - js-tokens: 3.0.2 - babel-core@7.0.0-bridge.0(@babel/core@7.26.9): dependencies: '@babel/core': 7.26.9 @@ -19062,20 +16651,14 @@ snapshots: mixin-deep: 1.3.2 pascalcase: 0.1.1 - basic-ftp@5.0.5: {} - batch@0.6.1: {} bcrypt-pbkdf@1.0.2: dependencies: tweetnacl: 0.14.5 - bcryptjs@2.4.3: {} - big.js@5.2.2: {} - binary-extensions@1.13.1: {} - binary-extensions@2.3.0: {} bindings@1.5.0: @@ -19089,31 +16672,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - blessed@0.1.81: {} - - bluebird@3.7.2: {} - - bn.js@4.12.0: {} - - bn.js@5.2.1: {} - - bodec@0.1.0: {} - - body-parser@1.19.0: - dependencies: - bytes: 3.1.0 - content-type: 1.0.5 - debug: 2.6.9 - depd: 1.1.2 - http-errors: 1.7.2 - iconv-lite: 0.4.24 - on-finished: 2.3.0 - qs: 6.7.0 - raw-body: 2.4.0 - type-is: 1.6.18 - transitivePeerDependencies: - - supports-color - body-parser@1.20.3: dependencies: bytes: 3.1.2 @@ -19152,10 +16710,6 @@ snapshots: boolbase@1.0.0: {} - bowser@1.9.4: {} - - bowser@2.9.0: {} - boxen@6.2.1: dependencies: ansi-align: 3.0.1 @@ -19206,58 +16760,12 @@ snapshots: dependencies: fill-range: 7.1.1 - brorand@1.1.0: {} - browser-process-hrtime@1.0.0: {} browser-resolve@1.11.3: dependencies: resolve: 1.1.7 - browserify-aes@1.2.0: - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.4 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-cipher@1.0.1: - dependencies: - browserify-aes: 1.2.0 - browserify-des: 1.0.2 - evp_bytestokey: 1.0.3 - - browserify-des@1.0.2: - dependencies: - cipher-base: 1.0.4 - des.js: 1.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-rsa@4.1.0: - dependencies: - bn.js: 5.2.1 - randombytes: 2.1.0 - - browserify-sign@4.2.3: - dependencies: - bn.js: 5.2.1 - browserify-rsa: 4.1.0 - create-hash: 1.2.0 - create-hmac: 1.1.7 - elliptic: 6.5.7 - hash-base: 3.0.4 - inherits: 2.0.4 - parse-asn1: 5.1.7 - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - - browserify-zlib@0.2.0: - dependencies: - pako: 1.0.11 - browserslist@4.23.3: dependencies: caniuse-lite: 1.0.30001701 @@ -19280,18 +16788,8 @@ snapshots: dependencies: node-int64: 0.4.0 - buffer-equal-constant-time@1.0.1: {} - buffer-from@1.1.2: {} - buffer-xor@1.0.3: {} - - buffer@4.9.2: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - isarray: 1.0.0 - buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -19302,41 +16800,12 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - builtin-modules@1.1.1: {} - builtin-modules@3.3.0: {} - builtin-status-codes@3.0.0: {} - - busboy@0.2.14: - dependencies: - dicer: 0.2.5 - readable-stream: 1.1.14 - bytes@3.0.0: {} - bytes@3.1.0: {} - bytes@3.1.2: {} - cacache@12.0.4: - dependencies: - bluebird: 3.7.2 - chownr: 1.1.4 - figgy-pudding: 3.5.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - infer-owner: 1.0.4 - lru-cache: 5.1.1 - mississippi: 3.0.0 - mkdirp: 0.5.6 - move-concurrently: 1.0.1 - promise-inflight: 1.0.1(bluebird@3.7.2) - rimraf: 2.7.1 - ssri: 6.0.2 - unique-filename: 1.1.1 - y18n: 4.0.3 - cache-base@1.0.1: dependencies: collection-visit: 1.0.0 @@ -19412,8 +16881,6 @@ snapshots: camelcase@7.0.1: {} - camelize@1.0.0: {} - caniuse-api@3.0.0: dependencies: browserslist: 4.23.3 @@ -19431,25 +16898,12 @@ snapshots: ccount@2.0.1: {} - chalk@1.1.3: - dependencies: - ansi-styles: 2.2.1 - escape-string-regexp: 1.0.5 - has-ansi: 2.0.0 - strip-ansi: 3.0.1 - supports-color: 2.0.0 - chalk@2.4.2: dependencies: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - chalk@3.0.0: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -19467,12 +16921,8 @@ snapshots: character-reference-invalid@2.0.1: {} - chardet@0.7.0: {} - chardet@2.1.0: {} - charm@0.1.2: {} - cheerio-select@2.1.0: dependencies: boolbase: 1.0.0 @@ -19492,44 +16942,6 @@ snapshots: parse5: 7.2.1 parse5-htmlparser2-tree-adapter: 7.1.0 - chokidar@2.0.4: - dependencies: - anymatch: 2.0.0 - async-each: 1.0.6 - braces: 2.3.2 - glob-parent: 3.1.0 - inherits: 2.0.4 - is-binary-path: 1.0.1 - is-glob: 4.0.3 - lodash.debounce: 4.0.8 - normalize-path: 2.1.1 - path-is-absolute: 1.0.1 - readdirp: 2.2.1 - upath: 1.2.0 - optionalDependencies: - fsevents: 1.2.13 - transitivePeerDependencies: - - supports-color - - chokidar@2.1.8: - dependencies: - anymatch: 2.0.0 - async-each: 1.0.6 - braces: 2.3.2 - glob-parent: 3.1.0 - inherits: 2.0.4 - is-binary-path: 1.0.1 - is-glob: 4.0.3 - normalize-path: 3.0.0 - path-is-absolute: 1.0.1 - readdirp: 2.2.1 - upath: 1.2.0 - optionalDependencies: - fsevents: 1.2.13 - transitivePeerDependencies: - - supports-color - optional: true - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -19546,8 +16958,6 @@ snapshots: dependencies: readdirp: 4.0.1 - chownr@1.1.4: {} - chrome-launcher@0.15.2: dependencies: '@types/node': 17.0.22 @@ -19574,13 +16984,6 @@ snapshots: ci-info@3.9.0: {} - cipher-base@1.0.4: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - class-transformer@0.2.3: {} - class-utils@0.3.6: dependencies: arr-union: 3.1.0 @@ -19588,11 +16991,6 @@ snapshots: isobject: 3.0.1 static-extend: 0.1.2 - class-validator@0.13.2: - dependencies: - libphonenumber-js: 1.11.8 - validator: 13.12.0 - classnames@2.5.1: {} clean-css@5.3.3: @@ -19608,51 +17006,22 @@ snapshots: cli-boxes@3.0.0: {} - cli-color@2.0.0: - dependencies: - ansi-regex: 2.1.1 - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - memoizee: 0.4.17 - timers-ext: 0.1.8 - - cli-cursor@2.1.0: - dependencies: - restore-cursor: 2.0.0 - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 - cli-highlight@2.1.11: + cli-cursor@5.0.0: dependencies: - chalk: 4.1.2 - highlight.js: 10.7.3 - mz: 2.7.0 - parse5: 5.1.1 - parse5-htmlparser2-tree-adapter: 6.0.1 - yargs: 16.2.0 + restore-cursor: 5.1.0 cli-spinners@2.9.2: {} - cli-table3@0.5.1: - dependencies: - object-assign: 4.1.1 - string-width: 2.1.1 - optionalDependencies: - colors: 1.4.0 - cli-table3@0.6.5: dependencies: string-width: 4.2.3 optionalDependencies: '@colors/colors': 1.5.0 - cli-tableau@2.0.1: - dependencies: - chalk: 3.0.0 - cli-truncate@2.1.0: dependencies: slice-ansi: 3.0.0 @@ -19663,8 +17032,6 @@ snapshots: slice-ansi: 5.0.0 string-width: 5.1.2 - cli-width@2.2.1: {} - cli-width@3.0.0: {} client-only@0.0.1: {} @@ -19730,9 +17097,6 @@ snapshots: colorette@2.0.20: {} - colors@1.4.0: - optional: true - combine-promises@1.2.0: {} combined-stream@1.0.8: @@ -19745,12 +17109,10 @@ snapshots: commander@10.0.1: {} - commander@2.15.1: {} + commander@13.1.0: {} commander@2.20.3: {} - commander@4.1.1: {} - commander@5.1.0: {} commander@7.2.0: {} @@ -19798,13 +17160,6 @@ snapshots: concat-map@0.0.1: {} - concat-stream@1.6.2: - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 2.3.8 - typedarray: 0.0.6 - concurrently@7.6.0: dependencies: chalk: 4.1.2 @@ -19841,20 +17196,10 @@ snapshots: transitivePeerDependencies: - supports-color - consola@2.15.3: {} - consola@3.4.0: {} - console-browserify@1.2.0: {} - - constants-browserify@1.0.0: {} - content-disposition@0.5.2: {} - content-disposition@0.5.3: - dependencies: - safe-buffer: 5.1.2 - content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 @@ -19863,8 +17208,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - content-security-policy-builder@2.1.0: {} - content-type@1.0.5: {} conventional-changelog-angular@6.0.0: @@ -19958,25 +17301,12 @@ snapshots: cookie-signature@1.2.2: {} - cookie@0.4.0: {} - cookie@0.7.1: {} - cookiejar@2.1.4: {} - copy-anything@2.0.6: dependencies: is-what: 3.14.1 - copy-concurrently@1.0.5: - dependencies: - aproba: 1.2.0 - fs-write-stream-atomic: 1.0.10 - iferr: 0.1.5 - mkdirp: 0.5.6 - rimraf: 2.7.1 - run-queue: 1.0.3 - copy-descriptor@0.1.1: {} copy-text-to-clipboard@3.2.0: {} @@ -19985,8 +17315,6 @@ snapshots: dependencies: toggle-selection: 1.0.6 - copy-to@2.0.1: {} - copy-webpack-plugin@11.0.0(webpack@5.98.0): dependencies: fast-glob: 3.3.2 @@ -19997,15 +17325,6 @@ snapshots: serialize-javascript: 6.0.2 webpack: 5.98.0 - copyfiles@2.2.0: - dependencies: - glob: 7.2.3 - minimatch: 3.1.2 - mkdirp: 0.5.6 - noms: 0.0.0 - through2: 2.0.5 - yargs: 13.3.2 - core-js-compat@3.38.1: dependencies: browserslist: 4.23.3 @@ -20026,11 +17345,6 @@ snapshots: core-util-is@1.0.3: {} - cors@2.8.5: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - cosmiconfig@5.2.1: dependencies: import-fresh: 2.0.0 @@ -20072,35 +17386,11 @@ snapshots: optionalDependencies: typescript: 4.6.2 - create-ecdh@4.0.4: - dependencies: - bn.js: 4.12.0 - elliptic: 6.5.7 - - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.4 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - - create-hmac@1.1.7: - dependencies: - cipher-base: 1.0.4 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - create-react-class@15.7.0: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - croner@4.1.97: {} - cross-env@7.0.3: dependencies: cross-spawn: 7.0.3 @@ -20125,20 +17415,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crypto-browserify@3.12.0: - dependencies: - browserify-cipher: 1.0.1 - browserify-sign: 4.2.3 - create-ecdh: 4.0.4 - create-hash: 1.2.0 - create-hmac: 1.1.7 - diffie-hellman: 5.0.3 - inherits: 2.0.4 - pbkdf2: 3.1.2 - public-encrypt: 4.0.3 - randombytes: 2.1.0 - randomfill: 1.0.4 - crypto-random-string@2.0.0: {} crypto-random-string@4.0.0: @@ -20296,18 +17572,9 @@ snapshots: csstype@3.1.3: {} - culvert@0.1.2: {} - cxs@6.2.0: {} - cyclist@1.0.2: {} - - d@1.0.2: - dependencies: - es5-ext: 0.10.64 - type: 2.7.3 - - damerau-levenshtein@1.0.8: {} + damerau-levenshtein@1.0.8: {} dargs@7.0.0: {} @@ -20315,12 +17582,8 @@ snapshots: dependencies: assert-plus: 1.0.0 - dasherize@2.0.0: {} - data-uri-to-buffer@4.0.1: {} - data-uri-to-buffer@6.0.2: {} - data-urls@1.1.0: dependencies: abab: 2.0.6 @@ -20349,26 +17612,16 @@ snapshots: dependencies: '@babel/runtime': 7.25.6 - date-format@4.0.14: {} - - dateformat@2.2.0: {} - dateformat@3.0.3: {} dayjs@1.11.13: {} - dayjs@1.8.36: {} - debounce@1.2.1: {} debug@2.6.9: dependencies: ms: 2.0.0 - debug@3.1.0: - dependencies: - ms: 2.0.0 - debug@3.2.7: dependencies: ms: 2.1.3 @@ -20431,10 +17684,6 @@ snapshots: dependencies: execa: 5.1.1 - default-user-agent@1.0.0: - dependencies: - os-name: 1.0.3 - defaults@1.0.4: dependencies: clone: 1.0.4 @@ -20468,12 +17717,6 @@ snapshots: is-descriptor: 1.0.3 isobject: 3.0.1 - degenerator@5.0.1: - dependencies: - ast-types: 0.13.4 - escodegen: 2.1.0 - esprima: 4.0.1 - del@4.1.1: dependencies: '@types/glob': 7.2.0 @@ -20507,13 +17750,6 @@ snapshots: dequal@2.0.3: {} - des.js@1.1.0: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - destroy@1.0.4: {} - destroy@1.2.0: {} detect-newline@2.1.0: {} @@ -20538,25 +17774,10 @@ snapshots: dependencies: dequal: 2.0.3 - dicer@0.2.5: - dependencies: - readable-stream: 1.1.14 - streamsearch: 0.1.2 - didyoumean@1.2.2: {} diff-sequences@24.9.0: {} - diff@4.0.2: {} - - diffie-hellman@5.0.3: - dependencies: - bn.js: 4.12.0 - miller-rabin: 4.0.1 - randombytes: 2.1.0 - - digest-header@1.1.0: {} - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -20610,8 +17831,6 @@ snapshots: domhandler: 5.0.3 entities: 4.5.0 - domain-browser@1.2.0: {} - domelementtype@2.3.0: {} domexception@1.0.1: @@ -20638,8 +17857,6 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 - dont-sniff-mimetype@1.1.0: {} - dot-case@3.0.4: dependencies: no-case: 3.0.4 @@ -20653,12 +17870,10 @@ snapshots: dependencies: is-obj: 2.0.0 - dotenv-expand@5.1.0: {} + dotenv@16.6.1: {} dotenv@17.2.3: {} - dotenv@8.2.0: {} - dotenv@8.6.0: {} draft-js@0.10.5(react-dom@17.0.2(react@17.0.2))(react@17.0.2): @@ -20677,13 +17892,6 @@ snapshots: duplexer@0.1.2: {} - duplexify@3.7.1: - dependencies: - end-of-stream: 1.4.4 - inherits: 2.0.4 - readable-stream: 2.3.8 - stream-shift: 1.0.3 - eastasianwidth@0.2.0: {} ecc-jsbn@0.1.2: @@ -20691,10 +17899,6 @@ snapshots: jsbn: 0.1.1 safer-buffer: 2.1.2 - ecdsa-sig-formatter@1.0.11: - dependencies: - safe-buffer: 5.2.1 - echarts-for-react@3.0.2(echarts@5.6.0)(react@17.0.2): dependencies: echarts: 5.6.0 @@ -20717,15 +17921,7 @@ snapshots: electron-to-chromium@1.5.27: {} - elliptic@6.5.7: - dependencies: - bn.js: 4.12.0 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 + emoji-regex@10.6.0: {} emoji-regex@7.0.3: {} @@ -20751,14 +17947,6 @@ snapshots: dependencies: once: 1.4.0 - end-or-error@1.0.1: {} - - enhanced-resolve@4.5.0: - dependencies: - graceful-fs: 4.2.11 - memory-fs: 0.5.0 - tapable: 1.1.3 - enhanced-resolve@5.17.1: dependencies: graceful-fs: 4.2.11 @@ -20767,6 +17955,7 @@ snapshots: enquirer@2.3.6: dependencies: ansi-colors: 4.1.3 + optional: true entities@2.2.0: {} @@ -20779,6 +17968,7 @@ snapshots: errno@0.1.8: dependencies: prr: 1.0.1 + optional: true error-ex@1.3.2: dependencies: @@ -20914,33 +18104,8 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 - es5-ext@0.10.64: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - - es6-iterator@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - es6-promise@3.3.1: {} - es6-symbol@3.1.4: - dependencies: - d: 1.0.2 - ext: 1.7.0 - - es6-weak-map@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -20978,14 +18143,6 @@ snapshots: optionalDependencies: source-map: 0.6.1 - escodegen@2.1.0: - dependencies: - esprima: 4.0.1 - estraverse: 5.3.0 - esutils: 2.0.3 - optionalDependencies: - source-map: 0.6.1 - eslint-config-next@12.1.0(eslint@8.11.0)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(typescript@4.6.2): dependencies: '@next/eslint-plugin-next': 12.1.0 @@ -21009,10 +18166,6 @@ snapshots: dependencies: eslint: 8.11.0 - eslint-config-prettier@8.10.0(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 @@ -21044,16 +18197,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.1.6) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint-import-resolver-typescript@2.7.1)(eslint@8.11.0): dependencies: '@rtsao/scc': 1.1.0 @@ -21082,34 +18225,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.15.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.1.6) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-jsx-a11y@6.10.0(eslint@8.11.0): dependencies: aria-query: 5.1.3 @@ -21138,14 +18253,6 @@ snapshots: optionalDependencies: eslint-config-prettier: 8.10.0(eslint@8.11.0) - eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@1.19.1): - dependencies: - eslint: 8.57.1 - prettier: 1.19.1 - prettier-linter-helpers: 1.0.0 - optionalDependencies: - eslint-config-prettier: 8.10.0(eslint@8.57.1) - eslint-plugin-react-hooks@4.6.2(eslint@8.11.0): dependencies: eslint: 8.11.0 @@ -21176,15 +18283,6 @@ snapshots: dependencies: eslint: 8.11.0 - eslint-plugin-simple-import-sort@7.0.0(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - - eslint-scope@4.0.3: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 @@ -21251,49 +18349,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint@8.57.1: - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.11.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.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.7(supports-color@9.4.0) - 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.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - 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.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - eslint@9.36.0(jiti@1.21.7): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@1.21.7)) @@ -21336,13 +18391,6 @@ snapshots: transitivePeerDependencies: - supports-color - esniff@2.0.1: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.3 - espree@10.4.0: dependencies: acorn: 8.15.0 @@ -21419,28 +18467,12 @@ snapshots: '@types/node': 17.0.22 require-like: 0.1.2 - event-emitter@0.3.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-target-shim@5.0.1: {} - eventemitter2@0.4.14: {} - - eventemitter2@5.0.1: {} - - eventemitter2@6.4.9: {} - eventemitter3@4.0.7: {} events@3.3.0: {} - evp_bytestokey@1.0.3: - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 - exec-sh@0.3.6: {} execa@1.0.0: @@ -21492,43 +18524,6 @@ snapshots: exponential-backoff@3.1.1: {} - express-rate-limit@5.5.1: {} - - express@4.17.1: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.19.0 - content-disposition: 0.5.3 - content-type: 1.0.5 - cookie: 0.4.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 1.1.2 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.1.2 - fresh: 0.5.2 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.3.0 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.7 - qs: 6.7.0 - range-parser: 1.2.1 - safe-buffer: 5.1.2 - send: 0.17.1 - serve-static: 1.14.1 - setprototypeof: 1.1.1 - statuses: 1.5.0 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - express@4.21.2: dependencies: accepts: 1.3.8 @@ -21597,10 +18592,6 @@ snapshots: transitivePeerDependencies: - supports-color - ext@1.7.0: - dependencies: - type: 2.7.3 - extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -21612,12 +18603,6 @@ snapshots: extend@3.0.2: {} - external-editor@3.1.0: - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 - extglob@2.0.4: dependencies: array-unique: 0.3.2 @@ -21631,16 +18616,8 @@ snapshots: transitivePeerDependencies: - supports-color - extrareqp2@1.0.0(debug@4.3.7): - dependencies: - follow-redirects: 1.15.9(debug@4.3.7) - transitivePeerDependencies: - - debug - extsprintf@1.3.0: {} - fast-deep-equal@2.0.1: {} - fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -21653,10 +18630,6 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-json-patch@3.1.1: {} - - fast-json-stable-stringify@2.0.0: {} - fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -21695,10 +18668,6 @@ snapshots: setimmediate: 1.0.5 ua-parser-js: 0.7.39 - fclone@1.0.11: {} - - feature-policy@0.3.0: {} - feed@4.2.2: dependencies: xml-js: 1.6.11 @@ -21708,12 +18677,6 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 - figgy-pudding@3.5.2: {} - - figures@2.0.0: - dependencies: - escape-string-regexp: 1.0.5 - figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -21846,20 +18809,7 @@ snapshots: flow-parser@0.246.0: {} - flush-write-stream@1.1.1: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - - follow-redirects@1.15.9(debug@4.3.7): - optionalDependencies: - debug: 4.3.7(supports-color@9.4.0) - - follow-redirects@1.5.10: - dependencies: - debug: 3.1.0 - transitivePeerDependencies: - - supports-color + follow-redirects@1.15.9: {} for-each@0.3.3: dependencies: @@ -21869,22 +18819,6 @@ snapshots: forever-agent@0.6.1: {} - fork-ts-checker-webpack-plugin@4.0.3(eslint@8.57.1)(typescript@3.9.10)(webpack@4.41.5): - dependencies: - babel-code-frame: 6.26.0 - chalk: 2.4.2 - micromatch: 3.1.10 - minimatch: 3.1.2 - semver: 5.7.2 - tapable: 1.1.3 - typescript: 3.9.10 - webpack: 4.41.5 - worker-rpc: 0.1.1 - optionalDependencies: - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - fork-ts-checker-webpack-plugin@6.5.3(eslint@9.36.0(jiti@1.21.7))(typescript@5.6.3)(webpack@5.98.0): dependencies: '@babel/code-frame': 7.24.7 @@ -21913,18 +18847,6 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - form-data@2.5.1: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - - form-data@4.0.0: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - form-data@4.0.4: dependencies: asynckit: 0.4.0 @@ -21939,15 +18861,6 @@ snapshots: dependencies: fetch-blob: 3.2.0 - formidable@1.2.6: {} - - formstream@1.5.1: - dependencies: - destroy: 1.2.0 - mime: 2.6.0 - node-hex: 1.0.1 - pause-stream: 0.0.11 - forwarded@0.2.0: {} fraction.js@4.3.7: {} @@ -21960,11 +18873,6 @@ snapshots: fresh@2.0.0: {} - from2@2.3.0: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -21992,13 +18900,6 @@ snapshots: fs-monkey@1.0.6: {} - fs-write-stream-atomic@1.0.10: - dependencies: - graceful-fs: 4.2.11 - iferr: 0.1.5 - imurmurhash: 0.1.4 - readable-stream: 2.3.8 - fs.realpath@1.0.0: {} fsevents@1.2.13: @@ -22031,6 +18932,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.6.0: {} + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 @@ -22066,8 +18969,6 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-ready@1.0.0: {} - get-stream@4.1.0: dependencies: pump: 3.0.2 @@ -22080,24 +18981,12 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 - get-uri@6.0.5: - dependencies: - basic-ftp: 5.0.5 - data-uri-to-buffer: 6.0.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - get-value@2.0.6: {} getpass@0.1.7: dependencies: assert-plus: 1.0.0 - git-node-fs@1.0.0(js-git@0.7.8): - optionalDependencies: - js-git: 0.7.8 - git-raw-commits@3.0.0: dependencies: dargs: 7.0.0 @@ -22114,8 +19003,6 @@ snapshots: meow: 8.1.2 semver: 7.6.3 - git-sha1@0.1.2: {} - gitconfiglocal@1.0.0: dependencies: ini: 1.3.8 @@ -22124,11 +19011,6 @@ snapshots: github-slugger@1.5.0: {} - glob-parent@3.1.0: - dependencies: - is-glob: 3.1.0 - path-dirname: 1.0.2 - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -22268,10 +19150,6 @@ snapshots: hard-rejection@2.1.0: {} - has-ansi@2.0.0: - dependencies: - ansi-regex: 2.1.1 - has-bigints@1.0.2: {} has-flag@3.0.0: {} @@ -22313,22 +19191,6 @@ snapshots: has-yarn@3.0.0: {} - hash-base@3.0.4: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - hash-base@3.1.0: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - safe-buffer: 5.2.1 - - hash.js@1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -22429,29 +19291,6 @@ snapshots: he@1.2.0: {} - helmet-crossdomain@0.4.0: {} - - helmet-csp@2.10.0: - dependencies: - bowser: 2.9.0 - camelize: 1.0.0 - content-security-policy-builder: 2.1.0 - dasherize: 2.0.0 - - helmet@3.23.3: - dependencies: - depd: 2.0.0 - dont-sniff-mimetype: 1.1.0 - feature-policy: 0.3.0 - helmet-crossdomain: 0.4.0 - helmet-csp: 2.10.0 - hide-powered-by: 1.1.0 - hpkp: 2.0.0 - hsts: 2.2.0 - nocache: 2.1.0 - referrer-policy: 1.2.0 - x-xss-protection: 1.3.0 - hermes-estree@0.22.0: {} hermes-estree@0.23.1: {} @@ -22464,10 +19303,6 @@ snapshots: dependencies: hermes-estree: 0.23.1 - hide-powered-by@1.1.0: {} - - highlight.js@10.7.3: {} - highlight.js@9.18.5: {} history@4.10.1: @@ -22479,12 +19314,6 @@ snapshots: tiny-warning: 1.0.3 value-equal: 1.0.1 - hmac-drbg@1.0.1: - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - hoist-non-react-statics@3.3.2: dependencies: react-is: 16.13.1 @@ -22502,12 +19331,6 @@ snapshots: readable-stream: 2.3.8 wbuf: 1.7.3 - hpkp@2.0.0: {} - - hsts@2.2.0: - dependencies: - depd: 2.0.0 - html-encoding-sniffer@1.0.2: dependencies: whatwg-encoding: 1.0.5 @@ -22575,22 +19398,6 @@ snapshots: setprototypeof: 1.1.0 statuses: 1.5.0 - http-errors@1.7.2: - dependencies: - depd: 1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.1 - statuses: 1.5.0 - toidentifier: 1.0.0 - - http-errors@1.7.3: - dependencies: - depd: 1.1.2 - inherits: 2.0.4 - setprototypeof: 1.1.1 - statuses: 1.5.0 - toidentifier: 1.0.0 - http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -22601,13 +19408,6 @@ snapshots: http-parser-js@0.5.9: {} - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - http-proxy-middleware@2.0.7(@types/express@4.17.18): dependencies: '@types/http-proxy': 1.17.16 @@ -22623,7 +19423,7 @@ snapshots: http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.9(debug@4.3.7) + follow-redirects: 1.15.9 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -22641,21 +19441,8 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-browserify@1.0.0: {} - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - human-signals@2.1.0: {} - humanize-ms@1.2.1: - dependencies: - ms: 2.1.3 - husky@7.0.4: {} iconv-lite@0.4.24: @@ -22670,6 +19457,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + icss-utils@5.1.0(postcss@8.5.3): dependencies: postcss: 8.5.3 @@ -22678,8 +19469,6 @@ snapshots: ieee754@1.2.1: {} - iferr@0.1.5: {} - ignore@5.3.2: {} image-size@0.5.5: @@ -22716,8 +19505,6 @@ snapshots: indent-string@4.0.0: {} - infer-owner@1.0.4: {} - infima@0.2.0-alpha.45: {} inflight@1.0.6: @@ -22735,58 +19522,6 @@ snapshots: inline-style-parser@0.2.4: {} - inquirer@6.2.1: - dependencies: - ansi-escapes: 3.2.0 - chalk: 2.4.2 - cli-cursor: 2.1.0 - cli-width: 2.2.1 - external-editor: 3.1.0 - figures: 2.0.0 - lodash: 4.17.21 - mute-stream: 0.0.7 - run-async: 2.4.1 - rxjs: 6.6.7 - string-width: 2.1.1 - strip-ansi: 5.2.0 - through: 2.3.8 - - inquirer@7.0.4: - dependencies: - ansi-escapes: 4.3.2 - chalk: 2.4.2 - cli-cursor: 3.1.0 - cli-width: 2.2.1 - external-editor: 3.1.0 - figures: 3.2.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - run-async: 2.4.1 - rxjs: 6.6.7 - string-width: 4.2.3 - strip-ansi: 5.2.0 - through: 2.3.8 - - inquirer@8.2.7(@types/node@12.20.55): - dependencies: - '@inquirer/external-editor': 1.0.2(@types/node@12.20.55) - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - figures: 3.2.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - ora: 5.4.1 - run-async: 2.4.1 - rxjs: 7.8.1 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - wrap-ansi: 6.2.0 - transitivePeerDependencies: - - '@types/node' - inquirer@8.2.7(@types/node@24.5.2): dependencies: '@inquirer/external-editor': 1.0.2(@types/node@24.5.2) @@ -22826,8 +19561,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - ip-address@10.0.1: {} - ipaddr.js@1.9.1: {} ipaddr.js@2.2.0: {} @@ -22863,10 +19596,6 @@ snapshots: dependencies: has-bigints: 1.0.2 - is-binary-path@1.0.1: - dependencies: - binary-extensions: 1.13.1 - is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -22888,8 +19617,6 @@ snapshots: dependencies: ci-info: 3.9.0 - is-class-hotfix@0.0.6: {} - is-core-module@2.15.1: dependencies: hasown: 2.0.2 @@ -22946,10 +19673,6 @@ snapshots: dependencies: has-tostringtag: 1.0.2 - is-glob@3.1.0: - dependencies: - is-extglob: 2.1.1 - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -22963,6 +19686,8 @@ snapshots: is-interactive@1.0.0: {} + is-interactive@2.0.0: {} + is-map@2.0.3: {} is-module@1.0.0: {} @@ -23007,8 +19732,6 @@ snapshots: dependencies: isobject: 3.0.1 - is-promise@2.2.2: {} - is-promise@4.0.0: {} is-property@1.0.2: {} @@ -23044,12 +19767,6 @@ snapshots: dependencies: text-extensions: 1.9.0 - is-type-of@1.4.0: - dependencies: - core-util-is: 1.0.3 - is-class-hotfix: 0.0.6 - isstream: 0.1.2 - is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 @@ -23058,6 +19775,10 @@ snapshots: is-unicode-supported@0.1.0: {} + is-unicode-supported@1.3.0: {} + + is-unicode-supported@2.1.0: {} + is-weakmap@2.0.2: {} is-weakref@1.0.2: @@ -23136,8 +19857,6 @@ snapshots: dependencies: html-escaper: 2.0.2 - iterare@1.2.0: {} - iterator.prototype@1.1.2: dependencies: define-properties: 1.2.1 @@ -23550,17 +20269,6 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 - js-base64@2.6.4: {} - - js-git@0.7.8: - dependencies: - bodec: 0.1.0 - culvert: 0.1.2 - git-sha1: 0.1.2 - pako: 0.2.9 - - js-tokens@3.0.2: {} - js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -23683,32 +20391,6 @@ snapshots: jsonpointer@5.0.1: {} - jsonwebtoken@8.5.1: - 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.1.1 - ms: 2.1.3 - semver: 5.7.2 - - jsonwebtoken@9.0.2: - 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.1.1 - ms: 2.1.3 - semver: 7.6.3 - jsprim@1.4.2: dependencies: assert-plus: 1.0.0 @@ -23716,8 +20398,6 @@ snapshots: json-schema: 0.4.0 verror: 1.10.0 - jstoxml@2.2.9: {} - jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 @@ -23725,17 +20405,6 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 - jwa@1.4.1: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - - jws@3.2.2: - dependencies: - jwa: 1.4.1 - safe-buffer: 5.2.1 - keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -23771,8 +20440,6 @@ snapshots: picocolors: 1.1.1 shell-quote: 1.8.1 - lazy@1.0.11: {} - left-pad@1.3.0: {} less-loader@10.2.0(less@4.2.0)(webpack@5.98.0): @@ -23811,8 +20478,6 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libphonenumber-js@1.11.8: {} - lighthouse-logger@1.4.2: dependencies: debug: 2.6.9 @@ -23865,16 +20530,8 @@ snapshots: pify: 3.0.0 strip-bom: 3.0.0 - loader-runner@2.4.0: {} - loader-runner@4.3.0: {} - loader-utils@1.4.2: - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 1.0.2 - loader-utils@2.0.4: dependencies: big.js: 5.2.2 @@ -23911,53 +20568,32 @@ snapshots: lodash.debounce@4.0.8: {} - lodash.get@4.4.2: {} - - lodash.has@4.5.2: {} - - lodash.includes@4.3.0: {} - - lodash.isboolean@3.0.3: {} - - lodash.isinteger@4.0.4: {} - lodash.ismatch@4.4.0: {} - lodash.isnumber@3.0.3: {} - - lodash.isplainobject@4.0.6: {} - - lodash.isstring@4.0.1: {} - lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} - lodash.once@4.1.1: {} - - lodash.set@4.3.2: {} - lodash.sortby@4.7.0: {} lodash.throttle@4.1.1: {} - lodash.toarray@4.4.0: {} - lodash.uniq@4.5.0: {} lodash.upperfirst@4.3.1: {} lodash@4.17.21: {} - log-symbols@3.0.0: - dependencies: - chalk: 2.4.2 - log-symbols@4.1.0: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 + log-symbols@6.0.0: + dependencies: + chalk: 5.4.1 + is-unicode-supported: 1.3.0 + log-update@4.0.0: dependencies: ansi-escapes: 4.3.2 @@ -23965,16 +20601,6 @@ snapshots: slice-ansi: 4.0.0 wrap-ansi: 6.2.0 - log4js@6.9.1: - dependencies: - date-format: 4.0.14 - debug: 4.3.7(supports-color@9.4.0) - flatted: 3.3.1 - rfdc: 1.4.1 - streamroller: 3.1.5 - transitivePeerDependencies: - - supports-color - logkitty@0.7.1: dependencies: ansi-fragments: 0.2.1 @@ -23983,6 +20609,8 @@ snapshots: long@5.2.3: {} + long@5.3.2: {} + longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -24005,15 +20633,11 @@ snapshots: lru-cache@7.18.3: {} - lru-queue@0.1.0: - dependencies: - es5-ext: 0.10.64 - lru.min@1.1.1: {} - lz-string@1.5.0: {} + lru.min@1.1.4: {} - macos-release@2.5.1: {} + lz-string@1.5.0: {} magic-string@0.25.9: dependencies: @@ -24034,8 +20658,6 @@ snapshots: dependencies: tmpl: 1.0.5 - mamacro@0.0.3: {} - map-cache@0.2.2: {} map-obj@1.0.1: {} @@ -24054,18 +20676,10 @@ snapshots: markdown-table@3.0.4: {} - marked@0.8.2: {} - marky@1.2.5: {} math-intrinsics@1.1.0: {} - md5.js@1.3.5: - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - mdast-util-directive@3.1.0: dependencies: '@types/mdast': 4.0.4 @@ -24268,27 +20882,6 @@ snapshots: memoize-one@5.2.1: {} - memoizee@0.4.17: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-weak-map: 2.0.3 - event-emitter: 0.3.5 - is-promise: 2.2.2 - lru-queue: 0.1.0 - next-tick: 1.1.0 - timers-ext: 0.1.8 - - memory-fs@0.4.1: - dependencies: - errno: 0.1.8 - readable-stream: 2.3.8 - - memory-fs@0.5.0: - dependencies: - errno: 0.1.8 - readable-stream: 2.3.8 - meow@8.1.2: dependencies: '@types/minimist': 1.2.5 @@ -24303,8 +20896,6 @@ snapshots: type-fest: 0.18.1 yargs-parser: 20.2.9 - merge-descriptors@1.0.1: {} - merge-descriptors@1.0.3: {} merge-descriptors@2.0.0: {} @@ -24493,8 +21084,6 @@ snapshots: - supports-color - utf-8-validate - microevent.ts@0.1.1: {} - micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.0.2 @@ -24815,11 +21404,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - miller-rabin@4.0.1: - dependencies: - bn.js: 4.12.0 - brorand: 1.1.0 - mime-db@1.33.0: {} mime-db@1.52.0: {} @@ -24844,10 +21428,10 @@ snapshots: mime@2.6.0: {} - mimic-fn@1.2.0: {} - mimic-fn@2.1.0: {} + mimic-function@5.0.1: {} + mimic-response@3.1.0: {} mimic-response@4.0.0: {} @@ -24862,8 +21446,6 @@ snapshots: minimalistic-assert@1.0.1: {} - minimalistic-crypto-utils@1.0.1: {} - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -24878,23 +21460,8 @@ snapshots: is-plain-obj: 1.1.0 kind-of: 6.0.3 - minimist@1.2.0: {} - minimist@1.2.8: {} - mississippi@3.0.0: - dependencies: - concat-stream: 1.6.2 - duplexify: 3.7.1 - end-of-stream: 1.4.4 - flush-write-stream: 1.1.1 - from2: 2.3.0 - parallel-transform: 1.2.0 - pump: 3.0.2 - pumpify: 1.5.1 - stream-each: 1.2.3 - through2: 2.0.5 - mixin-deep@1.3.2: dependencies: for-in: 1.0.2 @@ -24908,45 +21475,19 @@ snapshots: modify-values@1.0.1: {} - module-details-from-path@1.0.4: {} - monaco-editor@0.52.0: {} - move-concurrently@1.0.1: - dependencies: - aproba: 1.2.0 - copy-concurrently: 1.0.5 - fs-write-stream-atomic: 1.0.10 - mkdirp: 0.5.6 - rimraf: 2.7.1 - run-queue: 1.0.3 - mrmime@2.0.1: {} ms@2.0.0: {} - ms@2.1.1: {} - ms@2.1.3: {} - multer@1.4.2: - dependencies: - append-field: 1.0.0 - busboy: 0.2.14 - concat-stream: 1.6.2 - mkdirp: 0.5.6 - object-assign: 4.1.1 - on-finished: 2.4.1 - type-is: 1.6.18 - xtend: 4.0.2 - multicast-dns@7.2.5: dependencies: dns-packet: 5.6.1 thunky: 1.1.0 - mute-stream@0.0.7: {} - mute-stream@0.0.8: {} mysql2@3.12.0: @@ -24961,16 +21502,26 @@ snapshots: seq-queue: 0.0.5 sqlstring: 2.3.3 - mz@2.7.0: + mysql2@3.22.3(@types/node@24.5.2): dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 + '@types/node': 24.5.2 + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.2 + long: 5.3.2 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + sql-escaper: 1.3.3 named-placeholders@1.1.3: dependencies: lru-cache: 7.18.3 + named-placeholders@1.1.6: + dependencies: + lru.min: 1.1.4 + nan@2.20.0: optional: true @@ -24998,14 +21549,6 @@ snapshots: natural-compare@1.4.0: {} - needle@2.4.0: - dependencies: - debug: 3.2.7 - iconv-lite: 0.4.24 - sax: 1.4.1 - transitivePeerDependencies: - - supports-color - needle@3.3.1: dependencies: iconv-lite: 0.6.3 @@ -25018,8 +21561,6 @@ snapshots: neo-async@2.6.2: {} - netmask@2.0.2: {} - next-compose-plugins@2.2.1: {} next-fonts@1.5.1(webpack@5.98.0): @@ -25071,13 +21612,6 @@ snapshots: minimist: 1.2.8 next: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3) - next-tick@1.1.0: {} - - next-transpile-modules@6.4.1: - dependencies: - enhanced-resolve: 5.17.1 - escalade: 3.2.0 - next-with-less@2.0.5(less-loader@10.2.0(less@4.2.0)(webpack@5.98.0))(less@4.2.0)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)): dependencies: clone-deep: 4.0.1 @@ -25114,34 +21648,57 @@ snapshots: - '@babel/core' - babel-plugin-macros - nice-try@1.0.5: {} - - no-case@3.0.4: - dependencies: - lower-case: 2.0.2 - tslib: 2.7.0 - - nocache@2.1.0: {} - - nocache@3.0.4: {} - - node-abort-controller@3.1.1: {} - - node-dir@0.1.17: - dependencies: - minimatch: 3.1.2 - - node-domexception@1.0.0: {} - - node-emoji@1.10.0: - dependencies: - lodash.toarray: 4.4.0 - - node-emoji@1.11.0: - dependencies: - lodash: 4.17.21 - - node-emoji@2.2.0: + next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3): + dependencies: + '@next/env': 12.3.4 + '@swc/helpers': 0.4.11 + caniuse-lite: 1.0.30001701 + postcss: 8.4.14 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + styled-jsx: 5.0.7(@babel/core@7.26.9)(react@17.0.2) + use-sync-external-store: 1.2.0(react@17.0.2) + optionalDependencies: + '@next/swc-android-arm-eabi': 12.3.4 + '@next/swc-android-arm64': 12.3.4 + '@next/swc-darwin-arm64': 12.3.4 + '@next/swc-darwin-x64': 12.3.4 + '@next/swc-freebsd-x64': 12.3.4 + '@next/swc-linux-arm-gnueabihf': 12.3.4 + '@next/swc-linux-arm64-gnu': 12.3.4 + '@next/swc-linux-arm64-musl': 12.3.4 + '@next/swc-linux-x64-gnu': 12.3.4 + '@next/swc-linux-x64-musl': 12.3.4 + '@next/swc-win32-arm64-msvc': 12.3.4 + '@next/swc-win32-ia32-msvc': 12.3.4 + '@next/swc-win32-x64-msvc': 12.3.4 + sass: 1.79.3 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + nice-try@1.0.5: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.7.0 + + nocache@3.0.4: {} + + node-abort-controller@3.1.1: {} + + node-dir@0.1.17: + dependencies: + minimatch: 3.1.2 + + node-domexception@1.0.0: {} + + node-emoji@1.11.0: + dependencies: + lodash: 4.17.21 + + node-emoji@2.2.0: dependencies: '@sindresorhus/is': 4.6.0 char-regex: 1.0.2 @@ -25171,38 +21728,8 @@ snapshots: node-forge@1.3.1: {} - node-hex@1.0.1: {} - node-int64@0.4.0: {} - node-ip2region@1.0.2: {} - - node-libs-browser@2.2.1: - dependencies: - assert: 1.5.1 - browserify-zlib: 0.2.0 - buffer: 4.9.2 - console-browserify: 1.2.0 - constants-browserify: 1.0.0 - crypto-browserify: 3.12.0 - domain-browser: 1.2.0 - events: 3.3.0 - https-browserify: 1.0.0 - os-browserify: 0.3.0 - path-browserify: 0.0.1 - process: 0.11.10 - punycode: 1.4.1 - querystring-es3: 0.2.1 - readable-stream: 2.3.8 - stream-browserify: 2.0.2 - stream-http: 2.8.3 - string_decoder: 1.3.0 - timers-browserify: 2.0.12 - tty-browserify: 0.0.0 - url: 0.11.4 - util: 0.11.1 - vm-browserify: 1.1.2 - node-notifier@5.4.5: dependencies: growly: 1.3.0 @@ -25221,13 +21748,6 @@ snapshots: node-stream-zip@1.15.0: {} - nodemailer@6.9.15: {} - - noms@0.0.0: - dependencies: - inherits: 2.0.4 - readable-stream: 1.0.34 - normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 @@ -25262,17 +21782,10 @@ snapshots: nprogress@0.2.0: {} - nssocket@0.6.0: - dependencies: - eventemitter2: 0.4.14 - lazy: 1.0.11 - nth-check@2.1.1: dependencies: boolbase: 1.0.0 - nuid@1.1.6: {} - null-loader@4.0.1(webpack@5.98.0): dependencies: loader-utils: 2.0.4 @@ -25328,8 +21841,6 @@ snapshots: define-property: 0.2.5 kind-of: 3.2.2 - object-hash@2.0.3: {} - object-inspect@1.13.2: {} object-inspect@1.13.4: {} @@ -25413,14 +21924,14 @@ snapshots: dependencies: wrappy: 1.0.2 - onetime@2.0.1: - dependencies: - mimic-fn: 1.2.0 - onetime@5.1.2: dependencies: mimic-fn: 2.1.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + open@6.4.0: dependencies: is-wsl: 1.1.0 @@ -25438,8 +21949,6 @@ snapshots: opener@1.5.2: {} - optional@0.1.4: {} - optionator@0.8.3: dependencies: deep-is: 0.1.4 @@ -25458,17 +21967,6 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - ora@4.0.3: - dependencies: - chalk: 3.0.0 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - log-symbols: 3.0.0 - mute-stream: 0.0.8 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - ora@5.4.1: dependencies: bl: 4.1.0 @@ -25481,23 +21979,17 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 - os-browserify@0.3.0: {} - - os-name@1.0.3: - dependencies: - osx-release: 1.1.0 - win-release: 1.1.1 - - os-name@3.1.0: + ora@8.2.0: dependencies: - macos-release: 2.5.1 - windows-release: 3.3.3 - - os-tmpdir@1.0.2: {} - - osx-release@1.1.0: - dependencies: - minimist: 1.2.8 + chalk: 5.4.1 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.0 p-cancelable@3.0.0: {} @@ -25560,24 +22052,6 @@ snapshots: p-try@2.2.0: {} - pac-proxy-agent@7.2.0: - dependencies: - '@tootallnate/quickjs-emscripten': 0.23.0 - agent-base: 7.1.4 - debug: 4.4.3 - get-uri: 6.0.5 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - pac-resolver: 7.0.1 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - - pac-resolver@7.0.1: - dependencies: - degenerator: 5.0.1 - netmask: 2.0.2 - package-json@8.1.1: dependencies: got: 12.6.1 @@ -25585,16 +22059,6 @@ snapshots: registry-url: 6.0.1 semver: 7.6.3 - pako@0.2.9: {} - - pako@1.0.11: {} - - parallel-transform@1.2.0: - dependencies: - cyclist: 1.0.2 - inherits: 2.0.4 - readable-stream: 2.3.8 - param-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -25604,15 +22068,6 @@ snapshots: dependencies: callsites: 3.1.0 - parse-asn1@5.1.7: - dependencies: - asn1.js: 4.10.1 - browserify-aes: 1.2.0 - evp_bytestokey: 1.0.3 - hash-base: 3.0.4 - pbkdf2: 3.1.2 - safe-buffer: 5.2.1 - parse-entities@4.0.2: dependencies: '@types/unist': 2.0.11 @@ -25639,10 +22094,6 @@ snapshots: parse-numeric-range@1.3.0: {} - parse5-htmlparser2-tree-adapter@6.0.1: - dependencies: - parse5: 6.0.1 - parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 @@ -25650,10 +22101,6 @@ snapshots: parse5@4.0.0: {} - parse5@5.1.1: {} - - parse5@6.0.1: {} - parse5@7.2.1: dependencies: entities: 4.5.0 @@ -25667,22 +22114,6 @@ snapshots: pascalcase@0.1.1: {} - passport-jwt@4.0.1: - dependencies: - jsonwebtoken: 9.0.2 - passport-strategy: 1.0.0 - - passport-strategy@1.0.0: {} - - passport@0.4.1: - dependencies: - passport-strategy: 1.0.0 - pause: 0.0.1 - - path-browserify@0.0.1: {} - - path-dirname@1.0.2: {} - path-exists@3.0.0: {} path-exists@4.0.0: {} @@ -25701,16 +22132,12 @@ snapshots: path-to-regexp@0.1.12: {} - path-to-regexp@0.1.7: {} - path-to-regexp@1.9.0: dependencies: isarray: 0.0.1 path-to-regexp@2.4.0: {} - path-to-regexp@3.2.0: {} - path-to-regexp@3.3.0: {} path-to-regexp@8.3.0: {} @@ -25721,20 +22148,6 @@ snapshots: path-type@4.0.0: {} - pause-stream@0.0.11: - dependencies: - through: 2.3.8 - - pause@0.0.1: {} - - pbkdf2@3.1.2: - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - performance-now@0.2.0: {} performance-now@2.1.0: {} @@ -25745,15 +22158,6 @@ snapshots: pidtree@0.5.0: {} - pidusage@2.0.21: - dependencies: - safe-buffer: 5.2.1 - optional: true - - pidusage@3.0.2: - dependencies: - safe-buffer: 5.2.1 - pify@2.3.0: {} pify@3.0.0: {} @@ -25784,81 +22188,6 @@ snapshots: dependencies: find-up: 3.0.0 - platform@1.3.6: {} - - pm2-axon-rpc@0.7.1: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - pm2-axon@4.0.1: - dependencies: - amp: 0.3.1 - amp-message: 0.1.2 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - transitivePeerDependencies: - - supports-color - - pm2-deploy@1.0.2: - dependencies: - run-series: 1.1.9 - tv4: 1.3.0 - - pm2-multimeter@0.1.2: - dependencies: - charm: 0.1.2 - - pm2-sysmonit@1.2.8: - dependencies: - async: 3.2.6 - debug: 4.4.3 - pidusage: 2.0.21 - systeminformation: 5.27.10 - tx2: 1.0.5 - transitivePeerDependencies: - - supports-color - optional: true - - pm2@5.4.3: - dependencies: - '@pm2/agent': 2.0.4 - '@pm2/io': 6.0.1 - '@pm2/js-api': 0.8.0 - '@pm2/pm2-version-check': 1.0.4 - async: 3.2.6 - blessed: 0.1.81 - chalk: 3.0.0 - chokidar: 3.6.0 - cli-tableau: 2.0.1 - commander: 2.15.1 - croner: 4.1.97 - dayjs: 1.11.13 - debug: 4.4.3 - enquirer: 2.3.6 - eventemitter2: 5.0.1 - fclone: 1.0.11 - js-yaml: 4.1.0 - mkdirp: 1.0.4 - needle: 2.4.0 - pidusage: 3.0.2 - pm2-axon: 4.0.1 - pm2-axon-rpc: 0.7.1 - pm2-deploy: 1.0.2 - pm2-multimeter: 0.1.2 - promptly: 2.2.0 - semver: 7.6.3 - source-map-support: 0.5.21 - sprintf-js: 1.1.2 - vizion: 2.2.1 - optionalDependencies: - pm2-sysmonit: 1.2.8 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - pn@1.1.0: {} posix-character-classes@0.1.1: {} @@ -26314,8 +22643,6 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@1.19.1: {} - prettier@2.7.1: {} prettier@2.8.8: {} @@ -26365,12 +22692,6 @@ snapshots: process-nextick-args@2.0.1: {} - process@0.11.10: {} - - promise-inflight@1.0.1(bluebird@3.7.2): - optionalDependencies: - bluebird: 3.7.2 - promise@7.3.1: dependencies: asap: 2.0.6 @@ -26379,10 +22700,6 @@ snapshots: dependencies: asap: 2.0.6 - promptly@2.2.0: - dependencies: - read: 1.0.7 - prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -26405,52 +22722,18 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-agent@6.3.1: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - lru-cache: 7.18.3 - pac-proxy-agent: 7.2.0 - proxy-from-env: 1.1.0 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - proxy-from-env@1.1.0: {} - prr@1.0.1: {} + prr@1.0.1: + optional: true psl@1.9.0: {} - public-encrypt@4.0.3: - dependencies: - bn.js: 4.12.0 - browserify-rsa: 4.1.0 - create-hash: 1.2.0 - parse-asn1: 5.1.7 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - pump@2.0.1: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - pump@3.0.2: dependencies: end-of-stream: 1.4.4 once: 1.4.0 - pumpify@1.5.1: - dependencies: - duplexify: 3.7.1 - inherits: 2.0.4 - pump: 2.0.1 - - punycode@1.4.1: {} - punycode@2.3.1: {} pupa@3.1.0: @@ -26469,10 +22752,6 @@ snapshots: qs@6.5.3: {} - qs@6.7.0: {} - - querystring-es3@0.2.1: {} - queue-microtask@1.2.3: {} queue@6.0.2: @@ -26491,22 +22770,10 @@ snapshots: dependencies: safe-buffer: 5.2.1 - randomfill@1.0.4: - dependencies: - randombytes: 2.1.0 - safe-buffer: 5.2.1 - range-parser@1.2.0: {} range-parser@1.2.1: {} - raw-body@2.4.0: - dependencies: - bytes: 3.1.0 - http-errors: 1.7.2 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - raw-body@2.5.2: dependencies: bytes: 3.1.2 @@ -27231,24 +23498,6 @@ snapshots: parse-json: 5.2.0 type-fest: 0.6.0 - read@1.0.7: - dependencies: - mute-stream: 0.0.8 - - readable-stream@1.0.34: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 0.0.1 - string_decoder: 0.10.31 - - readable-stream@1.1.14: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 0.0.1 - string_decoder: 0.10.31 - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -27265,14 +23514,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readdirp@2.2.1: - dependencies: - graceful-fs: 4.2.11 - micromatch: 3.1.10 - readable-stream: 2.3.8 - transitivePeerDependencies: - - supports-color - readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -27337,10 +23578,6 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 - referrer-policy@1.2.0: {} - - reflect-metadata@0.1.14: {} - reflect.getprototypeof@1.0.6: dependencies: call-bind: 1.0.7 @@ -27555,14 +23792,6 @@ snapshots: require-from-string@2.0.2: {} - require-in-the-middle@5.2.0: - dependencies: - debug: 4.4.3 - module-details-from-path: 1.0.4 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - require-like@0.1.2: {} require-main-filename@2.0.0: {} @@ -27603,16 +23832,16 @@ snapshots: dependencies: lowercase-keys: 3.0.0 - restore-cursor@2.0.0: - dependencies: - onetime: 2.0.1 - signal-exit: 3.0.7 - restore-cursor@3.1.0: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + ret@0.1.15: {} retry@0.13.1: {} @@ -27629,19 +23858,10 @@ snapshots: dependencies: glob: 7.2.3 - rimraf@3.0.1: - dependencies: - glob: 7.2.3 - rimraf@3.0.2: dependencies: glob: 7.2.3 - ripemd160@2.0.2: - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - rollup-plugin-terser@7.0.2(rollup@2.79.1): dependencies: '@babel/code-frame': 7.24.7 @@ -27679,20 +23899,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - run-queue@1.0.3: - dependencies: - aproba: 1.2.0 - - run-series@1.1.9: {} - - rxjs@6.3.3: - dependencies: - tslib: 1.14.1 - - rxjs@6.6.7: - dependencies: - tslib: 1.14.1 - rxjs@7.8.1: dependencies: tslib: 2.7.0 @@ -27770,15 +23976,9 @@ snapshots: scheduler@0.25.0: {} - schema-utils@1.0.0: + schema-utils@2.7.0: dependencies: - ajv: 6.12.6 - ajv-errors: 1.0.1(ajv@6.12.6) - ajv-keywords: 3.5.2(ajv@6.12.6) - - schema-utils@2.7.0: - dependencies: - '@types/json-schema': 7.0.15 + '@types/json-schema': 7.0.15 ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) @@ -27805,10 +24005,6 @@ snapshots: dependencies: compute-scroll-into-view: 3.1.0 - sdk-base@2.0.1: - dependencies: - get-ready: 1.0.0 - search-insights@2.17.3: {} section-matter@1.0.0: @@ -27816,8 +24012,6 @@ snapshots: extend-shallow: 2.0.1 kind-of: 6.0.3 - segment@0.1.3: {} - select-hose@2.0.0: {} selfsigned@2.4.1: @@ -27833,30 +24027,8 @@ snapshots: semver@6.3.1: {} - semver@7.5.4: - dependencies: - lru-cache: 6.0.0 - semver@7.6.3: {} - send@0.17.1: - dependencies: - debug: 2.6.9 - depd: 1.1.2 - destroy: 1.0.4 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 1.7.3 - mime: 1.6.0 - ms: 2.1.1 - on-finished: 2.3.0 - range-parser: 1.2.1 - statuses: 1.5.0 - transitivePeerDependencies: - - supports-color - send@0.19.0: dependencies: debug: 2.6.9 @@ -27925,15 +24097,6 @@ snapshots: transitivePeerDependencies: - supports-color - serve-static@1.14.1: - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.17.1 - transitivePeerDependencies: - - supports-color - serve-static@1.16.2: dependencies: encodeurl: 2.0.0 @@ -27981,15 +24144,8 @@ snapshots: setprototypeof@1.1.0: {} - setprototypeof@1.1.1: {} - setprototypeof@1.2.0: {} - sha.js@2.4.11: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - shallow-clone@3.0.1: dependencies: kind-of: 6.0.3 @@ -28018,8 +24174,6 @@ snapshots: shellwords@0.1.1: {} - shimmer@1.2.1: {} - should-equal@2.0.0: dependencies: should-type: 1.4.0 @@ -28087,6 +24241,8 @@ snapshots: signal-exit@3.0.7: {} + signal-exit@4.1.0: {} + sirv@2.0.4: dependencies: '@polka/url': 1.0.0-next.28 @@ -28137,8 +24293,6 @@ snapshots: ansi-styles: 6.2.1 is-fullwidth-code-point: 4.0.0 - smart-buffer@4.2.0: {} - snake-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -28173,19 +24327,6 @@ snapshots: uuid: 8.3.2 websocket-driver: 0.7.4 - socks-proxy-agent@8.0.5: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - socks: 2.8.7 - transitivePeerDependencies: - - supports-color - - socks@2.8.7: - dependencies: - ip-address: 10.0.1 - smart-buffer: 4.2.0 - sort-css-media-queries@2.2.0: {} source-list-map@2.0.1: {} @@ -28211,8 +24352,6 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.3: {} - source-map@0.7.4: {} source-map@0.8.0-beta.0: @@ -28274,7 +24413,7 @@ snapshots: sprintf-js@1.0.3: {} - sprintf-js@1.1.2: {} + sql-escaper@1.3.3: {} sqlstring@2.3.3: {} @@ -28292,10 +24431,6 @@ snapshots: safer-buffer: 2.1.2 tweetnacl: 0.14.5 - ssri@6.0.2: - dependencies: - figgy-pudding: 3.5.2 - stack-utils@1.0.5: dependencies: escape-string-regexp: 2.0.0 @@ -28323,52 +24458,14 @@ snapshots: std-env@3.8.1: {} + stdin-discarder@0.2.2: {} + stealthy-require@1.1.1: {} stop-iteration-iterator@1.0.0: dependencies: internal-slot: 1.0.7 - stream-browserify@2.0.2: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - - stream-each@1.2.3: - dependencies: - end-of-stream: 1.4.4 - stream-shift: 1.0.3 - - stream-http@2.8.2: - dependencies: - builtin-status-codes: 3.0.0 - inherits: 2.0.4 - readable-stream: 2.3.8 - to-arraybuffer: 1.0.1 - xtend: 4.0.2 - - stream-http@2.8.3: - dependencies: - builtin-status-codes: 3.0.0 - inherits: 2.0.4 - readable-stream: 2.3.8 - to-arraybuffer: 1.0.1 - xtend: 4.0.2 - - stream-shift@1.0.3: {} - - stream-wormhole@1.1.0: {} - - streamroller@3.1.5: - dependencies: - date-format: 4.0.14 - debug: 4.4.3 - fs-extra: 8.1.0 - transitivePeerDependencies: - - supports-color - - streamsearch@0.1.2: {} - string-argv@0.3.2: {} string-convert@0.2.1: {} @@ -28378,11 +24475,6 @@ snapshots: astral-regex: 1.0.0 strip-ansi: 4.0.0 - string-width@2.1.1: - dependencies: - is-fullwidth-code-point: 2.0.0 - strip-ansi: 4.0.0 - string-width@3.1.0: dependencies: emoji-regex: 7.0.3 @@ -28401,6 +24493,12 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.1.0 + string.prototype.includes@2.0.0: dependencies: define-properties: 1.2.1 @@ -28445,8 +24543,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 - string_decoder@0.10.31: {} - string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -28466,10 +24562,6 @@ snapshots: is-obj: 1.0.1 is-regexp: 1.0.0 - strip-ansi@3.0.1: - dependencies: - ansi-regex: 2.1.1 - strip-ansi@4.0.0: dependencies: ansi-regex: 3.0.1 @@ -28520,6 +24612,12 @@ snapshots: optionalDependencies: '@babel/core': 7.25.2 + styled-jsx@5.0.7(@babel/core@7.26.9)(react@17.0.2): + dependencies: + react: 17.0.2 + optionalDependencies: + '@babel/core': 7.26.9 + stylehacks@6.1.1(postcss@8.5.3): dependencies: browserslist: 4.23.3 @@ -28530,30 +24628,6 @@ snapshots: sudo-prompt@9.2.1: {} - superagent@3.8.3: - dependencies: - component-emitter: 1.3.1 - cookiejar: 2.1.4 - debug: 3.2.7 - extend: 3.0.2 - form-data: 2.5.1 - formidable: 1.2.6 - methods: 1.1.2 - mime: 1.6.0 - qs: 6.13.0 - readable-stream: 2.3.8 - transitivePeerDependencies: - - supports-color - - supertest@4.0.2: - dependencies: - methods: 1.1.2 - superagent: 3.8.3 - transitivePeerDependencies: - - supports-color - - supports-color@2.0.0: {} - supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -28592,8 +24666,6 @@ snapshots: swagger-schema-official@2.0.0-bab6bed: {} - swagger-themes@1.4.3: {} - swagger-typescript-api@12.0.4(encoding@0.1.13): dependencies: '@types/swagger-schema-official': 2.0.22 @@ -28613,13 +24685,6 @@ snapshots: transitivePeerDependencies: - encoding - swagger-ui-dist@5.17.14: {} - - swagger-ui-express@4.6.3(express@4.21.2): - dependencies: - express: 4.21.2 - swagger-ui-dist: 5.17.14 - swagger2openapi@7.0.8(encoding@0.1.13): dependencies: call-me-maybe: 1.0.2 @@ -28642,13 +24707,8 @@ snapshots: react: 17.0.2 use-sync-external-store: 1.2.2(react@17.0.2) - symbol-observable@1.2.0: {} - symbol-tree@3.2.4: {} - systeminformation@5.27.10: - optional: true - tapable@1.1.3: {} tapable@2.2.1: {} @@ -28671,19 +24731,6 @@ snapshots: type-fest: 0.16.0 unique-string: 2.0.0 - terser-webpack-plugin@1.4.6(webpack@4.41.5): - dependencies: - cacache: 12.0.4 - find-cache-dir: 2.1.0 - is-wsl: 1.1.0 - schema-utils: 1.0.0 - serialize-javascript: 4.0.0 - source-map: 0.6.1 - terser: 4.8.1 - webpack: 4.41.5 - webpack-sources: 1.4.3 - worker-farm: 1.7.0 - terser-webpack-plugin@5.3.10(webpack@5.98.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -28702,13 +24749,6 @@ snapshots: terser: 5.33.0 webpack: 5.98.0 - terser@4.8.1: - dependencies: - acorn: 8.14.0 - commander: 2.20.3 - source-map: 0.6.1 - source-map-support: 0.5.21 - terser@5.33.0: dependencies: '@jridgewell/source-map': 0.3.6 @@ -28727,14 +24767,6 @@ snapshots: text-table@0.2.0: {} - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - three@0.168.0: {} throat@4.1.0: {} @@ -28752,27 +24784,12 @@ snapshots: thunky@1.1.0: {} - timers-browserify@2.0.12: - dependencies: - setimmediate: 1.0.5 - - timers-ext@0.1.8: - dependencies: - es5-ext: 0.10.64 - next-tick: 1.1.0 - tiny-invariant@1.3.3: {} tiny-warning@1.0.3: {} - tmp@0.0.33: - dependencies: - os-tmpdir: 1.0.2 - tmpl@1.0.5: {} - to-arraybuffer@1.0.1: {} - to-object-path@0.3.0: dependencies: kind-of: 3.2.2 @@ -28795,8 +24812,6 @@ snapshots: toggle-selection@1.0.6: {} - toidentifier@1.0.0: {} - toidentifier@1.0.1: {} totalist@3.0.1: {} @@ -28834,30 +24849,6 @@ snapshots: semver: 5.7.2 yargs-parser: 10.1.0 - ts-loader@6.2.2(typescript@4.1.6): - dependencies: - chalk: 2.4.2 - enhanced-resolve: 4.5.0 - loader-utils: 1.4.2 - micromatch: 4.0.8 - semver: 6.3.1 - typescript: 4.1.6 - - ts-node@8.10.2(typescript@4.1.6): - dependencies: - arg: 4.1.3 - diff: 4.0.2 - make-error: 1.3.6 - source-map-support: 0.5.21 - typescript: 4.1.6 - yn: 3.1.1 - - tsconfig-paths-webpack-plugin@3.2.0: - dependencies: - chalk: 2.4.2 - enhanced-resolve: 4.5.0 - tsconfig-paths: 3.15.0 - tsconfig-paths-webpack-plugin@3.5.2: dependencies: chalk: 4.1.2 @@ -28871,70 +24862,23 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tsconfig-paths@3.9.0: - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - - tslib@1.11.1: {} - tslib@1.14.1: {} - tslib@1.9.3: {} - tslib@2.3.0: {} tslib@2.7.0: {} - tslint@5.20.1(typescript@4.1.6): - dependencies: - '@babel/code-frame': 7.24.7 - builtin-modules: 1.1.1 - chalk: 2.4.2 - commander: 2.20.3 - diff: 4.0.2 - glob: 7.2.3 - js-yaml: 3.14.1 - minimatch: 3.1.2 - mkdirp: 0.5.6 - resolve: 1.22.8 - semver: 5.7.2 - tslib: 1.14.1 - tsutils: 2.29.0(typescript@4.1.6) - typescript: 4.1.6 - - tsutils@2.29.0(typescript@4.1.6): - dependencies: - tslib: 1.14.1 - typescript: 4.1.6 - - tsutils@3.21.0(typescript@4.1.6): - dependencies: - tslib: 1.14.1 - typescript: 4.1.6 - tsutils@3.21.0(typescript@4.6.2): dependencies: tslib: 1.14.1 typescript: 4.6.2 - tty-browserify@0.0.0: {} - tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 - tv4@1.3.0: {} - tweetnacl@0.14.5: {} - tx2@1.0.5: - dependencies: - json-stringify-safe: 5.0.1 - optional: true - type-check@0.3.2: dependencies: prelude-ls: 1.1.2 @@ -28974,8 +24918,6 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.1 - type@2.7.3: {} - typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 @@ -29012,34 +24954,6 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typedarray@0.0.6: {} - - typeorm@0.2.45(mysql2@3.12.0): - dependencies: - '@sqltools/formatter': 1.2.5 - app-root-path: 3.1.0 - buffer: 6.0.3 - chalk: 4.1.2 - cli-highlight: 2.1.11 - debug: 4.3.7(supports-color@9.4.0) - dotenv: 8.6.0 - glob: 7.2.3 - js-yaml: 4.1.0 - mkdirp: 1.0.4 - reflect-metadata: 0.1.14 - sha.js: 2.4.11 - tslib: 2.7.0 - uuid: 8.3.2 - xml2js: 0.4.23 - yargs: 17.7.2 - zen-observable-ts: 1.1.0 - optionalDependencies: - mysql2: 3.12.0 - transitivePeerDependencies: - - supports-color - - typescript@3.9.10: {} - typescript@4.1.6: {} typescript@4.6.2: {} @@ -29060,12 +24974,7 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - undici-types@7.12.0: - optional: true - - unescape@1.0.1: - dependencies: - extend-shallow: 2.0.1 + undici-types@7.12.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -29097,14 +25006,6 @@ snapshots: is-extendable: 0.1.1 set-value: 2.0.1 - unique-filename@1.1.1: - dependencies: - unique-slug: 2.0.2 - - unique-slug@2.0.2: - dependencies: - imurmurhash: 0.1.4 - unique-string@2.0.0: dependencies: crypto-random-string: 2.0.0 @@ -29197,26 +25098,6 @@ snapshots: optionalDependencies: file-loader: 6.2.0(webpack@5.98.0) - url@0.11.4: - dependencies: - punycode: 1.4.1 - qs: 6.13.0 - - urllib@2.44.0: - dependencies: - any-promise: 1.3.0 - content-type: 1.0.5 - default-user-agent: 1.0.0 - digest-header: 1.1.0 - ee-first: 1.1.1 - formstream: 1.5.1 - humanize-ms: 1.2.1 - iconv-lite: 0.6.3 - pump: 3.0.2 - qs: 6.13.0 - statuses: 1.5.0 - utility: 1.18.0 - use-intl@1.5.1(react@17.0.2): dependencies: intl-messageformat: 9.13.0 @@ -29244,34 +25125,14 @@ snapshots: object.getownpropertydescriptors: 2.1.8 safe-array-concat: 1.1.2 - util@0.10.4: - dependencies: - inherits: 2.0.3 - - util@0.11.1: - dependencies: - inherits: 2.0.3 - utila@0.4.0: {} utility-types@3.11.0: {} - utility@1.18.0: - dependencies: - copy-to: 2.0.1 - escape-html: 1.0.3 - mkdirp: 0.5.6 - mz: 2.7.0 - unescape: 1.0.1 - utils-merge@1.0.1: {} uuid@3.4.0: {} - uuid@7.0.1: {} - - uuid@7.0.3: {} - uuid@8.3.2: {} v8-compile-cache@2.4.0: {} @@ -29281,8 +25142,6 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - validator@13.12.0: {} - value-equal@1.0.1: {} vary@1.1.2: {} @@ -29310,17 +25169,8 @@ snapshots: viewerjs@1.11.6: {} - vizion@2.2.1: - dependencies: - async: 2.6.4 - git-node-fs: 1.0.0(js-git@0.7.8) - ini: 1.3.8 - js-git: 0.7.8 - vlq@1.0.1: {} - vm-browserify@1.1.2: {} - w3c-hr-time@1.0.2: dependencies: browser-process-hrtime: 1.0.0 @@ -29333,23 +25183,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - watchpack-chokidar2@2.0.1: - dependencies: - chokidar: 2.1.8 - transitivePeerDependencies: - - supports-color - optional: true - - watchpack@1.7.5: - dependencies: - graceful-fs: 4.2.11 - neo-async: 2.6.2 - optionalDependencies: - chokidar: 3.6.0 - watchpack-chokidar2: 2.0.1 - transitivePeerDependencies: - - supports-color - watchpack@2.4.2: dependencies: glob-to-regexp: 0.4.1 @@ -29450,8 +25283,6 @@ snapshots: flat: 5.0.2 wildcard: 2.0.1 - webpack-node-externals@1.7.2: {} - webpack-sources@1.4.3: dependencies: source-list-map: 2.0.1 @@ -29459,34 +25290,6 @@ snapshots: webpack-sources@3.2.3: {} - webpack@4.41.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-module-context': 1.8.5 - '@webassemblyjs/wasm-edit': 1.8.5 - '@webassemblyjs/wasm-parser': 1.8.5 - acorn: 6.4.2 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - chrome-trace-event: 1.0.4 - enhanced-resolve: 4.5.0 - eslint-scope: 4.0.3 - json-parse-better-errors: 1.0.2 - loader-runner: 2.4.0 - loader-utils: 1.4.2 - memory-fs: 0.4.1 - micromatch: 3.1.10 - mkdirp: 0.5.6 - neo-async: 2.6.2 - node-libs-browser: 2.2.1 - schema-utils: 1.0.0 - tapable: 1.1.3 - terser-webpack-plugin: 1.4.6(webpack@4.41.5) - watchpack: 1.7.5 - webpack-sources: 1.4.3 - transitivePeerDependencies: - - supports-color - webpack@5.98.0: dependencies: '@types/eslint-scope': 3.7.7 @@ -29616,14 +25419,6 @@ snapshots: wildcard@2.0.1: {} - win-release@1.1.1: - dependencies: - semver: 5.7.2 - - windows-release@3.3.3: - dependencies: - execa: 1.0.0 - word-wrap@1.2.5: {} wordwrap@1.0.0: {} @@ -29753,14 +25548,6 @@ snapshots: '@types/trusted-types': 2.0.7 workbox-core: 6.6.0 - worker-farm@1.7.0: - dependencies: - errno: 0.1.8 - - worker-rpc@0.1.1: - dependencies: - microevent.ts: 0.1.1 - wrap-ansi@5.1.0: dependencies: ansi-styles: 3.2.1 @@ -29818,8 +25605,6 @@ snapshots: ws@8.18.1: {} - x-xss-protection@1.3.0: {} - xdg-basedir@5.1.0: {} xml-js@1.6.11: @@ -29828,20 +25613,8 @@ snapshots: xml-name-validator@3.0.0: {} - xml2js@0.4.23: - dependencies: - sax: 1.4.1 - xmlbuilder: 11.0.1 - - xml2js@0.6.2: - dependencies: - sax: 1.4.1 - xmlbuilder: 11.0.1 - xml@1.0.1: {} - xmlbuilder@11.0.1: {} - xtend@4.0.2: {} y18n@4.0.3: {} @@ -29940,21 +25713,12 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yn@3.1.1: {} - yocto-queue@0.1.0: {} yocto-queue@1.1.1: {} zdog@1.1.3: {} - zen-observable-ts@1.1.0: - dependencies: - '@types/zen-observable': 0.8.3 - zen-observable: 0.8.15 - - zen-observable@0.8.15: {} - zrender@5.6.1: dependencies: tslib: 2.3.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5d4fcaf..f489b37 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,7 +1,7 @@ packages: # 客户端 - 'client' - # 服务器 + # API(薄封装,依赖 reactpress-cli) - 'server' # 文档 - 'docs' diff --git a/scripts/bundled-server-path.js b/scripts/bundled-server-path.js new file mode 100644 index 0000000..a51277e --- /dev/null +++ b/scripts/bundled-server-path.js @@ -0,0 +1,4 @@ +/** + * Re-export from server package (single source for CLI bundled paths). + */ +module.exports = require('../server/lib/bundled-server-path'); diff --git a/scripts/docker-dev.js b/scripts/docker-dev.js index c9af1b5..ce77553 100755 --- a/scripts/docker-dev.js +++ b/scripts/docker-dev.js @@ -128,12 +128,14 @@ switch (command) { } console.log('[ReactPress] Toolkit built successfully.'); - console.log('[ReactPress] Starting client and server in development mode...'); + console.log('[ReactPress] Starting client and API (reactpress-cli) in development mode...'); console.log('[ReactPress] Access your application at: http://localhost:8080'); // 执行并发命令 const concurrently = spawn('npx', [ 'concurrently', + '-n', 'api,web', + '-c', 'blue,green', 'pnpm:dev:server', 'pnpm:dev:client' ], { diff --git a/scripts/install.sh b/scripts/install.sh index f6bd8f1..1daaf6f 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -55,6 +55,14 @@ check_dependencies() { if ! docker info > /dev/null 2>&1; then error "Docker daemon is not running. Please start Docker and run this script again." fi + + if ! command -v node &> /dev/null; then + error "Node.js >= 18 is required for @fecommunity/reactpress-cli. See https://nodejs.org/" + fi + + if ! command -v pnpm &> /dev/null; then + error "pnpm is required. Install: npm install -g pnpm" + fi log "All dependencies found!" } @@ -122,18 +130,7 @@ NEXT_PUBLIC_SITE_URL=http://localhost:8080 NODE_ENV=production EOF - # Create server-specific .env file - cat > server/.env << 'EOF' -# Server Environment Variables -DB_HOST=db -DB_PORT=3306 -DB_USER=reactpress -DB_PASSWD=reactpress -DB_DATABASE=reactpress -NODE_ENV=production -PORT=3002 -CORS_ORIGIN=http://client:3001 -EOF + # API 由 @fecommunity/reactpress-cli 管理(.reactpress/config.json + 根目录 .env) # Create toolkit-specific .env file to prevent build errors mkdir -p toolkit @@ -170,9 +167,9 @@ server { proxy_connect_timeout 300; } - # Server API (NestJS) + # Server API (host: reactpress-cli start) location /api/ { - proxy_pass http://server:3002; + proxy_pass http://host.docker.internal:3002/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -339,6 +336,22 @@ EOF if [ ! -f "server/package.json" ]; then error "server/package.json not found" fi + + if ! grep -q '@fecommunity/reactpress-cli' server/package.json 2>/dev/null; then + error "server/package.json must depend on @fecommunity/reactpress-cli" + fi +} + +# Install deps and start API via reactpress-cli on the host +start_api_via_cli() { + log "Installing Node dependencies..." + pnpm install || error "pnpm install failed" + + log "Initializing ReactPress (reactpress-cli init)..." + pnpm exec reactpress-cli init . --force 2>/dev/null || pnpm exec reactpress-cli init . + + log "Starting API (reactpress-cli start)..." + pnpm exec reactpress-cli start || warn "reactpress-cli start failed — ensure port 3002 is free and Docker MySQL (db) is reachable" } # Create optimized Dockerfiles that handle environment files properly @@ -399,55 +412,7 @@ USER nextjs CMD ["pnpm", "run", "start"] EOF - # Server Dockerfile - cat > server/Dockerfile << 'EOF' -# Use Node.js 18 as the base image -FROM node:18-alpine - -# Set working directory -WORKDIR /app - -# Install pnpm globally -RUN npm install -g pnpm - -# Copy ALL files from the project root (including .env files) -COPY . . - -# Debug: Show environment files -RUN echo "=== Environment Files ===" && \ - find . -name ".env*" | head -10 - -# Install all dependencies -RUN pnpm install --no-frozen-lockfile - -# Build toolkit first with environment safety -RUN echo "=== Building Toolkit ===" && \ - cd toolkit && \ - pnpm run build || (echo "Toolkit build failed, creating basic structure..." && \ - mkdir -p dist && \ - echo 'exports.config = {}; exports.messages = {}; exports.emptyConfig = {}; exports.emptyMessages = {};' > dist/index.js && \ - echo 'export const config = {}; export const messages = {}; export const emptyConfig = {}; export const emptyMessages = {};' > dist/index.d.ts) - -# Build server application -WORKDIR /app/server -RUN pnpm run build - -# Expose port -EXPOSE 3002 - -# Create a non-root user -RUN addgroup -g 1001 -S nodejs && \ - adduser -S nestjs -u 1001 - -# Change ownership of the app directory -RUN chown -R nestjs:nodejs /app -USER nestjs - -# Start the application -CMD ["pnpm", "run", "start"] -EOF - - log "Dockerfiles updated with comprehensive environment handling" + log "Dockerfiles updated (API runs on host via reactpress-cli, not in a server container)" } # Clean Docker cache @@ -489,13 +454,13 @@ build_and_start_services() { while [ $elapsed -lt $wait_time ]; do running_count=$($DOCKER_COMPOSE_CMD -f docker-compose.prod.yml ps --services --filter "status=running" | wc -l) - if [ "$running_count" -eq 4 ]; then - log "✅ All 4 services are running!" + if [ "$running_count" -ge 3 ]; then + log "✅ Docker services are running (db, client, nginx)!" break fi sleep 10 elapsed=$((elapsed + 10)) - log "Waited ${elapsed}s for services... ($running_count/4 running)" + log "Waited ${elapsed}s for services... ($running_count/3+ running)" done if [ $elapsed -ge $wait_time ]; then @@ -518,6 +483,9 @@ deploy_full_application() { # Update Dockerfiles update_dockerfiles + + # API on host (before nginx proxies /api to host.docker.internal:3002) + start_api_via_cli # Build and start services build_and_start_services @@ -545,7 +513,7 @@ show_help() { echo " Or run: ./install.sh [directory]" echo "" echo "This script automatically handles environment file issues and provides" - echo "a complete ReactPress installation with MySQL, NestJS server, Next.js client, and nginx." + echo "a complete ReactPress installation with MySQL, reactpress-cli API, Next.js client, and nginx." echo "" echo "Access your application at: http://localhost:8080" } diff --git a/scripts/reactpress-cli.js b/scripts/reactpress-cli.js index 07cf15e..209f905 100755 --- a/scripts/reactpress-cli.js +++ b/scripts/reactpress-cli.js @@ -1,99 +1,123 @@ #!/usr/bin/env node /** - * ReactPress CLI - Unified entry point for ReactPress commands - * This script allows users to run reactpress commands after installing the package globally + * ReactPress CLI — unified entry for monorepo development. + * Server lifecycle is delegated to @fecommunity/reactpress-cli; client stays local. */ const { Command } = require('commander'); -const { spawn } = require('child_process'); +const { spawn, spawnSync } = require('child_process'); const path = require('path'); const chalk = require('chalk'); +const serverBin = path.join(rootDir, 'server', 'bin', 'reactpress-server.js'); -// Create the CLI program -const program = new Command(); - -// Get the directory where this script is located const binDir = __dirname; const rootDir = path.join(binDir, '..'); -// Server command with subcommands -const serverCmd = program - .command('server') - .description('Manage the ReactPress server'); +const program = new Command(); + +function runReactpressCli(args, options = {}) { + const result = spawnSync('pnpm', ['exec', 'reactpress-cli', ...args], { + cwd: options.cwd || rootDir, + stdio: 'inherit', + env: { + ...process.env, + REACTPRESS_ORIGINAL_CWD: process.env.REACTPRESS_ORIGINAL_CWD || process.cwd(), + }, + }); + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} + +function spawnNodeScript(scriptPath, args = [], options = {}) { + const child = spawn(process.execPath, [scriptPath, ...args], { + stdio: 'inherit', + cwd: options.cwd || rootDir, + env: { + ...process.env, + REACTPRESS_ORIGINAL_CWD: process.env.REACTPRESS_ORIGINAL_CWD || process.cwd(), + ...options.env, + }, + }); + child.on('error', (error) => { + console.error(chalk.red('[ReactPress CLI]'), error); + process.exit(1); + }); + child.on('close', (code) => process.exit(code ?? 0)); +} + +const serverCmd = program.command('server').description('Manage the ReactPress API (via reactpress-cli)'); serverCmd .command('start') - .description('Start the ReactPress server (equivalent to running npx @fecommunity/reactpress-server)') + .description('Start the API server (server/ wrapper → reactpress-cli or --pm2)') .option('--pm2', 'Start server with PM2 process manager') .action((options) => { - const serverScript = path.join(rootDir, 'server', 'bin', 'reactpress-server.js'); - - let args = []; - if (options.pm2) { - args.push('--pm2'); - } - - const serverProcess = spawn('node', [serverScript, ...args], { - stdio: 'inherit' - }); - - serverProcess.on('error', (error) => { - console.error(chalk.red('[ReactPress CLI] Failed to start server:'), error); - process.exit(1); - }); + const args = options.pm2 ? ['--pm2'] : []; + spawnNodeScript(serverBin, args); + }); + +serverCmd + .command('stop') + .description('Stop the API server') + .option('--database', 'Also stop embedded database container') + .action((options) => { + const args = ['stop']; + if (options.database) args.push('--database'); + runReactpressCli(args); }); -// Client command with subcommands -const clientCmd = program - .command('client') - .description('Manage the ReactPress client'); +serverCmd + .command('restart') + .description('Restart the API server') + .action(() => runReactpressCli(['restart'])); + +serverCmd + .command('status') + .description('Show API and database status') + .action(() => runReactpressCli(['status'])); + +const clientCmd = program.command('client').description('Manage the ReactPress client'); clientCmd .command('start') - .description('Start the ReactPress client (equivalent to running npx @fecommunity/reactpress-client)') + .description('Start the ReactPress client') .option('--pm2', 'Start client with PM2 process manager') .action((options) => { const clientScript = path.join(rootDir, 'client', 'bin', 'reactpress-client.js'); - - let args = []; - if (options.pm2) { - args.push('--pm2'); - } - - const clientProcess = spawn('node', [clientScript, ...args], { - stdio: 'inherit' - }); - - clientProcess.on('error', (error) => { - console.error(chalk.red('[ReactPress CLI] Failed to start client:'), error); - process.exit(1); - }); + const args = options.pm2 ? ['--pm2'] : []; + spawnNodeScript(clientScript, args); + }); + +program + .command('init') + .description('Initialize ReactPress in the current project (delegates to reactpress-cli)') + .argument('[directory]', 'Project directory', '.') + .option('-f, --force', 'Overwrite existing configuration') + .action((directory, options) => { + const args = ['init', directory]; + if (options.force) args.push('--force'); + runReactpressCli(args); }); -// Set the version from package.json const packageJson = require(path.join(rootDir, 'package.json')); program.version(packageJson.version); -// Configure help text program.on('--help', () => { console.log(''); console.log('Examples:'); - console.log(' $ reactpress server start # Start the ReactPress server'); - console.log(' $ reactpress client start # Start the ReactPress client'); - console.log(' $ reactpress server start --pm2 # Start server with PM2'); - console.log(' $ reactpress client start --pm2 # Start client with PM2'); - console.log(''); - console.log('Note: The "start" command is implicit in the individual bin scripts.'); - console.log('The CLI provides a consistent interface for all commands.'); + console.log(' $ reactpress init . # Initialize .reactpress/config.json + .env'); + console.log(' $ reactpress server start # Start API (reactpress-cli start)'); + console.log(' $ reactpress server start --pm2 # Start API with PM2'); + console.log(' $ reactpress client start # Start Next.js client'); + console.log(' $ pnpm dev # Build toolkit + API + client'); console.log(''); - console.log('For more information, visit: https://github.com/fecommunity/reactpress'); + console.log('API backend: server/ thin wrapper → @fecommunity/reactpress-cli bundled Nest server.'); }); -// Parse the command line arguments program.parse(process.argv); -// If no command is provided, show help if (!process.argv.slice(2).length) { program.outputHelp(); -} \ No newline at end of file +} diff --git a/scripts/reactpress-dev.js b/scripts/reactpress-dev.js index 667983a..59f40e0 100644 --- a/scripts/reactpress-dev.js +++ b/scripts/reactpress-dev.js @@ -25,6 +25,8 @@ build.on('close', (code) => { // 执行并发命令 const concurrently = spawn('npx', [ 'concurrently', + '-n', 'api,web', + '-c', 'blue,green', 'pnpm:dev:server', 'pnpm:dev:client' ], { diff --git a/scripts/reactpress-publish.js b/scripts/reactpress-publish.js index 1b236b4..be5fc59 100644 --- a/scripts/reactpress-publish.js +++ b/scripts/reactpress-publish.js @@ -15,9 +15,9 @@ const packages = [ description: 'Main ReactPress package' }, { - name: '@fecommunity/reactpress-server', + name: '@fecommunity/reactpress-server', path: 'server', - description: 'Backend API server package' + description: 'API server wrapper (runtime from @fecommunity/reactpress-cli)' }, { name: '@fecommunity/reactpress-client', @@ -381,7 +381,7 @@ function buildPackage(pkg) { if (pkg.path === 'config') { execSync('pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' }); } else if (pkg.path === 'server') { - execSync('pnpm run prebuild && pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' }); + execSync('pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' }); } else if (pkg.path === 'client') { execSync('pnpm run prebuild && pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' }); } else if (pkg.path === 'toolkit') { @@ -933,8 +933,8 @@ async function main() { // Default behavior - show help console.log(chalk.blue('🏗️ ReactPress CLI\n')); console.log('Usage:'); - console.log(' node scripts/reactpress-cli.js --build Build all packages'); - console.log(' node scripts/reactpress-cli.js --publish Publish packages (interactive)'); + console.log(' node scripts/reactpress-publish.js --build Build all packages'); + console.log(' node scripts/reactpress-publish.js --publish Publish packages (interactive)'); console.log(''); } } diff --git a/scripts/reactpress.js b/scripts/reactpress.js deleted file mode 100755 index eccf8df..0000000 --- a/scripts/reactpress.js +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env node - -/** - * ReactPress CLI - Main entry point for all ReactPress commands - * This script allows users to run reactpress commands after installing the package globally - */ - -const { Command } = require('commander'); -const { spawn } = require('child_process'); -const path = require('path'); -const chalk = require('chalk'); - -// Create the CLI program -const program = new Command(); - -// Get the directory where this script is located -const binDir = __dirname; -const rootDir = path.join(binDir, '..'); - -// Server command -program - .command('server') - .description('Manage the ReactPress server') - .option('install', 'Launch the installation wizard') - .option('start', 'Start the ReactPress server') - .option('--pm2', 'Start server with PM2 process manager') - .action((options) => { - const serverScript = path.join(rootDir, 'scripts', 'reactpress-server.js'); - - let args = []; - if (options.install) { - args.push('install'); - } else if (options.start) { - args.push('start'); - } - - if (options.pm2) { - args.push('--pm2'); - } - - const serverProcess = spawn('node', [serverScript, ...args], { - stdio: 'inherit' - }); - - serverProcess.on('error', (error) => { - console.error(chalk.red('[ReactPress CLI] Failed to start server:'), error); - process.exit(1); - }); - }); - -// Client command -program - .command('client') - .description('Manage the ReactPress client') - .option('--pm2', 'Start client with PM2 process manager') - .action((options) => { - const clientScript = path.join(rootDir, 'client', 'bin', 'reactpress-client.js'); - - let args = []; - if (options.pm2) { - args.push('--pm2'); - } - - const clientProcess = spawn('node', [clientScript, ...args], { - stdio: 'inherit' - }); - - clientProcess.on('error', (error) => { - console.error(chalk.red('[ReactPress CLI] Failed to start client:'), error); - process.exit(1); - }); - }); - -// Set the version from package.json -const packageJson = require(path.join(rootDir, 'package.json')); -program.version(packageJson.version); - -// Configure help text -program.on('--help', () => { - console.log(''); - console.log('For more information, visit: https://github.com/fecommunity/reactpress'); -}); - -// Parse the command line arguments -program.parse(process.argv); - -// If no command is provided, show help -if (!process.argv.slice(2).length) { - program.outputHelp(); -} \ No newline at end of file diff --git a/server/.eslintrc.js b/server/.eslintrc.js deleted file mode 100644 index 60a15ad..0000000 --- a/server/.eslintrc.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'simple-import-sort', 'prettier'], - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], - root: true, - env: { - node: true, - jest: true, - }, - settings: { - 'import/resolver': { - node: { - paths: ['src'], - extensions: ['.js', '.jsx', '.ts', '.tsx'], - }, - }, - }, - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/no-explicit-any': 'off', - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - }, -}; diff --git a/server/Dockerfile b/server/Dockerfile deleted file mode 100644 index acb938e..0000000 --- a/server/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -# Use Node.js 18 as the base image -FROM node:18-alpine - -# Set working directory -WORKDIR /app - -# Install pnpm globally -RUN npm install -g pnpm - -# Copy ALL files from the project root -COPY . . - -# Debug: Show what files were copied -RUN echo "=== Files in /app ===" && ls -la -RUN echo "=== pnpm-lock.yaml exists? ===" && test -f pnpm-lock.yaml && echo "YES" || echo "NO" -RUN echo "=== pnpm-workspace.yaml exists? ===" && test -f pnpm-workspace.yaml && echo "YES" || echo "NO" -RUN echo "=== server/package.json exists? ===" && test -f server/package.json && echo "YES" || echo "NO" - -# Install dependencies - ALWAYS use --no-frozen-lockfile to avoid issues -RUN pnpm install --no-frozen-lockfile - -# Build the server application -WORKDIR /app/server -RUN pnpm run build - -# Expose port -EXPOSE 3002 - -# Create a non-root user -RUN addgroup -g 1001 -S nodejs && \ - adduser -S nestjs -u 1001 - -# Change ownership of the app directory -RUN chown -R nestjs:nodejs /app -USER nestjs - -# Start the application -CMD ["pnpm", "run", "start"] \ No newline at end of file diff --git a/server/LICENSE b/server/LICENSE deleted file mode 100644 index fc16eb7..0000000 --- a/server/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 FECommunity - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/server/README.md b/server/README.md index 728dc01..4f49d32 100644 --- a/server/README.md +++ b/server/README.md @@ -1,366 +1,17 @@ # @fecommunity/reactpress-server -ReactPress Server - NestJS 10 backend API for ReactPress CMS with simple installation. +本目录**不包含 NestJS 源码**。API 运行时由依赖包 [`@fecommunity/reactpress-cli`](https://github.com/fecommunity/reactpress-cli) 内置的 `server/dist` 提供;此包仅保留 monorepo 中的 **入口、脚本与发布名**,便于沿用 `pnpm dev:server`、`reactpress-server` 等习惯。 -[![NPM Version](https://img.shields.io/npm/v/@fecommunity/reactpress-server.svg)](https://www.npmjs.com/package/@fecommunity/reactpress-server) -[![License](https://img.shields.io/npm/l/@fecommunity/reactpress-server.svg)](https://github.com/fecommunity/reactpress/blob/master/server/LICENSE) -[![Node Version](https://img.shields.io/node/v/@fecommunity/reactpress-server.svg)](https://nodejs.org) -[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) -[![NestJS](https://img.shields.io/badge/NestJS-10-red)](https://nestjs.com/) +## 命令 -## Overview +| 命令 | 说明 | +|------|------| +| `pnpm dev` | 必要时 `init`,`reactpress-cli start` 启动 API(供根目录 `pnpm dev` 并发) | +| `pnpm start` | 前台运行 CLI 内置 server(`bin/reactpress-server.js`) | +| `pnpm start:cli` | 仅调用 `reactpress-cli start` | +| `pnpm pm2` | 通过内置 bin 以 PM2 启动 | +| `pnpm generate:swagger` | 在 CLI 内置 server 目录生成 Swagger | -ReactPress Server is a backend API built with NestJS 10 that powers the ReactPress CMS platform. It provides RESTful APIs for content management, user authentication, media handling, and more. With its simple installation process, it offers a smooth setup experience. +## 修改后端逻辑 -The server is built with a modular architecture following NestJS best practices, making it extensible and maintainable. It automatically generates OpenAPI/Swagger documentation that powers the [ReactPress Toolkit](../toolkit). - -## Quick Start - -### Installation & Setup - -```bash -# Regular startup -npx @fecommunity/reactpress-server - -# PM2 startup for production -npx @fecommunity/reactpress-server --pm2 -``` - -That's it! The command will automatically: - -1. **Auto-detect** if configuration exists -2. **Launch installation wizard** in your browser if no configuration found -3. **Start the server** immediately after installation -4. **Open API documentation** at `http://localhost:3002/api` - -## Features - -- 🚀 **Simple Installation** - No complex CLI parameters needed -- 🔧 **Auto-Configuration** - Generates `.env` files automatically -- 🔌 **Database Setup** - Creates MySQL database with migrations -- 🎯 **Seamless Flow** - From installation to running server -- 📖 **Auto-Documentation** - Swagger API docs available immediately -- ⚡ **PM2 Support** - Optional PM2 process management -- 🔐 **Security** - JWT with refresh token rotation, rate limiting -- 🛡️ **Protection** - Helmet.js, CSRF protection, input validation -- 📱 **Responsive APIs** - Mobile-friendly RESTful endpoints -- 🌐 **Globalization** - Multi-language support -- 📊 **Analytics Tracking** - Built-in view and visitor analytics -- 🔄 **Data Synchronization** - Scheduled tasks and webhook support - -## Requirements - -- Node.js >= 18.20.4 -- MySQL 8.0+ or PostgreSQL 13+ -- npm or pnpm package manager - -## Usage Scenarios - -### Standalone API Server -Perfect for: -- Headless CMS implementation -- Mobile app backend -- Microservices architecture -- Custom frontend integration -- Enterprise API gateway - -### Full ReactPress Stack -Use with ReactPress client for complete CMS solution: -```bash -# Start server -npx @fecommunity/reactpress-server - -# In another terminal, start client -npx @fecommunity/reactpress-client -``` - -## API Modules - -ReactPress Server provides comprehensive API modules: - -- **Article Management** - Create, read, update, delete articles with versioning -- **User Authentication** - Registration, login, password management, 2FA -- **Comment System** - Comment moderation and management with spam detection -- **Media Management** - File upload and management (local/S3/Cloudinary) -- **Category & Tag** - Content organization systems with hierarchy -- **Page Management** - Custom page creation with templates -- **Settings** - System configuration management with environment overrides -- **SMTP** - Email sending capabilities with template system -- **Search** - Full-text search functionality with Elasticsearch integration -- **Analytics** - Visitor and view tracking with export capabilities -- **Webhooks** - Event-driven integrations with external services -- **Scheduled Tasks** - Cron jobs for automated operations - -## PM2 Support - -ReactPress server supports PM2 process management for production deployments: - -```bash -# Start with PM2 -npx @fecommunity/reactpress-server --pm2 -``` - -PM2 features: -- Automatic process restart on crash -- Memory monitoring -- Log management with rotation -- Process management -- Health checks - -## Configuration - -The installation wizard will create a `.env` file with: - -```env -# Database Configuration (Production) -DB_HOST=prod-db.cluster-xyz.amazonaws.com -DB_PORT=3306 -DB_USER=reactpress_user -DB_PASSWD=secure_password_here -DB_DATABASE=reactpress_prod -DB_SSL=true - -# Site URLs (Production) -CLIENT_SITE_URL=https://yourdomain.com -SERVER_SITE_URL=https://api.yourdomain.com - -# Security Settings (Production) -JWT_SECRET=your-very-secure-jwt-secret-here -JWT_EXPIRES_IN=24h -JWT_REFRESH_EXPIRES_IN=7d - -# SMTP Configuration (Production) -SMTP_HOST=email-smtp.us-east-1.amazonaws.com -SMTP_PORT=587 -SMTP_USER=your_smtp_username -SMTP_PASS=your_smtp_password -SMTP_FROM=noreply@yourdomain.com - -# Cloud Storage (Optional) -S3_ACCESS_KEY_ID=your_aws_access_key -S3_SECRET_ACCESS_KEY=your_aws_secret_key -S3_BUCKET_NAME=your_bucket_name -S3_REGION=us-east-1 -``` - -## API Documentation - -Once running, visit `http://localhost:3002/api` for: -- Interactive Swagger documentation -- API endpoint explorer -- Authentication examples -- Response schemas -- Request/response validation -- Code generation for multiple languages - -## Development - -```bash -# Clone repository -git clone https://github.com/fecommunity/reactpress.git -cd reactpress/server - -# Install dependencies -pnpm install - -# Start development server with hot reload -pnpm run dev - -# Start with PM2 (development) -pnpm run pm2:start - -# Build for production -pnpm run build - -# Run tests -pnpm run test - -# Run tests with coverage -pnpm run test:cov - -# Run end-to-end tests -pnpm run test:e2e -``` - -## Project Structure - -``` -server/ -├── src/ -│ ├── modules/ # Feature modules -│ │ ├── article/ # Article management -│ │ ├── auth/ # Authentication -│ │ ├── user/ # User management -│ │ └── ... # Other modules -│ ├── common/ # Shared utilities and decorators -│ ├── filters/ # Exception filters -│ ├── interceptors/ # Request/response interceptors -│ ├── guards/ # Authentication guards -│ ├── pipes/ # Data transformation pipes -│ ├── logger/ # Logging utilities -│ └── utils/ # Utility functions -├── public/ # Static assets -│ └── swagger/ # Swagger documentation -├── dist/ # Compiled output -└── bin/ # CLI entry points -``` - -## Environment Variables - -| Variable | Description | Default | -|----------|-------------|---------| -| `DB_HOST` | Database host | `127.0.0.1` | -| `DB_PORT` | Database port | `3306` | -| `DB_USER` | Database username | - | -| `DB_PASSWD` | Database password | - | -| `DB_DATABASE` | Database name | `reactpress` | -| `SERVER_PORT` | Server port | `3002` | -| `JWT_SECRET` | JWT secret key | - | -| `CLIENT_SITE_URL` | Client site URL | `http://localhost:3001` | -| `SERVER_SITE_URL` | Server site URL | `http://localhost:3002` | -| `SMTP_HOST` | SMTP server host | - | -| `SMTP_PORT` | SMTP server port | - | -| `SMTP_USER` | SMTP username | - | -| `SMTP_PASS` | SMTP password | - | - -## CLI Commands - -```bash -# Show help -npx @fecommunity/reactpress-server --help - -# Start server -npx @fecommunity/reactpress-server - -# Start with PM2 -npx @fecommunity/reactpress-server --pm2 - -# Specify port -npx @fecommunity/reactpress-server --port 3002 - -# Enable verbose logging -npx @fecommunity/reactpress-server --verbose - -# Run database migrations -npx @fecommunity/reactpress-server --migrate - -# Seed database with sample data -npx @fecommunity/reactpress-server --seed -``` - -## Integration with ReactPress Toolkit - -The server automatically generates the OpenAPI specification that powers the ReactPress Toolkit: - -```typescript -// The toolkit is automatically generated from this server's API -import { api, types } from '@fecommunity/reactpress-toolkit'; - -// All API endpoints are strongly typed -const articles: types.IArticle[] = await api.article.findAll(); -``` - -## Database Schema - -ReactPress uses MySQL/PostgreSQL with the following key tables: -- `users` - User accounts and profiles with 2FA support -- `articles` - Blog posts and content with versioning -- `categories` - Content categorization with hierarchy -- `tags` - Content tagging system -- `comments` - Reader comments and discussions with moderation -- `files` - Media file management -- `settings` - System configuration with environment overrides -- `views` - Analytics and tracking -- `webhooks` - Event-driven integrations -- `scheduled_tasks` - Automated operations - -## Security Features - -- **JWT Authentication** - Secure token-based authentication with refresh rotation -- **Rate Limiting** - Adaptive throttling to prevent abuse -- **Input Validation** - Sanitize all user inputs with Zod schema validation -- **Helmet.js** - Secure HTTP headers -- **CSRF Protection** - Prevent cross-site request forgery -- **SQL Injection Prevention** - Through TypeORM parameterized queries -- **CORS Configuration** - Controlled cross-origin resource sharing -- **Data Encryption** - At-rest encryption for sensitive data -- **Audit Logging** - Comprehensive activity tracking - -## Performance Optimization - -- **Database Indexing** - Optimized queries with proper indexing -- **Connection Pooling** - Efficient database connection management -- **Caching** - Redis integration for frequently accessed data -- **Compression** - Gzip compression for API responses -- **Pagination** - Efficient data retrieval for large datasets -- **Query Optimization** - TypeORM query builder for complex operations -- **Background Jobs** - Queue system for long-running tasks - -## Testing - -```bash -# Run unit tests -pnpm run test - -# Run integration tests -pnpm run test:integration - -# Run end-to-end tests -pnpm run test:e2e - -# Run tests with coverage -pnpm run test:cov - -# Run linting -pnpm run lint - -# Run formatting -pnpm run format - -# Run type checking -pnpm run type-check -``` - -## Deployment - -### Production Deployment with PM2 - -``` -# Start server with PM2 -npx @fecommunity/reactpress-server --pm2 - -# Or build and start manually -pnpm run build -pnpm run start:prod -``` - -## Monitoring & Logging - -- **Structured Logging** - JSON-formatted logs for easy parsing -- **Error Tracking** - Comprehensive error reporting with context -- **Performance Metrics** - Response time and throughput monitoring -- **Health Checks** - API endpoint for service status -- **Alerting** - Basic alerting capabilities - -## Support - -- 📖 [Documentation](https://github.com/fecommunity/reactpress) -- 🐛 [Issues](https://github.com/fecommunity/reactpress/issues) -- 💬 [Discussions](https://github.com/fecommunity/reactpress/discussions) -- 📧 [Support](mailto:support@reactpress.dev) - -## Contributing - -1. Fork the repository -2. Create your feature branch (`git checkout -b feature/AmazingFeature`) -3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) -4. Push to the branch (`git push origin feature/AmazingFeature`) -5. Open a pull request - -## License - -MIT License - see [LICENSE](LICENSE) file for details. - ---- - -Built with ❤️ by [FECommunity](https://github.com/fecommunity) \ No newline at end of file +请在 [reactpress-cli](https://github.com/fecommunity/reactpress-cli) 仓库维护 Nest 代码,发布后升级本包的 `@fecommunity/reactpress-cli` 版本。 diff --git a/server/bin/reactpress-server.js b/server/bin/reactpress-server.js old mode 100755 new mode 100644 index ca6c136..956ba6b --- a/server/bin/reactpress-server.js +++ b/server/bin/reactpress-server.js @@ -1,203 +1,31 @@ #!/usr/bin/env node /** - * ReactPress Server CLI Entry Point - * This script allows starting the ReactPress server via npx - * Supports both regular and PM2 startup modes + * @fecommunity/reactpress-server — thin entry that delegates to the server + * bundled in @fecommunity/reactpress-cli (no local NestJS source in this repo). */ +const { spawn } = require('child_process'); const path = require('path'); -const fs = require('fs'); -const { spawn, spawnSync } = require('child_process'); +const { getBundledServerBin, getBundledServerDir, getMonorepoRoot } = require('../lib/bundled-server-path'); -// Capture the original working directory where npx was executed -// BUT prioritize the REACTPRESS_ORIGINAL_CWD environment variable if it exists -// This ensures consistency when running via pnpm dev from root directory -const originalCwd = process.env.REACTPRESS_ORIGINAL_CWD || process.cwd(); - -// Get command line arguments const args = process.argv.slice(2); -const usePM2 = args.includes('--pm2'); -const showHelp = args.includes('--help') || args.includes('-h'); - -// Show help if requested -if (showHelp) { - console.log(` -ReactPress Server - NestJS-based backend API for ReactPress CMS - -Usage: - npx @fecommunity/reactpress-server [options] - -Options: - --pm2 Start server with PM2 process manager - --help, -h Show this help message - -Examples: - npx @fecommunity/reactpress-server # Start server normally - npx @fecommunity/reactpress-server --pm2 # Start server with PM2 - npx @fecommunity/reactpress-server --help # Show this help message - `); - process.exit(0); -} - -// Get the directory where this script is located -const binDir = __dirname; -const serverDir = path.join(binDir, '..'); -const distPath = path.join(serverDir, 'dist', 'main.js'); -const ecosystemPath = path.join(serverDir, 'ecosystem.config.js'); - -// Function to check if PM2 is installed -function isPM2Installed() { - try { - require.resolve('pm2'); - return true; - } catch (e) { - // Check if PM2 is installed globally - try { - spawnSync('pm2', ['--version'], { stdio: 'ignore' }); - return true; - } catch (e) { - return false; - } - } -} - -// Function to install PM2 -function installPM2() { - console.log('[ReactPress Server] Installing PM2...'); - const installResult = spawnSync('npm', ['install', 'pm2', '--no-save'], { - stdio: 'inherit', - cwd: serverDir - }); - - if (installResult.status !== 0) { - console.error('[ReactPress Server] Failed to install PM2'); - return false; - } - - return true; -} - -// Function to start with PM2 -function startWithPM2() { - // Check if PM2 is installed - if (!isPM2Installed()) { - // Try to install PM2 - if (!installPM2()) { - console.error('[ReactPress Server] Cannot start with PM2'); - process.exit(1); - } - } - - // Check if the server is built - if (!fs.existsSync(distPath)) { - console.log('[ReactPress Server] Server not built yet. Building...'); - - // Try to build the server - const buildResult = spawnSync('npm', ['run', 'build'], { - stdio: 'inherit', - cwd: serverDir - }); - - if (buildResult.status !== 0) { - console.error('[ReactPress Server] Failed to build server'); - process.exit(1); - } - } - - console.log('[ReactPress Server] Starting with PM2...'); - - // Use ecosystem.config.js if it exists, otherwise use direct command - let pm2Command = 'pm2'; - try { - // Try to resolve PM2 path - pm2Command = path.join(serverDir, 'node_modules', '.bin', 'pm2'); - if (!fs.existsSync(pm2Command)) { - pm2Command = 'pm2'; - } - } catch (e) { - pm2Command = 'pm2'; - } - - // Check if ecosystem.config.js exists - if (fs.existsSync(ecosystemPath)) { - const pm2 = spawn(pm2Command, ['start', ecosystemPath], { - stdio: 'inherit', - cwd: serverDir - }); - - pm2.on('close', (code) => { - console.log(`[ReactPress Server] PM2 process exited with code ${code}`); - process.exit(code); - }); - - pm2.on('error', (error) => { - console.error('[ReactPress Server] Failed to start with PM2:', error); - process.exit(1); - }); - } else { - // Fallback to direct start - const pm2 = spawn(pm2Command, ['start', distPath, '--name', 'reactpress-server'], { - stdio: 'inherit', - cwd: serverDir - }); - - pm2.on('close', (code) => { - console.log(`[ReactPress Server] PM2 process exited with code ${code}`); - process.exit(code); - }); - - pm2.on('error', (error) => { - console.error('[ReactPress Server] Failed to start with PM2:', error); - process.exit(1); - }); - } -} - -// Function to start with regular Node.js -function startWithNode() { - // Check if the server is built - if (!fs.existsSync(distPath)) { - console.log('[ReactPress Server] Server not built yet. Building...'); - - // Try to build the server - const buildResult = spawnSync('npm', ['run', 'build'], { - stdio: 'inherit', - cwd: serverDir - }); - - if (buildResult.status !== 0) { - console.error('[ReactPress Server] Failed to build server'); - process.exit(1); - } - } - - // ONLY set the environment variable if it's not already set - // This preserves the value set by set-env.js when running pnpm dev from root - if (!process.env.REACTPRESS_ORIGINAL_CWD) { - process.env.REACTPRESS_ORIGINAL_CWD = originalCwd; - } else { - console.log(`[ReactPress Server] Using existing REACTPRESS_ORIGINAL_CWD: ${process.env.REACTPRESS_ORIGINAL_CWD}`); - } - - // Change to the server directory - process.chdir(serverDir); - - // Set environment variables - process.env.NODE_ENV = process.env.NODE_ENV || 'production'; - - // Import and run the server - try { - require(distPath); - } catch (error) { - console.error('[ReactPress Server] Failed to start server:', error); - process.exit(1); - } -} - -// Main execution -if (usePM2) { - startWithPM2(); -} else { - startWithNode(); -} +const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot(); + +const child = spawn(process.execPath, [getBundledServerBin(), ...args], { + stdio: 'inherit', + cwd: getBundledServerDir(), + env: { + ...process.env, + REACTPRESS_ORIGINAL_CWD: projectRoot, + }, +}); + +child.on('error', (error) => { + console.error('[ReactPress Server] Failed to start:', error); + process.exit(1); +}); + +child.on('close', (code) => { + process.exit(code ?? 0); +}); diff --git a/server/ecosystem.config.js b/server/ecosystem.config.js index 6a90515..64a8562 100644 --- a/server/ecosystem.config.js +++ b/server/ecosystem.config.js @@ -1,8 +1,11 @@ +const path = require('path'); +const { getBundledServerMain } = require('./lib/bundled-server-path'); + module.exports = { apps: [ { name: 'reactpress-server', - script: './dist/main.js', + script: getBundledServerMain(), instances: 1, autorestart: true, watch: false, @@ -15,4 +18,4 @@ module.exports = { }, }, ], -}; \ No newline at end of file +}; diff --git a/server/nest-cli.json b/server/nest-cli.json deleted file mode 100644 index 56167b3..0000000 --- a/server/nest-cli.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "collection": "@nestjs/schematics", - "sourceRoot": "src" -} diff --git a/server/package.json b/server/package.json index 3b1ae03..c87aafe 100644 --- a/server/package.json +++ b/server/package.json @@ -1,20 +1,18 @@ { "name": "@fecommunity/reactpress-server", "version": "1.0.0-beta.16", - "description": "ReactPress Server - NestJS-based backend API for ReactPress CMS", + "description": "ReactPress API — thin wrapper around @fecommunity/reactpress-cli bundled server", "author": "fecommunity", "license": "MIT", - "main": "dist/main.js", - "types": "dist/index.d.ts", "bin": { "reactpress-server": "./bin/reactpress-server.js" }, "files": [ - "dist/**/*", - "public/**/*", "bin/**/*", - "README.md", - "LICENSE" + "lib/**/*", + "scripts/**/*", + "ecosystem.config.js", + "README.md" ], "keywords": [ "reactpress", @@ -22,8 +20,7 @@ "nestjs", "cms", "blog", - "api", - "typescript" + "api" ], "repository": { "type": "git", @@ -31,119 +28,23 @@ "directory": "server" }, "engines": { - "node": ">=16.5.0" + "node": ">=18.0.0" }, "scripts": { - "prebuild": "rimraf dist", - "build": "nest build && npm run copy-assets", - "copy-assets": "cp -r public dist/ 2>/dev/null || true", - "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", - "dev": "nest start --watch", - "debug": "nest start --debug --watch", - "start": "cross-env NODE_ENV=production node dist/main", - "pm2": "pm2 start npm --name @fecommunity/reactpress-server -- start", - "lint": "tslint -p tsconfig.json -c tslint.json", - "test": "jest", - "test:watch": "jest --watch", - "test:cov": "jest --coverage", - "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "jest --config ./test/jest-e2e.json", - "prepublishOnly": "npm run build", - "pm2:start": "pm2 start dist/main.js --name reactpress-server", - "pm2:stop": "pm2 stop reactpress-server", - "pm2:restart": "pm2 restart reactpress-server", - "pm2:delete": "pm2 delete reactpress-server", - "pm2:logs": "pm2 logs reactpress-server", - "pm2:status": "pm2 status reactpress-server", - "generate:swagger": "ts-node src/generate-swagger.ts" + "build": "node -e \"console.log('@fecommunity/reactpress-server: no build (runtime from @fecommunity/reactpress-cli)')\"", + "dev": "node ./scripts/dev.js", + "start": "node ./bin/reactpress-server.js", + "start:cli": "pnpm exec reactpress-cli start", + "stop": "pnpm exec reactpress-cli stop", + "restart": "pnpm exec reactpress-cli restart", + "status": "pnpm exec reactpress-cli status", + "pm2": "node ./bin/reactpress-server.js --pm2", + "pm2:stop": "pnpm exec reactpress-cli stop", + "pm2:restart": "pnpm exec reactpress-cli restart", + "pm2:status": "pnpm exec reactpress-cli status", + "generate:swagger": "node ./scripts/generate-swagger.js" }, "dependencies": { - "@fecommunity/reactpress-toolkit": "workspace:*", - "@nestjs/cli": "^6.9.0", - "@nestjs/common": "^6.7.2", - "@nestjs/config": "^0.6.3", - "@nestjs/core": "^6.7.2", - "@nestjs/jwt": "^6.1.1", - "@nestjs/passport": "^6.1.1", - "@nestjs/platform-express": "^6.11.5", - "@nestjs/swagger": "^4.8.2", - "@types/express-serve-static-core": "^4.19.5", - "ali-oss": "^6.5.1", - "axios": "^0.23.0", - "bcryptjs": "^2.4.3", - "body-parser": "^1.19.0", - "chalk": "^4.1.2", - "class-transformer": "^0.2.3", - "commander": "^9.4.1", - "compression": "^1.7.4", - "cross-env": "^7.0.3", - "date-fns": "^2.17.0", - "deepmerge": "^4.2.2", - "dotenv": "^8.2.0", - "express": "^4.18.2", - "express-rate-limit": "^5.0.0", - "fs-extra": "^10.0.0", - "helmet": "^3.21.2", - "highlight.js": "^9.18.0", - "inquirer": "^8.2.4", - "lodash": "^4.17.21", - "log4js": "^6.1.0", - "marked": "^0.8.0", - "mysql2": "^3.12.0", - "node-ip2region": "^1.0.2", - "nodemailer": "^6.4.2", - "nuid": "^1.1.0", - "open": "^8.2.1", - "passport": "^0.4.1", - "passport-jwt": "^4.0.0", - "pm2": "^5.2.0", - "reflect-metadata": "^0.1.13", - "rimraf": "^3.0.0", - "rxjs": "^6.5.3", - "segment": "^0.1.3", - "swagger-themes": "^1.4.3", - "swagger-ui-express": "^4.1.6", - "typeorm": "^0.2.45", - "ua-parser-js": "^0.7.28" - }, - "devDependencies": { - "@nestjs/schematics": "^6.7.0", - "@nestjs/testing": "^6.7.1", - "@nestjs/typeorm": "^6.3.4", - "@types/express": "4.17.18", - "@types/jest": "^24.0.18", - "@types/node": "^12.7.5", - "@types/supertest": "^2.0.8", - "@typescript-eslint/eslint-plugin": "^5.21.0", - "@typescript-eslint/parser": "^5.21.0", - "eslint": "^8.15.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-prettier": "^4.0.0", - "eslint-plugin-simple-import-sort": "^7.0.0", - "jest": "^24.9.0", - "next-transpile-modules": "^6.3.0", - "prettier": "^1.18.2", - "supertest": "^4.0.2", - "ts-jest": "^24.1.0", - "ts-loader": "^6.1.1", - "ts-node": "^8.4.1", - "tsconfig-paths": "^3.9.0", - "tslint": "^5.20.0", - "typescript": "~4.1.6" - }, - "jest": { - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], - "rootDir": "src", - "testRegex": ".spec.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - }, - "coverageDirectory": "../coverage", - "testEnvironment": "node" + "@fecommunity/reactpress-cli": "^0.1.0" } } diff --git a/server/public/favicon.png b/server/public/favicon.png deleted file mode 100644 index 521edf80e7dfb357e0bb99f8659aad49b04430b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33057 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

oLluaFg!lf8R;7G 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 FV1m^A{DS}h diff --git a/server/public/index.html b/server/public/index.html deleted file mode 100644 index 4c285e3..0000000 --- a/server/public/index.html +++ /dev/null @@ -1,439 +0,0 @@ - - - - - - ReactPress › Installation - - - -

- - -
-
-
- -
- -
-

Database Connection Information

- -
- You should have this information available from your web hosting provider. If you don't have it, contact them before continuing. -
- - - - - - - - - - - - - - - - - - - - - - -
- -

Usually "localhost" or "127.0.0.1"

-
- -

Default MySQL port is 3306

-
- -

Your MySQL username

-
- -

Your MySQL password

-
- -

The name of the database you want to use with ReactPress

-
- -
- -

- -

-
- - -
-

Site Information

- -
- Please provide the following information. Don't worry, you can always change these settings later. -
- - - - - - - - - - -
- -

The URL where your ReactPress frontend will be accessible

-
- -

The URL where your ReactPress API server will run

-
- -
- -

- -

-
- - -
-

🎉 Installation Complete!

- -
-

ReactPress has been installed successfully!

-
- -

Your ReactPress server configuration has been saved. You can:

- -
    -
  • Close this browser window
  • -
  • Restart the server by running npx @fecommunity/reactpress-server in your terminal
  • -
  • Access your admin panel at http://localhost:3001/admin (when client is running)
  • -
- - -
-

Waiting for server to start...

-
- -
- - -
- -
- Note: To start the server with your new configuration, run npx @fecommunity/reactpress-server in your terminal. -
-
-
- - -
- - - - \ No newline at end of file diff --git a/server/public/swagger/custom.css b/server/public/swagger/custom.css deleted file mode 100644 index fee918b..0000000 --- a/server/public/swagger/custom.css +++ /dev/null @@ -1,11 +0,0 @@ -.swagger-ui div.topbar { - display: none !important; - padding: 0 !important; -} - - -.swagger-ui .scheme-container { - display: none !important; - margin: 0 !important; - padding: 0 !important; -} \ No newline at end of file diff --git a/server/scripts/dev.js b/server/scripts/dev.js new file mode 100644 index 0000000..5d3a72b --- /dev/null +++ b/server/scripts/dev.js @@ -0,0 +1,60 @@ +#!/usr/bin/env node + +/** + * Development: ensure DB via reactpress-cli, then run bundled API in the foreground. + */ + +const { spawnSync, spawn } = require('child_process'); +const path = require('path'); +const fs = require('fs'); +const { getBundledServerBin, getMonorepoRoot } = require('../lib/bundled-server-path'); + +const projectRoot = getMonorepoRoot(); +const configPath = path.join(projectRoot, '.reactpress', 'config.json'); + +process.env.REACTPRESS_ORIGINAL_CWD = projectRoot; + +if (!fs.existsSync(configPath)) { + console.warn( + '[ReactPress Server] 未找到 .reactpress/config.json,正在执行 reactpress-cli init …' + ); + const init = spawnSync('pnpm', ['exec', 'reactpress-cli', 'init', '.'], { + cwd: projectRoot, + stdio: 'inherit', + }); + if (init.status !== 0) { + process.exit(init.status ?? 1); + } +} + +const start = spawnSync('pnpm', ['exec', 'reactpress-cli', 'start'], { + cwd: projectRoot, + stdio: 'inherit', +}); + +if (start.status !== 0) { + process.exit(start.status ?? 1); +} + +console.log( + '[ReactPress Server] API 已由 reactpress-cli 在后台启动。本进程保持运行以便 concurrently 管理;按 Ctrl+C 停止。' +); +console.log('[ReactPress Server] 停止 API: pnpm exec reactpress-cli stop'); + +process.stdin.resume(); + +process.on('SIGINT', () => { + spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], { + cwd: projectRoot, + stdio: 'inherit', + }); + process.exit(0); +}); + +process.on('SIGTERM', () => { + spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], { + cwd: projectRoot, + stdio: 'inherit', + }); + process.exit(0); +}); diff --git a/server/scripts/generate-swagger.js b/server/scripts/generate-swagger.js new file mode 100644 index 0000000..39b4ef1 --- /dev/null +++ b/server/scripts/generate-swagger.js @@ -0,0 +1,9 @@ +#!/usr/bin/env node + +const { execSync } = require('child_process'); +const { getBundledServerDir } = require('../lib/bundled-server-path'); + +execSync('npm run generate:swagger', { + cwd: getBundledServerDir(), + stdio: 'inherit', +}); diff --git a/server/src/app.module.ts b/server/src/app.module.ts deleted file mode 100644 index 8cb3919..0000000 --- a/server/src/app.module.ts +++ /dev/null @@ -1,82 +0,0 @@ -// 配置文件 -import { config } from '@fecommunity/reactpress-toolkit'; -import { Module } from '@nestjs/common'; -import { ConfigModule, ConfigService } from '@nestjs/config'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { Article } from './modules/article/article.entity'; -// 文章模块 -import { ArticleModule } from './modules/article/article.module'; -// 鉴权模块 -import { AuthModule } from './modules/auth/auth.module'; -import { Category } from './modules/category/category.entity'; -// 分类模块 -import { CategoryModule } from './modules/category/category.module'; -import { Comment } from './modules/comment/comment.entity'; -// 评论模块 -import { CommentModule } from './modules/comment/comment.module'; -import { File } from './modules/file/file.entity'; -// 文件模块 -import { FileModule } from './modules/file/file.module'; -import { Knowledge } from './modules/knowledge/knowledge.entity'; -// 知识库模块 -import { KnowledgeModule } from './modules/knowledge/knowledge.module'; -import { Page } from './modules/page/page.entity'; -// 页面模块 -import { PageModule } from './modules/page/page.module'; -// 搜索模块 -import { Search } from './modules/search/search.entity'; -import { SearchModule } from './modules/search/search.module'; -import { Setting } from './modules/setting/setting.entity'; -// 系统模块 -import { SettingModule } from './modules/setting/setting.module'; -import { SMTP } from './modules/smtp/smtp.entity'; -// 邮件模块 -import { SMTPModule } from './modules/smtp/smtp.module'; -import { Tag } from './modules/tag/tag.entity'; -// 标签模块 -import { TagModule } from './modules/tag/tag.module'; -import { User } from './modules/user/user.entity'; -// 用户模块 -import { UserModule } from './modules/user/user.module'; -import { View } from './modules/view/view.entity'; -// 访问统计模块 -import { ViewModule } from './modules/view/view.module'; - -@Module({ - imports: [ - ConfigModule.forRoot({ isGlobal: true, envFilePath: [config.file] }), - TypeOrmModule.forRootAsync({ - imports: [ConfigModule], - inject: [ConfigService], - useFactory: async (configService: ConfigService) => ({ - type: 'mysql', - entities: [User, File, Knowledge, Article, Category, Tag, Comment, Setting, SMTP, Page, View, Search], - host: configService.get('DB_HOST', '0.0.0.0'), - port: configService.get('DB_PORT', 3306), - username: configService.get('DB_USER', 'root'), - password: configService.get('DB_PASSWD', 'root'), - database: configService.get('DB_DATABASE', 'reactpress'), - charset: 'utf8mb4', - timezone: '+08:00', - synchronize: true, - }), - }), - UserModule, - FileModule, - TagModule, - ArticleModule, - KnowledgeModule, - CategoryModule, - CommentModule, - SettingModule, - SMTPModule, - AuthModule, - PageModule, - ViewModule, - SearchModule, - ], - controllers: [], - providers: [], -}) -export class AppModule {} \ No newline at end of file diff --git a/server/src/filters/http-exception.filter.ts b/server/src/filters/http-exception.filter.ts deleted file mode 100644 index 16a08aa..0000000 --- a/server/src/filters/http-exception.filter.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common'; - -import { errorLogger } from '../logger'; - -@Catch(HttpException) -export class HttpExceptionFilter implements ExceptionFilter { - catch(exception: HttpException, host: ArgumentsHost) { - const ctx = host.switchToHttp(); - const response = ctx.getResponse(); - const request = ctx.getRequest(); - - const url = request.originalUrl; // 请求路由 - const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; - const msg = exception.message.message || exception.message; // 错误信息 - const errorResponse = { - statusCode: status, - msg, - success: false, - data: null, - }; - - // 设置返回的状态码、请求头、发送错误信息 - response.status(status); - response.header('Content-Type', 'application/json; charset=utf-8'); - response.send(errorResponse); - errorLogger.error(url, errorResponse); - } -} diff --git a/server/src/generate-swagger.ts b/server/src/generate-swagger.ts deleted file mode 100644 index 43674db..0000000 --- a/server/src/generate-swagger.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { NestFactory } from '@nestjs/core'; -import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; -import { existsSync, unlinkSync, writeFileSync } from 'fs'; -import { join } from 'path'; -import { AppModule } from './app.module'; - -async function generateSwaggerJson() { - let app; - try { - console.log('🚀 Starting Swagger JSON generation...'); - - // 创建应用实例,但不初始化数据库连接 - app = await NestFactory.createApplicationContext(AppModule, { - logger: ['error', 'warn'], // 只记录错误和警告 - }); - - // 获取配置服务 - const configService = app.get('ConfigService'); - const apiPrefix = configService.get('SERVER_API_PREFIX', '/api'); - - console.log('📝 Configuring Swagger documentation...'); - - // 增强版 Swagger 配置 - const swaggerConfig = new DocumentBuilder() - .setTitle('ReactPress API Documentation') - .setDescription('Comprehensive API documentation for ReactPress - A modern content management system built with NestJS') - .setVersion('2.0') - .setContact('ReactPress Team', 'https://github.com/fecommunity/reactpress', 'admin@gaoredu.com') - .setLicense('MIT', 'https://github.com/fecommunity/reactpress/blob/main/LICENSE') - .addServer(configService.get('SERVER_SITE_URL', 'http://localhost:3002'), 'API Server') - .build(); - - // 创建 Swagger 文档 - console.log('🔨 Generating Swagger document...'); - const document = SwaggerModule.createDocument(app, swaggerConfig); - - // 写入文件 - const outputPath = join(__dirname, '../public/swagger.json'); - - // 确保 public 目录存在 - const publicDir = join(__dirname, '../public'); - if (!existsSync(publicDir)) { - console.log('📁 Creating public directory...'); - require('fs').mkdirSync(publicDir, { recursive: true }); - } - - // 如果文件已经存在,就覆盖掉 - if (existsSync(outputPath)) { - console.log('🗑️ Removing existing swagger.json file...'); - unlinkSync(outputPath); - } - - console.log('💾 Writing Swagger JSON to file...'); - writeFileSync(outputPath, JSON.stringify(document, null, 2)); - - console.log(`✅ Success! Swagger JSON generated at: ${outputPath}`); - - // 直接退出进程,避免关闭应用时的数据库连接错误 - console.log('🎉 Swagger generation process completed successfully'); - process.exit(0); - - } catch (error) { - console.error('❌ Error during Swagger generation:', error.message); - - // 检查是否已有现有的 swagger.json 文件 - const existingPath = join(__dirname, '../public/swagger.json'); - if (existsSync(existingPath)) { - console.log('ℹ️ Using existing swagger.json file'); - console.log('🎉 Swagger generation process completed successfully'); - process.exit(0); - } else { - console.error('❌ No existing swagger.json file found'); - process.exit(1); - } - } finally { - // 不尝试关闭应用,直接退出进程 - // 这样可以避免数据库连接池错误 - } -} - -// 运行生成函数 -generateSwaggerJson().catch(e => { - console.error('💥 Unhandled error in generateSwaggerJson:', e.message); - - // 检查是否已有现有的 swagger.json 文件 - const existingPath = join(__dirname, '../public/swagger.json'); - if (existsSync(existingPath)) { - console.log('ℹ️ Using existing swagger.json file'); - console.log('🎉 Swagger generation process completed successfully'); - process.exit(0); - } else { - console.error('❌ No existing swagger.json file found'); - process.exit(1); - } -}); \ No newline at end of file diff --git a/server/src/interceptors/transform.interceptor.ts b/server/src/interceptors/transform.interceptor.ts deleted file mode 100644 index 4e34786..0000000 --- a/server/src/interceptors/transform.interceptor.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import { responseLogger } from '../logger'; - -interface Response { - data: T; -} - -@Injectable() -export class TransformInterceptor implements NestInterceptor> { - intercept(context: ExecutionContext, next: CallHandler): Observable> { - return next.handle().pipe( - map((data) => { - const ctx = context.switchToHttp(); - const response = ctx.getResponse(); - const request = ctx.getRequest(); - - const statusCode = response.statusCode; - const url = request.originalUrl; - const res = { - statusCode, - msg: null, - success: true, - data, - }; - responseLogger.info(url, res); - return res; - }) - ); - } -} diff --git a/server/src/logger/index.ts b/server/src/logger/index.ts deleted file mode 100644 index 319c734..0000000 --- a/server/src/logger/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as fs from 'fs-extra'; -import * as log4js from 'log4js'; -import { join } from 'path'; - -const LOG_DIR_NAME = '../../logs'; - -fs.ensureDirSync(join(__dirname, LOG_DIR_NAME)); -void ['request', 'response', 'error'].forEach((t) => { - fs.ensureDirSync(join(__dirname, LOG_DIR_NAME, t)); -}); - -const resolvePath = (dir, filename) => join(__dirname, LOG_DIR_NAME, dir, filename); - -const commonCinfig = { - type: 'dateFile', - pattern: '-yyyy-MM-dd.log', - alwaysIncludePattern: true, -}; - -log4js.configure({ - appenders: { - request: { - ...commonCinfig, - filename: resolvePath('request', 'request.log'), - category: 'request', - }, - response: { - ...commonCinfig, - filename: resolvePath('response', 'response.log'), - category: 'response', - }, - error: { - ...commonCinfig, - filename: resolvePath('error', 'error.log'), - category: 'error', - }, - }, - categories: { - default: { appenders: ['request'], level: 'info' }, - response: { appenders: ['response'], level: 'info' }, - error: { appenders: ['error'], level: 'info' }, - }, -}); - -export const requestLogger = log4js.getLogger('request'); -export const responseLogger = log4js.getLogger('response'); -export const errorLogger = log4js.getLogger('error'); diff --git a/server/src/main.ts b/server/src/main.ts deleted file mode 100644 index f6fad2b..0000000 --- a/server/src/main.ts +++ /dev/null @@ -1,346 +0,0 @@ -import * as fs from 'fs'; -import { join, dirname } from 'path'; -import * as express from 'express'; -import * as bodyParser from 'body-parser'; -import * as open from 'open'; -import * as net from 'net'; - -// 全局状态管理 -declare global { - var installationServer: any; - var installationPort: number; - var isInstalling: boolean; -} - -const INSTALLATION_PORT = 3002; -const MAX_PORT_ATTEMPTS = 10; - -// 服务器状态跟踪 -interface ServerState { - server: any; - isClosing: boolean; - isListening: boolean; -} - -const serverState: ServerState = { - server: null, - isClosing: false, - isListening: false -}; - -// 增强的端口检测函数 -const checkPort = (port: number): Promise => { - return new Promise((resolve) => { - const server = net.createServer(); - server.once('error', (err: any) => { - if (err.code === 'EADDRINUSE') { - resolve(false); - } else { - resolve(false); - } - }); - server.once('listening', () => { - server.once('close', () => resolve(true)).close(); - }); - server.listen(port); - }); -}; - -// 获取可用端口 -const findAvailablePort = async (startPort: number): Promise => { - for (let port = startPort; port < startPort + MAX_PORT_ATTEMPTS; port++) { - if (await checkPort(port)) { - return port; - } - } - throw new Error(`No available ports found in range ${startPort}-${startPort + MAX_PORT_ATTEMPTS - 1}`); -}; - -// 安全关闭服务器 -const safelyCloseServer = async (): Promise => { - if (!serverState.server || serverState.isClosing) { - return; - } - - serverState.isClosing = true; - - return new Promise((resolve) => { - // 检查服务器是否仍在运行 - if (!serverState.isListening) { - serverState.server = null; - serverState.isClosing = false; - resolve(); - return; - } - - // 设置超时 - const timeout = setTimeout(() => { - console.log('[ReactPress] Force closing server due to timeout'); - serverState.server = null; - serverState.isClosing = false; - serverState.isListening = false; - resolve(); - }, 3000); - - // 尝试正常关闭 - serverState.server.close((err: any) => { - clearTimeout(timeout); - - if (err && err.code !== 'ERR_SERVER_NOT_RUNNING') { - console.warn('[ReactPress] Server close warning:', err.message); - } - - serverState.server = null; - serverState.isClosing = false; - serverState.isListening = false; - resolve(); - }); - - // 强制关闭所有连接(如果可用) - if (serverState.server.closeAllConnections) { - serverState.server.closeAllConnections(); - } - }); -}; - -// 启动服务器并跟踪状态 -const startServerWithState = (app: express.Express, port: number): Promise => { - return new Promise((resolve, reject) => { - if (serverState.server) { - reject(new Error('Server is already running')); - return; - } - - const server = app.listen(port, () => { - serverState.server = server; - serverState.isListening = true; - global.installationPort = port; - console.log(`[ReactPress] Installation server running on http://localhost:${port}`); - resolve(); - }); - - server.on('error', (error: any) => { - serverState.isListening = false; - reject(error); - }); - - server.on('close', () => { - serverState.isListening = false; - }); - }); -}; - -// 信号处理 -const setupSignalHandlers = () => { - const shutdown = async (signal: string) => { - console.log(`\n[ReactPress] Received ${signal}, shutting down gracefully...`); - - await safelyCloseServer(); - - process.exit(0); - }; - - process.on('SIGINT', () => shutdown('SIGINT')); - process.on('SIGTERM', () => shutdown('SIGTERM')); - process.on('SIGHUP', () => shutdown('SIGHUP')); -}; - -// 主执行函数 -const main = async () => { - try { - setupSignalHandlers(); - - // 获取项目根目录路径(考虑npm包场景) - const projectRoot = getProjectRoot(); - const envPath = join(projectRoot, '.env'); - - console.log(`[ReactPress] Checking for environment file at: ${envPath}`); - console.log(`[ReactPress] Project root determined to be: ${projectRoot}`); - - if (fs.existsSync(envPath)) { - console.log('[ReactPress] Environment file exists, starting main application'); - await startMainApplication(); - return; - } - - console.log('[ReactPress] Environment file not found, starting installation wizard'); - console.log('[ReactPress] Current working directory:', process.cwd()); - console.log('[ReactPress] __dirname:', __dirname); - - await runInstallationWizard(); - - } catch (error) { - console.error('[ReactPress] Fatal error:', error); - // 确保服务器被正确关闭 - await safelyCloseServer(); - process.exit(1); - } -}; - -// 获取项目根目录路径的函数 -const getProjectRoot = (): string => { - // 优先使用通过环境变量传递的原始工作目录 - // 这是在 bin/reactpress-server.js 中设置的,表示用户执行 npx 命令的目录 - if (process.env.REACTPRESS_ORIGINAL_CWD) { - console.log(`[ReactPress] Using original working directory from npx execution: ${process.env.REACTPRESS_ORIGINAL_CWD}`); - return process.env.REACTPRESS_ORIGINAL_CWD; - } - - // 如果没有设置环境变量,则回退到当前工作目录 - const projectRoot = process.cwd(); - console.log(`[ReactPress] Using current working directory as project root: ${projectRoot}`); - return projectRoot; -}; - -// 安装向导主函数 -const runInstallationWizard = async (): Promise => { - try { - // 查找可用端口 - const port = await findAvailablePort(INSTALLATION_PORT); - - const app = express(); - - // 中间件配置 - app.use(bodyParser.json({ limit: '10mb' })); - app.use(bodyParser.urlencoded({ limit: '10mb', extended: true })); - app.use('/public', express.static(join(__dirname, '../public'))); - - // 路由 - app.get('/', (req, res) => { - res.sendFile(join(__dirname, '../public/index.html')); - }); - - app.post('/test-db', async (req, res) => { - try { - const mysql = await import('mysql2/promise'); - const { host, port, user, password, database } = req.body; - const connection = await mysql.createConnection({ - host: host || 'localhost', - port: parseInt(port) || 3306, - user, - password, - database - }); - await connection.execute('SELECT 1'); - await connection.end(); - res.json({ success: true, message: 'Database connection successful!' }); - } catch (error: any) { - res.status(400).json({ - success: false, - message: `Database connection failed: ${error.message}` - }); - } - }); - - app.post('/install', async (req, res) => { - try { - const { db, site } = req.body; - if (!db || !site) { - return res.status(400).json({ - success: false, - message: 'Missing configuration data' - }); - } - - // 测试数据库连接 - const mysql = await import('mysql2/promise'); - const connection = await mysql.createConnection({ - host: db.host || 'localhost', - port: parseInt(db.port) || 3306, - user: db.user, - password: db.password, - database: db.database - }); - await connection.execute('SELECT 1'); - await connection.end(); - - // 创建环境文件到项目根目录 - const envContent = `# Database Config -DB_HOST=${db.host || '127.0.0.1'} -DB_PORT=${db.port || 3306} -DB_USER=${db.user} -DB_PASSWD=${db.password} -DB_DATABASE=${db.database} - -# Client Config -CLIENT_SITE_URL=${site.clientUrl || 'http://localhost:3001'} - -# Server Config -SERVER_SITE_URL=${site.serverUrl || 'http://localhost:3002'} -`.trim(); - - // 使用项目根目录路径创建.env文件 - const projectRoot = getProjectRoot(); - const envPath = join(projectRoot, '.env'); - fs.writeFileSync(envPath, envContent, 'utf8'); - - res.json({ - success: true, - message: 'Installation completed! Server will restart.', - serverUrl: site.serverUrl || 'http://localhost:3002' - }); - - // 确保响应已发送后再关闭服务器 - res.on('finish', async () => { - try { - console.log('[ReactPress] Installation complete, restarting server...'); - await safelyCloseServer(); - await startMainApplication(); - } catch (error) { - console.error('[ReactPress] Restart error:', error); - } - }); - - } catch (error: any) { - res.status(400).json({ - success: false, - message: `Installation failed: ${error.message}` - }); - } - }); - - // 使用状态跟踪启动服务器 - await startServerWithState(app, port); - - try { - await open(`http://localhost:${port}`); - } catch (error) { - console.log(`[ReactPress] Please visit http://localhost:${port} manually`); - } - - } catch (error) { - console.error('[ReactPress] Installation wizard failed:', error); - // 确保服务器被正确关闭 - await safelyCloseServer(); - throw error; - } -}; - -// 启动主应用 -const startMainApplication = async (): Promise => { - try { - console.log('[ReactPress] Starting main application...'); - - // 确保安装服务器完全关闭 - await safelyCloseServer(); - - // 清除安装状态 - global.isInstalling = false; - - // 延迟启动以确保端口释放 - await new Promise(resolve => setTimeout(resolve, 1000)); - - // 动态导入以避免在安装阶段加载 NestJS - const { bootstrap } = await import('./starter'); - if (typeof bootstrap === 'function') { - await bootstrap(); - } else { - throw new Error('Bootstrap function not found'); - } - } catch (error) { - console.error('[ReactPress] Failed to start main application:', error); - process.exit(1); - } -}; - -main(); \ No newline at end of file diff --git a/server/src/modules/article/article.controller.ts b/server/src/modules/article/article.controller.ts deleted file mode 100644 index 0445142..0000000 --- a/server/src/modules/article/article.controller.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - HttpCode, - HttpStatus, - Param, - Patch, - Post, - Query, - Request, - UseGuards, -} from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { User } from '../user/user.entity'; -import { UserService } from '../user/user.service'; -import { Article } from './article.entity'; -import { ArticleService } from './article.service'; - -@ApiTags('Article') -@Controller('article') -@UseGuards(RolesGuard) -export class ArticleController { - constructor( - private readonly articleService: ArticleService, - - private readonly jwtService: JwtService, - private readonly userService: UserService - ) {} - - /** - * 创建文章 - * @param article - */ - @ApiResponse({ status: 200, description: '创建文章', type: [Article] }) - @Post() - @Roles('admin') - @UseGuards(JwtAuthGuard) - create(@Body() article) { - return this.articleService.create(article); - } - - /** - * 获取所有文章 - */ - @Get() - @HttpCode(HttpStatus.OK) - findAll(@Query() queryParams) { - return this.articleService.findAll(queryParams); - } - - /** - * 获取标签下所有文章 - */ - @Get('/category/:id') - @HttpCode(HttpStatus.OK) - findArticlesByCategory(@Param('id') category, @Query() queryParams) { - return this.articleService.findArticlesByCategory(category, queryParams); - } - - /** - * 获取标签下所有文章 - */ - @Get('/tag/:id') - @HttpCode(HttpStatus.OK) - findArticlesByTag(@Param('id') tag, @Query() queryParams) { - return this.articleService.findArticlesByTag(tag, queryParams); - } - - /** - * 获取所有推荐文章 - */ - @Get('/all/recommend') - @HttpCode(HttpStatus.OK) - getRecommendArticles() { - return this.articleService.getRecommendArticles(); - } - - /** - * 获取所有文章归档 - */ - @Get('/archives') - @HttpCode(HttpStatus.OK) - getArchives(): Promise<{ [key: string]: Article[] }> { - return this.articleService.getArchives(); - } - - /** - * 获取相应文章的推荐文章 - */ - @Get('/recommend') - @HttpCode(HttpStatus.OK) - recommend(@Query('articleId') articleId) { - return this.articleService.recommend(articleId); - } - - /** - * 获取指定文章 - * @param id - */ - @Get(':id') - async findById(@Request() req, @Param('id') id, @Query('status') status) { - let token = req.headers.authorization; - - if (/Bearer/.test(token)) { - // 不需要 Bearer,否则验证失败 - token = token.split(' ').pop(); - } - - try { - const tokenUser = this.jwtService.decode(token) as User; - const userId = tokenUser.id; - const exist = await this.userService.findById(userId); - const isAdmin = userId && exist.role === 'admin'; - return this.articleService.findById(id, status, isAdmin); - } catch (e) { - return this.articleService.findById(id, status); - } - } - - /** - * 校验文章密码 - * @param id - * @param article - */ - @Post(':id/checkPassword') - @HttpCode(HttpStatus.OK) - checkPassword(@Param('id') id, @Body() article) { - return this.articleService.checkPassword(id, article); - } - - /** - * 文章访问量 +1 - */ - @Post(':id/views') - @HttpCode(HttpStatus.OK) - updateViewsById(@Param('id') id) { - return this.articleService.updateViewsById(id); - } - - /** - * 文章访问量 +1 - */ - @Post(':id/likes') - @HttpCode(HttpStatus.OK) - updateLikesById(@Param('id') id, @Body('type') type) { - return this.articleService.updateLikesById(id, type); - } - - /** - * 更新文章 - * @param id - * @param article - */ - @Patch(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - @HttpCode(HttpStatus.OK) - updateById(@Param('id') id, @Body() article) { - return this.articleService.updateById(id, article); - } - - /** - * 删除文章 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.articleService.deleteById(id); - } -} diff --git a/server/src/modules/article/article.entity.ts b/server/src/modules/article/article.entity.ts deleted file mode 100644 index 7b25d0a..0000000 --- a/server/src/modules/article/article.entity.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { - Column, - CreateDateColumn, - Entity, - JoinTable, - ManyToMany, - ManyToOne, - PrimaryGeneratedColumn, - UpdateDateColumn, -} from 'typeorm'; - -import { Category } from '../category/category.entity'; -import { Tag } from '../tag/tag.entity'; - -@Entity() -export class Article { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column() - title: string; - - @ApiProperty() - @Column({ default: null }) - cover: string; // 封面图 - - @ApiProperty() - @Column({ type: 'text', default: null }) - summary: string; // 摘要,自动生成 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) - content: string; // 原始内容 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) - html: string; // 格式化内容,自动生成 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null }) - toc: string; // 格式化内容索引,自动生成 - - @ApiProperty() - @ManyToOne(() => Category, (category) => category.articles, { cascade: true }) - @JoinTable() - category: Category; - - @ApiProperty() - @ManyToMany(() => Tag, (tag) => tag.articles, { cascade: true }) - @JoinTable() - tags: Array; - - @ApiProperty() - @Column('simple-enum', { enum: ['draft', 'publish'] }) - status: string; // 文章状态 - - @ApiProperty() - @Column({ type: 'int', default: 0 }) - views: number; // 阅读量 - - @ApiProperty() - @Column({ type: 'int', default: 0 }) - likes: number; // 喜欢数 - - @ApiProperty() - @Column({ type: 'boolean', default: false }) - isRecommended: boolean; // 是否推荐到首页 - - @ApiProperty() - @Column({ type: 'text', default: null, select: false }) - password: string; - - @ApiProperty() - @Column({ type: 'boolean', default: false }) - needPassword: boolean; - - @ApiProperty() - @Column({ type: 'boolean', default: true }) - isCommentable: boolean; - - @ApiProperty() - @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) - publishAt: Date; // 发布日期 - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/article/article.module.ts b/server/src/modules/article/article.module.ts deleted file mode 100644 index ac1ccc7..0000000 --- a/server/src/modules/article/article.module.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { CategoryModule } from '../category/category.module'; -import { TagModule } from '../tag/tag.module'; -import { UserModule } from '../user/user.module'; -import { ArticleController } from './article.controller'; -import { Article } from './article.entity'; -import { ArticleService } from './article.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([Article]), CategoryModule, TagModule, UserModule, AuthModule], - exports: [ArticleService], - providers: [ArticleService], - controllers: [ArticleController], -}) -export class ArticleModule {} diff --git a/server/src/modules/article/article.service.ts b/server/src/modules/article/article.service.ts deleted file mode 100644 index 3493129..0000000 --- a/server/src/modules/article/article.service.ts +++ /dev/null @@ -1,398 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { dateFormat } from '../../utils/date.util'; -import { CategoryService } from '../category/category.service'; -import { TagService } from '../tag/tag.service'; -import { Article } from './article.entity'; -import { extractProtectedArticle } from './article.util'; - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const Segment = require('segment'); -const segment = new Segment(); -segment.useDefault(); - -@Injectable() -export class ArticleService { - constructor( - @InjectRepository(Article) - private readonly articleRepository: Repository
, - private readonly tagService: TagService, - private readonly categoryService: CategoryService - ) {} - - /** - * 创建文章 - * @param article - */ - async create(article: Partial
): Promise
{ - const { title } = article; - const exist = await this.articleRepository.findOne({ where: { title } }); - - if (exist) { - throw new HttpException('文章标题已存在', HttpStatus.BAD_REQUEST); - } - - let { tags, category, status } = article; // eslint-disable-line prefer-const - - if (status === 'publish') { - Object.assign(article, { - publishAt: dateFormat(), - }); - } - - tags = await this.tagService.findByIds(('' + tags).split(',')); - const existCategory = await this.categoryService.findById(category); - const newArticle = await this.articleRepository.create({ - ...article, - category: existCategory, - tags, - needPassword: !!article.password, - }); - await this.articleRepository.save(newArticle); - return newArticle; - } - - /** - * 获取所有文章 - */ - async findAll(queryParams): Promise<[Article[], number]> { - const query = this.articleRepository - .createQueryBuilder('article') - .leftJoinAndSelect('article.tags', 'tag') - .leftJoinAndSelect('article.category', 'category') - .orderBy('article.publishAt', 'DESC'); - - const { page = 1, pageSize = 12, status, ...otherParams } = queryParams; - - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (status) { - query.andWhere('article.status=:status').setParameter('status', status); - } - - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`article.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - - const [data, total] = await query.getManyAndCount(); - - data.forEach((d) => { - if (d.needPassword) { - extractProtectedArticle(d); - } - }); - - return [data, total]; - } - - /** - * 根据 category 查找文章 - * @param category - * @param queryParams - */ - async findArticlesByCategory(category, queryParams) { - const query = this.articleRepository - .createQueryBuilder('article') - .leftJoinAndSelect('article.category', 'category') - .where('category.value=:value', { value: category }) - .orderBy('article.publishAt', 'DESC'); - - const { page = 1, pageSize = 12, status } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (status) { - query.andWhere('article.status=:status').setParameter('status', status); - } - - const [data, total] = await query.getManyAndCount(); - - data.forEach((d) => { - if (d.needPassword) { - extractProtectedArticle(d); - } - }); - - return [data, total]; - } - - /** - * 根据 tag 查找文章 - * @param tag - * @param queryParams - */ - async findArticlesByTag(tag, queryParams) { - const query = this.articleRepository - .createQueryBuilder('article') - .innerJoinAndSelect('article.tags', 'tag', 'tag.value=:value', { - value: tag, - }) - .orderBy('article.publishAt', 'DESC'); - - const { page = 1, pageSize = 12, status } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (status) { - query.andWhere('article.status=:status').setParameter('status', status); - } - - const [data, total] = await query.getManyAndCount(); - - data.forEach((d) => { - if (d.needPassword) { - extractProtectedArticle(d); - } - }); - - return [data, total]; - } - - /** - * 获取推荐文章 - */ - async getRecommendArticles() { - const data = await this.articleRepository.find({ - where: { isRecommended: true }, - order: { publishAt: 'DESC' }, - }); - - return data.filter((d) => !d.needPassword); - } - - /** - * 获取文章归档 - */ - async getArchives(): Promise<{ [key: string]: Article[] }> { - const data = await this.articleRepository.find({ - where: { status: 'publish' }, - order: { publishAt: 'DESC' }, - }); - const months = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', - ]; - const ret = {}; - data.forEach((d) => { - const year = new Date(d.publishAt).getFullYear(); - const month = new Date(d.publishAt).getMonth(); - if (d.needPassword) { - extractProtectedArticle(d); - } - if (!ret[year]) { - ret[year] = {}; - } - if (!ret[year][months[month]]) { - ret[year][months[month]] = []; - } - ret[year][months[month]].push(d); - }); - - return ret; - } - - /** - * 校验文章密码是否正确 - * @param id - * @param password - */ - async checkPassword(id, { password }): Promise<{ pass: boolean }> { - const data = await this.articleRepository - .createQueryBuilder('article') - .where('article.id=:id') - .andWhere('article.password=:password') - .setParameter('id', id) - .setParameter('password', password) - .getOne(); - - const pass = !!data; - return pass ? { pass: !!data, ...data } : { pass: false }; - } - - /** - * 获取指定文章信息 - * @param id - */ - async findById(id, status = null, isAdmin = false): Promise
{ - const query = this.articleRepository - .createQueryBuilder('article') - .leftJoinAndSelect('article.category', 'category') - .leftJoinAndSelect('article.tags', 'tags') - .where('article.id=:id') - .orWhere('article.title=:title') - .setParameter('id', id) - .setParameter('title', id); - - if (status) { - query.andWhere('article.status=:status').setParameter('status', status); - } - - const data = await query.getOne(); - - if (data && data.needPassword && !isAdmin) { - extractProtectedArticle(data); - } - - return data; - } - - /** - * 更新指定文章 - * @param id - * @param article - */ - async updateById(id, article: Partial
): Promise
{ - const oldArticle = await this.articleRepository.findOne(id); - let { tags, category, status } = article; // eslint-disable-line prefer-const - - if (tags) { - tags = await this.tagService.findByIds(('' + tags).split(',')); - } - - const existCategory = await this.categoryService.findById(category); - - const newArticle = { - ...article, - views: oldArticle.views, - category: existCategory, - needPassword: !!article.password, - publishAt: oldArticle.status === 'draft' && status === 'publish' ? dateFormat() : oldArticle.publishAt, - }; - - if (tags) { - Object.assign(newArticle, { tags }); - } - - const updatedArticle = await this.articleRepository.merge(oldArticle, newArticle); - return this.articleRepository.save(updatedArticle); - } - - /** - * 更新指定文章阅读量 + 1 - * @param id - * @param article - */ - async updateViewsById(id): Promise
{ - const oldArticle = await this.articleRepository.findOne(id); - const updatedArticle = await this.articleRepository.merge(oldArticle, { - views: oldArticle.views + 1, - }); - return this.articleRepository.save(updatedArticle); - } - - /** - * 更新喜欢数 - * @param id - * @returns - */ - async updateLikesById(id, type): Promise
{ - const oldArticle = await this.articleRepository.findOne(id); - const updatedArticle = await this.articleRepository.merge(oldArticle, { - likes: type === 'like' ? oldArticle.likes + 1 : oldArticle.likes - 1, - }); - return this.articleRepository.save(updatedArticle); - } - - /** - * 删除文章 - * @param id - */ - async deleteById(id) { - const article = await this.articleRepository.findOne(id); - return this.articleRepository.remove(article); - } - - /** - * 关键词搜索文章 - * @param keyword - */ - async search(keyword) { - const res = await this.articleRepository - .createQueryBuilder('article') - .where('article.title LIKE :keyword') - .setParameter('keyword', `%${keyword}%`) - .getMany(); - - return res; - } - - /** - * 推荐文章 - * @param articleId - */ - async recommend(articleId = null) { - const query = this.articleRepository - .createQueryBuilder('article') - .orderBy('article.publishAt', 'DESC') - .leftJoinAndSelect('article.category', 'category') - .leftJoinAndSelect('article.tags', 'tags'); - - if (!articleId) { - query.where('article.status=:status').setParameter('status', 'publish'); - return query.take(6).getMany(); - } - const sub = this.articleRepository - .createQueryBuilder('article') - .orderBy('article.publishAt', 'DESC') - .leftJoinAndSelect('article.category', 'category') - .leftJoinAndSelect('article.tags', 'tags') - .where('article.id=:id') - .setParameter('id', articleId); - const exist = await sub.getOne(); - - if (!exist) { - return query.take(6).getMany(); - } - - const { title, summary } = exist; - - try { - // nodejieba 安装太麻烦 - // const nodejieba = require('nodejieba'); - const kw1 = segment.doSegment(title, { - stripStopword: true, - }); - const kw2 = segment.doSegment(summary, { - stripStopword: true, - }); - - kw1.forEach((kw, i) => { - const paramKey = `title_` + i; - if (i === 0) { - query.where(`article.title LIKE :${paramKey}`); - } else { - query.orWhere(`article.title LIKE :${paramKey}`); - } - query.setParameter(paramKey, `%${kw.w}%`); - }); - - kw2.forEach((kw, i) => { - const paramKey = `summary_` + i; - if (!kw1.length) { - query.where(`article.summary LIKE :${paramKey}`); - } else { - query.orWhere(`article.summary LIKE :${paramKey}`); - } - query.setParameter(paramKey, `%${kw.w}%`); - }); - } catch (e) {} // eslint-disable-line no-empty - - const data = await query.getMany(); - return data.filter((d) => d.id !== articleId && d.status === 'publish'); - } -} diff --git a/server/src/modules/article/article.util.ts b/server/src/modules/article/article.util.ts deleted file mode 100644 index b11a654..0000000 --- a/server/src/modules/article/article.util.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const extractProtectedArticle = (article) => { - delete article.content; - delete article.html; -}; diff --git a/server/src/modules/auth/auth.controller.ts b/server/src/modules/auth/auth.controller.ts deleted file mode 100644 index 3236367..0000000 --- a/server/src/modules/auth/auth.controller.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - Body, - ClassSerializerInterceptor, - Controller, - HttpCode, - HttpStatus, - Post, - UseGuards, - UseInterceptors, -} from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; - -import { AuthService } from './auth.service'; -import { JwtAuthGuard } from './jwt-auth.guard'; -import { Roles } from './roles.guard'; - -@ApiTags('Auth') -@Controller('auth') -export class AuthController { - constructor(private readonly authService: AuthService) {} - - /** - * 用户登录 - * @param user - */ - @UseInterceptors(ClassSerializerInterceptor) - @Post('login') - @HttpCode(HttpStatus.OK) - async login(@Body() user) { - const res = await this.authService.login(user); - return res; - } - - @Post('admin') - @Roles('admin') - @UseGuards(JwtAuthGuard) - createBook() { - return this.authService.checkAdmin(); - } - - @Post('github') - loginWithGithub(@Body('code') code) { - return this.authService.loginWithGithub(code); - } -} diff --git a/server/src/modules/auth/auth.module.ts b/server/src/modules/auth/auth.module.ts deleted file mode 100644 index ad21d8b..0000000 --- a/server/src/modules/auth/auth.module.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { forwardRef, Module } from '@nestjs/common'; -import { JwtModule } from '@nestjs/jwt'; -import { PassportModule } from '@nestjs/passport'; - -import { SettingModule } from '../setting/setting.module'; -import { SMTPModule } from '../smtp/smtp.module'; -import { UserModule } from '../user/user.module'; -import { AuthController } from './auth.controller'; -import { AuthService } from './auth.service'; -import { JwtStrategy } from './jwt.strategy'; - -const passModule = PassportModule.register({ defaultStrategy: 'jwt' }); -const jwtModule = JwtModule.register({ - secret: 'reactpress', - signOptions: { expiresIn: '4h' }, -}); - -@Module({ - imports: [ - forwardRef(() => UserModule), - passModule, - jwtModule, - forwardRef(() => SettingModule), - forwardRef(() => SMTPModule), - ], - providers: [AuthService, JwtStrategy], - controllers: [AuthController], - exports: [passModule, jwtModule], -}) -export class AuthModule {} diff --git a/server/src/modules/auth/auth.service.ts b/server/src/modules/auth/auth.service.ts deleted file mode 100644 index 0149af6..0000000 --- a/server/src/modules/auth/auth.service.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { JwtService } from '@nestjs/jwt'; -import axios from 'axios'; - -import { uniqueid } from '../../utils/uniqueid.util'; -import { SettingService } from '../setting/setting.service'; -import { SMTPService } from '../smtp/smtp.service'; -import { User } from '../user/user.entity'; -import { UserService } from '../user/user.service'; - -@Injectable() -export class AuthService { - constructor( - private readonly userService: UserService, - private readonly jwtService: JwtService, - private readonly configService: ConfigService, - private readonly settingService: SettingService, - private readonly smtpService: SMTPService - ) {} - - createToken(user: Partial) { - const accessToken = this.jwtService.sign(user); - return accessToken; - } - - async login(user: Partial) { - const data = await this.userService.login(user); - const token = this.createToken({ - id: data.id, - name: data.name, - email: data.email, - role: data.role, - }); - return Object.assign(data, { token }); - } - - async loginWithoutPasswd(user: Partial) { - const data = await this.userService.loginWithoutPasswd(user); - const token = this.createToken({ - id: data.id, - name: data.name, - email: data.email, - role: data.role, - }); - return Object.assign(data, { token }); - } - - async checkAdmin() { - return true; - } - - async validateUser(payload: User) { - const user = await this.userService.findById(payload.id); - return user; - } - - async loginWithGithub(code) { - if (!code) { - throw new HttpException('请输入Gitub授权码', HttpStatus.BAD_REQUEST); - } - - try { - const tokenResponse = (await axios({ - method: 'post', - url: - 'https://github.com/login/oauth/access_token?' + - `client_id=${this.configService.get('GITHUB_CLIENT_ID')}&` + - `client_secret=${this.configService.get('GITHUB_CLIENT_SECRET')}&` + - `code=${code}`, - headers: { - accept: 'application/json', - }, - })) as any; - const accessToken = tokenResponse.data.access_token; - const result = (await axios({ - method: 'get', - url: `https://api.github.com/user`, - headers: { - accept: 'application/json', - Authorization: `token ${accessToken}`, - }, - })) as any; - - if (result.data.email) { - const user = { - name: result.data.name, - avatar: result.data.avatar_url, - email: result.data.email, - type: 'github', - }; - - const existUser = await this.userService.findByConditions(user); - - if (!existUser) { - const password = `easy-blog_${uniqueid()}_${result.data.email}`; - await this.userService.createUser({ ...user, password }); - const setting = await this.settingService.findAll(true); - const emailMessage = { - from: setting.smtpFromUser, - to: result.data.email, - subject: 'Github 用户登录通知', - html: `您好,您使用了 Github 登录了 reactpress。reactpress 已为您创建用户,用户名称:${result.data.name}, 用户密码:${password},请及时登录系统修改密码`, - }; - this.smtpService.create(emailMessage).catch(() => { - console.log(`通知用户 ${result.data.name}(${result.data.email}),但发送邮件通知失败`); - }); - } - - const res = await this.loginWithoutPasswd(user); - return res; - } else { - throw new HttpException('未获取到您的公开邮件地址,无法使用Github登录', HttpStatus.BAD_REQUEST); - } - } catch (e) { - throw new HttpException(e.message || e, HttpStatus.BAD_REQUEST); - } - } -} diff --git a/server/src/modules/auth/jwt-auth.guard.ts b/server/src/modules/auth/jwt-auth.guard.ts deleted file mode 100644 index 3c77b65..0000000 --- a/server/src/modules/auth/jwt-auth.guard.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; - -@Injectable() -export class JwtAuthGuard extends AuthGuard('jwt') { - getRequest(context: ExecutionContext) { - const ctx = context.switchToHttp(); - const request = ctx.getRequest(); - return request; - } - - handleRequest(err, user: User): User { - if (err || !user) { - throw new UnauthorizedException('身份验证失败'); - } - return user; - } -} diff --git a/server/src/modules/auth/jwt.strategy.ts b/server/src/modules/auth/jwt.strategy.ts deleted file mode 100644 index 34baa61..0000000 --- a/server/src/modules/auth/jwt.strategy.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { PassportStrategy } from '@nestjs/passport'; -import { ExtractJwt, Strategy } from 'passport-jwt'; - -import { User } from '../user/user.entity'; -import { AuthService } from './auth.service'; - -@Injectable() -export class JwtStrategy extends PassportStrategy(Strategy) { - constructor(private readonly authService: AuthService) { - super({ - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: 'reactpress', - }); - } - - async validate(payload: User) { - const user = await this.authService.validateUser(payload); - - if (!user) { - throw new UnauthorizedException('身份验证失败'); - } - return user; - } -} diff --git a/server/src/modules/auth/roles.guard.ts b/server/src/modules/auth/roles.guard.ts deleted file mode 100644 index ed3ba06..0000000 --- a/server/src/modules/auth/roles.guard.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CanActivate, ExecutionContext, Injectable, SetMetadata } from '@nestjs/common'; -import { Reflector } from '@nestjs/core'; -import { JwtService } from '@nestjs/jwt'; - -import { User } from '../user/user.entity'; - -export const Roles = (...roles: string[]) => SetMetadata('roles', roles); - -@Injectable() -export class RolesGuard implements CanActivate { - constructor(private readonly reflector: Reflector, private readonly jwtService: JwtService) {} - - canActivate(context: ExecutionContext): boolean { - const roles = this.reflector.get('roles', context.getHandler()); - if (!roles) { - return true; - } - const request = context.switchToHttp().getRequest(); - - let token = request.headers.authorization; - - if (/Bearer/.test(token)) { - // 不需要 Bearer,否则验证失败 - token = token.split(' ').pop(); - } - - const user = this.jwtService.decode(token) as User; - if (!user) { - return false; - } - const hasRole = roles.some((role) => role === user.role); - return user && user.role && hasRole; - } -} diff --git a/server/src/modules/category/category.controller.ts b/server/src/modules/category/category.controller.ts deleted file mode 100644 index 76191bb..0000000 --- a/server/src/modules/category/category.controller.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { Category } from './category.entity'; -import { CategoryService } from './category.service'; - -@ApiTags('Category') -@Controller('category') -@UseGuards(RolesGuard) -export class CategoryController { - constructor(private readonly categoryService: CategoryService) {} - - /** - * 添加标签 - * @param category - */ - @ApiResponse({ status: 200, description: '添加分类', type: [Category] }) - @Post() - @Roles('admin') - @UseGuards(JwtAuthGuard) - create(@Body() category) { - return this.categoryService.create(category); - } - - /** - * 获取所有标签 - */ - @Get() - findAll(@Query() queryParams): Promise { - return this.categoryService.findAll(queryParams); - } - - /** - * 获取指定标签 - * @param id - */ - @Get(':id') - findById(@Param('id') id) { - return this.categoryService.findById(id); - } - - /** - * 更新标签 - * @param id - * @param category - */ - @Patch(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - updateById(@Param('id') id, @Body() category) { - return this.categoryService.updateById(id, category); - } - - /** - * 删除标签 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.categoryService.deleteById(id); - } -} diff --git a/server/src/modules/category/category.entity.ts b/server/src/modules/category/category.entity.ts deleted file mode 100644 index 35111d9..0000000 --- a/server/src/modules/category/category.entity.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -import { Article } from '../article/article.entity'; - -@Entity() -export class Category { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column() - label: string; - - @ApiProperty() - @Column() - value: string; - - @ApiProperty() - @OneToMany( - () => Article, - (article) => article.category - ) - articles: Array
; - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/category/category.module.ts b/server/src/modules/category/category.module.ts deleted file mode 100644 index b4d18d5..0000000 --- a/server/src/modules/category/category.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { CategoryController } from './category.controller'; -import { Category } from './category.entity'; -import { CategoryService } from './category.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([Category]), AuthModule], - exports: [CategoryService], - providers: [CategoryService], - controllers: [CategoryController], -}) -export class CategoryModule {} diff --git a/server/src/modules/category/category.service.ts b/server/src/modules/category/category.service.ts deleted file mode 100644 index 8439e57..0000000 --- a/server/src/modules/category/category.service.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { Category } from './category.entity'; - -@Injectable() -export class CategoryService { - constructor( - @InjectRepository(Category) - private readonly categoryRepository: Repository - ) {} - - /** - * 添加分类 - * @param Category - */ - async create(Category: Partial): Promise { - const { label } = Category; - const existCategory = await this.categoryRepository.findOne({ - where: { label }, - }); - - if (existCategory) { - throw new HttpException('分类已存在', HttpStatus.BAD_REQUEST); - } - - const newCategory = await this.categoryRepository.create(Category); - await this.categoryRepository.save(newCategory); - return newCategory; - } - - /** - * 获取所有分类 - */ - async findAll(queryParams): Promise { - const { articleStatus } = queryParams; - const qb = this.categoryRepository.createQueryBuilder('category').orderBy('category.createAt', 'ASC'); - - if (articleStatus) { - qb.leftJoinAndSelect('category.articles', 'articles', 'articles.status=:status', { - status: articleStatus, - }); - } else { - qb.leftJoinAndSelect('category.articles', 'articles'); - } - - const data = await qb.getMany(); - - data.forEach((d) => { - Object.assign(d, { articleCount: d.articles.length }); - delete d.articles; - }); - - return data; - - // return this.categoryRepository.find({ order: { createAt: 'ASC' } }); - } - - /** - * 获取指定分类 - * @param id - */ - async findById(id): Promise { - const data = await this.categoryRepository - .createQueryBuilder('category') - .where('category.id=:id') - .orWhere('category.label=:id') - .orWhere('category.value=:id') - .setParameter('id', id) - .getOne(); - - return data; - } - - async findByIds(ids): Promise> { - return this.categoryRepository.findByIds(ids); - } - - /** - * 更新分类 - * @param id - * @param Category - */ - async updateById(id, category: Partial): Promise { - const oldCategory = await this.categoryRepository.findOne(id); - const updatedCategory = await this.categoryRepository.merge(oldCategory, category); - return this.categoryRepository.save(updatedCategory); - } - - /** - * 删除分类 - * @param id - */ - async deleteById(id) { - try { - const category = await this.categoryRepository.findOne(id); - await this.categoryRepository.remove(category); - return true; - } catch (e) { - throw new HttpException('删除失败,可能存在关联文章', HttpStatus.BAD_REQUEST); - } - } -} diff --git a/server/src/modules/comment/comment.controller.ts b/server/src/modules/comment/comment.controller.ts deleted file mode 100644 index d44e048..0000000 --- a/server/src/modules/comment/comment.controller.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Body, Controller, Delete, Get, Param, Patch, Post, Query, Request, UseGuards } from '@nestjs/common'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { Comment } from './comment.entity'; -import { CommentService } from './comment.service'; - -@ApiTags('Comment') -@Controller('comment') -@UseGuards(RolesGuard) -export class CommentController { - constructor(private readonly commentService: CommentService) {} - - /** - * 创建评论 - * @param comment - */ - @ApiResponse({ status: 200, description: '创建评论', type: [Comment] }) - @Post() - create(@Request() req, @Body() comment) { - const userAgent = req.headers['user-agent']; - return this.commentService.create(userAgent, comment); - } - - /** - * 获取所有评论 - */ - @Get() - findAll(@Query() queryParams) { - return this.commentService.findAll(queryParams); - } - - /** - * 获取指定评论 - * @param id - */ - @Get(':id') - findById(@Param('id') id) { - return this.commentService.findById(id); - } - - /** - * 获取文章或页面评论 - * @param hostId - */ - @Get('host/:hostId') - getArticleComments(@Param('hostId') hostId, @Query() qurey) { - return this.commentService.getArticleComments(hostId, qurey); - } - - /** - * 更新评论 - * @param id - * @param tag - */ - @Patch(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - updateById(@Param('id') id, @Body() data) { - return this.commentService.updateById(id, data); - } - - /** - * 删除评论 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.commentService.deleteById(id); - } -} diff --git a/server/src/modules/comment/comment.entity.ts b/server/src/modules/comment/comment.entity.ts deleted file mode 100644 index bd58c6c..0000000 --- a/server/src/modules/comment/comment.entity.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -@Entity() -export class Comment { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column() - name: string; - - @ApiProperty() - @Column() - email: string; // 联系方式 - - @ApiProperty() - @Column() - avatar: string; - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) // 评论内容 - content: string; - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) // 评论内容 - html: string; - - @ApiProperty() - @Column({ type: 'boolean', default: false }) - pass: boolean; // 是否审核通过 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) - userAgent: string; - - @ApiProperty() - @Column() - hostId: string; // 关联文章或页面 id - - @ApiProperty() - @Column() - url: string; // 关联页面路径,可与 systemUrl 拼接 - - @ApiProperty() - @Column({ default: null }) - parentCommentId: string; // 父级评论 id - - @ApiProperty() - @Column({ default: null }) - replyUserName: string; // 回复评论用户名 - - @ApiProperty() - @Column({ default: null }) - replyUserEmail: string; // 回复评论邮箱 - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/comment/comment.module.ts b/server/src/modules/comment/comment.module.ts deleted file mode 100644 index fe128eb..0000000 --- a/server/src/modules/comment/comment.module.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { ArticleModule } from '../article/article.module'; -import { AuthModule } from '../auth/auth.module'; -import { SettingModule } from '../setting/setting.module'; -import { SMTPModule } from '../smtp/smtp.module'; -import { UserModule } from '../user/user.module'; -import { CommentController } from './comment.controller'; -import { Comment } from './comment.entity'; -import { CommentService } from './comment.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([Comment]), AuthModule, ArticleModule, SettingModule, SMTPModule, UserModule], - providers: [CommentService], - controllers: [CommentController], -}) -export class CommentModule {} diff --git a/server/src/modules/comment/comment.service.ts b/server/src/modules/comment/comment.service.ts deleted file mode 100644 index c6ba2a2..0000000 --- a/server/src/modules/comment/comment.service.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { marked } from '../../utils/markdown.util'; -import { parseUserAgent } from '../../utils/ua.util'; -import { ArticleService } from '../article/article.service'; -import { SettingService } from '../setting/setting.service'; -import { SMTPService } from '../smtp/smtp.service'; -import { UserService } from '../user/user.service'; -import { Comment } from './comment.entity'; -import { getNewCommentHTML, getReplyCommentHTML } from './html'; - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const url = require('url'); - -@Injectable() -export class CommentService { - constructor( - @InjectRepository(Comment) - private readonly commentRepository: Repository, - private readonly articleService: ArticleService, - private readonly smtpService: SMTPService, - private readonly settingService: SettingService, - private readonly userService: UserService - ) {} - - /** - * 创建评论 - * @param comment - */ - async create(userAgent, comment: Partial & { reply?: string; createByAdmin?: boolean }): Promise { - const { hostId, name, email, content, createByAdmin = false } = comment; - - if (!hostId || !name || !email || !content) { - throw new HttpException('缺失参数', HttpStatus.BAD_REQUEST); - } - - comment.pass = false; - const { text: uaText } = parseUserAgent(userAgent); - comment.userAgent = uaText; - comment.html = marked(content).html; - const newComment = await this.commentRepository.create(comment); - await this.commentRepository.save(comment); - - if (!createByAdmin) { - // 发送通知邮件 - const setting = await this.settingService.findAll(true); - const sendEmail = (adminName, adminEmail) => { - const emailMessage = { - from: setting.smtpFromUser, - to: adminEmail, - subject: '新评论通知', - html: getNewCommentHTML({ ...setting, adminName, comment }), - }; - this.smtpService.create(emailMessage).catch(() => { - console.log('收到新评论,但发送邮件通知失败'); - }); - }; - try { - // 通知所有管理员审核评论 - const [users] = await this.userService.findAll({ role: 'admin' }); - users.forEach((user) => { - if (user.email) { - sendEmail(user.name, user.email); - } - }); - } catch (e) { - console.log(e); - } - } - - return newComment; - } - - /** - * 查询所有评论 - * 额外添加文章信息 - */ - async findAll(queryParams): Promise<[Comment[], number]> { - const query = this.commentRepository.createQueryBuilder('comment').orderBy('comment.createAt', 'DESC'); - - if (typeof queryParams === 'object') { - const { page = 1, pageSize = 12, pass, ...otherParams } = queryParams; - - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (pass) { - query.andWhere('comment.pass=:pass').setParameter('pass', pass); - } - - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`comment.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - } - - return query.getManyAndCount(); - } - - /** - * 获取指定评论 - * @param id - */ - async findById(id): Promise { - return this.commentRepository.findOne(id); - } - - /** - * 获取文章评论 - * @param articleId - */ - async getArticleComments(hostId, queryParams) { - const query = this.commentRepository - .createQueryBuilder('comment') - .where('comment.hostId=:hostId') - .andWhere('comment.pass=:pass') - .andWhere('comment.parentCommentId is NULL') - .orderBy('comment.createAt', 'DESC') - .setParameter('hostId', hostId) - .setParameter('pass', true); - - const subQuery = this.commentRepository - .createQueryBuilder('comment') - .andWhere('comment.pass=:pass') - .andWhere('comment.parentCommentId=:parentCommentId') - .orderBy('comment.createAt', 'ASC') - .setParameter('pass', true); - - const { page = 1, pageSize = 12 } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - const [data, count] = await query.getManyAndCount(); - - for (const item of data) { - const subComments = await subQuery.setParameter('parentCommentId', item.id).getMany(); - Object.assign(item, { children: subComments }); - } - - return [data, count]; - } - - async findByIds(ids): Promise> { - return this.commentRepository.findByIds(ids); - } - - /** - * 更新评论 - * @param id - * @param tag - */ - async updateById(id, data: Partial): Promise { - const old = await this.commentRepository.findOne(id); - const newData = await this.commentRepository.merge(old, data); - - if (newData.pass) { - const { replyUserName, replyUserEmail, url: link } = newData; - const isReply = replyUserName && replyUserEmail; - if (isReply) { - // 发送通知邮件 - try { - const setting = await this.settingService.findAll(true); - const emailMessage = { - from: setting.smtpFromUser, - to: replyUserEmail, - subject: '评论回复通知', - html: getReplyCommentHTML({ - ...setting, - replyUserName, - commentHostUrl: url.resolve(setting.systemUrl, link), - }), - }; - this.smtpService.create(emailMessage).catch(() => { - console.log(`通知用户 ${replyUserName}(${replyUserEmail}),但发送邮件通知失败`); - }); - } catch (e) {} // eslint-disable-line no-empty - } - } - - return this.commentRepository.save(newData); - } - - async deleteById(id) { - const data = await this.commentRepository.findOne(id); - return this.commentRepository.remove(data); - } -} diff --git a/server/src/modules/comment/html.ts b/server/src/modules/comment/html.ts deleted file mode 100644 index 13a7a5b..0000000 --- a/server/src/modules/comment/html.ts +++ /dev/null @@ -1,641 +0,0 @@ -import { dateFormat } from '../../utils/date.util'; - -export const getNewCommentHTML = ({ - systemTitle, - systemUrl, - adminSystemUrl, - adminName, - comment, -}) => { - return ` - - - - - - -
-
- - - - - - - - - -
- - - - - - - - - -
- - - - - - -
- ${systemTitle} -
-
- - - - - - -
- - - - - - - - - - - - -
- - - - - - - - - - -
- 新评论通知 -
-

亲爱的${adminName},站点收到新评论:

-

评论人:${comment.name}

-

评论内容:${comment.content}

-
-
- - - - - - -
- -
-
- - - - - - - - - -
- 此致 -
- ${systemTitle} 敬上 -
-
-
-
-
-
-
- `; -}; - -export const getReplyCommentHTML = ({ - systemLogo, - systemTitle, - systemFavicon, - systemUrl, - replyUserName, - commentHostUrl, -}) => { - return ` - - - - - - -
-
- - - - - - - - - -
- - - - - - - - - -
- - - - - - -
- ${systemTitle} -
-
- - - - - - -
- - - - - - - - - - - - -
- - - - - - - - - - -
- 评论回复通知 -
-

亲爱的${replyUserName},您的评论已经被他人回复。

-
-
- - - - - - -
- -
-
- - - - - - - - - -
- 此致 -
- ${systemTitle} 敬上 -
-
-
-
-
-
-
- `; -}; diff --git a/server/src/modules/file/file.controller.ts b/server/src/modules/file/file.controller.ts deleted file mode 100644 index 9c48cad..0000000 --- a/server/src/modules/file/file.controller.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Controller, Delete, Get, Param, Post, Query, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common'; -import { FileInterceptor } from '@nestjs/platform-express'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { File } from './file.entity'; -import { FileService } from './file.service'; - -@ApiTags('File') -@Controller('file') -@UseGuards(RolesGuard) -export class FileController { - constructor(private readonly fileService: FileService) {} - - /** - * 上传文件 - * @param file - */ - @ApiResponse({ status: 200, description: '上传文件', type: [File] }) - @Post('upload') - @UseInterceptors( - FileInterceptor('file', { - limits: { - fieldSize: 5 * 1024 * 1024, // 5MB - }, - }) - ) - @UseGuards(JwtAuthGuard) - uploadFile(@UploadedFile() file, @Query('unique') unique) { - return this.fileService.uploadFile(file, unique); - } - - /** - * 获取所有文件 - */ - @Get() - findAll(@Query() queryParam) { - return this.fileService.findAll(queryParam); - } - - /** - * 获取指定文件 - * @param id - */ - @Get(':id') - findById(@Param('id') id) { - return this.fileService.findById(id); - } - - /** - * 删除文件 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.fileService.deleteById(id); - } -} diff --git a/server/src/modules/file/file.entity.ts b/server/src/modules/file/file.entity.ts deleted file mode 100644 index 7ff11e0..0000000 --- a/server/src/modules/file/file.entity.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm'; - -@Entity() -export class File { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column() - originalname: string; // 文件名 - - @ApiProperty() - @Column() - filename: string; // 文件名 - - @ApiProperty() - @Column() - type: string; // 文件信息 - - @ApiProperty() - @Column() - size: number; // 文件大小 - - @ApiProperty() - @Column() - url: string; - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; -} diff --git a/server/src/modules/file/file.module.ts b/server/src/modules/file/file.module.ts deleted file mode 100644 index f1a909a..0000000 --- a/server/src/modules/file/file.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { SettingModule } from '../setting/setting.module'; -import { FileController } from './file.controller'; -import { File } from './file.entity'; -import { FileService } from './file.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([File]), AuthModule, SettingModule], - controllers: [FileController], - providers: [FileService], -}) -export class FileModule {} diff --git a/server/src/modules/file/file.service.ts b/server/src/modules/file/file.service.ts deleted file mode 100644 index 2697148..0000000 --- a/server/src/modules/file/file.service.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { HttpException, Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { InjectRepository } from '@nestjs/typeorm'; -import * as path from 'path'; -import { Repository } from 'typeorm'; - -import { dateFormat } from '../../utils/date.util'; -import { Oss } from '../../utils/oss.util'; -import { uniqueid } from '../../utils/uniqueid.util'; -import { LocalUpload } from '../../utils/upload.util'; -import { SettingService } from '../setting/setting.service'; -import { File } from './file.entity'; - -@Injectable() -export class FileService { - private oss: Oss; - private localUpload: LocalUpload; - - constructor( - @InjectRepository(File) - private readonly fileRepository: Repository, - private readonly settingService: SettingService, - private readonly configService: ConfigService - ) { - this.oss = new Oss(this.settingService); - this.localUpload = new LocalUpload(); - } - - /** - * 上传文件 - * @param file - */ - async uploadFile(file, unique): Promise { - const { originalname, mimetype, size, buffer } = file; - const dataFolder = dateFormat(new Date(), 'yyyy-MM-dd'); - const ext = path.extname(originalname); - const filename = +unique === 1 ? `${dataFolder}/${originalname}` : `${dataFolder}/${uniqueid()}.${ext}`; - // 获取oss的配置 - const hasOssConfig = await this.oss.hasOssConfig(); - let url; - if (hasOssConfig) { - // 上传到OSS - url = await this.oss.putFile(filename, buffer); - } else { - // 本地上传 - url = await this.localUpload.putFile(filename, buffer); - // 上传的路径 - const uploadUrl = - this.configService.get('SERVER_PUBLIC_UPLOAD_URL') || `${this.configService.get('SERVER_SITE_URL')}/public/uploads`; - // 最终的地址 - url = `${uploadUrl}/${filename}`; - } - const newFile = await this.fileRepository.create({ - originalname, - filename, - url, - type: mimetype, - size, - }); - await this.fileRepository.save(newFile); - return newFile; - } - - /** - * 获取所有文件 - */ - async findAll(queryParams): Promise<[File[], number]> { - const query = this.fileRepository.createQueryBuilder('file').orderBy('file.createAt', 'DESC'); - - if (typeof queryParams === 'object') { - const { page = 1, pageSize = 12, ...otherParams } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`file.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - } - - return query.getManyAndCount(); - } - - /** - * 获取指定文件 - * @param id - */ - async findById(id): Promise { - return this.fileRepository.findOne(id); - } - - async findByIds(ids): Promise> { - return this.fileRepository.findByIds(ids); - } - - /** - * 删除文件 - * @param id - */ - async deleteById(id) { - const target = await this.fileRepository.findOne(id); - const hasOssConfig = await this.oss.hasOssConfig(); - if (hasOssConfig) { - // 先删除oss的配置 - await this.oss.deleteFile(target.filename); - } else { - // 删除本地的文件 - await this.localUpload.deleteFile(target.filename); - } - return this.fileRepository.remove(target); - } -} diff --git a/server/src/modules/install/install.controller.ts b/server/src/modules/install/install.controller.ts deleted file mode 100644 index 42f0bd8..0000000 --- a/server/src/modules/install/install.controller.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Controller, Post, Body, Get, Res, UseGuards } from '@nestjs/common'; -import { InstallService } from './install.service'; -import { Response } from 'express'; -import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger'; - -@ApiTags('install') -@Controller('install') -export class InstallController { - constructor(private readonly installService: InstallService) {} - - @Post('check') - async checkEnvFileExists(): Promise { - return this.installService.checkEnvFileExists() ? 'Environment file exists.' : 'Please configure your database.'; - } - - @Post('configure') - async configureDatabase(@Body() body: { username: string, password: string, database: string }): Promise { - return this.installService.configureDatabase(body).then(() => 'Database configured successfully.'); - } -} \ No newline at end of file diff --git a/server/src/modules/install/install.module.ts b/server/src/modules/install/install.module.ts deleted file mode 100644 index 3ee7861..0000000 --- a/server/src/modules/install/install.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { SettingModule } from '../setting/setting.module'; -import { InstallController } from './install.controller'; -import { InstallService } from './install.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([File]), AuthModule, SettingModule], - controllers: [InstallController], - providers: [InstallService], -}) -export class InstallModule {} diff --git a/server/src/modules/install/install.service.ts b/server/src/modules/install/install.service.ts deleted file mode 100644 index 83e41eb..0000000 --- a/server/src/modules/install/install.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import * as fs from 'fs'; -import * as path from 'path'; -import { createConnection } from 'typeorm'; -import { ConfigService } from '@nestjs/config'; - -@Injectable() -export class InstallService { - private envConfigPath = path.resolve(__dirname, '..', '..', '.env'); - private configService: ConfigService; - - constructor(configService: ConfigService) { - this.configService = configService; - } - - checkEnvFileExists(): boolean { - return fs.existsSync(this.envConfigPath); - } - - async configureDatabase(config: { username: string, password: string, database: string }): Promise { - const connection = await createConnection({ - type: 'mysql', - host: 'localhost', // 这里可以改为从body中获取,但为了简化我们固定为localhost - port: 3306, // 同样,可以改为动态获取 - username: config.username, - password: config.password, - database: config.database, - synchronize: true, // 注意:在生产中不要启用synchronize - logging: false, // 控制台不输出orm日志 - entities: [__dirname + '/../**/*.entity{.ts,.js}'], // 扫描实体位置 - }); - - try { - await connection.connect(); - console.log('Connected to the database'); - - // 写入.env文件 - const envConfigLines = [ - `DB_HOST=localhost`, // 也可以动态写入 - `DB_PORT=3306`, // 同上 - `DB_USERNAME=${config.username}`, - `DB_PASSWORD=${config.password}`, - `DB_NAME=${config.database}`, - ]; - - fs.writeFileSync(this.envConfigPath, envConfigLines.join('\n'), { encoding: 'utf8' }); - } catch (error) { - throw new Error('Failed to connect to the database: ' + error.message); - } finally { - await connection.close(); - } - } -} \ No newline at end of file diff --git a/server/src/modules/knowledge/knowledge.controller.ts b/server/src/modules/knowledge/knowledge.controller.ts deleted file mode 100644 index 5f00f9c..0000000 --- a/server/src/modules/knowledge/knowledge.controller.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - HttpCode, - HttpStatus, - Param, - Patch, - Post, - Query, - UseGuards, -} from '@nestjs/common'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { Knowledge } from './knowledge.entity'; -import { KnowledgeService } from './knowledge.service'; - -@ApiTags('Knowledge') -@Controller('Knowledge') -@UseGuards(RolesGuard) -export class KnowledgeController { - constructor(private readonly service: KnowledgeService) {} - - /** - * 创建知识库 - * @param data - */ - @ApiResponse({ status: 200, description: '创建知识库', type: [Knowledge] }) - @Post('/book') - @Roles('admin') - @UseGuards(JwtAuthGuard) - createBook(@Body() data) { - return this.service.createKnowledgeBook(data); - } - - /** - * 创建知识库章节 - * @param data - */ - @ApiResponse({ status: 200, description: '创建知识章节', type: [Knowledge] }) - @Post('/chapter') - @Roles('admin') - @UseGuards(JwtAuthGuard) - createChapter(@Body() data) { - return this.service.createKnowledgeChapter(data); - } - - /** - * 删除文章 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.service.deleteById(id); - } - - /** - * 更新知识 - * @param id - * @param data - */ - @Patch(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - @HttpCode(HttpStatus.OK) - updateById(@Param('id') id, @Body() data) { - return this.service.updateById(id, data); - } - - /** - * 获取所有知识库(不包含章节) - */ - @Get() - @HttpCode(HttpStatus.OK) - findAll(@Query() queryParams) { - return this.service.findAll(queryParams); - } - - /** - * 获取章节详情(如果是知识库,会返回所包含的章节) - * @param id - */ - @Get(':id') - async findById(@Param('id') id) { - return this.service.findById(id); - } - - /** - * 文章访问量 +1 - */ - @Post(':id/views') - @HttpCode(HttpStatus.OK) - updateViewsById(@Param('id') id) { - return this.service.updateViewsById(id); - } - - /** - * 文章访问量 +1 - */ - @Post(':id/likes') - @HttpCode(HttpStatus.OK) - updateLikesById(@Param('id') id, @Body('type') type) { - return this.service.updateLikesById(id, type); - } -} diff --git a/server/src/modules/knowledge/knowledge.entity.ts b/server/src/modules/knowledge/knowledge.entity.ts deleted file mode 100644 index b037b17..0000000 --- a/server/src/modules/knowledge/knowledge.entity.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -@Entity() -export class Knowledge { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column({ default: null }) - parentId: string; // 父级 id,如果该项为空,则是书的封面,不为空则是一个章节 - - @ApiProperty() - @Column({ type: 'int', default: 0 }) - order: number; // 章节排序 - - @ApiProperty() - @Column() - title: string; // 标题 - - @ApiProperty() - @Column({ default: null }) - cover: string; // 封面图 - - @ApiProperty() - @Column({ type: 'text', default: null }) - summary: string; // 摘要,自动生成 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) - content: string; // 原始内容 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) - html: string; // 格式化内容,自动生成 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null }) - toc: string; // 格式化内容索引,自动生成 - - @ApiProperty() - @Column('simple-enum', { enum: ['draft', 'publish'], default: 'draft' }) - status: string; // 文章状态 - - @ApiProperty() - @Column({ type: 'int', default: 0 }) - views: number; // 阅读量 - - @ApiProperty() - @Column({ type: 'int', default: 0 }) - likes: number; // 喜欢数 - - @ApiProperty() - @Column({ type: 'boolean', default: true }) - isCommentable: boolean; - - @ApiProperty() - @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) - publishAt: Date; // 发布日期 - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/knowledge/knowledge.module.ts b/server/src/modules/knowledge/knowledge.module.ts deleted file mode 100644 index 0614723..0000000 --- a/server/src/modules/knowledge/knowledge.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { KnowledgeController } from './knowledge.controller'; -import { Knowledge } from './knowledge.entity'; -import { KnowledgeService } from './knowledge.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([Knowledge]), AuthModule], - exports: [KnowledgeService], - providers: [KnowledgeService], - controllers: [KnowledgeController], -}) -export class KnowledgeModule {} diff --git a/server/src/modules/knowledge/knowledge.service.ts b/server/src/modules/knowledge/knowledge.service.ts deleted file mode 100644 index 5770ee0..0000000 --- a/server/src/modules/knowledge/knowledge.service.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { dateFormat } from '../../utils/date.util'; -import { Knowledge } from './knowledge.entity'; - -@Injectable() -export class KnowledgeService { - constructor( - @InjectRepository(Knowledge) - private readonly repository: Repository - ) {} - - /** - * 新建知识库 - * @param knowledge - */ - async createKnowledgeBook(knowledge: Partial): Promise { - const { title, status, parentId } = knowledge; - - const exist = await this.repository.findOne({ where: { title } }); - if (exist && !parentId) { - // 章节不考虑重名 - throw new HttpException('知识库已存在', HttpStatus.BAD_REQUEST); - } - - if (status === 'publish') { - Object.assign(knowledge, { publishAt: dateFormat() }); - } - - const data = await this.repository.create(knowledge); - await this.repository.save(data); - return data; - } - - /** - * 新建知识章节 - * @param knowledge - */ - async createKnowledgeChapter(knowledges: Partial | Array>): Promise> { - if (!Array.isArray(knowledges)) { - knowledges = [knowledges]; - } - if (knowledges.some((knowledge) => !knowledge.parentId)) { - throw new HttpException('无效的知识库章节', HttpStatus.BAD_REQUEST); - } - const result = []; - for (const knowledge of knowledges) { - result.push(await this.createKnowledgeBook(knowledge)); - } - return result; - } - - /** - * 删除章节 - * @param id - */ - async deleteById(id) { - const data = await this.repository.findOne(id); - if (!data.parentId) { - const query = this.repository - .createQueryBuilder('knowledge') - .where('knowledge.parentId=:parentId') - .setParameter('parentId', data.id); - const children = await query.getMany(); - if (children.length) { - for (const item of children) { - await this.repository.remove(item); - } - } - } - return this.repository.remove(data); - } - - /** - * 更新指定知识 - * @param id - * @param data - */ - async updateById(id, data: Partial): Promise { - const oldData = await this.repository.findOne(id); - const { status } = oldData; - const newData = { - ...data, - views: oldData.views, - publishAt: oldData.status === 'draft' && status === 'publish' ? dateFormat() : oldData.publishAt, - }; - const result = await this.repository.merge(oldData, newData); - await this.repository.save(result); - return result; - } - - /** - * 更新指定文章阅读量 + 1 - * @param id - * @param article - */ - async updateViewsById(id): Promise { - const oldData = await this.repository.findOne(id); - const newData = await this.repository.merge(oldData, { - views: oldData.views + 1, - }); - return this.repository.save(newData); - } - - /** - * 更新喜欢数 - * @param id - * @returns - */ - async updateLikesById(id, type): Promise { - const oldData = await this.repository.findOne(id); - const newData = await this.repository.merge(oldData, { - likes: type === 'like' ? oldData.likes + 1 : oldData.likes - 1, - }); - return this.repository.save(newData); - } - - /** - * 获取所有知识库 - */ - async findAll(queryParams): Promise<[Knowledge[], number]> { - const query = this.repository - .createQueryBuilder('knowledge') - .orderBy('knowledge.publishAt', 'DESC') - .where('knowledge.parentId is :parentId') - .setParameter('parentId', null); - - const { page = 1, pageSize = 12, status, ...otherParams } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - if (status) { - query.andWhere('knowledge.status=:status').setParameter('status', status); - } - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`knowledge.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - const [data, total] = await query.getManyAndCount(); - return [data, total]; - } - - /** - * 获取指定文章信息 - * @param id - */ - async findById(id): Promise> { - const data = (await this.repository.findOne(id)) as Partial; - - if (!data) { - return null; - } - - if (!data.parentId) { - const query = this.repository - .createQueryBuilder('knowledge') - .where('knowledge.parentId=:parentId') - .setParameter('parentId', data.id); - const children = await query.getMany(); - children.sort((a, b) => a.order - b.order); - Object.assign(data, { children: children || [] }); - } - - return data; - } -} diff --git a/server/src/modules/page/page.controller.ts b/server/src/modules/page/page.controller.ts deleted file mode 100644 index 968056e..0000000 --- a/server/src/modules/page/page.controller.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - HttpCode, - HttpStatus, - Param, - Patch, - Post, - Query, - UseGuards, -} from '@nestjs/common'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { Page } from './page.entity'; -import { PageService } from './page.service'; - -@ApiTags('Page') -@Controller('page') -@UseGuards(RolesGuard) -export class PageController { - constructor(private readonly pageService: PageService) {} - - /** - * 创建页面 - * @param page - */ - @ApiResponse({ status: 200, description: '创建页面', type: [Page] }) - @Post() - @Roles('admin') - @UseGuards(JwtAuthGuard) - create(@Body() page) { - return this.pageService.create(page); - } - - /** - * 获取所有文章 - */ - @Get() - findAll(@Query() queryParams) { - return this.pageService.findAll(queryParams); - } - - /** - * 获取指定页面 - * @param id - */ - @Get(':id') - findById(@Param('id') id) { - return this.pageService.findById(id); - } - - /** - * 更新页面 - * @param id - * @param page - */ - @Patch(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - updateById(@Param('id') id, @Body() page) { - return this.pageService.updateById(id, page); - } - - /** - * 文章访问量 +1 - */ - @Post(':id/views') - @HttpCode(HttpStatus.OK) - updateViewsById(@Param('id') id) { - return this.pageService.updateViewsById(id); - } - - /** - * 删除文章 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.pageService.deleteById(id); - } -} diff --git a/server/src/modules/page/page.entity.ts b/server/src/modules/page/page.entity.ts deleted file mode 100644 index a8a4fb2..0000000 --- a/server/src/modules/page/page.entity.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -@Entity() -export class Page { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column({ default: null }) - cover: string; // 页面封面 - - @ApiProperty() - @Column() - name: string; // 页面名 - - @ApiProperty() - @Column() - path: string; // 页面路径 - - @ApiProperty() - @Column({ type: 'int', default: 0 }) - order: number; // 顺序 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) - content: string; // 原始内容 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) - html: string; // 格式化内容,自动生成 - - @ApiProperty() - @Column({ type: 'mediumtext', default: null }) - toc: string; // 格式化内容索引,自动生成 - - @ApiProperty() - @Column('simple-enum', { enum: ['draft', 'publish'] }) - status: string; // 页面状态 - - @ApiProperty() - @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) - publishAt: Date; // 发布日期 - - @ApiProperty() - @Column({ type: 'int', default: 0 }) - views: number; // 阅读量 - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/page/page.module.ts b/server/src/modules/page/page.module.ts deleted file mode 100644 index d6d2209..0000000 --- a/server/src/modules/page/page.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { PageController } from './page.controller'; -import { Page } from './page.entity'; -import { PageService } from './page.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([Page]), AuthModule], - exports: [PageService], - providers: [PageService], - controllers: [PageController], -}) -export class PageModule {} diff --git a/server/src/modules/page/page.service.ts b/server/src/modules/page/page.service.ts deleted file mode 100644 index 1863cc4..0000000 --- a/server/src/modules/page/page.service.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { dateFormat } from '../../utils/date.util'; -import { Page } from './page.entity'; - -@Injectable() -export class PageService { - constructor( - @InjectRepository(Page) - private readonly pageRepository: Repository - ) {} - - /** - * 新建页面 - * @param page - */ - async create(page: Partial): Promise { - const { path } = page; - const exist = await this.pageRepository.findOne({ where: { path } }); - - if (exist) { - throw new HttpException('页面已存在', HttpStatus.BAD_REQUEST); - } - - const newPage = await this.pageRepository.create({ - ...page, - }); - await this.pageRepository.save(newPage); - return newPage; - } - - /** - * 获取所有页面 - */ - async findAll(queryParams): Promise<[Page[], number]> { - const query = this.pageRepository.createQueryBuilder('page').orderBy('publishAt', 'DESC'); - - if (typeof queryParams === 'object') { - const { page = 1, pageSize = 12, status, ...otherParams } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (status) { - query.andWhere('page.status=:status').setParameter('status', status); - } - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`page.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - } - - return query.getManyAndCount(); - } - - /** - * 获取指定页面信息 - * @param id - */ - async findById(id): Promise { - const query = this.pageRepository - .createQueryBuilder('page') - .where('page.id=:id') - .orWhere('page.path=:path') - .setParameter('id', id) - .setParameter('path', id); - - return query.getOne(); - } - - /** - * 更新指定文章阅读量 + 1 - * @param id - * @param article - */ - async updateViewsById(id): Promise { - const old = await this.pageRepository.findOne(id); - const newData = await this.pageRepository.merge(old, { - views: old.views + 1, - }); - return this.pageRepository.save(newData); - } - - /** - * 更新指定页面 - * @param id - * @param article - */ - async updateById(id, page: Partial): Promise { - const old = await this.pageRepository.findOne(id); - const { status } = page; - - const newPage = { - ...page, - publishAt: status === 'publish' ? dateFormat() : old && old.publishAt, - }; - - const updatedPage = await this.pageRepository.merge(old, newPage); - return this.pageRepository.save(updatedPage); - } - - /** - * 删除页面 - * @param id - */ - async deleteById(id) { - const page = await this.pageRepository.findOne(id); - return this.pageRepository.remove(page); - } -} diff --git a/server/src/modules/search/search.controller.ts b/server/src/modules/search/search.controller.ts deleted file mode 100644 index 9672f2a..0000000 --- a/server/src/modules/search/search.controller.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Controller, Delete, Get, Param, Query, UseGuards } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { SearchService } from './search.service'; - -@ApiTags('Search') -@Controller('search') -@UseGuards(RolesGuard) -export class SearchController { - constructor(private readonly searchService: SearchService) {} - - /** - * 搜索文章 - * @param keyword - */ - @Get('/article') - async searchArticle(@Query('keyword') keyword) { - const data = await this.searchService.searchArticle('article', keyword); - return data; - } - - /** - * 获取搜索记录 - */ - @Get('/') - @UseGuards(JwtAuthGuard) - async findAll(@Query() queryParam) { - return this.searchService.findAll(queryParam); - } - - /** - * 删除文件 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.searchService.deleteById(id); - } -} diff --git a/server/src/modules/search/search.entity.ts b/server/src/modules/search/search.entity.ts deleted file mode 100644 index 7f9fc0d..0000000 --- a/server/src/modules/search/search.entity.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -@Entity() -export class Search { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column() - type: string; // 搜索类型 - - @ApiProperty() - @Column() - keyword: string; // 搜索关键词 - - @ApiProperty() - @Column({ default: 1 }) - count: number; - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/search/search.module.ts b/server/src/modules/search/search.module.ts deleted file mode 100644 index 8d70955..0000000 --- a/server/src/modules/search/search.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { ArticleModule } from '../article/article.module'; -import { AuthModule } from '../auth/auth.module'; -import { SearchController } from './search.controller'; -import { Search } from './search.entity'; -import { SearchService } from './search.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([Search]), AuthModule, ArticleModule], - providers: [SearchService], - controllers: [SearchController], -}) -export class SearchModule {} diff --git a/server/src/modules/search/search.service.ts b/server/src/modules/search/search.service.ts deleted file mode 100644 index b5c47b8..0000000 --- a/server/src/modules/search/search.service.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { ArticleService } from '../article/article.service'; -import { Search } from './search.entity'; - -@Injectable() -export class SearchService { - constructor( - @InjectRepository(Search) - private readonly searchRepository: Repository, - private readonly articleService: ArticleService - ) {} - - /** - * 搜素文章 - * @param type - */ - async searchArticle(type, keyword) { - const articles = await this.articleService.search(keyword); - await this.addRecord(type, keyword); - return articles; - } - - async addRecord(type, keyword) { - const exist = await this.searchRepository.findOne({ - where: { type, keyword }, - }); - - if (exist) { - const count = exist.count; - const newData = await this.searchRepository.merge(exist, { - count: count + 1, - }); - await this.searchRepository.save(newData); - return newData; - } - - const newData = await this.searchRepository.create({ type, keyword }); - const d = await this.searchRepository.save(newData); - return d; - } - - /** - * 获取所有搜索记录 - */ - async findAll(queryParams): Promise<[Search[], number]> { - const query = this.searchRepository.createQueryBuilder('search').orderBy('search.updateAt', 'DESC'); - - if (typeof queryParams === 'object') { - const { page = 1, pageSize = 12, ...otherParams } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`search.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - } - - return query.getManyAndCount(); - } - - /** - * 删除搜索记录 - * @param id - */ - async deleteById(id) { - const data = await this.searchRepository.findOne(id); - return this.searchRepository.remove(data); - } -} diff --git a/server/src/modules/setting/setting.constant.ts b/server/src/modules/setting/setting.constant.ts deleted file mode 100644 index 1f38e35..0000000 --- a/server/src/modules/setting/setting.constant.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { config } from '@fecommunity/reactpress-toolkit'; - -/** - * 国际化配置 - */ -export { messages as i18n } from '@fecommunity/reactpress-toolkit/config'; - -/** - * 全局配置 - */ -export const settings = config.globalSetting; - -export const UNPROTECTED_KEYS = [ - 'i18n', - 'systemUrl', - 'adminSystemUrl', - 'systemTitle', - 'systemSubTitle', - 'systemBg', - 'systemLogo', - 'systemFavicon', - 'systemNoticeInfo', - 'systemFooterInfo', - 'seoKeyword', - 'seoDesc', - 'baiduAnalyticsId', - 'googleAnalyticsId', - 'globalSetting', -]; \ No newline at end of file diff --git a/server/src/modules/setting/setting.controller.ts b/server/src/modules/setting/setting.controller.ts deleted file mode 100644 index f5c2f53..0000000 --- a/server/src/modules/setting/setting.controller.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Body, Controller, HttpCode, HttpStatus, Post, Request, UseGuards } from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { User } from '../user/user.entity'; -import { UserService } from '../user/user.service'; -import { Setting } from './setting.entity'; -import { SettingService } from './setting.service'; - -@ApiTags('Setting') -@Controller('setting') -@UseGuards(RolesGuard) -export class SettingController { - constructor( - private readonly settingService: SettingService, - private readonly jwtService: JwtService, - private readonly userService: UserService - ) {} - - /** - * 更新设置 - * @param tag - */ - @ApiResponse({ status: 200, description: '更新设置', type: [Setting] }) - @Post() - @Roles('admin') - @UseGuards(JwtAuthGuard) - update(@Body() setting) { - return this.settingService.update(setting); - } - - /** - * 获取设置 - */ - @Post('/get') - @HttpCode(HttpStatus.OK) - async findAll(@Request() req): Promise { - let token = req.headers.authorization; - - if (/Bearer/.test(token)) { - // 不需要 Bearer,否则验证失败 - token = token.split(' ').pop(); - } - - try { - const tokenUser = this.jwtService.decode(token) as User; - const id = tokenUser.id; - const exist = await this.userService.findById(id); - const isAdmin = id && exist.role === 'admin'; - return this.settingService.findAll(false, isAdmin); - } catch (e) { - return this.settingService.findAll(false, false); - } - } -} diff --git a/server/src/modules/setting/setting.entity.ts b/server/src/modules/setting/setting.entity.ts deleted file mode 100644 index 49d500e..0000000 --- a/server/src/modules/setting/setting.entity.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -@Entity() -export class Setting { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column({ type: 'text', default: null }) - i18n: string; // 国际化 - - @ApiProperty() - @Column({ type: 'text', default: null }) - globalSetting: string; // 导航设置 - - @ApiProperty() - @Column({ type: 'text', default: null }) - systemUrl: string; // 系统地址 - - @ApiProperty() - @Column({ type: 'text', default: null }) - systemTitle: string; // 系统标题 - - @ApiProperty() - @Column({ type: 'text', default: null }) - systemSubTitle: string; // 系统副标题 - - @ApiProperty() - @Column({ type: 'text', default: null }) - systemLogo: string; // 系统Logo - - @ApiProperty() - @Column({ type: 'text', default: null }) - systemBg: string; // 全局背景 - - @ApiProperty() - @Column({ type: 'text', default: null }) - systemFavicon: string; // 系统 favicon - - @ApiProperty() - @Column({ type: 'text', default: null }) - systemNoticeInfo: string; // 系统通知信息 - - @ApiProperty() - @Column({ type: 'text', default: null }) - systemFooterInfo: string; // 系统页脚 - - @ApiProperty() - @Column({ type: 'text', default: null }) - adminSystemUrl: string; // 后台系统地址 - - @ApiProperty() - @Column({ type: 'text', default: null }) - baiduAnalyticsId: string; // 百度统计id - - @ApiProperty() - @Column({ type: 'text', default: null }) - googleAnalyticsId: string; // 谷歌分析 id - - @ApiProperty() - @Column({ type: 'text', default: null }) - seoKeyword: string; // SEO 关键词 - - @ApiProperty() - @Column({ type: 'text', default: null }) - seoDesc: string; // SEO 描述 - - @ApiProperty() - @Column({ type: 'text', default: null }) - oss: string; // OSS 上传配置 - - @ApiProperty() - @Column({ type: 'text', default: null }) - smtpHost: string; // SMTP 地址 - - @ApiProperty() - @Column({ type: 'text', default: null }) - smtpPort: string; // SMTP 端口 - - @ApiProperty() - @Column({ type: 'text', default: null }) - smtpUser: string; // SMTP 用户 - - @ApiProperty() - @Column({ type: 'text', default: null }) - smtpPass: string; // SMTP 授权码 - - @ApiProperty() - @Column({ type: 'text', default: null }) - smtpFromUser: string; // SMTP 发件人 - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/setting/setting.module.ts b/server/src/modules/setting/setting.module.ts deleted file mode 100644 index 17cf8c3..0000000 --- a/server/src/modules/setting/setting.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { forwardRef, Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { UserModule } from '../user/user.module'; -import { SettingController } from './setting.controller'; -import { Setting } from './setting.entity'; -import { SettingService } from './setting.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([Setting]), forwardRef(() => UserModule), forwardRef(() => AuthModule)], - exports: [SettingService], - providers: [SettingService], - controllers: [SettingController], -}) -export class SettingModule {} diff --git a/server/src/modules/setting/setting.service.ts b/server/src/modules/setting/setting.service.ts deleted file mode 100644 index d0e2d21..0000000 --- a/server/src/modules/setting/setting.service.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import * as merge from 'deepmerge'; -import { Repository } from 'typeorm'; - -import { i18n, settings, UNPROTECTED_KEYS } from './setting.constant'; -import { Setting } from './setting.entity'; - -@Injectable() -export class SettingService { - constructor( - @InjectRepository(Setting) - private readonly settingRepository: Repository - ) { - this.initI18n(); - this.initGlobalConfig(); - } - - /** - * 初始化时加载 i18n 配置 - */ - async initI18n() { - try { - const items = await this.settingRepository.find(); - const target = (items && items[0]) || ({} as Setting); - - let data = {}; - try { - if (target.i18n) { - data = JSON.parse(target.i18n); - } - } catch (e) { - console.warn('[SettingService] Error parsing i18n from DB:', e); - data = {}; - } - - // Merge default i18n with data from DB - const mergedI18n = merge({}, i18n, data); - - // Only update if there's a change or if it's empty - const mergedI18nString = JSON.stringify(mergedI18n); - if (!target.i18n || target.i18n !== mergedI18nString) { - target.i18n = mergedI18nString; - await this.settingRepository.save(target); - console.log('[SettingService] i18n updated in database'); - } else { - console.log('[SettingService] i18n already up to date'); - } - } catch (error) { - console.error('[SettingService] Error in initI18n:', error); - throw error; - } - } - - /** - * 初始化时加载 nav 配置 - */ - async initGlobalConfig() { - const items = await this.settingRepository.find(); - const target = (items && items[0]) || ({} as Setting); - let data = {}; - try { - if (target.globalSetting) { - data = JSON.parse(target.globalSetting); - } - } catch (e) { - data = {}; - } - const mergedSettings = merge({}, settings, data); - const mergedSettingsString = JSON.stringify(mergedSettings); - - if (!target.globalSetting || target.globalSetting !== mergedSettingsString) { - target.globalSetting = mergedSettingsString; - await this.settingRepository.save(target); - } - } - - /** - * - * 获取系统设置 - * @param user - * @param innerInvoke - * @param isAdmin - */ - async findAll(innerInvoke = false, isAdmin = false): Promise { - const data = await this.settingRepository.find(); - const res = data[0]; - if (!res) { - return {} as Setting; - } - if (innerInvoke || isAdmin) { - return res; - } - const filterRes = UNPROTECTED_KEYS.reduce((a, c) => { - a[c] = res[c]; - return a; - }, {}) as Setting; - - return filterRes; - } - - /** - * 更新系统设置 - * @param id - * @param setting - */ - async update(setting: Partial): Promise { - const old = await this.settingRepository.find(); - - const updatedTag = - old && old[0] - ? await this.settingRepository.merge(old[0], setting) - : await this.settingRepository.create(setting); - return this.settingRepository.save(updatedTag); - } -} \ No newline at end of file diff --git a/server/src/modules/smtp/mail.util.ts b/server/src/modules/smtp/mail.util.ts deleted file mode 100644 index 03d37f7..0000000 --- a/server/src/modules/smtp/mail.util.ts +++ /dev/null @@ -1,31 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const nodemailer = require('nodemailer'); - -export const sendEmail = (message, { host, port, user, pass }) => { - if (!host || !port || !user || !pass) { - console.log('邮箱配置不正确,无法发送邮件'); - return null; - } - - const transport = nodemailer.createTransport({ - host, - port, - secureConnection: true, - secure: true, - auth: { - user, - pass, - }, - }); - - return new Promise((resolve, reject) => { - transport.sendMail(message, function(err, info) { - if (err) { - console.log('发送邮件失败', err); - reject(err); - } else { - resolve(info); - } - }); - }); -}; diff --git a/server/src/modules/smtp/smtp.controller.ts b/server/src/modules/smtp/smtp.controller.ts deleted file mode 100644 index 452aebb..0000000 --- a/server/src/modules/smtp/smtp.controller.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Body, Controller, Delete, Get, Param, Post, Query, UseGuards } from '@nestjs/common'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { SMTP } from './smtp.entity'; -import { SMTPService } from './smtp.service'; - -@ApiTags('Smtp') -@Controller('smtp') -@UseGuards(RolesGuard) -export class SMTPController { - constructor(private readonly smtpService: SMTPService) {} - - /** - * 发送邮件 - * @param data - */ - @ApiResponse({ status: 200, description: '发送邮件', type: [SMTP] }) - @Post() - @UseGuards(JwtAuthGuard) - create(@Body() data) { - return this.smtpService.create(data); - } - - /** - * 获取所有邮件记录 - */ - @Get() - @UseGuards(JwtAuthGuard) - findAll(@Query() queryParam) { - return this.smtpService.findAll(queryParam); - } - - /** - * 删除邮件记录 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.smtpService.deleteById(id); - } -} diff --git a/server/src/modules/smtp/smtp.entity.ts b/server/src/modules/smtp/smtp.entity.ts deleted file mode 100644 index 7192062..0000000 --- a/server/src/modules/smtp/smtp.entity.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm'; - -@Entity() -export class SMTP { - @ApiProperty() - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column({ type: 'text', default: null }) - from: string; // 发件人 - - @ApiProperty() - @Column({ type: 'text', default: null }) - to: string; // 收件人 - - @ApiProperty() - @Column({ type: 'text', default: null }) - subject: string; // 主题 - - @ApiProperty() - @Column({ type: 'text', default: null }) - text: string; // 文本内容 - - @ApiProperty() - @Column({ type: 'text', default: null }) - html: string; // html 内容 - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; -} diff --git a/server/src/modules/smtp/smtp.module.ts b/server/src/modules/smtp/smtp.module.ts deleted file mode 100644 index 452a15d..0000000 --- a/server/src/modules/smtp/smtp.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { forwardRef, Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { SettingModule } from '../setting/setting.module'; -import { SMTPController } from './smtp.controller'; -import { SMTP } from './smtp.entity'; -import { SMTPService } from './smtp.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([SMTP]), forwardRef(() => SettingModule), forwardRef(() => AuthModule)], - exports: [SMTPService], - controllers: [SMTPController], - providers: [SMTPService], -}) -export class SMTPModule {} diff --git a/server/src/modules/smtp/smtp.service.ts b/server/src/modules/smtp/smtp.service.ts deleted file mode 100644 index da53532..0000000 --- a/server/src/modules/smtp/smtp.service.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { SettingService } from '../setting/setting.service'; -import { sendEmail } from './mail.util'; -import { SMTP } from './smtp.entity'; - -@Injectable() -export class SMTPService { - constructor( - @InjectRepository(SMTP) - private readonly smtpRepository: Repository, - private readonly settingService: SettingService - ) {} - - /** - * 添加邮件,发送邮件并保存 - * @param SMTP - */ - async create(data: Partial): Promise { - const setting = await this.settingService.findAll(true); - const { smtpHost, smtpPort, smtpUser, smtpPass, smtpFromUser } = setting; - Object.assign(data, { - from: smtpFromUser, - }); - await sendEmail(data, { - host: smtpHost, - port: smtpPort, - user: smtpUser, - pass: smtpPass, - }).catch(() => { - throw new HttpException('邮件发送失败', HttpStatus.BAD_REQUEST); - }); - const newSMTP = await this.smtpRepository.create(data); - await this.smtpRepository.save(newSMTP); - return newSMTP; - } - - /** - * 获取所有邮件 - */ - async findAll(queryParams): Promise<[SMTP[], number]> { - const query = this.smtpRepository.createQueryBuilder('smtp').orderBy('smtp.createAt', 'DESC'); - - if (typeof queryParams === 'object') { - const { page = 1, pageSize = 12, ...otherParams } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`smtp.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - } - - return query.getManyAndCount(); - } - - /** - * 删除邮件 - * @param id - */ - async deleteById(id) { - const SMTP = await this.smtpRepository.findOne(id); - return this.smtpRepository.remove(SMTP); - } -} diff --git a/server/src/modules/tag/tag.controller.ts b/server/src/modules/tag/tag.controller.ts deleted file mode 100644 index 5de932e..0000000 --- a/server/src/modules/tag/tag.controller.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { Tag } from './tag.entity'; -import { TagService } from './tag.service'; - -@ApiTags('Tag') -@Controller('tag') -@UseGuards(RolesGuard) -export class TagController { - constructor(private readonly tagService: TagService) {} - - /** - * 添加标签 - * @param tag - */ - @ApiResponse({ status: 200, description: '创建标签', type: [Tag] }) - @Post() - @Roles('admin') - @UseGuards(JwtAuthGuard) - create(@Body() tag) { - return this.tagService.create(tag); - } - - /** - * 获取所有标签 - */ - @Get() - findAll(@Query() queryParams): Promise { - return this.tagService.findAll(queryParams); - } - - /** - * 获取指定标签 - * @param id - */ - @Get(':id') - findById(@Param('id') id) { - return this.tagService.findById(id); - } - - /** - * 获取指定标签,包含相关文章信息 - * @param id - */ - @Get(':id/article') - getArticleById(@Param('id') id, @Query('status') status) { - return this.tagService.getArticleById(id, status); - } - - /** - * 更新标签 - * @param id - * @param tag - */ - @Patch(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - updateById(@Param('id') id, @Body() tag) { - return this.tagService.updateById(id, tag); - } - - /** - * 删除标签 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.tagService.deleteById(id); - } -} diff --git a/server/src/modules/tag/tag.entity.ts b/server/src/modules/tag/tag.entity.ts deleted file mode 100644 index 2998419..0000000 --- a/server/src/modules/tag/tag.entity.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, ManyToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -import { Article } from '../article/article.entity'; - -@Entity() -export class Tag { - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column() - label: string; - - @ApiProperty() - @Column() - value: string; - - @ApiProperty() - @ManyToMany( - () => Article, - (article) => article.tags - ) - articles: Array
; - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/tag/tag.module.ts b/server/src/modules/tag/tag.module.ts deleted file mode 100644 index c1adcc7..0000000 --- a/server/src/modules/tag/tag.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { TagController } from './tag.controller'; -import { Tag } from './tag.entity'; -import { TagService } from './tag.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([Tag]), AuthModule], - exports: [TagService], - providers: [TagService], - controllers: [TagController], -}) -export class TagModule {} diff --git a/server/src/modules/tag/tag.service.ts b/server/src/modules/tag/tag.service.ts deleted file mode 100644 index 35d347a..0000000 --- a/server/src/modules/tag/tag.service.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { Tag } from './tag.entity'; - -@Injectable() -export class TagService { - constructor( - @InjectRepository(Tag) - private readonly tagRepository: Repository - ) {} - - /** - * 添加标签 - * @param tag - */ - async create(tag: Partial): Promise { - const { label } = tag; - const existTag = await this.tagRepository.findOne({ where: { label } }); - - if (existTag) { - throw new HttpException('标签已存在', HttpStatus.BAD_REQUEST); - } - - const newTag = await this.tagRepository.create(tag); - await this.tagRepository.save(newTag); - return newTag; - } - - /** - * 获取所有标签 - */ - async findAll(queryParams): Promise { - const { articleStatus } = queryParams; - const qb = this.tagRepository.createQueryBuilder('tag').orderBy('tag.createAt', 'ASC'); - - if (articleStatus) { - qb.leftJoinAndSelect('tag.articles', 'articles', 'articles.status=:status', { - status: articleStatus, - }); - } else { - qb.leftJoinAndSelect('tag.articles', 'articles'); - } - - const data = await qb.getMany(); - - data.forEach((d) => { - Object.assign(d, { articleCount: d.articles.length }); - delete d.articles; - }); - - return data; - } - - /** - * 获取指定标签 - * @param id - */ - async findById(id): Promise { - const data = await this.tagRepository - .createQueryBuilder('tag') - .where('tag.id=:id') - .orWhere('tag.label=:id') - .orWhere('tag.value=:id') - .setParameter('id', id) - .getOne(); - - return data; - } - - /** - * 获取指定标签信息,包含相关文章 - * @param id - */ - async getArticleById(id, status = null): Promise { - const data = await this.tagRepository - .createQueryBuilder('tag') - .leftJoinAndSelect('tag.articles', 'articles') - .orderBy('articles.updateAt', 'DESC') - .where('tag.id=:id') - .orWhere('tag.label=:id') - .orWhere('tag.value=:id') - .setParameter('id', id) - .getOne(); - - if (status) { - data.articles = data.articles.filter((a) => a.status === status); - return data; - } - return data; - } - - async findByIds(ids): Promise> { - return this.tagRepository.findByIds(ids); - } - - /** - * 更新标签 - * @param id - * @param tag - */ - async updateById(id, tag: Partial): Promise { - const oldTag = await this.tagRepository.findOne(id); - const updatedTag = await this.tagRepository.merge(oldTag, tag); - return this.tagRepository.save(updatedTag); - } - - /** - * 删除标签 - * @param id - */ - async deleteById(id) { - try { - const tag = await this.tagRepository.findOne(id); - await this.tagRepository.remove(tag); - return true; - } catch (e) { - throw new HttpException('删除失败,可能存在关联文章', HttpStatus.BAD_REQUEST); - } - } -} diff --git a/server/src/modules/user/user.controller.ts b/server/src/modules/user/user.controller.ts deleted file mode 100644 index e4344f6..0000000 --- a/server/src/modules/user/user.controller.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { - Body, - ClassSerializerInterceptor, - Controller, - Get, - HttpCode, - HttpException, - HttpStatus, - Post, - Query, - Request, - UseGuards, - UseInterceptors, -} from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { User } from './user.entity'; -import { UserService } from './user.service'; - -@ApiTags('User') -@Controller('user') -@UseGuards(RolesGuard) -export class UserController { - constructor(private readonly userService: UserService, private readonly jwtService: JwtService) {} - - @ApiResponse({ status: 200, description: '获取用户列表', type: [User] }) - @ApiResponse({ status: 403, description: '无权获取用户列表' }) - @UseInterceptors(ClassSerializerInterceptor) - @Get() - @Roles('admin') - @UseGuards(JwtAuthGuard) - findAll(@Query() query) { - return this.userService.findAll(query); - } - - /** - * 用户注册 - * @param user - */ - @ApiResponse({ status: 201, description: '创建用户', type: [User] }) - @UseInterceptors(ClassSerializerInterceptor) - @Post('register') - @HttpCode(HttpStatus.CREATED) - async register(@Body() user: Partial): Promise { - const d = await this.userService.createUser(user); - return d; - } - - async checkPermission(req, user) { - let token = req.headers.authorization; - - if (!token) { - throw new HttpException('未认证', HttpStatus.UNAUTHORIZED); - } - - if (/Bearer/.test(token)) { - // 不需要 Bearer,否则验证失败 - token = token.split(' ').pop(); - } - const tokenUser = this.jwtService.decode(token) as User; - const id = tokenUser.id; - - if (!id) { - throw new HttpException('未认证', HttpStatus.UNAUTHORIZED); - } - - const exist = await this.userService.findById(id); - if (exist.id !== user.id && exist.role !== 'admin') { - throw new HttpException('无权处理', HttpStatus.FORBIDDEN); - } - - req.user = tokenUser; - } - - /** - * 用户更新 - * @param user - */ - @ApiResponse({ status: 200, description: '更新用户成功', type: [User] }) - @UseInterceptors(ClassSerializerInterceptor) - @Post('update') - @HttpCode(HttpStatus.CREATED) - async update(@Request() req, @Body() user: Partial): Promise { - await this.checkPermission(req, user); - const d = await this.userService.updateById(req.user, user.id, user); - return d; - } - - /** - * 更新用户密码 - * @param user - */ - @ApiResponse({ status: 201, description: '更新密码成功', type: [User] }) - @UseInterceptors(ClassSerializerInterceptor) - @Post('password') - @HttpCode(HttpStatus.CREATED) - async updatePassword(@Request() req, @Body() user: Partial): Promise { - await this.checkPermission(req, user); - const d = await this.userService.updatePassword(user.id, user); - return d; - } -} diff --git a/server/src/modules/user/user.entity.ts b/server/src/modules/user/user.entity.ts deleted file mode 100644 index dc50dd5..0000000 --- a/server/src/modules/user/user.entity.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import * as bcrypt from 'bcryptjs'; -import { Exclude } from 'class-transformer'; -import { BeforeInsert, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -@Entity() -export class User { - /** - * 检测密码是否一致 - * @param password0 加密前密码 - * @param password1 加密后密码 - */ - static comparePassword(password0, password1) { - return bcrypt.compareSync(password0, password1); - } - - static encryptPassword(password) { - return bcrypt.hashSync(password, 10); - } - - @PrimaryGeneratedColumn('uuid') - id: number; - - @ApiProperty() - @Column({ length: 500 }) - name: string; - - @ApiProperty() - @Exclude() - @Column({ length: 500 }) - password: string; - - @ApiProperty() - @Column({ length: 500, default: null }) - avatar: string; // 头像 - - @ApiProperty() - @Column({ length: 500, default: null }) - email: string; // 邮箱 - - @ApiProperty() - @Column('simple-enum', { enum: ['admin', 'visitor'], default: 'visitor' }) - role: string; // 用户角色 - - @ApiProperty() - @Column('simple-enum', { enum: ['locked', 'active'], default: 'active' }) - status: string; // 用户状态 - - @ApiProperty() - @Column({ default: 'normal' }) - type: string; // 用户类型 - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; - - /** - * 插入数据前,对密码进行加密 - */ - @BeforeInsert() - encrypt() { - this.password = bcrypt.hashSync(this.password, 10); - } -} diff --git a/server/src/modules/user/user.module.ts b/server/src/modules/user/user.module.ts deleted file mode 100644 index b9220e2..0000000 --- a/server/src/modules/user/user.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { forwardRef, Module } from '@nestjs/common'; -import { ConfigModule } from '@nestjs/config'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { UserController } from './user.controller'; -import { User } from './user.entity'; -import { UserService } from './user.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([User]), ConfigModule, forwardRef(() => AuthModule)], - providers: [UserService], - exports: [UserService], - controllers: [UserController], -}) -export class UserModule {} diff --git a/server/src/modules/user/user.service.ts b/server/src/modules/user/user.service.ts deleted file mode 100644 index 28fa4e6..0000000 --- a/server/src/modules/user/user.service.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { InjectRepository } from '@nestjs/typeorm'; -import { FindManyOptions, Repository } from 'typeorm'; -import { isValidUsername } from '../../utils/user.util'; - -import { User } from './user.entity'; - -@Injectable() -export class UserService { - constructor( - @InjectRepository(User) - private readonly userRepository: Repository, - private readonly configService: ConfigService - ) { - const name = this.configService.get('ADMIN_USER', 'admin'); - const password = this.configService.get('ADMIN_PASSWD', 'admin'); - - this.createUser({ name, password, role: 'admin' }, true) - .then(() => { - console.log(`[reactpress] 管理员账户创建成功,用户名:${name},密码:${password},请及时登录系统修改默认密码`); - }) - .catch(async (e) => { - const existAdminUser = await this.userRepository.findOne({ where: { name } }); - const isDefaultPasswd = User.comparePassword(password, existAdminUser.password); - if (isDefaultPasswd) { - console.log(`[reactpress] 管理员账户已经存在,用户名:${name},密码:${password},请及时登录系统修改默认密码`); - } - }); - } - - async findByConditions(conditions: Partial) { - return await this.userRepository.findOne(conditions); - } - - async findAll(queryParams): Promise<[User[], number]> { - const query = this.userRepository.createQueryBuilder('user').orderBy('user.createAt', 'DESC'); - - if (typeof queryParams === 'object') { - const { page = 1, pageSize = 12, status, ...otherParams } = queryParams; - - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (status) { - query.andWhere('user.status=:status').setParameter('status', status); - } - - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`user.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - } - - return query.getManyAndCount(); - } - - /** - * 创建用户 - * @param user 用户模型 - * @param ignoreValidator 是否忽略名称校验 - */ - async createUser(user: Partial, ignoreValidator?: boolean): Promise { - const { name, password } = user; - - // 如果忽略了名称校验,来自于系统内部默认的注入 - if (!ignoreValidator) { - if (!name || !password) { - throw new HttpException('请输入用户名和密码', HttpStatus.BAD_REQUEST); - } - - // 防止用户名称非法 - if (!isValidUsername(name)) { - throw new HttpException('用户名不能包含空格和非法字符', HttpStatus.BAD_REQUEST); - } - } - - const existUser = await this.userRepository.findOne({ where: { name } }); - - if (existUser) { - throw new HttpException('用户已存在', HttpStatus.BAD_REQUEST); - } - - const newUser = await this.userRepository.create(user); - await this.userRepository.save(newUser); - return newUser; - } - - /** - * 用户登录 - * @param user - */ - async login(user: Partial): Promise { - const { name, password } = user; - const existUser = await this.userRepository.findOne({ where: { name } }); - - if (!existUser || !(await User.comparePassword(password, existUser.password))) { - throw new HttpException( - '用户名或密码错误', - // tslint:disable-next-line: trailing-comma - HttpStatus.BAD_REQUEST - ); - } - - if (existUser.status === 'locked') { - throw new HttpException( - '用户已锁定,无法登录', - // tslint:disable-next-line: trailing-comma - HttpStatus.BAD_REQUEST - ); - } - - delete existUser.password; - - return existUser; - } - - /** - * 无密码登录 - * @param user - */ - async loginWithoutPasswd(user: Partial): Promise { - const { name } = user; - const existUser = await this.userRepository.findOne({ where: { name } }); - - if (existUser.status === 'locked') { - throw new HttpException( - '用户已锁定,无法登录', - // tslint:disable-next-line: trailing-comma - HttpStatus.BAD_REQUEST - ); - } - - delete existUser.password; - - return existUser; - } - - /** - * 获取指定用户 - * @param id - */ - async findById(id): Promise { - return this.userRepository.findOne(id); - } - - /** - * 更新指定用户 - * @param id - */ - async updateById(currentUser, id, user): Promise { - if (user.role === 'admin') { - if (!currentUser || currentUser.role !== 'admin') { - throw new HttpException( - '您无权操作', - // tslint:disable-next-line: trailing-comma - HttpStatus.FORBIDDEN - ); - } - } - - const oldUser = await this.userRepository.findOne(id); - delete user.password; - - if (user.name && user.name !== oldUser.name) { - const existUser = await this.userRepository.findOne({ where: { name: user.name } }); - - if (existUser) { - throw new HttpException('用户已存在', HttpStatus.BAD_REQUEST); - } - } - - const newUser = await this.userRepository.merge(oldUser, user); - return this.userRepository.save(newUser); - } - - /** - * 更新指定用户密码 - * @param id - */ - async updatePassword(id, user): Promise { - const existUser = await this.userRepository.findOne(id); - const { oldPassword, newPassword } = user; - - if (!existUser || !(await User.comparePassword(oldPassword, existUser.password))) { - throw new HttpException( - '用户名或密码错误', - // tslint:disable-next-line: trailing-comma - HttpStatus.BAD_REQUEST - ); - } - - const hashNewPassword = User.encryptPassword(newPassword); - const newUser = await this.userRepository.merge(existUser, { - password: hashNewPassword, - }); - const d = await this.userRepository.save(newUser); - return d; - } -} diff --git a/server/src/modules/view/view.controller.ts b/server/src/modules/view/view.controller.ts deleted file mode 100644 index fffa3d9..0000000 --- a/server/src/modules/view/view.controller.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Body, Controller, Delete, Get, Param, Post, Query, Request, UseGuards } from '@nestjs/common'; -import { ApiResponse, ApiTags } from '@nestjs/swagger'; - -import { getClientIP } from '../../utils/ip.util'; -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; -import { Roles, RolesGuard } from '../auth/roles.guard'; -import { View } from './view.entity'; -import { ViewService } from './view.service'; - -@ApiTags('View') -@Controller('view') -@UseGuards(RolesGuard) -export class ViewController { - constructor(private readonly viewService: ViewService) {} - - /** - * 添加访问 - * @param tag - */ - @ApiResponse({ status: 200, description: '访问记录添加成功', type: [View] }) - @Post() - create(@Request() req, @Body() data) { - const userAgent = req.headers['user-agent']; - const url = data.url; - return this.viewService.create(getClientIP(req), userAgent, url); - } - - /** - * 获取所有访问 - */ - @Get() - @UseGuards(JwtAuthGuard) - findAll(@Query() queryParam) { - return this.viewService.findAll(queryParam); - } - - /** - * 获取指定访问 - * @param id - */ - @Get('/url') - findByUrl(@Query('url') url) { - return this.viewService.findByUrl(url); - } - - /** - * 获取指定访问 - * @param id - */ - @Get(':id') - @UseGuards(JwtAuthGuard) - findById(@Param('id') id) { - return this.viewService.findById(id); - } - - /** - * 删除访问 - * @param id - */ - @Delete(':id') - @Roles('admin') - @UseGuards(JwtAuthGuard) - deleteById(@Param('id') id) { - return this.viewService.deleteById(id); - } -} diff --git a/server/src/modules/view/view.entity.ts b/server/src/modules/view/view.entity.ts deleted file mode 100644 index acaceef..0000000 --- a/server/src/modules/view/view.entity.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; - -@Entity() -export class View { - @PrimaryGeneratedColumn('uuid') - id: string; - - @ApiProperty() - @Column() - ip: string; - - @ApiProperty() - @Column({ type: 'text', default: null }) - userAgent: string; - - @ApiProperty() - @Column({ type: 'text', default: null }) - url: string; - - @ApiProperty() - @Column({ default: 1 }) - count: number; // 同一 userAgent ,同一 url 的访问量 - - @ApiProperty() - @Column({ type: 'text', default: null }) - address: string; // 访问地址 - - @ApiProperty() - @Column({ type: 'text', default: null }) - browser: string; // 访问浏览器 - - @ApiProperty() - @Column({ type: 'text', default: null }) - engine: string; // 访问的浏览器内核 - - @ApiProperty() - @Column({ type: 'text', default: null }) - os: string; // 访问操作系统 - - @ApiProperty() - @Column({ type: 'text', default: null }) - device: string; // 访问设备 - - @ApiProperty() - @CreateDateColumn({ - type: 'datetime', - comment: '创建时间', - name: 'create_at', - }) - createAt: Date; - - @ApiProperty() - @UpdateDateColumn({ - type: 'datetime', - comment: '更新时间', - name: 'update_at', - }) - updateAt: Date; -} diff --git a/server/src/modules/view/view.module.ts b/server/src/modules/view/view.module.ts deleted file mode 100644 index d749a10..0000000 --- a/server/src/modules/view/view.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AuthModule } from '../auth/auth.module'; -import { ViewController } from './view.controller'; -import { View } from './view.entity'; -import { ViewService } from './view.service'; - -@Module({ - imports: [TypeOrmModule.forFeature([View]), AuthModule], - exports: [ViewService], - providers: [ViewService], - controllers: [ViewController], -}) -export class ViewModule {} diff --git a/server/src/modules/view/view.service.ts b/server/src/modules/view/view.service.ts deleted file mode 100644 index 7f06c8d..0000000 --- a/server/src/modules/view/view.service.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -import { parseIp } from '../../utils/ip.util'; -import { parseUserAgent } from '../../utils/ua.util'; -import { View } from './view.entity'; - -@Injectable() -export class ViewService { - constructor( - @InjectRepository(View) - private readonly viewRepository: Repository - ) {} - - /** - * 添加访问 - * @param tag - */ - async create(ip: string, userAgent: string, url: string): Promise { - const exist = await this.viewRepository.findOne({ - where: { ip, userAgent, url }, - }); - if (exist) { - const count = exist.count; - const newData = await this.viewRepository.merge(exist, { - count: count + 1, - }); - await this.viewRepository.save(newData); - return newData; - } - const { data: uaInfo } = parseUserAgent(userAgent); - const address = parseIp(ip); - const newData = await this.viewRepository.create({ ip, userAgent, url, address, ...uaInfo }); - await this.viewRepository.save(newData); - return newData; - } - - /** - * 获取所有访问 - */ - async findAll(queryParams): Promise<[View[], number]> { - const query = this.viewRepository.createQueryBuilder('view').orderBy('view.createAt', 'DESC'); - if (typeof queryParams === 'object') { - const { page = 1, pageSize = 12, ...otherParams } = queryParams; - query.skip((+page - 1) * +pageSize); - query.take(+pageSize); - - if (otherParams) { - Object.keys(otherParams).forEach((key) => { - query.andWhere(`view.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); - }); - } - } - - return query.getManyAndCount(); - } - - /** - * 查找指定路径访问统计 - * @param url - */ - async findByUrl(url): Promise { - return this.viewRepository.find({ - where: { url }, - order: { updateAt: 'ASC' }, - }); - } - - /** - * 获取指定访问 - * @param id - */ - async findById(id): Promise { - return this.viewRepository.findOne(id); - } - - /** - * 删除访问量 - * @param id - */ - async deleteById(id) { - const data = await this.viewRepository.findOne(id); - return this.viewRepository.remove(data); - } -} diff --git a/server/src/starter.ts b/server/src/starter.ts deleted file mode 100644 index c3d02b0..0000000 --- a/server/src/starter.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { NestFactory } from '@nestjs/core'; -import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; -import * as bodyParser from 'body-parser'; -import * as compression from 'compression'; -import * as express from 'express'; -import * as rateLimit from 'express-rate-limit'; -import * as helmet from 'helmet'; -import { join } from 'path'; -import { SwaggerTheme, SwaggerThemeNameEnum } from 'swagger-themes'; - -import { AppModule } from './app.module'; -import { HttpExceptionFilter } from './filters/http-exception.filter'; -import { TransformInterceptor } from './interceptors/transform.interceptor'; - -export async function bootstrap() { - try { - const app = await NestFactory.create(AppModule); - const configService = app.get('ConfigService'); - - app.enableCors(); - app.setGlobalPrefix(configService.get('SERVER_API_PREFIX', '/api')); - - app.use( - rateLimit({ - windowMs: 60 * 1000, - max: 10000, - }) - ); - - const rootDir = join(__dirname, '../public'); - app.use('/public', express.static(rootDir)); - - app.use(compression()); - app.use(helmet()); - app.useGlobalInterceptors(new TransformInterceptor()); - app.useGlobalFilters(new HttpExceptionFilter()); - app.use(bodyParser.json({ limit: '10mb' })); - app.use(bodyParser.urlencoded({ limit: '10mb', extended: true })); - - // 增强版 Swagger 配置 - const swaggerConfig = new DocumentBuilder() - .setTitle('ReactPress API Documentation') - .setDescription('Comprehensive API documentation for ReactPress - A modern content management system built with NestJS') - .setVersion('2.0') - .setContact('ReactPress Team', 'https://github.com/fecommunity/reactpress', 'admin@gaoredu.com') - .setLicense('MIT', 'https://github.com/fecommunity/reactpress/blob/main/LICENSE') - .addServer(configService.get('SERVER_SITE_URL', 'http://localhost:3002'), 'API Server') - .build(); - - const document = SwaggerModule.createDocument(app, swaggerConfig); - - // 使用 swagger-themes 提供专业主题 - const theme = new SwaggerTheme(); - - // 自定义 Swagger 设置 - const options = { - customCss: theme.getBuffer(SwaggerThemeNameEnum.MATERIAL), // 应用主题 - customSiteTitle: 'ReactPress API Documentation', - customfavIcon: '/public/favicon.png', - swaggerOptions: { - docExpansion: 'list', - filter: true, - showRequestDuration: true, - persistAuthorization: true, // 保持授权数据 - displayOperationId: true, - operationsSorter: 'method', // 按方法排序 - tagsSorter: 'alpha', // 按字母顺序排序标签 - }, - customCssUrl: '/public/swagger/custom.css', // 额外的自定义CSS - }; - - // 设置 Swagger UI - SwaggerModule.setup('api', app, document, options); - - const configuredPort = configService.get('SERVER_PORT', 3002); - - await app.listen(configuredPort); - console.log(`[ReactPress] Application started on http://localhost:${configuredPort}`); - console.log(`[ReactPress] API Documentation available at http://localhost:${configuredPort}/api`); - - return app; - - } catch (error) { - console.error('[ReactPress] Failed to start application:', error); - - if (error.code === 'EADDRINUSE') { - console.error('[ReactPress] Port is already in use. Please check for other running instances.'); - console.error('[ReactPress] You can change the port in your .env file or terminate the conflicting process.'); - } - - throw error; - } -} - -process.on('SIGINT', () => { - console.log('\n[ReactPress] Application shutting down gracefully...'); - process.exit(0); -}); - -process.on('SIGTERM', () => { - console.log('\n[ReactPress] Application shutting down gracefully...'); - process.exit(0); -}); \ No newline at end of file diff --git a/server/src/utils/date.util.ts b/server/src/utils/date.util.ts deleted file mode 100644 index e95825a..0000000 --- a/server/src/utils/date.util.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { format as dateFormatFn } from 'date-fns'; - -export const dateFormat = (date = null, format = 'yyyy-MM-dd HH:mm:ss') => { - if (date === null || date === undefined) { - date = new Date(); // eslint-disable-line no-param-reassign - } - - const t = date instanceof Date ? date : new Date(date); - - return dateFormatFn(t, format); -}; diff --git a/server/src/utils/ip.util.ts b/server/src/utils/ip.util.ts deleted file mode 100644 index 56ef98d..0000000 --- a/server/src/utils/ip.util.ts +++ /dev/null @@ -1,25 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const ipSearcher = require('node-ip2region').create(); - -export function getClientIP(req) { - const ip = - req.headers['x-real-ip'] || - req.headers['x-forwarded-for'] || // 判断是否有反向代理 IP - (req.connection && req.connection.remoteAddress) || // 判断 connection 的远程 IP - (req.socket && req.socket.remoteAddress) || // 判断后端的 socket 的 IP - (req.connection && req.connection.socket && req.connection.socket.remoteAddress); - - return ip ? ip.split(':').pop() : ''; -} - -export function parseIp(ip) { - try { - const { region } = ipSearcher.btreeSearchSync(ip); - return region - .split('|') - .filter((d) => +d !== 0) - .join(' '); - } catch (e) { - return ''; - } -} diff --git a/server/src/utils/markdown.util.ts b/server/src/utils/markdown.util.ts deleted file mode 100644 index e9a9656..0000000 --- a/server/src/utils/markdown.util.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as hljs from 'highlight.js'; -import * as Marked from 'marked'; - -const renderer = new Marked.Renderer(); - -renderer.heading = (text, level) => { - const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); - - return ` - - - - - ${text} -`; -}; - -Marked.setOptions({ - highlight(code: string, lang: string) { - if (hljs.getLanguage(lang)) { - return hljs.highlight(lang, code).value; - } - return hljs.highlightAuto(code).value; - }, - renderer, -}); - -export const marked = (content: string): { html: string; toc: string } => { - const toc = []; - - renderer.heading = (text: string, level: number) => { - const anchor = 'heading-' + toc.length; - - toc.push([level, anchor, text]); - return `${text}`; - }; - - const marked = (text: string) => { - const tok = Marked.lexer(text); - text = Marked.parser(tok).replace(/
/gi, '
'); // eslint-disable-line no-param-reassign
-    return text;
-  };
-
-  const html = marked(content);
-  return { html, toc: JSON.stringify(toc, null, 2) };
-};
diff --git a/server/src/utils/oss.util.ts b/server/src/utils/oss.util.ts
deleted file mode 100644
index 6ed91f5..0000000
--- a/server/src/utils/oss.util.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { HttpException, HttpStatus } from '@nestjs/common';
-
-import { SettingService } from '../modules/setting/setting.service';
-import { AliyunOssClient } from './oss/aliyun-oss-client';
-import { OssClient } from './oss/oss-client';
-
-export class Oss {
-  settingService: SettingService;
-  config: Record;
-  ossClient: OssClient;
-
-  constructor(settingService: SettingService) {
-    this.settingService = settingService;
-  }
-
-  /**
-   * 是否有OSS的配置
-   */
-  public async hasOssConfig() {
-    try {
-      const data = await this.settingService.findAll(true);
-      const config = JSON.parse(data.oss);
-      return !!config;
-    } catch (e) {
-      return false;
-    }
-  }
-
-  private async getConfig() {
-    const data = await this.settingService.findAll(true);
-    const config = JSON.parse(data.oss);
-    if (!config) {
-      throw new HttpException('OSS 配置不完善,无法进行操作', HttpStatus.BAD_REQUEST);
-    }
-    return config as Record;
-  }
-
-  private async getOssClient() {
-    const config = await this.getConfig();
-    const type = String(config.type).toLowerCase();
-
-    switch (type) {
-      case 'aliyun':
-      default:
-        return new AliyunOssClient(config);
-    }
-  }
-
-  async putFile(filepath: string, buffer: ReadableStream) {
-    const client = await this.getOssClient();
-    const url = await client.putFile(filepath, buffer);
-    return url;
-  }
-
-  async deleteFile(url: string) {
-    const client = await this.getOssClient();
-    await client.deleteFile(url);
-  }
-}
diff --git a/server/src/utils/oss/aliyun-oss-client.ts b/server/src/utils/oss/aliyun-oss-client.ts
deleted file mode 100644
index 116a7aa..0000000
--- a/server/src/utils/oss/aliyun-oss-client.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as AliyunOSS from 'ali-oss';
-
-import { OssClient } from './oss-client';
-
-export class AliyunOssClient extends OssClient {
-  private async buildClient() {
-    const config = this.config;
-    return new AliyunOSS({
-      region: config.region,
-      accessKeyId: config.accessKeyId,
-      accessKeySecret: config.accessKeySecret,
-      bucket: config.bucket,
-      secure: config.https,
-    });
-  }
-
-  async putFile(filepath: string, buffer: ReadableStream) {
-    const client = await this.buildClient();
-    const { url } = await client.put(filepath, buffer);
-    return url;
-  }
-
-  async deleteFile(url: string) {
-    const client = await this.buildClient();
-    await client.delete(url);
-  }
-}
diff --git a/server/src/utils/oss/oss-client.ts b/server/src/utils/oss/oss-client.ts
deleted file mode 100644
index 874b00b..0000000
--- a/server/src/utils/oss/oss-client.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export abstract class OssClient {
-  config: Record;
-
-  constructor(config) {
-    this.config = config;
-  }
-
-  abstract putFile(filepath: string, buffer: ReadableStream): Promise;
-  abstract deleteFile(url: string): Promise;
-}
diff --git a/server/src/utils/ua.util.ts b/server/src/utils/ua.util.ts
deleted file mode 100644
index bd9c3de..0000000
--- a/server/src/utils/ua.util.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import * as get from 'lodash/get';
-import * as UAParser from 'ua-parser-js';
-
-const keys = [
-  'browser.name',
-  'browser.version',
-  'engine.name',
-  'engine.version',
-  'os.name',
-  'os.version',
-  'device.vendor',
-  'device.model',
-  'device.type',
-];
-
-const joinMsg = (ua, keys) =>
-  keys
-    .map((key) => get(ua, key))
-    .filter(Boolean)
-    .join(' ');
-
-export const parseUserAgent = (userAgent) => {
-  const uaparser = new UAParser();
-  uaparser.setUA(userAgent);
-  const ua = uaparser.getResult();
-
-  return {
-    data: {
-      browser: joinMsg(ua, keys.slice(0, 2)),
-      engine: joinMsg(ua, keys.slice(2, 4)),
-      os: joinMsg(ua, keys.slice(4, 6)),
-      device: joinMsg(ua, keys.slice(6)),
-    },
-    text: joinMsg(ua, keys),
-  };
-};
diff --git a/server/src/utils/uniqueid.util.ts b/server/src/utils/uniqueid.util.ts
deleted file mode 100644
index f0e0823..0000000
--- a/server/src/utils/uniqueid.util.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { next } from 'nuid';
-
-export function uniqueid() {
-  return next();
-}
diff --git a/server/src/utils/upload.util.ts b/server/src/utils/upload.util.ts
deleted file mode 100644
index 62eceab..0000000
--- a/server/src/utils/upload.util.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import * as fs from 'fs';
-import * as path from 'path';
-
-export class LocalUpload {
-  // 递归创建目录 同步方法
-  private mkdDirsSync(dirname) {
-    if (fs.existsSync(dirname)) {
-      return true;
-    } else {
-      if (this.mkdDirsSync(path.dirname(dirname))) {
-        fs.mkdirSync(dirname);
-        return true;
-      }
-    }
-  }
-
-  public putFile(filename, buffer: ReadableStream) {
-    const saveFile = path.join(__dirname, `../../public/uploads/${filename}`);
-    const dirName = path.dirname(saveFile);
-    // 递归创建目录
-    this.mkdDirsSync(dirName);
-    // 创建文件
-    fs.writeFileSync(saveFile, buffer);
-    return saveFile;
-  }
-
-  public deleteFile(filename) {
-    const saveFileFolder = path.join(__dirname, '../../public/uploads');
-    const filePath = `${saveFileFolder}/${filename}`;
-    if (fs.existsSync(filePath)) {
-      fs.unlinkSync(filePath);
-    }
-  }
-}
diff --git a/server/src/utils/user.util.ts b/server/src/utils/user.util.ts
deleted file mode 100644
index 5976f55..0000000
--- a/server/src/utils/user.util.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-export function isValidUsername(username) {
-  // 字符限制,只允许字母、数字、下划线
-  var reg = /^[a-zA-Z0-9_]+$/;
-  if (!reg.test(username)) {
-    return false;
-  }
-  // 空格限制
-  if (/\s/.test(username)) {
-    return false;
-  }
-  // 敏感词限制,这里假设不允许包含 admin、root 等词汇
-  if (username.indexOf('admin') >= 0 || username.indexOf('root') >= 0) {
-    return false;
-  }
-  return true;
-}
diff --git a/server/tsconfig.build.json b/server/tsconfig.build.json
deleted file mode 100644
index 64f86c6..0000000
--- a/server/tsconfig.build.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
-}
diff --git a/server/tsconfig.json b/server/tsconfig.json
deleted file mode 100644
index 27e5a48..0000000
--- a/server/tsconfig.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "compilerOptions": {
-    "module": "commonjs",
-    "declaration": true,
-    "removeComments": true,
-    "emitDecoratorMetadata": true,
-    "experimentalDecorators": true,
-    "skipLibCheck": true,
-    "target": "es2017",
-    "sourceMap": true,
-    "outDir": "./dist",
-    "baseUrl": "./",
-    "incremental": true,
-    "typeRoots": ["./node_modules/@types"],
-    "paths": {
-      "@fecommunity/reactpress-toolkit": ["../toolkit/dist"],
-      "@fecommunity/reactpress-toolkit/*": ["../toolkit/dist/*"]
-    }
-  },
-  "exclude": ["node_modules", "dist"]
-}
\ No newline at end of file
diff --git a/server/tslint.json b/server/tslint.json
deleted file mode 100644
index 5651b2f..0000000
--- a/server/tslint.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "defaultSeverity": "error",
-  "extends": ["tslint:recommended"],
-  "jsRules": {
-    "no-unused-expression": true
-  },
-  "rules": {
-    "quotemark": [true, "single"],
-    "member-access": [false],
-    "ordered-imports": [false],
-    "max-line-length": [true, 150],
-    "member-ordering": [false],
-    "interface-name": [false],
-    "arrow-parens": false,
-    "object-literal-sort-keys": false
-  },
-  "rulesDirectory": []
-}
diff --git a/toolkit/scripts/generate-api-types.js b/toolkit/scripts/generate-api-types.js
index ebf1ca3..b0c20a5 100755
--- a/toolkit/scripts/generate-api-types.js
+++ b/toolkit/scripts/generate-api-types.js
@@ -5,7 +5,7 @@ const fs = require('fs-extra');
 
 // 配置常量
 const CONFIG = {
-  input: path.resolve(__dirname, '../../server/public/swagger.json'),
+  input: require('./resolve-swagger-input').getSwaggerInputPath(),
   output: path.resolve(__dirname, '../src'),
   templates: path.resolve(__dirname, '../node_modules/swagger-typescript-api/templates/base'),
 };
diff --git a/toolkit/scripts/generate-api.js b/toolkit/scripts/generate-api.js
index 01b21ca..81bea79 100644
--- a/toolkit/scripts/generate-api.js
+++ b/toolkit/scripts/generate-api.js
@@ -1,10 +1,11 @@
 const { generateApi } = require('swagger-typescript-api');
 const path = require('path');
 const fs = require('fs-extra');
+const { getSwaggerInputPath } = require('./resolve-swagger-input');
 
 // 配置常量
 const CONFIG = {
-  input: path.resolve(__dirname, '../../server/public/swagger.json'),
+  input: getSwaggerInputPath(),
   output: path.resolve(__dirname, '../src'),
   templates: path.resolve(__dirname, '../node_modules/swagger-typescript-api/templates/base'),
   utilsDir: path.resolve(__dirname, '../src/utils'),
diff --git a/toolkit/scripts/generate-swagger.js b/toolkit/scripts/generate-swagger.js
index f1f0e17..b2e7cf3 100755
--- a/toolkit/scripts/generate-swagger.js
+++ b/toolkit/scripts/generate-swagger.js
@@ -1,48 +1,43 @@
 const { execSync } = require('child_process');
 const { unlinkSync, existsSync } = require('fs');
 const { join } = require('path');
+const { getSwaggerInputPath, getBundledServerPathForGenerate } = require('./resolve-swagger-input');
 
 console.log('🚀 Starting API types generation process...\n');
 
+const bundledServerDir = getBundledServerPathForGenerate();
+const swaggerPath = getSwaggerInputPath();
+
 try {
-  // Step 1: Enter server directory and generate swagger.json
-  console.log('1️⃣ Generating Swagger JSON in server directory...');
+  console.log('1️⃣ Generating Swagger JSON via @fecommunity/reactpress-cli bundled server...');
   try {
-    execSync('cd ../server && npm run generate:swagger', { stdio: 'inherit' });
-    console.log('✅ Swagger JSON generated successfully in server directory!\n');
+    execSync('npm run generate:swagger', { cwd: bundledServerDir, stdio: 'inherit' });
+    console.log('✅ Swagger JSON generated successfully!\n');
   } catch (error) {
     console.log('⚠️  Failed to generate new swagger.json, checking for existing file...\n');
   }
 
-  // Step 2: Check if swagger.json exists in server directory
-  const serverSwaggerPath = join(__dirname, '../../server/public/swagger.json');
-  if (!existsSync(serverSwaggerPath)) {
-    console.error('❌ No swagger.json file available in server directory');
+  if (!existsSync(swaggerPath)) {
+    console.error(`❌ No swagger.json at ${swaggerPath}`);
+    console.error('   Ensure @fecommunity/reactpress-cli is installed (pnpm install).');
     process.exit(1);
   }
-  console.log('✅ Using swagger.json from server directory!\n');
+  console.log(`✅ Using swagger.json from ${swaggerPath}\n`);
 
-  // Step 3: Generate TypeScript definitions (only updates api and types directories)
   console.log('📝 Note: Only api and types directories will be regenerated. Other src files will remain untouched.\n');
   console.log('2️⃣ Generating TypeScript definitions (api and types only)...');
-  execSync('node scripts/generate-api.js', { stdio: 'inherit' });
+  execSync('node scripts/generate-api.js', { stdio: 'inherit', cwd: join(__dirname, '..') });
   console.log('✅ TypeScript definitions generated successfully!\n');
 
-  // Step 4: Clean up - remove swagger.json from server directory
-  console.log('3️⃣ Cleaning up swagger.json files...');
-  
-  // Remove from server directory
-  if (existsSync(serverSwaggerPath)) {
-    unlinkSync(serverSwaggerPath);
-    console.log('✅ Removed swagger.json from server directory');
+  console.log('3️⃣ Cleaning up swagger.json...');
+  if (existsSync(swaggerPath)) {
+    unlinkSync(swaggerPath);
+    console.log('✅ Removed swagger.json from bundled server public/');
   }
-  
   console.log('✅ Cleanup completed!\n');
 
   console.log('🎉 API generation process completed successfully!');
-  console.log('📁 Only api and types directories were updated. Other src files remain untouched.');
-
 } catch (error) {
   console.error('❌ Error during generation process:', error.message);
   process.exit(1);
-}
\ No newline at end of file
+}
diff --git a/toolkit/scripts/resolve-swagger-input.js b/toolkit/scripts/resolve-swagger-input.js
new file mode 100644
index 0000000..ec56447
--- /dev/null
+++ b/toolkit/scripts/resolve-swagger-input.js
@@ -0,0 +1,11 @@
+const { getBundledSwaggerPath, getBundledServerDir } = require('../../server/lib/bundled-server-path');
+
+function getSwaggerInputPath() {
+  return getBundledSwaggerPath();
+}
+
+function getBundledServerPathForGenerate() {
+  return getBundledServerDir();
+}
+
+module.exports = { getSwaggerInputPath, getBundledServerPathForGenerate };

From 9c4486db121430836be19570c372b157cdd3d1ce Mon Sep 17 00:00:00 2001
From: m0_37981569 
Date: Sat, 2 May 2026 22:15:00 +0800
Subject: [PATCH 02/20] chore: update configuration for external database mode
 and enhance development script with API readiness checks

---
 .reactpress/config.json   |   2 +-
 .reactpress/server.pid    |   1 +
 scripts/reactpress-dev.js | 157 ++++++++++++++++++++++++++++++++------
 3 files changed, 136 insertions(+), 24 deletions(-)
 create mode 100644 .reactpress/server.pid

diff --git a/.reactpress/config.json b/.reactpress/config.json
index 7144102..d102f84 100644
--- a/.reactpress/config.json
+++ b/.reactpress/config.json
@@ -1,7 +1,7 @@
 {
   "version": 1,
   "database": {
-    "mode": "embedded-docker",
+    "mode": "external",
     "containerName": "reactpress_cli_db"
   },
   "server": {
diff --git a/.reactpress/server.pid b/.reactpress/server.pid
new file mode 100644
index 0000000..7919108
--- /dev/null
+++ b/.reactpress/server.pid
@@ -0,0 +1 @@
+86851
\ No newline at end of file
diff --git a/scripts/reactpress-dev.js b/scripts/reactpress-dev.js
index 59f40e0..057be01 100644
--- a/scripts/reactpress-dev.js
+++ b/scripts/reactpress-dev.js
@@ -1,19 +1,141 @@
-// scripts/dev.js
 const { spawn } = require('child_process');
+const fs = require('fs');
+const http = require('http');
 const path = require('path');
 
-// 获取当前工作目录
 const currentWorkingDir = process.cwd();
-
-// 设置环境变量
 process.env.REACTPRESS_ORIGINAL_CWD = currentWorkingDir;
 
+const API_READY_TIMEOUT_MS = 180_000;
+const API_POLL_INTERVAL_MS = 500;
+
 console.log(`设置 REACTPRESS_ORIGINAL_CWD: ${currentWorkingDir}`);
 
-// 执行构建命令
+function loadServerSiteUrl() {
+  const envPath = path.join(currentWorkingDir, '.env');
+  try {
+    const content = fs.readFileSync(envPath, 'utf8');
+    const match = content.match(/^SERVER_SITE_URL=(.+)$/m);
+    if (match) {
+      return match[1].trim().replace(/^['"]|['"]$/g, '');
+    }
+  } catch {
+    // ignore
+  }
+  return 'http://localhost:3002';
+}
+
+function isApiResponding(url, timeoutMs = 2000) {
+  return new Promise((resolve) => {
+    let parsed;
+    try {
+      parsed = new URL(url);
+    } catch {
+      resolve(false);
+      return;
+    }
+
+    const port = parsed.port || (parsed.protocol === 'https:' ? 443 : 80);
+    const req = http.request(
+      {
+        hostname: parsed.hostname,
+        port,
+        path: parsed.pathname || '/',
+        method: 'GET',
+        timeout: timeoutMs,
+      },
+      (res) => {
+        resolve(res.statusCode > 0);
+      }
+    );
+
+    req.on('timeout', () => {
+      req.destroy();
+      resolve(false);
+    });
+    req.on('error', () => resolve(false));
+    req.end();
+  });
+}
+
+async function waitForApi(url, timeoutMs = API_READY_TIMEOUT_MS) {
+  const deadline = Date.now() + timeoutMs;
+  while (Date.now() < deadline) {
+    if (await isApiResponding(url)) {
+      return true;
+    }
+    await new Promise((r) => setTimeout(r, API_POLL_INTERVAL_MS));
+  }
+  return false;
+}
+
+let apiChild;
+let webChild;
+let shuttingDown = false;
+
+function shutdown(signal = 'SIGINT') {
+  if (shuttingDown) return;
+  shuttingDown = true;
+  if (webChild && !webChild.killed) {
+    webChild.kill(signal);
+  }
+  if (apiChild && !apiChild.killed) {
+    apiChild.kill(signal);
+  }
+}
+
+process.on('SIGINT', () => shutdown('SIGINT'));
+process.on('SIGTERM', () => shutdown('SIGTERM'));
+
+async function startDev() {
+  const serverUrl = loadServerSiteUrl();
+
+  console.log('[reactpress] 正在启动 API(首次可能需安装内置服务端依赖,请稍候)…');
+  apiChild = spawn('pnpm', ['dev:server'], {
+    stdio: 'inherit',
+    shell: true,
+    cwd: currentWorkingDir,
+  });
+
+  apiChild.on('close', (code) => {
+    if (shuttingDown) {
+      process.exit(code ?? 0);
+      return;
+    }
+    if (webChild && !webChild.killed) {
+      webChild.kill('SIGINT');
+    }
+    process.exit(code ?? 1);
+  });
+
+  console.log(`[reactpress] 等待 API 就绪: ${serverUrl}`);
+  const ready = await waitForApi(serverUrl);
+  if (!ready) {
+    console.error(
+      `[reactpress] API 在 ${API_READY_TIMEOUT_MS / 1000}s 内未就绪。请检查 Docker/MySQL 与 .env 中的 DB_* 配置。`
+    );
+    shutdown('SIGINT');
+    process.exit(1);
+  }
+
+  console.log('[reactpress] API 已就绪,正在启动前端…');
+  webChild = spawn('pnpm', ['dev:client'], {
+    stdio: 'inherit',
+    shell: true,
+    cwd: currentWorkingDir,
+  });
+
+  webChild.on('close', (code) => {
+    if (!shuttingDown) {
+      shutdown('SIGINT');
+    }
+    process.exit(code ?? 0);
+  });
+}
+
 const build = spawn('pnpm', ['build:toolkit'], {
   stdio: 'inherit',
-  shell: true
+  shell: true,
 });
 
 build.on('close', (code) => {
@@ -21,21 +143,10 @@ build.on('close', (code) => {
     console.error(`构建失败,退出码: ${code}`);
     process.exit(code);
   }
-  
-  // 执行并发命令
-  const concurrently = spawn('npx', [
-    'concurrently',
-    '-n', 'api,web',
-    '-c', 'blue,green',
-    'pnpm:dev:server',
-    'pnpm:dev:client'
-  ], {
-    stdio: 'inherit',
-    shell: true,
-    cwd: currentWorkingDir
-  });
-  
-  concurrently.on('close', (code) => {
-    process.exit(code);
+
+  startDev().catch((err) => {
+    console.error('[reactpress] 启动失败:', err);
+    shutdown('SIGINT');
+    process.exit(1);
   });
-});
\ No newline at end of file
+});

From 35a0206e8434b99882f17616c86a964092c8478a Mon Sep 17 00:00:00 2001
From: m0_37981569 
Date: Sun, 3 May 2026 22:30:00 +0800
Subject: [PATCH 03/20] chore: update contributing and documentation for
 monorepo structure, enhance API management, and remove server references

---
 .reactpress/server.pid                        |   2 +-
 CONTRIBUTING.md                               |  75 ++--
 DESIGN.md                                     | 399 ++++++++++++++++++
 README-zh_CN.md                               |  52 +--
 README.md                                     |  70 +--
 TODO.md                                       | 358 +++++++++-------
 client/README.md                              |   6 +-
 package.json                                  |  21 +-
 pnpm-lock.yaml                                |   6 -
 pnpm-workspace.yaml                           |   4 +-
 scripts/bundled-server-path.js                |  37 +-
 scripts/docker-dev.js                         |   2 +-
 scripts/install.sh                            |  10 +-
 .../dev.js => scripts/reactpress-api-dev.js   |  29 +-
 .../reactpress-api-pm2.js                     |  11 +-
 scripts/reactpress-cli.js                     |  16 +-
 scripts/reactpress-dev.js                     |   3 +-
 scripts/reactpress-publish.js                 |   7 -
 server/README.md                              |  17 -
 server/ecosystem.config.js                    |  21 -
 server/package.json                           |  50 ---
 server/scripts/generate-swagger.js            |   9 -
 toolkit/scripts/resolve-swagger-input.js      |   2 +-
 23 files changed, 778 insertions(+), 429 deletions(-)
 create mode 100644 DESIGN.md
 rename server/scripts/dev.js => scripts/reactpress-api-dev.js (54%)
 rename server/bin/reactpress-server.js => scripts/reactpress-api-pm2.js (53%)
 delete mode 100644 server/README.md
 delete mode 100644 server/ecosystem.config.js
 delete mode 100644 server/package.json
 delete mode 100644 server/scripts/generate-swagger.js

diff --git a/.reactpress/server.pid b/.reactpress/server.pid
index 7919108..d728acc 100644
--- a/.reactpress/server.pid
+++ b/.reactpress/server.pid
@@ -1 +1 @@
-86851
\ No newline at end of file
+79734
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cf13fde..e0bb75a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -20,9 +20,9 @@ Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md) to ensure a wel
 
 ### Prerequisites
 
-- Node.js >= 16.5.0
+- Node.js >= 18.0.0
 - pnpm >= 7.0.0
-- MySQL 5.7 or higher
+- MySQL 5.7 or higher (or Docker via `reactpress-cli init`)
 
 ### Installation
 
@@ -34,22 +34,25 @@ cd reactpress
 # Install dependencies
 pnpm install
 
-# Start development servers
+# First-time: generate .reactpress/config.json + .env
+pnpm run init
+
+# Start API + client
 pnpm run dev
 ```
 
 ## Project Structure
 
-ReactPress follows a monorepo structure:
+ReactPress follows a monorepo structure. **API runtime lives in `@fecommunity/reactpress-cli`**, not in this repo.
 
 ```
 reactpress/
 ├── client/          # Next.js frontend application
-├── server/          # NestJS backend API
-├── toolkit/         # Auto-generated API client SDK
+├── toolkit/         # OpenAPI-generated API client SDK
 ├── templates/       # Project templates
-├── scripts/         # Build and deployment scripts
-└── docs/            # Documentation
+├── scripts/         # dev, publish, bundled API paths
+├── docs/            # Documentation
+└── .reactpress/     # CLI-written config (local)
 ```
 
 ## Development Workflow
@@ -57,39 +60,44 @@ reactpress/
 ### Running Services
 
 ```bash
-# Start both client and server in development mode
+# API + client (builds toolkit first, waits for API health)
 pnpm run dev
 
-# Start only the server
-pnpm run dev:server
+# API only (reactpress-cli)
+pnpm run dev:api
 
-# Start only the client
+# Client only
 pnpm run dev:client
+
+# API lifecycle
+pnpm exec reactpress-cli start
+pnpm exec reactpress-cli stop
+pnpm exec reactpress-cli status
 ```
 
 ### Building Packages
 
 ```bash
-# Build all packages
+# Build toolkit + client
 pnpm run build
 
+# Build publishable workspace packages
+pnpm run build:packages
+
 # Build specific packages
 pnpm run build:client
-pnpm run build:server
 pnpm run build:toolkit
 ```
 
-### Testing
+### Publishing
 
 ```bash
-# Run all tests
-pnpm test
-
-# Run tests for specific package
-pnpm test --dir client
-pnpm test --dir server
+pnpm login
+pnpm run release
 ```
 
+Published packages: root meta, client, toolkit, templates. API is published as `@fecommunity/reactpress-cli`.
+
 ## Code Style
 
 - Follow the existing code style in the project
@@ -99,24 +107,11 @@ pnpm test --dir server
 
 ## Pull Request Process
 
-1. Ensure your changes are well-tested
-2. Update the README.md if you've changed functionality
-3. Create a pull request with a clear title and description
-4. Link any related issues in your pull request description
-5. Be responsive to feedback during the review process
-
-## Reporting Issues
-
-If you find a bug or have a feature request, please [create an issue](https://github.com/fecommunity/reactpress/issues/new) on GitHub. Include as much detail as possible to help us understand and reproduce the problem.
-
-## Publishing Packages
-
-To publish packages to npm:
-
-1. Ensure you're logged into npm: `pnpm login`
-2. Run the publish script: `pnpm run publish`
-3. Follow the interactive prompts to select packages and version increments
+1. Ensure your code follows the project's style guidelines
+2. Update documentation if you're changing functionality
+3. Make sure all tests pass (if applicable)
+4. Request review from maintainers
 
-## License
+## Architecture
 
-By contributing to ReactPress, you agree that your contributions will be licensed under the MIT License.
\ No newline at end of file
+See [DESIGN.md](./DESIGN.md) for module boundaries and [TODO.md](./TODO.md) for the migration roadmap.
diff --git a/DESIGN.md b/DESIGN.md
new file mode 100644
index 0000000..d3c2edf
--- /dev/null
+++ b/DESIGN.md
@@ -0,0 +1,399 @@
+# ReactPress 系统架构设计
+
+> 目标态架构说明:原则、系统视图、模块职责与目录结构。  
+> 实施步骤见 [TODO.md](./TODO.md)。
+
+---
+
+## 1. 设计原则
+
+| 原则 | 含义 |
+|------|------|
+| **边界清晰** | 平台运行时(API、DB、生命周期)归 `reactpress-cli`;本仓只做 Web 产品与契约 SDK。 |
+| **契约优先** | 后端能力以 OpenAPI 为准;`toolkit` 生成类型与客户端;业务代码不手写 REST 路径。 |
+| **目录守恒** | 保持现有顶层与 `client/src` 布局;优化模块内涵,不大规模搬迁文件夹。 |
+| **单向依赖** | 依赖只能从上层指向下层(页面 → 门面 → SDK → API),禁止反向与环依赖。 |
+| **渐进演进** | 允许删除已无价值的 `server/` 薄封装;其余变更以「改实现、不改路径」为主。 |
+
+---
+
+## 2. 系统架构
+
+### 2.1 上下文(系统与外部角色)
+
+```mermaid
+flowchart TB
+  subgraph actors [角色]
+    V[访客]
+    A[管理员]
+    D[主题开发者]
+  end
+
+  subgraph system [easy-blog-publish + reactpress-cli]
+    RP[ReactPress 系统]
+  end
+
+  DB[(MySQL)]
+
+  V -->|浏览内容| RP
+  A -->|管理内容| RP
+  D -->|开发主题| RP
+  RP --> DB
+```
+
+### 2.2 容器(主要运行时组件)
+
+```mermaid
+flowchart TB
+  subgraph browser [浏览器]
+    WEB[client Next.js]
+  end
+
+  subgraph node [Node 进程]
+    CLI[@fecommunity/reactpress-cli]
+    API[Nest API 内置]
+  end
+
+  DB[(MySQL)]
+
+  WEB -->|HTTPS /api| API
+  CLI -->|start/stop/config| API
+  CLI -->|Docker / 连接串| DB
+  API --> DB
+```
+
+| 容器 | 部署形态 | 默认端口 |
+|------|----------|----------|
+| **client** | Next.js(`server.js` 启动) | 3001 |
+| **API** | CLI 内置 Nest | 3002(前缀 `/api`) |
+| **MySQL** | CLI `init` 提供的 compose 或外部实例 | 3306 |
+
+### 2.3 仓库与平台(逻辑模块全景)
+
+```mermaid
+flowchart TB
+  subgraph repo [本仓库 easy-blog-publish]
+    CLIENT[client 产品应用]
+    TK[toolkit 契约 SDK]
+    TMPL[templates 主题]
+    DOCS[docs 文档]
+    SCR[scripts 开发/发布脚本]
+  end
+
+  subgraph platform [外部 reactpress-cli]
+    CLI[CLI]
+    API[Nest API]
+  end
+
+  CFG[.reactpress/config.json]
+  ENV[.env]
+
+  CLIENT --> TK
+  TMPL --> TK
+  SCR --> CLI
+  CLI --> CFG
+  CLI --> ENV
+  CLI --> API
+  TK -->|REST| API
+  ENV --> CLIENT
+  ENV --> TK
+```
+
+### 2.4 请求与配置(两条主链路)
+
+**业务请求链路:**
+
+```mermaid
+sequenceDiagram
+  participant P as pages 页面
+  participant C as components
+  participant R as providers 门面
+  participant T as toolkit
+  participant A as Nest API
+
+  P->>C: 渲染
+  C->>R: 领域方法
+  R->>T: Api 类 / HttpClient
+  T->>A: HTTP
+  A-->>T: JSON
+  T-->>R: DTO
+  R-->>C: 数据
+  C-->>P: UI
+```
+
+**配置链路:**
+
+```mermaid
+flowchart LR
+  JSON[.reactpress/config.json]
+  CLI[reactpress-cli]
+  ENV[.env]
+  TK[toolkit config]
+  NX[client next.config / server.js]
+
+  JSON --> CLI
+  CLI -->|syncEnvFromConfig| ENV
+  ENV --> TK
+  ENV --> NX
+```
+
+---
+
+## 3. 模块设计
+
+### 3.1 模块一览
+
+| 模块 | 位置 | 职责 | 依赖 |
+|------|------|------|------|
+| **reactpress-cli** | 外部 npm | 项目 `init`、API 启停、DB、生成 `.reactpress/*` 与 `.env` | — |
+| **toolkit** | `toolkit/` | OpenAPI → TS API/类型;`config`;i18n;无 UI | CLI(swagger 源)、`.env` |
+| **client** | `client/` | 前台、Admin、路由、组件、领域门面 | toolkit |
+| **templates** | `templates/*` | 可安装主题(前台页面与样式) | toolkit(可选 client 对齐) |
+| **docs** | `docs/` | 产品/开发文档 | 无运行时依赖 |
+| **scripts** | `scripts/` | 本地 `dev`、发布等编排 | CLI |
+
+**终态移除**:`server/`(薄封装,职责并入 CLI,不再作为本仓模块)。
+
+### 3.2 模块关系(依赖规则)
+
+```mermaid
+flowchart TD
+  CLI[reactpress-cli]
+  API[Nest API]
+  TK[toolkit]
+  PR[client providers]
+  PG[client pages/components]
+  TMPL[templates]
+
+  CLI --> API
+  TK -.->|契约来源| API
+  TMPL --> TK
+  PR --> TK
+  PG --> PR
+  PG --> TK
+  PG -.->|禁止| API
+  TK -.->|禁止| PG
+  CLI -.->|禁止 浏览器侧| PG
+```
+
+| 关系 | 允许 | 禁止 |
+|------|------|------|
+| client → toolkit | ✓ 唯一后端访问路径 | — |
+| client → API 直连 | — | ✓ 绕过 toolkit/providers |
+| toolkit → client | — | ✓ SDK 不依赖 UI |
+| templates → client 核心 Admin | — | ✓ 主题不 fork 后台 |
+| 本仓 → Nest 源码 | — | ✓ API 只在 CLI 演进 |
+
+### 3.3 toolkit 模块
+
+```mermaid
+flowchart LR
+  subgraph toolkit [toolkit]
+    API[src/api 生成]
+    TYP[src/types]
+    CFG[src/config]
+    UTL[src/utils]
+    LOC[src/locales]
+    GEN[scripts/generate]
+  end
+
+  SW[swagger.json] --> GEN
+  GEN --> API
+  GEN --> TYP
+  ENV[.env] --> CFG
+  API --> HC[HttpClient / instance]
+```
+
+| 子模块 | 说明 |
+|--------|------|
+| `src/api/*` | 由 Swagger 生成,**不手改**;按资源分文件(Article、User…) |
+| `src/config` | 读取 env,导出站点 URL、API 前缀等 |
+| `src/types` | 对外 DTO |
+| `scripts/` | 从 CLI 内置 server 拉取 swagger 并 regenerate |
+
+### 3.4 client 模块(内部分层)
+
+```mermaid
+flowchart TB
+  subgraph presentation [表现层]
+    PAGES[pages/ 路由]
+    COMP[components/ UI]
+    LAY[layout/ 布局]
+  end
+
+  subgraph application [应用层]
+    PROV[providers/ 领域门面]
+    HOOKS[hooks/]
+    CTX[context/]
+  end
+
+  subgraph cross [横切]
+    HTTP[providers/http.ts]
+    UTIL[utils constants theme]
+  end
+
+  TK[toolkit]
+
+  PAGES --> COMP
+  PAGES --> LAY
+  PAGES --> PROV
+  COMP --> PROV
+  COMP --> HOOKS
+  COMP --> CTX
+  PROV --> HTTP
+  PROV --> TK
+  HTTP --> TK
+```
+
+| 子模块 | 职责 | 与其它模块关系 |
+|--------|------|----------------|
+| **pages/** | URL 与页面组装;保持薄 | 调用 `components`、`providers`、`layout` |
+| **components/** | 展示与交互(Editor、Comment、Setting…) | 不直接请求 API;经 `providers` 或 `hooks` |
+| **providers/** | 按领域封装 API(Article、User…) | 对外稳定入口;内部委托 `toolkit` |
+| **providers/http.ts** | axios 实例、Token 拦截、baseURL | 与 toolkit `HttpClient` 对齐或包装 |
+| **layout/** | 前台/后台布局、Admin 菜单 | 与 `pages/admin` 路由对应 |
+| **hooks/** | 分页、设置等复用逻辑 | 可调用 `providers` |
+| **context/** | 全局 UI 状态 | 不替代 `providers` 做数据请求 |
+
+**providers 与 toolkit 的分工**:`toolkit` 提供通用、生成的 HTTP 与类型;`providers` 提供业务语义方法名与参数组合,供页面/组件 import 路径稳定。
+
+### 3.5 templates 模块
+
+```mermaid
+flowchart LR
+  TMPL[templates 主题包]
+  TK[toolkit]
+  CORE[client 核心]
+
+  TMPL -->|前台页面/样式| TMPL
+  TMPL --> TK
+  CORE -->|Admin 不拆分| CORE
+```
+
+- 主题只覆盖 **前台** 展示;**Admin 始终留在 client**。
+- 与 client 共享同一 API 契约(经 toolkit)。
+
+### 3.6 reactpress-cli 模块(外部,本仓不实现)
+
+| 能力 | 说明 |
+|------|------|
+| `init` | 生成 `.reactpress/config.json`、`.env`、compose 等 |
+| `start` / `stop` / `status` | 管理内置 API 进程 |
+| 内置 API | Nest 业务实现唯一源码仓 |
+| 内置 swagger | toolkit `generate` 的契约源 |
+
+---
+
+## 4. 目录设计
+
+### 4.1 仓库顶层(终态)
+
+在**现有结构**上仅删除 `server/`:
+
+```
+easy-blog-publish/
+├── .reactpress/          # CLI 写入:config.json、compose、pid 等
+├── client/               # 主应用 → 见 4.2
+├── toolkit/              # 契约 SDK → 见 4.3
+├── templates/            # 主题包(如 hello-world、twentytwentyfive)
+├── docs/                 # Docusaurus 文档
+├── scripts/              # reactpress-dev、publish 等
+├── pnpm-workspace.yaml
+└── package.json
+```
+
+### 4.2 client 目录
+
+```
+client/
+├── pages/                 # 路由(Pages Router,保持不变)
+│   ├── index.tsx          # 首页
+│   ├── article/           # 文章
+│   ├── knowledge/         # 知识库
+│   ├── admin/             # 管理后台
+│   └── …
+├── public/
+├── server.js              # 开发/生产启动
+├── next.config.js
+└── src/
+    ├── components/        # UI,按业务分子目录
+    ├── providers/         # 领域 API 门面(article.ts、user.ts…)
+    ├── layout/            # AppLayout、AdminLayout
+    ├── hooks/
+    ├── context/
+    ├── utils/
+    ├── constants/
+    └── theme/
+```
+
+| 路径 | 变更策略 |
+|------|----------|
+| `pages/`、`src/*` 一级目录 | **不更名、不迁到 `app/` 或 `features/`** |
+| `src/providers/*.ts` | 仅改文件**内部**实现(委托 toolkit) |
+| `src/components/*` | 新业务组件放入已有业务子目录 |
+
+### 4.3 toolkit 目录
+
+```
+toolkit/
+├── src/
+│   ├── api/               # 生成:Article.ts、User.ts、HttpClient.ts…
+│   ├── types/
+│   ├── config/            # env、global、i18n
+│   ├── utils/
+│   └── locales/
+├── scripts/               # generate-swagger、resolve-swagger-input
+└── dist/                  # 构建产物(npm 入口)
+```
+
+### 4.4 配置相关路径(跨模块)
+
+| 路径 | 写入方 | 读取方 |
+|------|--------|--------|
+| `.reactpress/config.json` | CLI | CLI、人 |
+| `.env` | CLI(由 config 同步) | toolkit、client 启动脚本 |
+| `.env.example` | 仓库模板 | 开发者 |
+
+---
+
+## 5. 模块协作示例
+
+**管理员发布文章(简化):**
+
+```mermaid
+flowchart LR
+  A[pages/admin/article/editor] --> B[components/ArticleEditor]
+  B --> C[providers/article]
+  C --> D[toolkit ArticleApi]
+  D --> E[Nest API]
+```
+
+**访客阅读文章:**
+
+```mermaid
+flowchart LR
+  A[pages/article/id] --> B[components/MarkdownReader]
+  B --> C[providers/article]
+  C --> D[toolkit]
+  D --> E[Nest API]
+```
+
+**主题开发者定制首页:**
+
+```mermaid
+flowchart LR
+  A[templates/.../pages] --> B[toolkit]
+  B --> C[Nest API]
+  D[client Admin] --> B
+```
+
+---
+
+## 6. 参考
+
+| 文档 | 内容 |
+|------|------|
+| [TODO.md](./TODO.md) | 重构任务与阶段 |
+| [reactpress-cli](https://github.com/fecommunity/reactpress-cli) | 平台 CLI 与 API 源码 |
+
+默认地址:Web `http://localhost:3001` · API `http://localhost:3002/api`
diff --git a/README-zh_CN.md b/README-zh_CN.md
index b84810d..b031bb0 100644
--- a/README-zh_CN.md
+++ b/README-zh_CN.md
@@ -70,28 +70,24 @@
 ## 🚀 快速开始
 
 ### 📋 前置要求
-- Node.js >= 16.5.0
-- MySQL 数据库
+- Node.js >= 18.0.0
+- MySQL 数据库(或通过 `reactpress-cli init` 使用 Docker)
 - pnpm 包管理器
 
-### 🏁 安装选项
+### 🏁 本仓库开发(Monorepo)
 
-#### 选项 1:统一 CLI(推荐)
 ```bash
-# 全局安装 ReactPress
-npm install -g @fecommunity/reactpress
-
-# 启动服务
-reactpress server start
-reactpress client start
+pnpm install
+pnpm run init      # 首次:生成 .reactpress/config.json + .env
+pnpm run dev       # API (3002) + 前端 (3001)
 ```
 
-#### 选项 2:独立服务
-```bash
-# 安装并启动 ReactPress 服务器
-npx @fecommunity/reactpress-server
+### 🏁 终端用户项目(仅 CLI)
 
-# 独立安装并运行客户端
+```bash
+npm install -g @fecommunity/reactpress-cli
+reactpress-cli init .
+reactpress-cli start
 npx @fecommunity/reactpress-client
 ```
 
@@ -121,22 +117,14 @@ reactpress client start --pm2
 ```
 
 
-### 独立包命令
-
-您也可以直接使用各个包的命令:
+### API 与客户端命令
 
 ```bash
-# 启动服务器
-npx @fecommunity/reactpress-server
-
-# 启动客户端
+pnpm exec reactpress-cli start
+pnpm exec reactpress-cli stop
 npx @fecommunity/reactpress-client
-
-# 使用 PM2 启动服务器
-npx @fecommunity/reactpress-server --pm2
-
-# 使用 PM2 启动客户端
-npx @fecommunity/reactpress-client --pm2
+pnpm run pm2:api
+pnpm run pm2:client
 ```
 
 ## 📦 包与组件
@@ -147,10 +135,10 @@ ReactPress 组织为**具有模块化包的 monorepo**:
 
 | 包 | 描述 | 版本 |
 |---------|-------------|---------|
-| [`@fecommunity/reactpress`](.) | 主 CLI 和统一入口点 | 2.0.0 |
+| [`@fecommunity/reactpress`](.) | Monorepo 元包与开发脚本 | 2.0.0 |
+| [`@fecommunity/reactpress-cli`](https://github.com/fecommunity/reactpress-cli) | **API 运行时**(init/start/stop) | npm |
 | [`@fecommunity/reactpress-client`](./client) | Next.js 12 前端应用 | 1.0.0 |
-| [`@fecommunity/reactpress-server`](./server) | NestJS 6 后端 API | 1.0.0 |
-| [`@fecommunity/reactpress-toolkit`](./toolkit) | 自动生成的 API 客户端 SDK | 1.0.0 |
+| [`@fecommunity/reactpress-toolkit`](./toolkit) | OpenAPI 生成的 API SDK | 1.0.0 |
 
 ### 模板
 
@@ -189,7 +177,7 @@ SERVER_SITE_URL=http://localhost:3002
 npm install -g pm2
 
 # 使用 PM2 启动 ReactPress 服务器
-npx @fecommunity/reactpress-server --pm2
+pnpm run pm2:api
 
 # 使用 PM2 启动 ReactPress 客户端
 npx @fecommunity/reactpress-client --pm2
diff --git a/README.md b/README.md
index 2ab6a07..13c9e99 100644
--- a/README.md
+++ b/README.md
@@ -59,8 +59,8 @@ ReactPress is engineered for developers who need the publishing power of a tradi
 ## ✨ Core Features
 
 ### ⚡ Rapid Deployment
-- **Zero‑Configuration Setup** – based on intelligent defaults
-- **WordPress‑Style Installation Wizard** – intuitive initialization process
+- **Zero‑Configuration Setup** – `reactpress-cli init` generates config and `.env`
+- **CLI‑Managed API** – database and Nest API via `@fecommunity/reactpress-cli`
 - **Auto‑Database Configuration** – automatic database migrations
 
 ### 🎨 Deep Customization
@@ -97,28 +97,30 @@ ReactPress is engineered for developers who need the publishing power of a tradi
 ## 🚀 Quick Start
 
 ### 📋 Prerequisites
-- Node.js >= 16.5.0
-- MySQL database
+- Node.js >= 18.0.0
+- MySQL database (or Docker via `reactpress-cli init`)
 - `pnpm` package manager
 
-### 🏁 Installation Options
+### 🏁 Quick Start (Monorepo / Product Repo)
 
-#### Option 1: Unified CLI (Recommended)
 ```bash
-# Install ReactPress globally
-npm install -g @fecommunity/reactpress
+git clone https://github.com/fecommunity/reactpress.git
+cd reactpress
+pnpm install
 
-# Start services
-reactpress server start
-reactpress client start
+# Initialize .reactpress/config.json + .env (first time)
+pnpm run init
+
+# API (3002) + Web (3001)
+pnpm run dev
 ```
 
-#### Option 2: Independent Services
-```bash
-# Install and start ReactPress server
-npx @fecommunity/reactpress-server
+### 🏁 End‑User Project (CLI Only)
 
-# Install and run client independently
+```bash
+npm install -g @fecommunity/reactpress-cli
+reactpress-cli init .
+reactpress-cli start
 npx @fecommunity/reactpress-client
 ```
 
@@ -147,20 +149,20 @@ reactpress server start --pm2
 reactpress client start --pm2
 ```
 
-### Individual Package Commands
+### API & Client Commands
 
 ```bash
-# Start server
-npx @fecommunity/reactpress-server
+# API lifecycle (reactpress-cli)
+pnpm exec reactpress-cli start
+pnpm exec reactpress-cli stop
+pnpm exec reactpress-cli status
 
-# Start client
+# Client only
 npx @fecommunity/reactpress-client
 
-# Start server with PM2
-npx @fecommunity/reactpress-server --pm2
-
-# Start client with PM2
-npx @fecommunity/reactpress-client --pm2
+# Production PM2
+pnpm run pm2:api    # bundled API via CLI package
+pnpm run pm2:client
 ```
 
 ---
@@ -173,10 +175,10 @@ ReactPress uses a **Modular Monorepo Architecture**:
 
 | Package | Description | Version |
 |---------|-------------|---------|
-| [`@fecommunity/reactpress`](.) | Main CLI and unified entry point | 2.0.0 |
+| [`@fecommunity/reactpress`](.) | Monorepo meta + dev scripts | 2.0.0 |
+| [`@fecommunity/reactpress-cli`](https://github.com/fecommunity/reactpress-cli) | **API runtime** (init/start/stop, bundled Nest) | npm |
 | [`@fecommunity/reactpress-client`](./client) | Next.js 12 frontend application | 1.0.0 |
-| [`@fecommunity/reactpress-server`](./server) | NestJS 6 backend API | 1.0.0 |
-| [`@fecommunity/reactpress-toolkit`](./toolkit) | Auto‑generated API client SDK | 1.0.0 |
+| [`@fecommunity/reactpress-toolkit`](./toolkit) | OpenAPI‑generated API client SDK | 1.0.0 |
 
 ### Templates
 
@@ -228,7 +230,7 @@ The development environment includes:
 - MySQL Database (port 3306)
 - Nginx Reverse Proxy (port 8080)
 - Client Development Server (port 3001)
-- Server Development Server (port 3002)
+- API via reactpress-cli (port 3002)
 
 Access your application at: `http://localhost:8080`
 
@@ -244,13 +246,11 @@ Access your application at: `http://localhost:8080`
 # Install PM2 globally
 npm install -g pm2
 
-# Start ReactPress server with PM2
-npx @fecommunity/reactpress-server --pm2
-
-# Start ReactPress client with PM2
-npx @fecommunity/reactpress-client --pm2
+# Start API and client with PM2
+pnpm run pm2:api
+pnpm run pm2:client
 
-# Or use the unified CLI
+# Or use the unified reactpress CLI
 reactpress server start --pm2
 reactpress client start --pm2
 ```
diff --git a/TODO.md b/TODO.md
index 14de78d..ff6feed 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,77 +1,140 @@
 # easy-blog-publish 重构 TODO
 
-> 目标:参考 [reactpress-cli](https://github.com/fecommunity/reactpress-cli) 简化仓库架构;后端运行时依赖 `@fecommunity/reactpress-cli`,本仓库聚焦 client / toolkit / 文档与模板。  
-> 状态说明:`[ ]` 未开始 · `[~]` 进行中 · `[x]` 已完成
+> 目标:参考 [reactpress-cli](https://github.com/fecommunity/reactpress-cli) 简化仓库架构;后端运行时依赖 `@fecommunity/reactpress-cli`,本仓库聚焦 **client / toolkit / 文档与模板**。  
+> 状态说明:`[ ]` 未开始 · `[~]` 进行中 · `[x]` 已完成  
+> **文档更新**:2026-05-17(架构评审 + 仓库现状核对)
 
 ---
 
-## 一、现状与问题清单
+## 〇、当前仓库快照(2026-05-17)
 
-### 1.1 与 reactpress-cli 的定位差异
+| 项 | 现状 |
+|----|------|
+| **实质角色** | Next 前端 monorepo + 外部 CLI 后端;**外壳仍像旧版全栈多包 CMS** |
+| **server/** | **已删除**;API 由 `@fecommunity/reactpress-cli` 与 `scripts/bundled-server-path.js` 提供 |
+| **根 dev** | `scripts/reactpress-dev.js`:API 健康检查后起 client;API 经 `reactpress-api-dev.js` → CLI |
+| **配置** | 已有 `.reactpress/config.json`;toolkit / client 仍以根目录 `.env` 为主 |
+| **CLI 依赖** | 根 `devDependencies` 与 `server` 均依赖 `@fecommunity/reactpress-cli@^0.1.0` |
+| **init/stop 等** | 根脚本已部分委托 `pnpm exec reactpress-cli` |
+
+```mermaid
+flowchart TB
+  subgraph root [根包 scripts + bin]
+    DEV[reactpress-dev.js]
+    PUB[reactpress-publish.js]
+    RPCLI[reactpress-cli.js]
+  end
+  subgraph ws [pnpm workspace]
+    C[client Next 12 + React 17]
+    T[toolkit Swagger/API 类型]
+    D[docs / templates]
+  end
+  subgraph ext [@fecommunity/reactpress-cli]
+    RCLI[start/stop/init]
+    API[内置 Nest dist]
+  end
+  DEV --> RCLI --> API
+  RPCLI --> RCLI --> API
+  C -->|providers/http axios| API
+  C -->|next.config 等| T
+  T -->|generate swagger| API
+```
+
+**请求链路**:`client/pages` → `client/src/providers/*` → `SERVER_API_URL` / `http://localhost:3002/api` → CLI 内置 API。
+
+---
+
+## 一、工程质量问题清单
+
+### 1.1 与 reactpress-cli 的定位差异(未收敛)
 
 | 维度 | 当前仓库(easy-blog-publish) | 参考工程(reactpress-cli) |
 |------|------------------------------|----------------------------|
-| 目标 | 全栈 CMS(client + server + docs + templates) | CLI + 内置 server/toolkit,零配置跑通 |
+| 目标 | 名义全栈 CMS(client + server 包 + docs + templates) | 单包 CLI + 内置 server/toolkit |
 | npm 发布 | 6+ 包(root / server / client / toolkit / 2 模板) | 单包 `@fecommunity/reactpress-cli` |
-| CLI | 多入口薄封装 + 各包自带 bin | TypeScript CLI(init/start/stop/restart/status/config)+ Vitest |
-| 初始化 | Server `main.ts` 内嵌 Web 安装向导 | `init` + `config.default.json` + Docker MySQL |
-| 内置资源 | 各包独立发布 | `sync-bundled-assets` 将 server/toolkit 打进 CLI 包 |
+| CLI | 根 `reactpress` + `reactpress-cli.js` + server/client 各自 bin | TS CLI(init/start/stop/restart/status/config)+ Vitest |
+| 初始化 | ~~Web 安装向导~~(已随 server 源码移除) | `init` + `.reactpress/config.json` + Docker MySQL |
+| 内置资源 | 各包独立发布 | `sync-bundled-assets` 打进 CLI |
 
-**结论**:业务代码可保留;**发布与运维层过重、入口分散**,应向「单 CLI 管生命周期 + 本仓管前端」收敛。
+**结论**:后端源码迁移已基本完成;**发布叙事、多 bin、server 发包、根 scripts 仍停留在旧全栈模型**,应向「单 CLI 管 API 生命周期 + 本仓管前端」收敛。
 
 ---
 
 ### 1.2 CLI / 脚本层
 
-- [ ] **多入口重复**:`scripts/reactpress-cli.js` 与 `scripts/reactpress.js` 逻辑重复;`reactpress.js` 未挂到 `package.json` bin,且引用不存在的 `scripts/reactpress-server.js`(死代码)。
-- [ ] **脚本与实现不一致**:根 `package.json` 中 `build:packages` 指向 `reactpress-cli.js --build`,但 `--build` / `--publish` 实际在 `reactpress-publish.js`(约 944 行),`pnpm build:packages` 可能无效。
-- [ ] **根包职责模糊**:`@fecommunity/reactpress` 的 `files` 仅含 scripts/bin,却与 server/client 独立发包并存,用户心智成本高。
-- [ ] **发布脚本过重**:`reactpress-publish.js` 单文件承担哈希缓存、多包交互发布、GitHub Release 等;参考工程已拆为 `prepare-publish.mjs`、`publish-cli.mjs`、`verify-npm-pack.mjs` 等。
+- [x] **`build:packages` / `release` 指向**:根 `package.json` 已指向 `reactpress-publish.js --build` / `--publish`。
+- [x] **多入口收敛**:已移除 `reactpress-server` bin;API 统一经 `reactpress-cli` / `reactpress-api-dev.js`。
+- [x] **`scripts/reactpress.js` 死代码**:仓库内已不存在;文档与 checklist 中残留引用需清理。
+- [x] **`reactpress-cli.js` 隐患**:已修复 `rootDir` 顺序;`server start` 直接委托 CLI 或 PM2 脚本。
+- [ ] **根包职责模糊**:`@fecommunity/reactpress` 的 `files` 仅含 scripts/bin,却与 server/client 独立发包并存。
+- [ ] **发布脚本过重**:`reactpress-publish.js` 单文件承担哈希缓存、多包交互发布、GitHub Release;参考工程已拆为小脚本。
 
 ---
 
 ### 1.3 发布与版本
 
-- [ ] **版本号不同步**(示例,以仓库当时为准):
+- [ ] **版本号不同步**(2026-05-17):
   - root: `2.0.0-beta-4-beta.1`
   - client: `1.0.0-beta.32`
   - server: `1.0.0-beta.16`
   - toolkit / 模板: `1.0.0-beta.4`
-- [ ] **workspace 范围过大**:`docs`、`templates/*` 纳入 pnpm workspace,日常 dev / 安装 / CI 与「仅发 CLI+前端」路径纠缠。
-- [ ] **多包发布维护成本高**:`@fecommunity/reactpress-server` 与本仓 server 源码重复(与 reactpress-cli 的 `packages/server/src` 已对齐)。
+- [ ] **workspace 范围过大**:`docs`、`templates/*` 纳入 pnpm workspace,日常 install / dev / CI 与「仅 client + toolkit」路径纠缠。
+- [x] **`@fecommunity/reactpress-server` 已移除**:不再在本仓发包;API 使用 `@fecommunity/reactpress-cli`。
 
 ---
 
 ### 1.4 配置与路径
 
-- [ ] **`REACTPRESS_ORIGINAL_CWD` 多处维护**:`reactpress-dev.js`、`docker-dev.js`、`server/bin`、`client/bin`、`server/main.ts`、`toolkit/config/env.ts` 等,根因是 npx 全局安装时 cwd 与包内路径不一致。
-- [ ] **toolkit 启动时强依赖 `.env`**:`toolkit/src/config/env.ts` 在模块加载时 `parseEnv()`,多路径猜测 `.env`,失败即抛错,对 monorepo / 仅 server 场景偏脆。
-- [ ] **配置格式不统一**:Web 安装向导写 `.env`;reactpress-cli 使用 `.reactpress/config.json` + `syncEnvFromConfig` 写 `.env`。
+- [ ] **`REACTPRESS_ORIGINAL_CWD` 多处维护**:`reactpress-dev.js`、`docker-dev.js`、`server/bin`、`client/bin`、`toolkit/config/env.ts` 等;根因是 npx / monorepo 下 cwd 与包内路径不一致。
+- [ ] **toolkit 启动时强依赖 `.env`**:`toolkit/src/config/env.ts` 模块加载时 `parseEnv()`,多路径猜测 `.env`,失败即抛错。
+- [~] **配置双轨未完全统一**:CLI 使用 `.reactpress/config.json` + `syncEnvFromConfig`;本仓已有 `config.json`,但 toolkit/client 仍以 `.env` 为运行时主来源。
+- [x] **Web 安装向导**:随 `server/src` 移除,不再存在;文档若仍描述需删除。
+
+---
+
+### 1.5 server 包:薄封装但未删除(架构半迁移)
+
+- [x] **Nest 源码已迁出**:`server/` 无 `src/`,仅 `bin`、`lib/bundled-server-path.js`、`scripts`、`ecosystem.config.js`。
+- [x] **运行时已委托 CLI**:`server/bin/reactpress-server.js` spawn CLI 内置 server;`server/package.json` 仅依赖 `@fecommunity/reactpress-cli`。
+- [x] **工程外壳已收敛**:根 `package.json` 已移除 server 相关 scripts/bin;`pnpm build` 仅 toolkit + client。
+- [x] **dev 直连 CLI**:`reactpress-dev.js` → `reactpress-api-dev.js` → `reactpress-cli start`。
+
+---
+
+### 1.6 前端(client)工程质量
+
+- [ ] **技术栈偏旧**:Next **12**、React **17**、client TS 4.6;文档若写 Next 14 与实现不符。
+- [ ] **无清晰 feature 边界**:`pages/`(Pages Router)+ `src/components` 大组件 + `src/providers` 按领域分散,admin/前台/知识库耦合在目录层级而非模块包。
+- [ ] **API 双轨(高优先级技术债)**:
+  - **手写**:`client/src/providers/*` + `providers/http.ts`(axios,约 15+ Provider 文件);
+  - **生成**:`toolkit` 内 Swagger → `api/*`,但业务代码几乎未用,仅 `next.config.js` / `server.js` / sitemap 读 `toolkit` 的 `config`。
+  - 改后端接口易漏改、类型与路径漂移。
+- [ ] **依赖与构建**:自定义 `server.js` 启动(非裸 `next dev`);Less、PWA、`@ant-design/compatible` 等增加升级成本。
+- [ ] **lint 范围**:根 `lint:server` 已为占位;client ESLint 覆盖,无统一 monorepo 质量门禁。
 
 ---
 
-### 1.5 安装 / 初始化双轨
+### 1.7 toolkit
 
-- [ ] **Server `main.ts`**:无 `.env` 时启动 Express 安装向导(WordPress 式 Web UI)。
-- [ ] **reactpress-cli**:`init` + 默认配置 + Docker MySQL + `start`。
-- [ ] 用户可能混用两套路径,后续难以只保留一条。
+- [ ] **与 CLI bundled toolkit 需定期对齐**:CLI 包内 toolkit 多为 `dist`;本仓保留 `src` + `generate` 脚本(**删 server 包后仍建议保留 toolkit**)。
+- [ ] **`resolve-swagger-input.js` 仍引用 `server/lib/bundled-server-path`**:删 server 后需改为 CLI 路径或 env。
 
 ---
 
-### 1.6 工程债与运维
+### 1.8 工程债与运维(剩余)
 
-- [ ] **`@nestjs/cli` 写在 server `dependencies`**,应属 devDependencies,膨胀生产安装体积。
-- [ ] **技术栈偏旧**:NestJS 6、Next 12、TS ~4.1、Node `>=16.5`;reactpress-cli 要求 Node `>=18`、CLI 为 TS 5 + ESM。
-- [ ] **`server/src/main.ts` 职责过重**:安装向导、端口探测、Express 路由与 Nest 启动混在一起。
-- [ ] **`scripts/install.sh` 约 578 行**:与 CLI `init` 能力重叠,且假设存在 `server/package.json`。
-- [ ] **文档与实现不一致**:文档写 Next.js 14,client 仍为 Next 12;README 多包 `npx` 与统一 CLI 叙事并存。
+- [x] **`@nestjs/cli` 在本仓 server**:已随 server 源码移除,不再适用。
+- [x] **根 `engines.node`**:已为 `>=18.0.0`(与 CLI 对齐)。
+- [ ] **`scripts/install.sh`(约 578 行)**:与 CLI `init` 重叠,仍假设旧 server 构建/镜像路径。
+- [ ] **文档与实现不一致**:README / docs 多包 `npx @fecommunity/reactpress-server` 与 `reactpress-cli init` 叙事并存。
+- [ ] **生产 Docker / compose**:`.reactpress/docker-compose.yml` 存在,与 `install.sh`、server Dockerfile 叙事需统一为 CLI 方案。
 
 ---
 
-### 1.7 代码对齐事实(迁移前提)
+### 1.9 迁移前提(历史记录)
 
-- [x] **已验证**:`easy-blog-publish/server/src` 与 `reactpress-cli/packages/server/src` **当前完全一致**(`diff -rq` 无差异)。  
-  → **删除本仓 server、依赖 CLI 内置 server 在技术上可行**;后续 server 变更需在 reactpress-cli 仓库维护。
+- [x] **曾验证**:删除 server 前 `easy-blog-publish/server/src` 与 `reactpress-cli/packages/server/src` 一致(`diff -rq` 无差异)。
+- [x] **当前**:本仓已无 `server/src`;后端变更应在 **reactpress-cli** 仓库维护。
 
 ---
 
@@ -81,11 +144,11 @@
 flowchart LR
   subgraph repo [easy-blog-publish]
     C[client Next.js]
-    T[toolkit 建议保留]
-    D[docs / templates]
+    T[toolkit 保留]
+    D[docs / templates 可二期移出 workspace]
   end
   subgraph ext [@fecommunity/reactpress-cli]
-    CLI[CLI 命令]
+    CLI[CLI init/start/stop]
     S[内置 server/dist]
     DB[(MySQL Docker / 外部)]
   end
@@ -98,27 +161,37 @@ flowchart LR
 
 | 角色 | 职责 |
 |------|------|
-| reactpress-cli | `init` / `start` / `stop` / `restart` / `status` / `config`;内置 Nest server + 运行时 toolkit |
-| 本仓库 | client 产品与定制;toolkit 源码与 Swagger 生成(推荐保留);文档与模板 |
+| **reactpress-cli** | 项目生命周期、内置 Nest API、可选 Docker DB |
+| **本仓库** | client 产品与 UI 定制;toolkit 源码与 Swagger 生成;文档与模板 |
+
+**重构后本仓不应再包含**:`server/` 目录、`@fecommunity/reactpress-server` npm 包、根 `reactpress-server` bin、依赖 `server/main.ts` 的安装叙事。
 
 ---
 
-## 三、技术方案
+## 三、架构重构方案
 
 ### 3.1 方案总览
 
 | 方案 | 说明 | 推荐度 |
 |------|------|--------|
-| **主方案** | 移除 `server/`,dev/prod 用 `reactpress-cli` 起 API;本仓保留 client + toolkit | ⭐ 推荐 |
-| 备选 A | 仅修 P0 脚本问题,暂不删 server | 短期止血 |
-| 备选 B | 本仓并进 reactpress-cli monorepo | 职责混杂,不推荐 |
-| 备选 C | server 改为 git submodule 指向 reactpress-cli | 运维复杂,仅在不发 npm CLI 时考虑 |
+| **主方案** | 删除 `server/` 包;dev/prod 直接用 `reactpress-cli` 起 API;保留 client + toolkit | ⭐ 推荐 |
+| 备选 A | 仅 P0/P1(脚本修复 + CLI 联调),暂不删 server 目录 | 短期止血 |
+| 备选 B | 本仓并入 reactpress-cli monorepo | 职责混杂,不推荐 |
+| 备选 C | server 改为 git submodule | 运维复杂,不推荐 |
 
----
+### 3.2 推荐实施顺序(重构切入点)
+
+| 阶段 | 焦点 | 为何先做 |
+|------|------|----------|
+| **P0** | 脚本止血、`reactpress-cli.js` bug、文档与 checklist 去陈旧项 | 低成本,避免错误发布与运行时错误 |
+| **P1** | `reactpress-cli init` + `start` + `dev:client` 联调验收 | 架构收敛的闸门;不通过不删 server |
+| **P2** | 删除 `server/`、重写根 `dev`/`build`/bin、精简 `reactpress-publish.js` | **工程架构主战场** |
+| **P3** | 配置统一(`config.json` → `.env` 单一路径)、toolkit swagger 路径 | 降低 `REACTPRESS_ORIGINAL_CWD` 扩散 |
+| **P4** | providers → toolkit 生成 API;client 技术栈升级独立里程碑 | 业务面大,依赖 P2 稳定 |
 
-### 3.2 移除 server 后的依赖策略
+### 3.3 移除 server 包后的依赖与脚本
 
-**根目录 `package.json`(devDependencies):**
+**根 `package.json`(已有,保持):**
 
 ```json
 "@fecommunity/reactpress-cli": "^0.1.0"
@@ -130,9 +203,7 @@ flowchart LR
 "@fecommunity/reactpress-cli": "link:../reactpress-cli/packages/cli"
 ```
 
-或:`pnpm link --global`(见 reactpress-cli README)。
-
-**开发脚本示例:**
+**目标 `dev` 脚本(Phase 2 后):**
 
 ```json
 {
@@ -142,78 +213,62 @@ flowchart LR
 }
 ```
 
-**一次性初始化(仓库根):**
+**初始化:**
 
 ```bash
 pnpm exec reactpress-cli init .
-# 或 force 覆盖:pnpm exec reactpress-cli init . --force
+# 端口:client 3001,API 3002(.reactpress/config.json)
 ```
 
-默认端口建议与现网一致:client `3001`,server `3002`(在 `.reactpress/config.json` 调整)。
-
----
+### 3.4 toolkit(三选一)
 
-### 3.3 toolkit 处理(三选一)
-
-| 选项 | 做法 | 适用 |
+| 选项 | 做法 | 推荐 |
 |------|------|------|
-| **A(推荐)** | **保留 `toolkit/`**,client/templates 继续 `workspace:*` | 仍会改 API、需 `swagger-typescript-api` 重新 generate |
-| B | 删除 toolkit,client 依赖 npm `@fecommunity/reactpress-toolkit` | 不再改 API 类型,版本跟 CLI/npm 走 |
-| C | toolkit 薄封装 re-export CLI 包内路径 | 路径脆弱,不推荐 |
-
-reactpress-cli 内 toolkit 仅有 `dist`、无 `src`;本仓 toolkit 含生成脚本,**删 server 时建议仍保留 toolkit**。
+| **A** | **保留 `toolkit/`**,workspace 依赖 + `swagger-typescript-api` generate | ⭐ 仍会改 API 类型 |
+| B | 删除 toolkit,client 依赖 npm `@fecommunity/reactpress-toolkit` | 不再改 API,跟 CLI 版本 |
+| C | toolkit re-export CLI 内路径 | 脆弱,不推荐 |
 
----
-
-### 3.4 配置统一
+### 3.5 配置统一(P3)
 
 | 项 | 迁移后 |
 |----|--------|
-| 项目元数据 | `.reactpress/config.json`(CLI 管理) |
-| 运行时 env | 根目录 `.env`(由 CLI `syncEnvFromConfig` 生成/更新) |
-| client API 地址 | 继续读 `SERVER_SITE_URL` / `SERVER_API_URL`,默认 `http://localhost:3002/api` |
-| 废弃 | 依赖 server `main.ts` Web 安装向导作为唯一初始化方式 |
-
-**env 关键字段(与 CLI 模板一致):**
-
-- `DB_*`、`CLIENT_SITE_URL`、`SERVER_SITE_URL`、`SERVER_PORT`、`SERVER_API_PREFIX`
-
----
+| 项目元数据 | `.reactpress/config.json`(CLI) |
+| 运行时 | 根 `.env`(CLI `syncEnvFromConfig`) |
+| client API | `SERVER_SITE_URL` / `SERVER_API_URL`,默认 `http://localhost:3002/api` |
+| 废弃 | 多路径 `parseEnv` 猜测;`REACTPRESS_ORIGINAL_CWD` 由 CLI 单点设置 |
 
-### 3.5 待删除 / 待修改清单
+### 3.6 待删除 / 待修改清单
 
-**删除:**
+**删除(Phase 2):**
 
-- [ ] 目录 `server/`(含 `bin`、`Dockerfile`、`ecosystem.config.js`)
-- [ ] `pnpm-workspace.yaml` 中的 `server`
-- [ ] 根 `package.json`:`reactpress-server` bin、`dev:server`、`build:server`、`pm2:server`、`start:server`
-- [ ] `scripts/reactpress-cli.js`(或改为仅文档说明,不再 spawn 本地 server)
-- [ ] `scripts/reactpress.js`(死代码)
-- [ ] 发布流程中的 `@fecommunity/reactpress-server` 包项
+- [x] 目录 `server/`(含 `bin`、`lib`、`ecosystem.config.js`)
+- [x] `pnpm-workspace.yaml` 中的 `server`
+- [x] 根 `package.json`:`reactpress-server` bin、`dev:server`、`build:server`、`pm2:server`、`start:server`
+- [x] 发布流程中的 `@fecommunity/reactpress-server`
+- [x] `scripts/bundled-server-path.js` 改为 CLI 路径解析(不再 re-export server/lib)
 
 **修改:**
 
-- [ ] 根 `package.json`:增加 `@fecommunity/reactpress-cli`;重写 `dev` / `build` / `release`
-- [ ] `scripts/reactpress-publish.js`:移除 server 包逻辑,或拆分为小脚本对齐 reactpress-cli
-- [ ] `scripts/reactpress-dev.js`:改为调 CLI + client,或合并进根 `dev`
-- [ ] `scripts/install.sh`:去掉 server 构建/镜像假设,改为 CLI 起 API + client 镜像
-- [ ] `server/Dockerfile` 相关文档与 compose:改为 CLI 镜像或 API 侧车方案
-- [ ] README / docs:安装改为 `reactpress-cli init` + `start`;删除 `npx @fecommunity/reactpress-server` 主推
+- [x] 根 `package.json`:重写 `dev` / `build`(去掉 `build:server`)/ `release`
+- [x] `scripts/reactpress-publish.js`:移除 server 包项
+- [x] `scripts/reactpress-dev.js`:经 `reactpress-api-dev.js` 调 CLI
+- [x] `scripts/reactpress-cli.js`:修复 `rootDir`;server 子命令委托 CLI
+- [x] `toolkit/scripts/resolve-swagger-input.js`:swagger 路径指向 `scripts/bundled-server-path`
+- [ ] `scripts/install.sh`、Docker 文档:CLI 起 API + client 镜像
+- [ ] README / docs:唯一推荐 `reactpress-cli init` + `start`
 
 **保留(首期):**
 
 - [ ] `client/`
 - [ ] `toolkit/`(方案 A)
-- [ ] `docs/`、`templates/`(可二期移出 workspace)
-
----
+- [ ] `docs/`、`templates/`(可 Phase 4 移出 workspace)
 
-### 3.6 P0 止血(不删 server 也可先做)
+### 3.7 P0 止血(可立即做)
 
-- [ ] 修正 `build:packages` → `node scripts/reactpress-publish.js --build`
-- [ ] 修正 `release` → `node scripts/reactpress-publish.js --publish`(若尚未正确)
-- [ ] 删除 `scripts/reactpress.js` 或修复并明确是否挂 bin
-- [ ] 统一 `reactpress-publish.js` 帮助文案中的脚本名
+- [x] `build:packages` / `release` → `reactpress-publish.js`
+- [x] 修复 `reactpress-cli.js` 中 `serverBin` / `rootDir` 定义顺序
+- [x] 确认无 `scripts/reactpress.js`(更新本文档与 README 中的过时描述)
+- [ ] `reactpress-publish.js` 帮助文案与包列表与现状一致
 
 ---
 
@@ -221,17 +276,17 @@ reactpress-cli 内 toolkit 仅有 `dist`、无 `src`;本仓 toolkit 含生成
 
 | 维度 | 评估 | 说明 |
 |------|------|------|
-| API 兼容 | ✅ 高 | server 源码与 CLI 内置一致 |
-| client 改造量 | ✅ 低 | 仍连 `localhost:3002/api`,env 名不变 |
-| 初始化体验 | ⚠️ 中 | 从 Web 向导改为 CLI `init`,需更新文档 |
-| 发版耦合 | ⚠️ 中 | server 修复需先进 reactpress-cli 并发 npm |
-| CLI 成熟度 | ⚠️ 中 | 当前 CLI `0.1.0`,需确认 npm 可用或 workspace link |
-| 生产 Docker | ⚠️ 中 | `install.sh` / compose 需重新设计 |
-| toolkit | ✅ 高 | 建议保留本仓 toolkit,与 CLI bundled 版本定期对齐 |
-
-**不适合删 server 的情况:**
-
-- 计划在本仓库长期独立 fork 后端(大量 Nest 定制),且不愿回流 reactpress-cli。
+| API 兼容 | ✅ 高 | 运行时已是 CLI 内置 server |
+| 删 server 目录 | ✅ 高 | 仅剩薄封装,无 `src` |
+| client 改造量(P2) | ✅ 低 | env 与 API URL 可不变 |
+| 初始化体验 | ⚠️ 中 | 统一 CLI `init`,更新文档 |
+| 发版耦合 | ⚠️ 中 | API 修复需 reactpress-cli 发版 |
+| CLI 成熟度 | ⚠️ 中 | `0.1.0`,dev 可用 link |
+| 生产 Docker | ⚠️ 中 | `install.sh` / compose 需重设计 |
+| toolkit | ✅ 高 | 建议保留;发版前与 CLI bundled 对齐 |
+| 前端现代化 | ⚠️ 低优先级 | Next 升级宜在 P2 之后独立立项 |
+
+**不适合删 server 包的情况**:计划在本仓库长期 fork 大量 Nest 定制且不回流 reactpress-cli。
 
 ---
 
@@ -239,11 +294,12 @@ reactpress-cli 内 toolkit 仅有 `dist`、无 `src`;本仓 toolkit 含生成
 
 | 风险 | 缓解 |
 |------|------|
-| 两仓库 server 漂移 | 约定 server 仅以 reactpress-cli 为源码;本仓 CI 可加「API 冒烟」对 CLI 版本 |
-| CLI 未发布 / 版本过旧 | dev 用 `link:../reactpress-cli`;CI 锁定 CLI 版本号 |
-| 安装文档过时 | 迁移时同步 README-zh_CN、deploy 文档 |
-| `install.sh` 失效 | 分阶段:先文档化 CLI 流程,再改 shell |
-| 首次无 Web 向导 | `init` 后文档说明访问 `http://localhost:3001/admin` |
+| CLI 与本仓 toolkit 版本漂移 | 发版前 diff / e2e;锁定 CLI 版本 |
+| CLI 未发布或过旧 | 开发 `link:../reactpress-cli`;CI 锁版本 |
+| 文档过时 | P2 同步 README、deploy、docs 安装章节 |
+| `install.sh` 失效 | 先文档化 CLI 流程,再改 shell |
+| 删 server 后 swagger 路径断裂 | 提前改 `resolve-swagger-input.js` |
+| providers 与 toolkit API 不一致 | P4 渐进迁移,按模块替换 |
 
 ---
 
@@ -251,67 +307,73 @@ reactpress-cli 内 toolkit 仅有 `dist`、无 `src`;本仓 toolkit 含生成
 
 ### Phase 0 — 止血(0.5~1 天)
 
-- [ ] 修复 `build:packages` / `release` 脚本指向
-- [ ] 删除或修复 `scripts/reactpress.js`
-- [ ] 在 README 注明当前脚本问题与临时正确命令
+- [x] 修复 `build:packages` / `release` 脚本指向
+- [x] 修复 `reactpress-cli.js` `rootDir` / `serverBin` 顺序
+- [ ] README:去掉对已删除 `reactpress.js`、Web 安装向导、`server/src` 的描述
+- [ ] 清理 TODO / 文档中的过时 checklist 项
 
 ### Phase 1 — 验证 CLI 联调(1~2 天)
 
-- [ ] 根目录执行 `reactpress-cli init`(端口 3001/3002)
-- [ ] `reactpress-cli start` + `pnpm dev:client` 跑通登录、文章列表、管理后台
-- [ ] 确认 `.env` 字段满足 client / toolkit 读取
-- [ ] 决定 CLI 依赖方式:**npm 正式版** vs **`link:../reactpress-cli`**
+- [~] 根目录已有 `.reactpress/config.json`;需完整跑通 `init` → `start` + `dev:client`
+- [ ] 验收:登录、文章列表、管理后台、`/api` 健康
+- [ ] 确认 `.env` 满足 client / toolkit
+- [ ] 决策:CLI **npm 正式版** vs **`link:../reactpress-cli`**
 
-### Phase 2 — 删除 server(1~2 天)
+### Phase 2 — 删除 server 包(1~2 天)【架构收敛核心】
 
-- [ ] 从 workspace 移除 `server`
-- [ ] 删除 `server/` 目录
-- [ ] 更新根 `package.json` scripts / bin
-- [ ] 更新 `reactpress-dev.js` 或合并为根 `dev`
-- [ ] 精简 `reactpress-publish.js`(去掉 server 包)
+- [x] workspace 移除 `server`
+- [x] 删除 `server/` 目录
+- [x] 更新根 `package.json` scripts / bin / `build`
+- [x] `reactpress-dev.js` 经 `reactpress-api-dev.js` 调 `reactpress-cli start`
+- [x] `reactpress-publish.js` 去掉 server 包
+- [x] `toolkit` swagger 路径改 CLI
 
-### Phase 3 — 工程与文档(2~3 天)
+### Phase 3 — 配置、API 与文档(2~4 天)
 
-- [ ] 更新 `install.sh`、Docker、compose(如仍需要生产一键装)
-- [ ] README / docs:安装、部署、环境变量以 CLI 为准
-- [ ] 统一 Node `>=18` engines(与 CLI 对齐)
+- [ ] 配置:`config.json` 为唯一元数据源;弱化 toolkit 多路径 `.env` 猜测
+- [ ] `REACTPRESS_ORIGINAL_CWD` 收敛到 CLI 设置
+- [ ] `install.sh`、Docker、compose 对齐 CLI
+- [ ] README / docs 安装与 env 以 CLI 为准
 - [ ] (可选)`docs`、`templates` 移出 workspace
-- [ ] (可选)`@nestjs/cli` 等仅存在于 reactpress-cli 侧,本仓不再关心
+- [ ] (启动)providers 逐步改用 toolkit `api/*`
 
-### Phase 4 — 发布与长期(持续)
+### Phase 4 — 前端现代化与发布(持续)
 
-- [ ] 本仓 npm 发布范围收敛为:`@fecommunity/reactpress-client`(+ 可选 toolkit / 模板)
-- [ ] 建立 toolkit API 与 CLI bundled toolkit 版本对齐检查(发版前 diff dist 或跑 e2e)
-- [ ] 评估是否将 toolkit 改为纯 npm 依赖(方案 B)
+- [ ] npm 发布收敛:`@fecommunity/reactpress-client`(+ toolkit / 模板可选)
+- [ ] toolkit 与 CLI bundled 版本对齐检查
+- [ ] Next 12 → 14+、React 18(独立里程碑,不与 P2 捆绑)
+- [ ] 评估根包 `@fecommunity/reactpress` 是否改为 workspace meta-only
 
 ---
 
 ## 七、验收标准
 
-- [ ] 克隆仓库后:`pnpm install` → `reactpress-cli init` → `pnpm dev` 可访问前台与管理端
-- [ ] 仓库内无 `server/` 目录,无 `@fecommunity/reactpress-server` 发包配置
-- [ ] `pnpm build:packages` / `pnpm release`(若保留)指向正确且可执行
-- [ ] CI(若有)不依赖本仓 server 构建
-- [ ] 文档无 `npx @fecommunity/reactpress-server` 作为推荐路径
+- [ ] `pnpm install` → `reactpress-cli init` → `pnpm dev` 可访问前台与管理端
+- [x] 无 `server/` 目录,无 `@fecommunity/reactpress-server` 发包配置
+- [x] `pnpm build:packages` / `pnpm release` 可执行且不含 server 包
+- [ ] CI 不依赖本仓 server 构建
+- [ ] 文档不推荐 `npx @fecommunity/reactpress-server` 为主路径
+- [ ] (P4)client 关键路径有 API 冒烟或 e2e
 
 ---
 
 ## 八、待决策项
 
-- [ ] CLI 依赖:**npm `@fecommunity/reactpress-cli@^x`** 还是 **monorepo link 本地路径**
-- [ ] toolkit:**保留 workspace(A)** 还是 **改 npm 依赖(B)**
+- [ ] CLI 依赖:**npm `@fecommunity/reactpress-cli@^x`** vs **`link:../reactpress-cli`**
+- [ ] toolkit:**保留 workspace(A)** vs **纯 npm(B)**
 - [ ] `docs` / `templates`:是否移出 pnpm workspace
-- [ ] 是否继续发布根包 `@fecommunity/reactpress`,或改名为纯 client 元包
-- [ ] 生产环境:CLI 进容器 vs API 独立部署 + 仅容器化 client
+- [ ] 根包 `@fecommunity/reactpress`:继续发布 vs meta-only
+- [ ] 生产:CLI 进容器 vs API 旁路 + 仅容器化 client
+- [ ] 前端升级:是否与 P2 同迭代(建议 **否**)
 
 ---
 
-## 九、参考链接
+## 九、参考
 
-- reactpress-cli 仓库:`/Users/xiu/Documents/my-code/reactpress-cli`(或 GitHub `fecommunity/reactpress-cli`)
-- 用户项目结构:`.env` + `.reactpress/config.json` + `docker-compose.yml`(由 `init` 生成)
-- 默认 API:`http://localhost:3002/api` · 默认前台:`http://localhost:3001`
+- reactpress-cli:`fecommunity/reactpress-cli`(本地路径示例:`../reactpress-cli`)
+- 用户项目:`.env` + `.reactpress/config.json` + `docker-compose.yml`(`init` 生成)
+- 默认:前台 `http://localhost:3001` · API `http://localhost:3002/api`
 
 ---
 
-*文档生成自架构评审与「依赖 reactpress-cli、移除 server」方案讨论,随实施进度更新 checkbox。*
+*随实施进度更新 checkbox;「当前仓库快照」与第一节问题清单应在重大结构变更后同步修订。*
diff --git a/client/README.md b/client/README.md
index 6d49396..154717e 100644
--- a/client/README.md
+++ b/client/README.md
@@ -56,10 +56,10 @@ Perfect for:
 - Microfrontend architecture
 
 ### Full ReactPress Stack
-Use with ReactPress server for complete CMS solution:
+Use with ReactPress API for complete CMS solution:
 ```bash
-# Start server first
-npx @fecommunity/reactpress-server
+# Start API first
+pnpm exec reactpress-cli start
 
 # In another terminal, start client
 npx @fecommunity/reactpress-client
diff --git a/package.json b/package.json
index f84bfc0..ad80ac8 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "@fecommunity/reactpress",
   "author": "fecommunity",
   "version": "2.0.0-beta-4-beta.1",
-  "description": "ReactPress - A full-stack CMS built with React, Next.js, and NestJS",
+  "description": "ReactPress — Web CMS product monorepo (client + toolkit); API via @fecommunity/reactpress-cli",
   "keywords": [
     "reactpress",
     "cms",
@@ -14,14 +14,12 @@
   ],
   "bin": {
     "reactpress": "./scripts/reactpress-cli.js",
-    "reactpress-server": "./server/bin/reactpress-server.js",
     "reactpress-client": "./client/bin/reactpress-client.js"
   },
   "files": [
     "bin/**/*",
     "scripts/**/*",
     "client/bin/**/*",
-    "server/bin/**/*",
     "CONTRIBUTING.md"
   ],
   "scripts": {
@@ -31,8 +29,7 @@
     "init": "pnpm exec reactpress-cli init .",
     "init:force": "pnpm exec reactpress-cli init . --force",
     "dev": "node ./scripts/reactpress-dev.js",
-    "dev:server": "pnpm run --dir ./server dev",
-    "dev:api": "pnpm run dev:server",
+    "dev:api": "node ./scripts/reactpress-api-dev.js",
     "dev:client": "pnpm run --dir ./client dev",
     "dev:docs": "pnpm run --dir ./docs dev",
     "docker:dev": "node ./scripts/docker-dev.js",
@@ -41,28 +38,24 @@
     "docker:dev:restart": "node ./scripts/docker-dev.js restart",
     "docker:dev:status": "node ./scripts/docker-dev.js status",
     "docker:dev:logs": "node ./scripts/docker-dev.js logs",
-    "build": "pnpm build:toolkit && pnpm build:server && pnpm build:client",
+    "build": "pnpm build:toolkit && pnpm build:client",
     "build:packages": "node scripts/reactpress-publish.js --build",
     "build:toolkit": "pnpm run --dir ./toolkit build",
-    "build:server": "pnpm run --dir ./server build",
     "build:client": "pnpm run --dir ./client build",
     "build:docs": "pnpm run --dir ./docs build",
     "deploy:docs": "pnpm run --dir ./docs deploy:surge",
     "deploy": "sh scripts/deploy.sh",
-    "start": "concurrently -n api,web -c blue,green \"pnpm run start:server\" \"pnpm run start:client\"",
-    "start:server": "pnpm run --dir ./server start",
-    "start:api": "pnpm run start:server",
+    "start": "concurrently -n api,web -c blue,green \"pnpm run start:api\" \"pnpm run start:client\"",
+    "start:api": "pnpm exec reactpress-cli start",
     "start:client": "pnpm run --dir ./client start",
     "stop": "pnpm exec reactpress-cli stop",
     "restart": "pnpm exec reactpress-cli restart",
     "status": "pnpm exec reactpress-cli status",
-    "pm2": "pnpm run pm2:server && pnpm run pm2:client",
-    "pm2:server": "pnpm run --dir ./server pm2",
-    "pm2:api": "pnpm run pm2:server",
+    "pm2": "pnpm run pm2:api && pnpm run pm2:client",
+    "pm2:api": "node ./scripts/reactpress-api-pm2.js",
     "pm2:client": "pnpm run --dir ./client pm2",
     "lint": "concurrently 'pnpm:lint:*'",
     "lint:client": "eslint --fix './client/**/*.{ts,tsx,js,jsx}'",
-    "lint:server": "node -e \"console.log('server: no local TS sources (see @fecommunity/reactpress-cli)')\"",
     "format": "concurrently 'pnpm:format:*'",
     "format:js": "prettier --write --parser typescript './**/*.{ts,tsx,js,jsx}'",
     "prepare": "husky",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3bdd7ed..34fbf5f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -300,12 +300,6 @@ importers:
         specifier: ~5.6.2
         version: 5.6.3
 
-  server:
-    dependencies:
-      '@fecommunity/reactpress-cli':
-        specifier: ^0.1.0
-        version: 0.1.0(@types/node@24.5.2)
-
   templates/hello-world:
     dependencies:
       '@fecommunity/reactpress-toolkit':
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index f489b37..b44048d 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,11 +1,9 @@
 packages:
   # 客户端
   - 'client'
-  # API(薄封装,依赖 reactpress-cli)
-  - 'server'
   # 文档
   - 'docs'
   # 工具包
   - 'toolkit'
   # 模板
-  - 'templates/*'
\ No newline at end of file
+  - 'templates/*'
diff --git a/scripts/bundled-server-path.js b/scripts/bundled-server-path.js
index a51277e..d924534 100644
--- a/scripts/bundled-server-path.js
+++ b/scripts/bundled-server-path.js
@@ -1,4 +1,37 @@
 /**
- * Re-export from server package (single source for CLI bundled paths).
+ * Resolve paths to the Nest server bundled inside @fecommunity/reactpress-cli.
  */
-module.exports = require('../server/lib/bundled-server-path');
+const path = require('path');
+
+function getCliPackageRoot() {
+  return path.dirname(require.resolve('@fecommunity/reactpress-cli/package.json'));
+}
+
+function getBundledServerDir() {
+  return path.join(getCliPackageRoot(), 'server');
+}
+
+function getBundledServerBin() {
+  return path.join(getBundledServerDir(), 'bin', 'reactpress-server.js');
+}
+
+function getBundledSwaggerPath() {
+  return path.join(getBundledServerDir(), 'public', 'swagger.json');
+}
+
+function getBundledServerMain() {
+  return path.join(getBundledServerDir(), 'dist', 'main.js');
+}
+
+function getMonorepoRoot() {
+  return path.resolve(__dirname, '..');
+}
+
+module.exports = {
+  getCliPackageRoot,
+  getBundledServerDir,
+  getBundledServerBin,
+  getBundledSwaggerPath,
+  getBundledServerMain,
+  getMonorepoRoot,
+};
diff --git a/scripts/docker-dev.js b/scripts/docker-dev.js
index ce77553..1ef8fda 100755
--- a/scripts/docker-dev.js
+++ b/scripts/docker-dev.js
@@ -136,7 +136,7 @@ switch (command) {
             'concurrently',
             '-n', 'api,web',
             '-c', 'blue,green',
-            'pnpm:dev:server',
+            'pnpm:dev:api',
             'pnpm:dev:client'
           ], {
             stdio: 'inherit',
diff --git a/scripts/install.sh b/scripts/install.sh
index 1daaf6f..5dbe7ad 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -328,17 +328,13 @@ EOF
         info "toolkit/package.json already exists"
     fi
     
-    # Check client and server packages
+    # Check client package and CLI dependency at repo root
     if [ ! -f "client/package.json" ]; then
         error "client/package.json not found"
     fi
-    
-    if [ ! -f "server/package.json" ]; then
-        error "server/package.json not found"
-    fi
 
-    if ! grep -q '@fecommunity/reactpress-cli' server/package.json 2>/dev/null; then
-        error "server/package.json must depend on @fecommunity/reactpress-cli"
+    if ! grep -q '@fecommunity/reactpress-cli' package.json 2>/dev/null; then
+        error "Root package.json must depend on @fecommunity/reactpress-cli"
     fi
 }
 
diff --git a/server/scripts/dev.js b/scripts/reactpress-api-dev.js
similarity index 54%
rename from server/scripts/dev.js
rename to scripts/reactpress-api-dev.js
index 5d3a72b..1ec9a68 100644
--- a/server/scripts/dev.js
+++ b/scripts/reactpress-api-dev.js
@@ -1,23 +1,21 @@
 #!/usr/bin/env node
 
 /**
- * Development: ensure DB via reactpress-cli, then run bundled API in the foreground.
+ * Development API: ensure config, start via reactpress-cli, keep process alive for concurrently.
  */
 
-const { spawnSync, spawn } = require('child_process');
+const { spawnSync } = require('child_process');
 const path = require('path');
 const fs = require('fs');
-const { getBundledServerBin, getMonorepoRoot } = require('../lib/bundled-server-path');
+const { getMonorepoRoot } = require('./bundled-server-path');
 
-const projectRoot = getMonorepoRoot();
+const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
 const configPath = path.join(projectRoot, '.reactpress', 'config.json');
 
 process.env.REACTPRESS_ORIGINAL_CWD = projectRoot;
 
 if (!fs.existsSync(configPath)) {
-  console.warn(
-    '[ReactPress Server] 未找到 .reactpress/config.json,正在执行 reactpress-cli init …'
-  );
+  console.warn('[reactpress] 未找到 .reactpress/config.json,正在执行 reactpress-cli init …');
   const init = spawnSync('pnpm', ['exec', 'reactpress-cli', 'init', '.'], {
     cwd: projectRoot,
     stdio: 'inherit',
@@ -36,25 +34,24 @@ if (start.status !== 0) {
   process.exit(start.status ?? 1);
 }
 
-console.log(
-  '[ReactPress Server] API 已由 reactpress-cli 在后台启动。本进程保持运行以便 concurrently 管理;按 Ctrl+C 停止。'
-);
-console.log('[ReactPress Server] 停止 API: pnpm exec reactpress-cli stop');
+console.log('[reactpress] API 已由 reactpress-cli 启动。按 Ctrl+C 停止 API 与前端。');
+console.log('[reactpress] 单独停止 API: pnpm exec reactpress-cli stop');
 
 process.stdin.resume();
 
-process.on('SIGINT', () => {
+function stopApi() {
   spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], {
     cwd: projectRoot,
     stdio: 'inherit',
   });
+}
+
+process.on('SIGINT', () => {
+  stopApi();
   process.exit(0);
 });
 
 process.on('SIGTERM', () => {
-  spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], {
-    cwd: projectRoot,
-    stdio: 'inherit',
-  });
+  stopApi();
   process.exit(0);
 });
diff --git a/server/bin/reactpress-server.js b/scripts/reactpress-api-pm2.js
similarity index 53%
rename from server/bin/reactpress-server.js
rename to scripts/reactpress-api-pm2.js
index 956ba6b..725fb26 100644
--- a/server/bin/reactpress-server.js
+++ b/scripts/reactpress-api-pm2.js
@@ -1,18 +1,15 @@
 #!/usr/bin/env node
 
 /**
- * @fecommunity/reactpress-server — thin entry that delegates to the server
- * bundled in @fecommunity/reactpress-cli (no local NestJS source in this repo).
+ * Start bundled API with PM2 (production).
  */
 
 const { spawn } = require('child_process');
-const path = require('path');
-const { getBundledServerBin, getBundledServerDir, getMonorepoRoot } = require('../lib/bundled-server-path');
+const { getBundledServerBin, getBundledServerDir, getMonorepoRoot } = require('./bundled-server-path');
 
-const args = process.argv.slice(2);
 const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
 
-const child = spawn(process.execPath, [getBundledServerBin(), ...args], {
+const child = spawn(process.execPath, [getBundledServerBin(), '--pm2'], {
   stdio: 'inherit',
   cwd: getBundledServerDir(),
   env: {
@@ -22,7 +19,7 @@ const child = spawn(process.execPath, [getBundledServerBin(), ...args], {
 });
 
 child.on('error', (error) => {
-  console.error('[ReactPress Server] Failed to start:', error);
+  console.error('[reactpress] Failed to start API with PM2:', error);
   process.exit(1);
 });
 
diff --git a/scripts/reactpress-cli.js b/scripts/reactpress-cli.js
index 209f905..65e732a 100755
--- a/scripts/reactpress-cli.js
+++ b/scripts/reactpress-cli.js
@@ -2,14 +2,13 @@
 
 /**
  * ReactPress CLI — unified entry for monorepo development.
- * Server lifecycle is delegated to @fecommunity/reactpress-cli; client stays local.
+ * API lifecycle is delegated to @fecommunity/reactpress-cli; client stays local.
  */
 
 const { Command } = require('commander');
 const { spawn, spawnSync } = require('child_process');
 const path = require('path');
 const chalk = require('chalk');
-const serverBin = path.join(rootDir, 'server', 'bin', 'reactpress-server.js');
 
 const binDir = __dirname;
 const rootDir = path.join(binDir, '..');
@@ -51,11 +50,14 @@ const serverCmd = program.command('server').description('Manage the ReactPress A
 
 serverCmd
   .command('start')
-  .description('Start the API server (server/ wrapper → reactpress-cli or --pm2)')
-  .option('--pm2', 'Start server with PM2 process manager')
+  .description('Start the API server (reactpress-cli start, or --pm2 for production)')
+  .option('--pm2', 'Start API with PM2 process manager')
   .action((options) => {
-    const args = options.pm2 ? ['--pm2'] : [];
-    spawnNodeScript(serverBin, args);
+    if (options.pm2) {
+      spawnNodeScript(path.join(rootDir, 'scripts', 'reactpress-api-pm2.js'));
+      return;
+    }
+    runReactpressCli(['start']);
   });
 
 serverCmd
@@ -113,7 +115,7 @@ program.on('--help', () => {
   console.log('  $ reactpress client start        # Start Next.js client');
   console.log('  $ pnpm dev                       # Build toolkit + API + client');
   console.log('');
-  console.log('API backend: server/ thin wrapper → @fecommunity/reactpress-cli bundled Nest server.');
+  console.log('API backend: @fecommunity/reactpress-cli bundled Nest server.');
 });
 
 program.parse(process.argv);
diff --git a/scripts/reactpress-dev.js b/scripts/reactpress-dev.js
index 057be01..5f53ffc 100644
--- a/scripts/reactpress-dev.js
+++ b/scripts/reactpress-dev.js
@@ -91,9 +91,8 @@ async function startDev() {
   const serverUrl = loadServerSiteUrl();
 
   console.log('[reactpress] 正在启动 API(首次可能需安装内置服务端依赖,请稍候)…');
-  apiChild = spawn('pnpm', ['dev:server'], {
+  apiChild = spawn(process.execPath, [path.join(__dirname, 'reactpress-api-dev.js')], {
     stdio: 'inherit',
-    shell: true,
     cwd: currentWorkingDir,
   });
 
diff --git a/scripts/reactpress-publish.js b/scripts/reactpress-publish.js
index be5fc59..9302967 100644
--- a/scripts/reactpress-publish.js
+++ b/scripts/reactpress-publish.js
@@ -14,11 +14,6 @@ const packages = [
     path: '.',
     description: 'Main ReactPress package'
   },
-  {
-    name: '@fecommunity/reactpress-server',
-    path: 'server',
-    description: 'API server wrapper (runtime from @fecommunity/reactpress-cli)'
-  },
   {
     name: '@fecommunity/reactpress-client',
     path: 'client', 
@@ -380,8 +375,6 @@ function buildPackage(pkg) {
     try {
       if (pkg.path === 'config') {
         execSync('pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' });
-      } else if (pkg.path === 'server') {
-        execSync('pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' });
       } else if (pkg.path === 'client') {
         execSync('pnpm run prebuild && pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' });
       } else if (pkg.path === 'toolkit') {
diff --git a/server/README.md b/server/README.md
deleted file mode 100644
index 4f49d32..0000000
--- a/server/README.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# @fecommunity/reactpress-server
-
-本目录**不包含 NestJS 源码**。API 运行时由依赖包 [`@fecommunity/reactpress-cli`](https://github.com/fecommunity/reactpress-cli) 内置的 `server/dist` 提供;此包仅保留 monorepo 中的 **入口、脚本与发布名**,便于沿用 `pnpm dev:server`、`reactpress-server` 等习惯。
-
-## 命令
-
-| 命令 | 说明 |
-|------|------|
-| `pnpm dev` | 必要时 `init`,`reactpress-cli start` 启动 API(供根目录 `pnpm dev` 并发) |
-| `pnpm start` | 前台运行 CLI 内置 server(`bin/reactpress-server.js`) |
-| `pnpm start:cli` | 仅调用 `reactpress-cli start` |
-| `pnpm pm2` | 通过内置 bin 以 PM2 启动 |
-| `pnpm generate:swagger` | 在 CLI 内置 server 目录生成 Swagger |
-
-## 修改后端逻辑
-
-请在 [reactpress-cli](https://github.com/fecommunity/reactpress-cli) 仓库维护 Nest 代码,发布后升级本包的 `@fecommunity/reactpress-cli` 版本。
diff --git a/server/ecosystem.config.js b/server/ecosystem.config.js
deleted file mode 100644
index 64a8562..0000000
--- a/server/ecosystem.config.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const path = require('path');
-const { getBundledServerMain } = require('./lib/bundled-server-path');
-
-module.exports = {
-  apps: [
-    {
-      name: 'reactpress-server',
-      script: getBundledServerMain(),
-      instances: 1,
-      autorestart: true,
-      watch: false,
-      max_memory_restart: '1G',
-      env: {
-        NODE_ENV: 'production',
-      },
-      env_development: {
-        NODE_ENV: 'development',
-      },
-    },
-  ],
-};
diff --git a/server/package.json b/server/package.json
deleted file mode 100644
index c87aafe..0000000
--- a/server/package.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "name": "@fecommunity/reactpress-server",
-  "version": "1.0.0-beta.16",
-  "description": "ReactPress API — thin wrapper around @fecommunity/reactpress-cli bundled server",
-  "author": "fecommunity",
-  "license": "MIT",
-  "bin": {
-    "reactpress-server": "./bin/reactpress-server.js"
-  },
-  "files": [
-    "bin/**/*",
-    "lib/**/*",
-    "scripts/**/*",
-    "ecosystem.config.js",
-    "README.md"
-  ],
-  "keywords": [
-    "reactpress",
-    "server",
-    "nestjs",
-    "cms",
-    "blog",
-    "api"
-  ],
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/fecommunity/reactpress.git",
-    "directory": "server"
-  },
-  "engines": {
-    "node": ">=18.0.0"
-  },
-  "scripts": {
-    "build": "node -e \"console.log('@fecommunity/reactpress-server: no build (runtime from @fecommunity/reactpress-cli)')\"",
-    "dev": "node ./scripts/dev.js",
-    "start": "node ./bin/reactpress-server.js",
-    "start:cli": "pnpm exec reactpress-cli start",
-    "stop": "pnpm exec reactpress-cli stop",
-    "restart": "pnpm exec reactpress-cli restart",
-    "status": "pnpm exec reactpress-cli status",
-    "pm2": "node ./bin/reactpress-server.js --pm2",
-    "pm2:stop": "pnpm exec reactpress-cli stop",
-    "pm2:restart": "pnpm exec reactpress-cli restart",
-    "pm2:status": "pnpm exec reactpress-cli status",
-    "generate:swagger": "node ./scripts/generate-swagger.js"
-  },
-  "dependencies": {
-    "@fecommunity/reactpress-cli": "^0.1.0"
-  }
-}
diff --git a/server/scripts/generate-swagger.js b/server/scripts/generate-swagger.js
deleted file mode 100644
index 39b4ef1..0000000
--- a/server/scripts/generate-swagger.js
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env node
-
-const { execSync } = require('child_process');
-const { getBundledServerDir } = require('../lib/bundled-server-path');
-
-execSync('npm run generate:swagger', {
-  cwd: getBundledServerDir(),
-  stdio: 'inherit',
-});
diff --git a/toolkit/scripts/resolve-swagger-input.js b/toolkit/scripts/resolve-swagger-input.js
index ec56447..545f971 100644
--- a/toolkit/scripts/resolve-swagger-input.js
+++ b/toolkit/scripts/resolve-swagger-input.js
@@ -1,4 +1,4 @@
-const { getBundledSwaggerPath, getBundledServerDir } = require('../../server/lib/bundled-server-path');
+const { getBundledSwaggerPath, getBundledServerDir } = require('../../scripts/bundled-server-path');
 
 function getSwaggerInputPath() {
   return getBundledSwaggerPath();

From 89c0d4f6b23542c68c71dee9e837bf8b853b26dd Mon Sep 17 00:00:00 2001
From: m0_37981569 
Date: Mon, 4 May 2026 22:45:00 +0800
Subject: [PATCH 04/20] chore: refactor project structure to integrate server
 directory, update API management scripts, and enhance documentation

---
 .env                                          |    1 +
 .reactpress/config.json                       |    2 +-
 CONTRIBUTING.md                               |  114 +-
 README-zh_CN.md                               |  109 +-
 README.md                                     |   15 +-
 docker-compose.prod.yml                       |    2 +-
 package.json                                  |  104 +-
 pnpm-lock.yaml                                | 4693 ++++++++++++++++-
 pnpm-workspace.yaml                           |    2 +
 scripts/bundled-server-path.js                |   53 +-
 scripts/deploy.sh                             |   65 +-
 scripts/docker-dev.js                         |    2 +-
 scripts/reactpress-api-dev.js                 |   63 +-
 scripts/reactpress-api-lifecycle.js           |  257 +
 scripts/reactpress-api-pm2.js                 |   14 +-
 scripts/reactpress-cli.js                     |   39 +-
 scripts/reactpress-publish.js                 |    7 +-
 server/.eslintrc.js                           |   25 +
 server/Dockerfile                             |   38 +
 server/LICENSE                                |   21 +
 server/README.md                              |  366 ++
 server/bin/reactpress-server.js               |  203 +
 server/ecosystem.config.js                    |   18 +
 server/nest-cli.json                          |    4 +
 server/package.json                           |  149 +
 server/public/favicon.png                     |  Bin 0 -> 33057 bytes
 server/public/index.html                      |  439 ++
 server/public/swagger/custom.css              |   11 +
 server/src/app.module.ts                      |   82 +
 server/src/filters/http-exception.filter.ts   |   28 +
 server/src/generate-swagger.ts                |   95 +
 .../src/interceptors/transform.interceptor.ts |   33 +
 server/src/logger/index.ts                    |   47 +
 server/src/main.ts                            |  346 ++
 .../src/modules/article/article.controller.ts |  178 +
 server/src/modules/article/article.entity.ts  |  103 +
 server/src/modules/article/article.module.ts  |   18 +
 server/src/modules/article/article.service.ts |  398 ++
 server/src/modules/article/article.util.ts    |    4 +
 server/src/modules/auth/auth.controller.ts    |   45 +
 server/src/modules/auth/auth.module.ts        |   30 +
 server/src/modules/auth/auth.service.ts       |  119 +
 server/src/modules/auth/jwt-auth.guard.ts     |   18 +
 server/src/modules/auth/jwt.strategy.ts       |   25 +
 server/src/modules/auth/roles.guard.ts        |   34 +
 .../modules/category/category.controller.ts   |   66 +
 .../src/modules/category/category.entity.ts   |   42 +
 .../src/modules/category/category.module.ts   |   15 +
 .../src/modules/category/category.service.ts  |  104 +
 .../src/modules/comment/comment.controller.ts |   74 +
 server/src/modules/comment/comment.entity.ts  |   73 +
 server/src/modules/comment/comment.module.ts  |   18 +
 server/src/modules/comment/comment.service.ts |  189 +
 server/src/modules/comment/html.ts            |  641 +++
 server/src/modules/file/file.controller.ts    |   61 +
 server/src/modules/file/file.entity.ts        |   37 +
 server/src/modules/file/file.module.ts        |   15 +
 server/src/modules/file/file.service.ts       |  113 +
 .../src/modules/install/install.controller.ts |   20 +
 server/src/modules/install/install.module.ts  |   14 +
 server/src/modules/install/install.service.ts |   53 +
 .../modules/knowledge/knowledge.controller.ts |  110 +
 .../src/modules/knowledge/knowledge.entity.ts |   77 +
 .../src/modules/knowledge/knowledge.module.ts |   15 +
 .../modules/knowledge/knowledge.service.ts    |  168 +
 server/src/modules/page/page.controller.ts    |   87 +
 server/src/modules/page/page.entity.ts        |   65 +
 server/src/modules/page/page.module.ts        |   15 +
 server/src/modules/page/page.service.ts       |  112 +
 .../src/modules/search/search.controller.ts   |   43 +
 server/src/modules/search/search.entity.ts    |   37 +
 server/src/modules/search/search.module.ts    |   15 +
 server/src/modules/search/search.service.ts   |   74 +
 .../src/modules/setting/setting.constant.ts   |   29 +
 .../src/modules/setting/setting.controller.ts |   57 +
 server/src/modules/setting/setting.entity.ts  |  109 +
 server/src/modules/setting/setting.module.ts  |   16 +
 server/src/modules/setting/setting.service.ts |  116 +
 server/src/modules/smtp/mail.util.ts          |   31 +
 server/src/modules/smtp/smtp.controller.ts    |   45 +
 server/src/modules/smtp/smtp.entity.ts        |   37 +
 server/src/modules/smtp/smtp.module.ts        |   16 +
 server/src/modules/smtp/smtp.service.ts       |   69 +
 server/src/modules/tag/tag.controller.ts      |   75 +
 server/src/modules/tag/tag.entity.ts          |   41 +
 server/src/modules/tag/tag.module.ts          |   15 +
 server/src/modules/tag/tag.service.ts         |  122 +
 server/src/modules/user/user.controller.ts    |  105 +
 server/src/modules/user/user.entity.ts        |   76 +
 server/src/modules/user/user.module.ts        |   16 +
 server/src/modules/user/user.service.ts       |  201 +
 server/src/modules/view/view.controller.ts    |   66 +
 server/src/modules/view/view.entity.ts        |   60 +
 server/src/modules/view/view.module.ts        |   15 +
 server/src/modules/view/view.service.ts       |   86 +
 server/src/starter.ts                         |  103 +
 server/src/utils/date.util.ts                 |   11 +
 server/src/utils/ip.util.ts                   |   25 +
 server/src/utils/markdown.util.ts             |   46 +
 server/src/utils/oss.util.ts                  |   59 +
 server/src/utils/oss/aliyun-oss-client.ts     |   27 +
 server/src/utils/oss/oss-client.ts            |   10 +
 server/src/utils/ua.util.ts                   |   36 +
 server/src/utils/uniqueid.util.ts             |    5 +
 server/src/utils/upload.util.ts               |   34 +
 server/src/utils/user.util.ts                 |   16 +
 server/tsconfig.build.json                    |    4 +
 server/tsconfig.json                          |   21 +
 server/tslint.json                            |   18 +
 toolkit/scripts/generate-swagger.js           |    4 +-
 110 files changed, 12229 insertions(+), 365 deletions(-)
 create mode 100644 scripts/reactpress-api-lifecycle.js
 create mode 100644 server/.eslintrc.js
 create mode 100644 server/Dockerfile
 create mode 100644 server/LICENSE
 create mode 100644 server/README.md
 create mode 100755 server/bin/reactpress-server.js
 create mode 100644 server/ecosystem.config.js
 create mode 100644 server/nest-cli.json
 create mode 100644 server/package.json
 create mode 100644 server/public/favicon.png
 create mode 100644 server/public/index.html
 create mode 100644 server/public/swagger/custom.css
 create mode 100644 server/src/app.module.ts
 create mode 100644 server/src/filters/http-exception.filter.ts
 create mode 100644 server/src/generate-swagger.ts
 create mode 100644 server/src/interceptors/transform.interceptor.ts
 create mode 100644 server/src/logger/index.ts
 create mode 100644 server/src/main.ts
 create mode 100644 server/src/modules/article/article.controller.ts
 create mode 100644 server/src/modules/article/article.entity.ts
 create mode 100644 server/src/modules/article/article.module.ts
 create mode 100644 server/src/modules/article/article.service.ts
 create mode 100644 server/src/modules/article/article.util.ts
 create mode 100644 server/src/modules/auth/auth.controller.ts
 create mode 100644 server/src/modules/auth/auth.module.ts
 create mode 100644 server/src/modules/auth/auth.service.ts
 create mode 100644 server/src/modules/auth/jwt-auth.guard.ts
 create mode 100644 server/src/modules/auth/jwt.strategy.ts
 create mode 100644 server/src/modules/auth/roles.guard.ts
 create mode 100644 server/src/modules/category/category.controller.ts
 create mode 100644 server/src/modules/category/category.entity.ts
 create mode 100644 server/src/modules/category/category.module.ts
 create mode 100644 server/src/modules/category/category.service.ts
 create mode 100644 server/src/modules/comment/comment.controller.ts
 create mode 100644 server/src/modules/comment/comment.entity.ts
 create mode 100644 server/src/modules/comment/comment.module.ts
 create mode 100644 server/src/modules/comment/comment.service.ts
 create mode 100644 server/src/modules/comment/html.ts
 create mode 100644 server/src/modules/file/file.controller.ts
 create mode 100644 server/src/modules/file/file.entity.ts
 create mode 100644 server/src/modules/file/file.module.ts
 create mode 100644 server/src/modules/file/file.service.ts
 create mode 100644 server/src/modules/install/install.controller.ts
 create mode 100644 server/src/modules/install/install.module.ts
 create mode 100644 server/src/modules/install/install.service.ts
 create mode 100644 server/src/modules/knowledge/knowledge.controller.ts
 create mode 100644 server/src/modules/knowledge/knowledge.entity.ts
 create mode 100644 server/src/modules/knowledge/knowledge.module.ts
 create mode 100644 server/src/modules/knowledge/knowledge.service.ts
 create mode 100644 server/src/modules/page/page.controller.ts
 create mode 100644 server/src/modules/page/page.entity.ts
 create mode 100644 server/src/modules/page/page.module.ts
 create mode 100644 server/src/modules/page/page.service.ts
 create mode 100644 server/src/modules/search/search.controller.ts
 create mode 100644 server/src/modules/search/search.entity.ts
 create mode 100644 server/src/modules/search/search.module.ts
 create mode 100644 server/src/modules/search/search.service.ts
 create mode 100644 server/src/modules/setting/setting.constant.ts
 create mode 100644 server/src/modules/setting/setting.controller.ts
 create mode 100644 server/src/modules/setting/setting.entity.ts
 create mode 100644 server/src/modules/setting/setting.module.ts
 create mode 100644 server/src/modules/setting/setting.service.ts
 create mode 100644 server/src/modules/smtp/mail.util.ts
 create mode 100644 server/src/modules/smtp/smtp.controller.ts
 create mode 100644 server/src/modules/smtp/smtp.entity.ts
 create mode 100644 server/src/modules/smtp/smtp.module.ts
 create mode 100644 server/src/modules/smtp/smtp.service.ts
 create mode 100644 server/src/modules/tag/tag.controller.ts
 create mode 100644 server/src/modules/tag/tag.entity.ts
 create mode 100644 server/src/modules/tag/tag.module.ts
 create mode 100644 server/src/modules/tag/tag.service.ts
 create mode 100644 server/src/modules/user/user.controller.ts
 create mode 100644 server/src/modules/user/user.entity.ts
 create mode 100644 server/src/modules/user/user.module.ts
 create mode 100644 server/src/modules/user/user.service.ts
 create mode 100644 server/src/modules/view/view.controller.ts
 create mode 100644 server/src/modules/view/view.entity.ts
 create mode 100644 server/src/modules/view/view.module.ts
 create mode 100644 server/src/modules/view/view.service.ts
 create mode 100644 server/src/starter.ts
 create mode 100644 server/src/utils/date.util.ts
 create mode 100644 server/src/utils/ip.util.ts
 create mode 100644 server/src/utils/markdown.util.ts
 create mode 100644 server/src/utils/oss.util.ts
 create mode 100644 server/src/utils/oss/aliyun-oss-client.ts
 create mode 100644 server/src/utils/oss/oss-client.ts
 create mode 100644 server/src/utils/ua.util.ts
 create mode 100644 server/src/utils/uniqueid.util.ts
 create mode 100644 server/src/utils/upload.util.ts
 create mode 100644 server/src/utils/user.util.ts
 create mode 100644 server/tsconfig.build.json
 create mode 100644 server/tsconfig.json
 create mode 100644 server/tslint.json

diff --git a/.env b/.env
index f9118cf..5b308a6 100644
--- a/.env
+++ b/.env
@@ -7,3 +7,4 @@ DB_DATABASE=reactpress
 CLIENT_SITE_URL=http://localhost:3001
 SERVER_SITE_URL=http://localhost:3002
 SERVER_PORT=3002
+SERVER_API_PREFIX=/api
diff --git a/.reactpress/config.json b/.reactpress/config.json
index d102f84..7144102 100644
--- a/.reactpress/config.json
+++ b/.reactpress/config.json
@@ -1,7 +1,7 @@
 {
   "version": 1,
   "database": {
-    "mode": "external",
+    "mode": "embedded-docker",
     "containerName": "reactpress_cli_db"
   },
   "server": {
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e0bb75a..033f800 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,117 +1,79 @@
 # Contributing to ReactPress
 
-Thank you for your interest in contributing to ReactPress! We welcome contributions from the community to help improve the project.
-
-## Code of Conduct
-
-Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md) to ensure a welcoming and inclusive environment for all contributors.
-
-## Getting Started
-
-1. Fork the repository
-2. Clone your fork: `git clone https://github.com/your-username/reactpress.git`
-3. Create a new branch: `git checkout -b feature/your-feature-name`
-4. Make your changes
-5. Commit your changes: `git commit -m "Add your feature description"`
-6. Push to your fork: `git push origin feature/your-feature-name`
-7. Create a pull request
+Thank you for your interest in contributing to ReactPress!
 
 ## Development Setup
 
 ### Prerequisites
 
 - Node.js >= 18.0.0
-- pnpm >= 7.0.0
-- MySQL 5.7 or higher (or Docker via `reactpress-cli init`)
+- pnpm >= 8.0.0
+- MySQL 5.7+ (or Docker via `pnpm run init` / `pnpm docker:dev`)
 
-### Installation
+### First run
 
 ```bash
-# Clone the repository
 git clone https://github.com/fecommunity/reactpress.git
 cd reactpress
-
-# Install dependencies
 pnpm install
-
-# First-time: generate .reactpress/config.json + .env
-pnpm run init
-
-# Start API + client
-pnpm run dev
+pnpm run init      # .reactpress/config.json + .env
+pnpm run dev       # toolkit → API (3002) → client (3001)
 ```
 
-## Project Structure
-
-ReactPress follows a monorepo structure. **API runtime lives in `@fecommunity/reactpress-cli`**, not in this repo.
+## Project structure
 
 ```
 reactpress/
-├── client/          # Next.js frontend application
-├── toolkit/         # OpenAPI-generated API client SDK
-├── templates/       # Project templates
-├── scripts/         # dev, publish, bundled API paths
-├── docs/            # Documentation
-└── .reactpress/     # CLI-written config (local)
+├── server/          # NestJS API (primary backend in this repo)
+├── client/          # Next.js frontend
+├── toolkit/         # OpenAPI-generated API SDK
+├── templates/       # Starter templates
+├── scripts/         # dev, deploy, lifecycle
+├── docs/            # Docusaurus site
+└── .reactpress/     # Local CLI config
 ```
 
-## Development Workflow
+## Development workflow
 
-### Running Services
+| Task | Command |
+|------|---------|
+| Full stack dev | `pnpm dev` |
+| API only (watch) | `pnpm dev:api` or `pnpm dev:server` |
+| Client only | `pnpm dev:client` |
+| Docker MySQL + proxy | `pnpm docker:dev` |
+| Regenerate API types | `pnpm run build:toolkit` |
+| API lifecycle | `pnpm run start:api` / `stop` / `restart` / `status` |
 
-```bash
-# API + client (builds toolkit first, waits for API health)
-pnpm run dev
+`pnpm dev` builds toolkit first, waits for API health, then starts the client.
 
-# API only (reactpress-cli)
-pnpm run dev:api
+## Building
 
-# Client only
-pnpm run dev:client
-
-# API lifecycle
-pnpm exec reactpress-cli start
-pnpm exec reactpress-cli stop
-pnpm exec reactpress-cli status
+```bash
+pnpm run build              # toolkit + server + client
+pnpm run build:server       # Nest only
+pnpm run build:client       # Next.js only
+pnpm run generate:swagger   # swagger.json from server
 ```
 
-### Building Packages
+## Production
 
 ```bash
-# Build toolkit + client
 pnpm run build
-
-# Build publishable workspace packages
-pnpm run build:packages
-
-# Build specific packages
-pnpm run build:client
-pnpm run build:toolkit
+pnpm run pm2                # PM2 for API + client
+# or
+sh scripts/deploy.sh
 ```
 
-### Publishing
+## Publishing
 
 ```bash
 pnpm login
 pnpm run release
 ```
 
-Published packages: root meta, client, toolkit, templates. API is published as `@fecommunity/reactpress-cli`.
-
-## Code Style
-
-- Follow the existing code style in the project
-- Use TypeScript for type safety
-- Write clear, concise commit messages
-- Update documentation as needed
-
-## Pull Request Process
-
-1. Ensure your code follows the project's style guidelines
-2. Update documentation if you're changing functionality
-3. Make sure all tests pass (if applicable)
-4. Request review from maintainers
+Packages: root meta, **server**, client, toolkit, templates.  
+`@fecommunity/reactpress-cli` is used for `init` and optional Docker database only.
 
 ## Architecture
 
-See [DESIGN.md](./DESIGN.md) for module boundaries and [TODO.md](./TODO.md) for the migration roadmap.
+See [DESIGN.md](./DESIGN.md) and [TODO.md](./TODO.md).
diff --git a/README-zh_CN.md b/README-zh_CN.md
index b031bb0..c2b3eda 100644
--- a/README-zh_CN.md
+++ b/README-zh_CN.md
@@ -74,15 +74,25 @@
 - MySQL 数据库(或通过 `reactpress-cli init` 使用 Docker)
 - pnpm 包管理器
 
-### 🏁 本仓库开发(Monorepo)
+### 🏁 本仓库开发(Monorepo,含 server/)
 
 ```bash
 pnpm install
-pnpm run init      # 首次:生成 .reactpress/config.json + .env
-pnpm run dev       # API (3002) + 前端 (3001)
+pnpm run init          # 首次:.reactpress/config.json + .env(可用 Docker MySQL)
+pnpm run docker:dev    # 可选:仅起 MySQL + nginx 代理
+pnpm run dev           # 构建 toolkit → API 热更新 (3002) → 前端 (3001)
 ```
 
-### 🏁 终端用户项目(仅 CLI)
+| 命令 | 说明 |
+|------|------|
+| `pnpm dev` | 一键本地全栈(推荐) |
+| `pnpm dev:api` | 仅 API(`server/` nest watch) |
+| `pnpm dev:client` | 仅 Next.js 前端 |
+| `pnpm build` | 生产构建:toolkit → server → client |
+| `pnpm start` | 生产模式同时起 API + 前端 |
+| `pnpm run status` | 查看 API 进程与 HTTP 健康 |
+
+### 🏁 终端用户项目(仅 CLI,不含本仓 server 源码)
 
 ```bash
 npm install -g @fecommunity/reactpress-cli
@@ -120,11 +130,22 @@ reactpress client start --pm2
 ### API 与客户端命令
 
 ```bash
-pnpm exec reactpress-cli start
-pnpm exec reactpress-cli stop
-npx @fecommunity/reactpress-client
+# API(本仓 server/)
+pnpm run start:api
+pnpm run stop
+pnpm run restart
+pnpm run status
+
+# 或统一 CLI
+reactpress server start
+reactpress client start
+
+# 生产 PM2
 pnpm run pm2:api
 pnpm run pm2:client
+
+# 初始化 / Docker 数据库(仍用 reactpress-cli)
+pnpm run init
 ```
 
 ## 📦 包与组件
@@ -136,9 +157,10 @@ ReactPress 组织为**具有模块化包的 monorepo**:
 | 包 | 描述 | 版本 |
 |---------|-------------|---------|
 | [`@fecommunity/reactpress`](.) | Monorepo 元包与开发脚本 | 2.0.0 |
-| [`@fecommunity/reactpress-cli`](https://github.com/fecommunity/reactpress-cli) | **API 运行时**(init/start/stop) | npm |
+| [`@fecommunity/reactpress-server`](./server) | **NestJS API**(本仓开发与部署) | 1.0.0 |
 | [`@fecommunity/reactpress-client`](./client) | Next.js 12 前端应用 | 1.0.0 |
 | [`@fecommunity/reactpress-toolkit`](./toolkit) | OpenAPI 生成的 API SDK | 1.0.0 |
+| [`@fecommunity/reactpress-cli`](https://github.com/fecommunity/reactpress-cli) | 项目初始化与 Docker DB(可选) | npm |
 
 ### 模板
 
@@ -147,9 +169,43 @@ ReactPress 组织为**具有模块化包的 monorepo**:
 | [`hello-world`](./templates/hello-world) | 用于快速原型设计的最小模板 | `@fecommunity/reactpress-template-hello-world` |
 | [`twentytwentyfive`](./templates/twentytwentyfive) | 功能丰富的博客模板 | `@fecommunity/reactpress-template-twentytwentyfive` |
 
+## 🛠 研发流程
+
+```mermaid
+flowchart LR
+  subgraph init [首次]
+    A[pnpm install] --> B[pnpm init]
+    B --> C[.env + .reactpress/config.json]
+  end
+  subgraph dev [日常开发]
+    D[pnpm dev] --> E[toolkit build]
+    E --> F[server nest watch :3002]
+    F --> G[client next dev :3001]
+  end
+  subgraph ship [上线]
+    H[pnpm build] --> I[pnpm deploy 或 pm2]
+  end
+  init --> dev
+  dev --> ship
+```
+
+**改 API 契约后同步前端类型:**
+
+```bash
+pnpm run generate:swagger   # 从 server 生成 swagger.json
+pnpm run build:toolkit      # 重新生成 toolkit 的 api/types
+```
+
+**Docker 本地(MySQL + 反向代理):**
+
+```bash
+pnpm docker:dev:start    # MySQL :3306,入口 http://localhost:8080
+pnpm docker:dev:stop
+```
+
 ## 🔧 配置
 
-在根目录中创建 `.env` 文件用于本地开发:
+在根目录中创建 `.env` 文件用于本地开发(`pnpm init` 可自动生成):
 
 ```env
 # 数据库配置
@@ -171,29 +227,34 @@ SERVER_SITE_URL=http://localhost:3002
 ### 使用 Vercel 部署(推荐)
 [![使用 Vercel 部署](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/fecommunity/reactpress)
 
-### PM2 部署(推荐)
-```bash
-# 全局安装 PM2
-npm install -g pm2
+### PM2 部署(推荐,自托管)
 
-# 使用 PM2 启动 ReactPress 服务器
-pnpm run pm2:api
+```bash
+pnpm install
+pnpm run build
+pnpm run pm2          # API + 前端
+pm2 save
+```
 
-# 使用 PM2 启动 ReactPress 客户端
-npx @fecommunity/reactpress-client --pm2
+或使用一键脚本(在服务器仓库根目录):
 
-# 或者使用统一 CLI
-reactpress server start --pm2
-reactpress client start --pm2
+```bash
+sh scripts/deploy.sh
 ```
 
-### 传统部署(自托管)
+### 传统部署(前台进程)
+
 ```bash
-# 构建生产版本
 pnpm run build
+pnpm run start        # concurrently: API + client
+```
 
-# 启动生产服务器
-pnpm run start
+### Docker 生产(DB + 前端容器,API 在宿主机)
+
+```bash
+pnpm run build
+pnpm run start:api    # 或 pm2:api,监听 3002
+docker compose -f docker-compose.prod.yml up -d
 ```
 
 ## 🤝 贡献
diff --git a/README.md b/README.md
index 13c9e99..7bca9ed 100644
--- a/README.md
+++ b/README.md
@@ -111,10 +111,12 @@ pnpm install
 # Initialize .reactpress/config.json + .env (first time)
 pnpm run init
 
-# API (3002) + Web (3001)
+# API from server/ (3002) + Web (3001)
 pnpm run dev
 ```
 
+See [README-zh_CN.md](./README-zh_CN.md) for the full dev/deploy workflow (Chinese).
+
 ### 🏁 End‑User Project (CLI Only)
 
 ```bash
@@ -152,10 +154,10 @@ reactpress client start --pm2
 ### API & Client Commands
 
 ```bash
-# API lifecycle (reactpress-cli)
-pnpm exec reactpress-cli start
-pnpm exec reactpress-cli stop
-pnpm exec reactpress-cli status
+# API lifecycle (monorepo server/)
+pnpm run start:api
+pnpm run stop
+pnpm run status
 
 # Client only
 npx @fecommunity/reactpress-client
@@ -176,8 +178,9 @@ ReactPress uses a **Modular Monorepo Architecture**:
 | Package | Description | Version |
 |---------|-------------|---------|
 | [`@fecommunity/reactpress`](.) | Monorepo meta + dev scripts | 2.0.0 |
-| [`@fecommunity/reactpress-cli`](https://github.com/fecommunity/reactpress-cli) | **API runtime** (init/start/stop, bundled Nest) | npm |
+| [`@fecommunity/reactpress-server`](./server) | **NestJS API** (developed and deployed from this repo) | 1.0.0 |
 | [`@fecommunity/reactpress-client`](./client) | Next.js 12 frontend application | 1.0.0 |
+| [`@fecommunity/reactpress-cli`](https://github.com/fecommunity/reactpress-cli) | Project init & Docker DB (optional) | npm |
 | [`@fecommunity/reactpress-toolkit`](./toolkit) | OpenAPI‑generated API client SDK | 1.0.0 |
 
 ### Templates
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 1d3f19b..2196089 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -19,7 +19,7 @@ services:
     networks:
       - reactpress-network
 
-  # API 由宿主机上的 @fecommunity/reactpress-cli 提供(pnpm exec reactpress-cli start)
+  # API 由宿主机 monorepo server/ 提供(pnpm run start:api 或 pm2:api)
   # nginx 通过 host.docker.internal:3002 转发 /api
 
   client:
diff --git a/package.json b/package.json
index ad80ac8..aaf0974 100644
--- a/package.json
+++ b/package.json
@@ -1,100 +1,10 @@
 {
-  "name": "@fecommunity/reactpress",
-  "author": "fecommunity",
-  "version": "2.0.0-beta-4-beta.1",
-  "description": "ReactPress — Web CMS product monorepo (client + toolkit); API via @fecommunity/reactpress-cli",
-  "keywords": [
-    "reactpress",
-    "cms",
-    "blog",
-    "react",
-    "nextjs",
-    "nestjs",
-    "typescript"
-  ],
-  "bin": {
-    "reactpress": "./scripts/reactpress-cli.js",
-    "reactpress-client": "./client/bin/reactpress-client.js"
-  },
-  "files": [
-    "bin/**/*",
-    "scripts/**/*",
-    "client/bin/**/*",
-    "CONTRIBUTING.md"
-  ],
+  "name": "reactpress-site",
+  "private": true,
+  "version": "1.0.0",
+  "description": "ReactPress CMS & Blog site",
   "scripts": {
-    "clean": "pnpm clean:node_modules && pnpm clean:dist",
-    "clean:node_modules": "npx rimraf ./node_modules ./**/node_modules",
-    "clean:dist": "npx rimraf ./dist ./**/dist",
-    "init": "pnpm exec reactpress-cli init .",
-    "init:force": "pnpm exec reactpress-cli init . --force",
-    "dev": "node ./scripts/reactpress-dev.js",
-    "dev:api": "node ./scripts/reactpress-api-dev.js",
-    "dev:client": "pnpm run --dir ./client dev",
-    "dev:docs": "pnpm run --dir ./docs dev",
-    "docker:dev": "node ./scripts/docker-dev.js",
-    "docker:dev:start": "node ./scripts/docker-dev.js start",
-    "docker:dev:stop": "node ./scripts/docker-dev.js stop",
-    "docker:dev:restart": "node ./scripts/docker-dev.js restart",
-    "docker:dev:status": "node ./scripts/docker-dev.js status",
-    "docker:dev:logs": "node ./scripts/docker-dev.js logs",
-    "build": "pnpm build:toolkit && pnpm build:client",
-    "build:packages": "node scripts/reactpress-publish.js --build",
-    "build:toolkit": "pnpm run --dir ./toolkit build",
-    "build:client": "pnpm run --dir ./client build",
-    "build:docs": "pnpm run --dir ./docs build",
-    "deploy:docs": "pnpm run --dir ./docs deploy:surge",
-    "deploy": "sh scripts/deploy.sh",
-    "start": "concurrently -n api,web -c blue,green \"pnpm run start:api\" \"pnpm run start:client\"",
-    "start:api": "pnpm exec reactpress-cli start",
-    "start:client": "pnpm run --dir ./client start",
-    "stop": "pnpm exec reactpress-cli stop",
-    "restart": "pnpm exec reactpress-cli restart",
-    "status": "pnpm exec reactpress-cli status",
-    "pm2": "pnpm run pm2:api && pnpm run pm2:client",
-    "pm2:api": "node ./scripts/reactpress-api-pm2.js",
-    "pm2:client": "pnpm run --dir ./client pm2",
-    "lint": "concurrently 'pnpm:lint:*'",
-    "lint:client": "eslint --fix './client/**/*.{ts,tsx,js,jsx}'",
-    "format": "concurrently 'pnpm:format:*'",
-    "format:js": "prettier --write --parser typescript './**/*.{ts,tsx,js,jsx}'",
-    "prepare": "husky",
-    "precommit": "lint-staged",
-    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s  -r 0",
-    "release": "node scripts/reactpress-publish.js --publish"
-  },
-  "dependencies": {
-    "chalk": "^4.1.2",
-    "commander": "^9.4.1",
-    "concurrently": "^7.0.0",
-    "conventional-changelog-cli": "^3.0.0",
-    "cross-env": "^7.0.3",
-    "dotenv": "^17.2.3",
-    "express": "^5.1.0",
-    "fs-extra": "^10.0.0",
-    "inquirer": "^8.2.4",
-    "mysql2": "^3.12.0",
-    "open": "^8.2.1",
-    "rimraf": "^3.0.2"
-  },
-  "engines": {
-    "node": ">=18.0.0"
-  },
-  "devDependencies": {
-    "@fecommunity/reactpress-cli": "^0.1.0",
-    "husky": "^7.0.4",
-    "lint-staged": "^12.4.1",
-    "prettier": "^2.3.2",
-    "typescript": "~4.1.6"
-  },
-  "lint-staged": {
-    "*.{ts,tsx,js,jsx,.css,.scss}": "prettier --write",
-    "./client/**/*.{ts,tsx,js,jsx}": [
-      "eslint --fix"
-    ],
-    "./config/**/*.{ts,tsx,js,jsx}": [
-      "eslint --fix"
-    ]
-  },
-  "packageManager": "pnpm@10.12.1+sha512.f0dda8580f0ee9481c5c79a1d927b9164f2c478e90992ad268bbb2465a736984391d6333d2c327913578b2804af33474ca554ba29c04a8b13060a717675ae3ac"
+    "start": "reactpress-cli start",
+    "stop": "reactpress-cli stop"
+  }
 }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 34fbf5f..7fc36ca 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -300,6 +300,223 @@ importers:
         specifier: ~5.6.2
         version: 5.6.3
 
+  server:
+    dependencies:
+      '@fecommunity/reactpress-toolkit':
+        specifier: workspace:*
+        version: link:../toolkit
+      '@nestjs/cli':
+        specifier: ^6.9.0
+        version: 6.14.2(eslint@8.57.1)
+      '@nestjs/common':
+        specifier: ^6.7.2
+        version: 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nestjs/config':
+        specifier: ^0.6.3
+        version: 0.6.3(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nestjs/core':
+        specifier: ^6.7.2
+        version: 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nestjs/jwt':
+        specifier: ^6.1.1
+        version: 6.1.2(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))
+      '@nestjs/passport':
+        specifier: ^6.1.1
+        version: 6.2.0(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(passport@0.4.1)
+      '@nestjs/platform-express':
+        specifier: ^6.11.5
+        version: 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))
+      '@nestjs/swagger':
+        specifier: ^4.8.2
+        version: 4.8.2(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))(class-transformer@0.2.3)(class-validator@0.13.2)(reflect-metadata@0.1.14)(swagger-ui-express@4.6.3(express@4.21.2))
+      '@nestjs/typeorm':
+        specifier: ^6.3.4
+        version: 6.3.4(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))(reflect-metadata@0.1.14)(rxjs@6.6.7)(typeorm@0.2.45(mysql2@3.22.3(@types/node@12.20.55)))
+      '@types/express-serve-static-core':
+        specifier: ^4.19.5
+        version: 4.19.5
+      ali-oss:
+        specifier: ^6.5.1
+        version: 6.23.0
+      axios:
+        specifier: ^0.23.0
+        version: 0.23.0
+      bcryptjs:
+        specifier: ^2.4.3
+        version: 2.4.3
+      body-parser:
+        specifier: ^1.19.0
+        version: 1.20.3
+      chalk:
+        specifier: ^4.1.2
+        version: 4.1.2
+      class-transformer:
+        specifier: ^0.2.3
+        version: 0.2.3
+      commander:
+        specifier: ^9.4.1
+        version: 9.5.0
+      compression:
+        specifier: ^1.7.4
+        version: 1.7.4
+      cross-env:
+        specifier: ^7.0.3
+        version: 7.0.3
+      date-fns:
+        specifier: ^2.17.0
+        version: 2.30.0
+      deepmerge:
+        specifier: ^4.2.2
+        version: 4.3.1
+      dotenv:
+        specifier: ^8.2.0
+        version: 8.6.0
+      express:
+        specifier: ^4.18.2
+        version: 4.21.2
+      express-rate-limit:
+        specifier: ^5.0.0
+        version: 5.5.1
+      fs-extra:
+        specifier: ^10.0.0
+        version: 10.1.0
+      helmet:
+        specifier: ^3.21.2
+        version: 3.23.3
+      highlight.js:
+        specifier: ^9.18.0
+        version: 9.18.5
+      inquirer:
+        specifier: ^8.2.4
+        version: 8.2.7(@types/node@12.20.55)
+      lodash:
+        specifier: ^4.17.21
+        version: 4.17.21
+      log4js:
+        specifier: ^6.1.0
+        version: 6.9.1
+      marked:
+        specifier: ^0.8.0
+        version: 0.8.2
+      mysql2:
+        specifier: ^3.12.0
+        version: 3.22.3(@types/node@12.20.55)
+      node-ip2region:
+        specifier: ^1.0.2
+        version: 1.0.2
+      nodemailer:
+        specifier: ^6.4.2
+        version: 6.10.1
+      nuid:
+        specifier: ^1.1.0
+        version: 1.1.6
+      open:
+        specifier: ^8.2.1
+        version: 8.4.2
+      passport:
+        specifier: ^0.4.1
+        version: 0.4.1
+      passport-jwt:
+        specifier: ^4.0.0
+        version: 4.0.1
+      pm2:
+        specifier: ^5.2.0
+        version: 5.4.3
+      reflect-metadata:
+        specifier: ^0.1.13
+        version: 0.1.14
+      rimraf:
+        specifier: ^3.0.0
+        version: 3.0.2
+      rxjs:
+        specifier: ^6.5.3
+        version: 6.6.7
+      segment:
+        specifier: ^0.1.3
+        version: 0.1.3
+      swagger-themes:
+        specifier: ^1.4.3
+        version: 1.4.3
+      swagger-ui-express:
+        specifier: ^4.1.6
+        version: 4.6.3(express@4.21.2)
+      typeorm:
+        specifier: ^0.2.45
+        version: 0.2.45(mysql2@3.22.3(@types/node@12.20.55))
+      ua-parser-js:
+        specifier: ^0.7.28
+        version: 0.7.39
+    devDependencies:
+      '@nestjs/schematics':
+        specifier: ^6.7.0
+        version: 6.9.4(typescript@4.1.6)
+      '@nestjs/testing':
+        specifier: ^6.7.1
+        version: 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))
+      '@types/express':
+        specifier: 4.17.18
+        version: 4.17.18
+      '@types/jest':
+        specifier: ^24.0.18
+        version: 24.9.1
+      '@types/node':
+        specifier: ^12.7.5
+        version: 12.20.55
+      '@types/supertest':
+        specifier: ^2.0.8
+        version: 2.0.16
+      '@typescript-eslint/eslint-plugin':
+        specifier: ^5.21.0
+        version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1)(typescript@4.1.6)
+      '@typescript-eslint/parser':
+        specifier: ^5.21.0
+        version: 5.62.0(eslint@8.57.1)(typescript@4.1.6)
+      eslint:
+        specifier: ^8.15.0
+        version: 8.57.1
+      eslint-config-prettier:
+        specifier: ^8.5.0
+        version: 8.10.0(eslint@8.57.1)
+      eslint-plugin-import:
+        specifier: ^2.26.0
+        version: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1)
+      eslint-plugin-prettier:
+        specifier: ^4.0.0
+        version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@1.19.1)
+      eslint-plugin-simple-import-sort:
+        specifier: ^7.0.0
+        version: 7.0.0(eslint@8.57.1)
+      jest:
+        specifier: ^24.9.0
+        version: 24.9.0
+      next-transpile-modules:
+        specifier: ^6.3.0
+        version: 6.4.1
+      prettier:
+        specifier: ^1.18.2
+        version: 1.19.1
+      supertest:
+        specifier: ^4.0.2
+        version: 4.0.2
+      ts-jest:
+        specifier: ^24.1.0
+        version: 24.3.0(jest@24.9.0)
+      ts-loader:
+        specifier: ^6.1.1
+        version: 6.2.2(typescript@4.1.6)
+      ts-node:
+        specifier: ^8.4.1
+        version: 8.10.2(typescript@4.1.6)
+      tsconfig-paths:
+        specifier: ^3.9.0
+        version: 3.15.0
+      tslint:
+        specifier: ^5.20.0
+        version: 5.20.1(typescript@4.1.6)
+      typescript:
+        specifier: ~4.1.6
+        version: 4.1.6
+
   templates/hello-world:
     dependencies:
       '@fecommunity/reactpress-toolkit':
@@ -483,6 +700,19 @@ packages:
     resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
     engines: {node: '>=6.0.0'}
 
+  '@angular-devkit/core@7.3.8':
+    resolution: {integrity: sha512-3X9uzaZXFpm5o2TSzhD6wEOtVU32CgeytKjD1Scxj+uMMVo48SWLlKiFh312T+smI9ko7tOT8VqxglwYkWosgg==}
+    engines: {node: '>= 8.9.0', npm: '>= 5.5.1'}
+
+  '@angular-devkit/schematics-cli@0.13.8':
+    resolution: {integrity: sha512-PnVetGOLqONNhKcUfJoCRUJU8BSpcTZpWwQS6YywyNrvyVXtnUi/dgMTQkS8fva3XC/5Ij3Mj7yrfTHaG7M7bw==}
+    engines: {node: '>= 8.9.0', npm: '>= 5.5.1'}
+    hasBin: true
+
+  '@angular-devkit/schematics@7.3.8':
+    resolution: {integrity: sha512-mvaKoORZIaW/h0VNZ3IQWP0qThRCZRX6869FNlzV0jlW0mhn07XbiIGHCGGSCDRxS7qJ0VbuIVnKXntF+iDeWw==}
+    engines: {node: '>= 8.9.0', npm: '>= 5.5.1'}
+
   '@ant-design/colors@6.0.0':
     resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==}
 
@@ -577,10 +807,6 @@ packages:
     peerDependencies:
       ajv: '>=8'
 
-  '@babel/code-frame@7.24.7':
-    resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
-    engines: {node: '>=6.9.0'}
-
   '@babel/code-frame@7.26.2':
     resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
     engines: {node: '>=6.9.0'}
@@ -747,10 +973,6 @@ packages:
     resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-validator-identifier@7.25.9':
-    resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
-    engines: {node: '>=6.9.0'}
-
   '@babel/helper-validator-identifier@7.27.1':
     resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
     engines: {node: '>=6.9.0'}
@@ -779,10 +1001,6 @@ packages:
     resolution: {integrity: sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/highlight@7.24.7':
-    resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
-    engines: {node: '>=6.9.0'}
-
   '@babel/parser@7.25.6':
     resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==}
     engines: {node: '>=6.0.0'}
@@ -2272,10 +2490,18 @@ packages:
     resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
 
+  '@eslint/eslintrc@2.1.4':
+    resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
   '@eslint/eslintrc@3.3.1':
     resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
+  '@eslint/js@8.57.1':
+    resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
   '@eslint/js@9.36.0':
     resolution: {integrity: sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -2325,6 +2551,11 @@ packages:
     resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
     engines: {node: '>=18.18.0'}
 
+  '@humanwhocodes/config-array@0.13.0':
+    resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
+    engines: {node: '>=10.10.0'}
+    deprecated: Use @eslint/config-array instead
+
   '@humanwhocodes/config-array@0.9.5':
     resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==}
     engines: {node: '>=10.10.0'}
@@ -2338,6 +2569,10 @@ packages:
     resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
     deprecated: Use @eslint/object-schema instead
 
+  '@humanwhocodes/object-schema@2.0.3':
+    resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+    deprecated: Use @eslint/object-schema instead
+
   '@humanwhocodes/retry@0.4.3':
     resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
     engines: {node: '>=18.18'}
@@ -2468,6 +2703,90 @@ packages:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
       react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
 
+  '@nestjs/cli@6.14.2':
+    resolution: {integrity: sha512-Bv6ZoziyuXrCmeWMf4rcEjN84O4RmZtQugscFm0k2nOWVfW79eltqMJlpj6h9IutLLC52Je/SOw0XTiDGOukyg==}
+    engines: {node: '>= 8.9.0', npm: '>= 5.5.1'}
+    hasBin: true
+
+  '@nestjs/common@6.11.11':
+    resolution: {integrity: sha512-K4wuK/V2M82AsoudtY0UYV+M1nYDSSb10t8AkMwFiP+AWMuxCJNtE8qLc9jUe2aTKMbhBiQUfsbZFmg/MRinPg==}
+    peerDependencies:
+      reflect-metadata: ^0.1.12
+      rxjs: ^6.0.0
+
+  '@nestjs/config@0.6.3':
+    resolution: {integrity: sha512-JxvvUpmH0/WOrTB+zh8dEkxSUQXhB7V3d/qeQXyCnMiEFjaq89+fNFztpWjz4DlOfdS4/eYTzIEy9PH2uGnfzA==}
+    peerDependencies:
+      '@nestjs/common': ^6.10.0 || ^7.0.0
+      reflect-metadata: ^0.1.12
+      rxjs: ^6.0.0
+
+  '@nestjs/core@6.11.11':
+    resolution: {integrity: sha512-ewUy2rjiRWi6SziI5gXZnlat7PfnVklL3tusnU1qqtUm74cPY1Zre+zDCJ27P/+B7sFJHbkFfpi0qQP2pQv9jQ==}
+    peerDependencies:
+      '@nestjs/common': ^6.0.0
+      reflect-metadata: ^0.1.12
+      rxjs: ^6.0.0
+
+  '@nestjs/jwt@6.1.2':
+    resolution: {integrity: sha512-+qfcAeAuZiwGRj5WqmDCtzhlY109l2e6QJR4K2ANu1UJskxxaD9O7QS8SGegzpfTaIL01NAF8BWNxwy5ps6Lzg==}
+    peerDependencies:
+      '@nestjs/common': ^6.0.0
+
+  '@nestjs/mapped-types@0.4.1':
+    resolution: {integrity: sha512-JXrw2LMangSU3vnaXWXVX47GRG1FbbNh4aVBbidDjxT3zlghsoNQY6qyWtT001MCl8lJGo8I6i6+DurBRRxl/Q==}
+    peerDependencies:
+      '@nestjs/common': ^7.0.8
+      class-transformer: ^0.2.0 || ^0.3.0 || ^0.4.0
+      class-validator: ^0.11.1 || ^0.12.0 || ^0.13.0
+      reflect-metadata: ^0.1.12
+
+  '@nestjs/passport@6.2.0':
+    resolution: {integrity: sha512-Wy8FeSCNxbfTKRe/mJk0w5hSLsqoNMehg6DUQOoDug+6Uaq+QLEy6wvGPUJbVqGKpJwFHGgUoWp2ag05zh4zpA==}
+    peerDependencies:
+      '@nestjs/common': ^6.0.0
+      passport: ^0.4.0
+
+  '@nestjs/platform-express@6.11.11':
+    resolution: {integrity: sha512-4h3F3hDhNlO5+Ruy6eS+lSL2yIz5r4hF/BB3QkZVOuRdfji9n0gZAIR7tuSLTizqYxaHYRZ7dBv+PscQS/7ztQ==}
+    peerDependencies:
+      '@nestjs/common': ^6.0.0
+      '@nestjs/core': ^6.0.0
+
+  '@nestjs/schematics@6.9.4':
+    resolution: {integrity: sha512-tZoLDboqXQT+DcWUFTJyDsOIg9Qt6ilXYWWbrbbEPCP2+UKjfsqZPsEnG31DOj0IbovFS5g+Mbn3IanVsEcIsQ==}
+    peerDependencies:
+      typescript: ^3.4.5
+
+  '@nestjs/swagger@4.8.2':
+    resolution: {integrity: sha512-RSUwcVxrzXF7/b/IZ5lXnYHJ6jIGS9wWRTJKIt1kIaCNWT+0wRfTlAyhQkzs2g35/PTXJEcdIwwY7mBO/bwHzw==}
+    peerDependencies:
+      '@nestjs/common': ^6.8.0 || ^7.0.0
+      '@nestjs/core': ^6.8.0 || ^7.0.0
+      fastify-swagger: '*'
+      reflect-metadata: ^0.1.12
+      swagger-ui-express: '*'
+    peerDependenciesMeta:
+      fastify-swagger:
+        optional: true
+      swagger-ui-express:
+        optional: true
+
+  '@nestjs/testing@6.11.11':
+    resolution: {integrity: sha512-Mqu4IWZhnLdIFfVfueAFFCm3jPfQoWg+YmDLBsFS2kpab3az5gsRCZQv9R9CCHGa1hHKYWqM1lMcz1IQc70kww==}
+    peerDependencies:
+      '@nestjs/common': ^6.0.0
+      '@nestjs/core': ^6.0.0
+
+  '@nestjs/typeorm@6.3.4':
+    resolution: {integrity: sha512-qMUHaTMo+U5WOlMfL0ogNm8C2T/Kej/v+NnjSixx/UmtluLvTbNYuZUfbHI9ePCmtCXDV0lMRvIAi+U5LCjsbA==}
+    peerDependencies:
+      '@nestjs/common': ^6.7.0
+      '@nestjs/core': ^6.7.0
+      reflect-metadata: ^0.1.12
+      rxjs: ^6.0.0
+      typeorm: ^0.2.7
+
   '@next/env@12.3.4':
     resolution: {integrity: sha512-H/69Lc5Q02dq3o+dxxy5O/oNxFsZpdL6WREtOOtOM1B/weonIwDXkekr1KV5DPVPr12IHFPrMrcJQ6bgPMfn7A==}
 
@@ -2564,6 +2883,25 @@ packages:
     resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
     engines: {node: '>= 8'}
 
+  '@nuxtjs/opencollective@0.2.2':
+    resolution: {integrity: sha512-69gFVDs7mJfNjv9Zs5DFVD+pvBW+k1TaHSOqUWqAyTTfLcKI/EMYQgvEvziRd+zAFtUOoye6MfWh0qvinGISPw==}
+    engines: {node: '>=8.0.0', npm: '>=5.0.0'}
+    hasBin: true
+
+  '@pm2/agent@2.0.4':
+    resolution: {integrity: sha512-n7WYvvTJhHLS2oBb1PjOtgLpMhgImOq8sXkPBw6smeg9LJBWZjiEgPKOpR8mn9UJZsB5P3W4V/MyvNnp31LKeA==}
+
+  '@pm2/io@6.0.1':
+    resolution: {integrity: sha512-KiA+shC6sULQAr9mGZ1pg+6KVW9MF8NpG99x26Lf/082/Qy8qsTCtnJy+HQReW1A9Rdf0C/404cz0RZGZro+IA==}
+    engines: {node: '>=6.0'}
+
+  '@pm2/js-api@0.8.0':
+    resolution: {integrity: sha512-nmWzrA/BQZik3VBz+npRcNIu01kdBhWL0mxKmP1ciF/gTcujPTQqt027N9fc1pK9ERM8RipFhymw7RcmCyOEYA==}
+    engines: {node: '>=4.0'}
+
+  '@pm2/pm2-version-check@1.0.4':
+    resolution: {integrity: sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==}
+
   '@pnpm/config.env-replace@1.1.0':
     resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
     engines: {node: '>=12.22.0'}
@@ -2843,6 +3181,13 @@ packages:
   '@rushstack/eslint-patch@1.10.4':
     resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==}
 
+  '@scarf/scarf@1.4.0':
+    resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
+
+  '@schematics/schematics@0.13.8':
+    resolution: {integrity: sha512-7Bqw2DzCbt7EkR0IYDEUXJ6WQjE90NqSMFqK0Lylps0WswJfjUq5axJduz5LwbmrIDhWdDhXMtI4QimUBm4Qsw==}
+    engines: {node: '>= 8.9.0', npm: '>= 5.5.1'}
+
   '@sideway/address@4.1.5':
     resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
 
@@ -2878,6 +3223,9 @@ packages:
   '@slorber/remark-comment@1.0.0':
     resolution: {integrity: sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==}
 
+  '@sqltools/formatter@1.2.5':
+    resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==}
+
   '@surma/rollup-plugin-off-main-thread@2.2.3':
     resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
 
@@ -2989,6 +3337,9 @@ packages:
       '@types/react-dom':
         optional: true
 
+  '@tootallnate/quickjs-emscripten@0.23.0':
+    resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
+
   '@trysound/sax@0.2.0':
     resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
     engines: {node: '>=10.13.0'}
@@ -2996,6 +3347,10 @@ packages:
   '@types/acorn@4.0.6':
     resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==}
 
+  '@types/anymatch@3.0.4':
+    resolution: {integrity: sha512-9u8Rl6ILxwTPYXvLjcYZsLnrj2acjmYrmQeqtrA2iR0LN98ctu1fzR02mfWRGXouMK30GtjhPTaC7xye/MK0QQ==}
+    deprecated: This is a stub types definition. anymatch provides its own type definitions, so you do not need this installed.
+
   '@types/aria-query@5.0.4':
     resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
 
@@ -3023,6 +3378,9 @@ packages:
   '@types/connect@3.4.38':
     resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
 
+  '@types/cookiejar@2.1.5':
+    resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==}
+
   '@types/debounce@1.2.4':
     resolution: {integrity: sha512-jBqiORIzKDOToaF63Fm//haOCHuwQuLa2202RK4MozpA6lh93eCBc+/8+wZn5OzjJt3ySdc+74SXWXB55Ewtyw==}
 
@@ -3098,12 +3456,18 @@ packages:
   '@types/json5@0.0.29':
     resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
 
+  '@types/jsonwebtoken@8.3.7':
+    resolution: {integrity: sha512-B5SSifLkjB0ns7VXpOOtOUlynE78/hKcY8G8pOAhkLJZinwofIBYqz555nRj2W9iDWZqFhK5R+7NZDaRmKWAoQ==}
+
   '@types/mdast@4.0.4':
     resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
 
   '@types/mdx@2.0.13':
     resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==}
 
+  '@types/methods@1.1.4':
+    resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==}
+
   '@types/mime@1.3.5':
     resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
 
@@ -3119,6 +3483,9 @@ packages:
   '@types/node-forge@1.3.11':
     resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==}
 
+  '@types/node@12.20.55':
+    resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
+
   '@types/node@17.0.22':
     resolution: {integrity: sha512-8FwbVoG4fy+ykY86XCAclKZDORttqE5/s7dyWZKLXTdv3vRy5HozBEinG5IqhvPXXzIZEcTVbuHlQEI6iuwcmw==}
 
@@ -3191,24 +3558,45 @@ packages:
   '@types/sockjs@0.3.36':
     resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==}
 
+  '@types/source-list-map@0.1.6':
+    resolution: {integrity: sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==}
+
   '@types/stack-utils@1.0.1':
     resolution: {integrity: sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==}
 
   '@types/stack-utils@2.0.3':
     resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
 
+  '@types/superagent@8.1.9':
+    resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==}
+
+  '@types/supertest@2.0.16':
+    resolution: {integrity: sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==}
+
   '@types/swagger-schema-official@2.0.22':
     resolution: {integrity: sha512-7yQiX6MWSFSvc/1wW5smJMZTZ4fHOd+hqLr3qr/HONDxHEa2bnYAsOcGBOEqFIjd4yetwMOdEDdeW+udRAQnHA==}
 
+  '@types/tapable@2.3.0':
+    resolution: {integrity: sha512-oMnbAXeVo+KUnje3hzdORXUbfnzTfqD0H92mLl19NE5hFqH9Q4ktq+xehNSxcNeeLm1COopYwa0zeP6Iz+oIXg==}
+
   '@types/trusted-types@2.0.7':
     resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
 
+  '@types/uglify-js@3.17.5':
+    resolution: {integrity: sha512-TU+fZFBTBcXj/GpDpDaBmgWk/gn96kMZ+uocaFUlV2f8a6WdMzzI44QBCmGcCiYR0Y6ZlNRiyUyKKt5nl/lbzQ==}
+
   '@types/unist@2.0.11':
     resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
 
   '@types/unist@3.0.3':
     resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
 
+  '@types/webpack-sources@3.2.3':
+    resolution: {integrity: sha512-4nZOdMwSPHZ4pTEZzSp0AsTM4K7Qmu40UKW4tJDiOVs20UzYF9l+qUe4s0ftfN0pin06n+5cWWDJXH+sbhAiDw==}
+
+  '@types/webpack@4.41.5':
+    resolution: {integrity: sha512-693JfV/83UZxpQY8vutDSwkDjNujy2327UrFqQciJWXh761B/aUIZIM5N05IRIZ17WwsG8VfUSE3edwXvkehiQ==}
+
   '@types/webxr@0.5.20':
     resolution: {integrity: sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==}
 
@@ -3227,6 +3615,9 @@ packages:
   '@types/yargs@17.0.33':
     resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
 
+  '@types/zen-observable@0.8.3':
+    resolution: {integrity: sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==}
+
   '@typescript-eslint/eslint-plugin@5.62.0':
     resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -3295,52 +3686,107 @@ packages:
 
   '@ungap/structured-clone@1.2.0':
     resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+    deprecated: Potential CWE-502 - Update to 1.3.1 or higher
 
   '@webassemblyjs/ast@1.14.1':
     resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==}
 
+  '@webassemblyjs/ast@1.8.5':
+    resolution: {integrity: sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==}
+
   '@webassemblyjs/floating-point-hex-parser@1.13.2':
     resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==}
 
+  '@webassemblyjs/floating-point-hex-parser@1.8.5':
+    resolution: {integrity: sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==}
+
   '@webassemblyjs/helper-api-error@1.13.2':
     resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==}
 
+  '@webassemblyjs/helper-api-error@1.8.5':
+    resolution: {integrity: sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==}
+
   '@webassemblyjs/helper-buffer@1.14.1':
     resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==}
 
+  '@webassemblyjs/helper-buffer@1.8.5':
+    resolution: {integrity: sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==}
+
+  '@webassemblyjs/helper-code-frame@1.8.5':
+    resolution: {integrity: sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==}
+
+  '@webassemblyjs/helper-fsm@1.8.5':
+    resolution: {integrity: sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==}
+
+  '@webassemblyjs/helper-module-context@1.8.5':
+    resolution: {integrity: sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==}
+
   '@webassemblyjs/helper-numbers@1.13.2':
     resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==}
 
   '@webassemblyjs/helper-wasm-bytecode@1.13.2':
     resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==}
 
+  '@webassemblyjs/helper-wasm-bytecode@1.8.5':
+    resolution: {integrity: sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==}
+
   '@webassemblyjs/helper-wasm-section@1.14.1':
     resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==}
 
+  '@webassemblyjs/helper-wasm-section@1.8.5':
+    resolution: {integrity: sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==}
+
   '@webassemblyjs/ieee754@1.13.2':
     resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==}
 
+  '@webassemblyjs/ieee754@1.8.5':
+    resolution: {integrity: sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==}
+
   '@webassemblyjs/leb128@1.13.2':
     resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==}
 
+  '@webassemblyjs/leb128@1.8.5':
+    resolution: {integrity: sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==}
+
   '@webassemblyjs/utf8@1.13.2':
     resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==}
 
+  '@webassemblyjs/utf8@1.8.5':
+    resolution: {integrity: sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==}
+
   '@webassemblyjs/wasm-edit@1.14.1':
     resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==}
 
+  '@webassemblyjs/wasm-edit@1.8.5':
+    resolution: {integrity: sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==}
+
   '@webassemblyjs/wasm-gen@1.14.1':
     resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==}
 
+  '@webassemblyjs/wasm-gen@1.8.5':
+    resolution: {integrity: sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==}
+
   '@webassemblyjs/wasm-opt@1.14.1':
     resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==}
 
+  '@webassemblyjs/wasm-opt@1.8.5':
+    resolution: {integrity: sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==}
+
   '@webassemblyjs/wasm-parser@1.14.1':
     resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==}
 
+  '@webassemblyjs/wasm-parser@1.8.5':
+    resolution: {integrity: sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==}
+
+  '@webassemblyjs/wast-parser@1.8.5':
+    resolution: {integrity: sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==}
+
   '@webassemblyjs/wast-printer@1.14.1':
     resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==}
 
+  '@webassemblyjs/wast-printer@1.8.5':
+    resolution: {integrity: sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==}
+
   '@xtuc/ieee754@1.2.0':
     resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
 
@@ -3418,10 +3864,23 @@ packages:
     resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==}
     engines: {node: '>= 10.0.0'}
 
+  agent-base@7.1.4:
+    resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
+    engines: {node: '>= 14'}
+
+  agentkeepalive@3.5.3:
+    resolution: {integrity: sha512-yqXL+k5rr8+ZRpOAntkaaRgWgE5o8ESAj5DyRmVTCSoZxXmqemb9Dd7T4i5UzwuERdLAJUy6XzR9zFVuf0kzkw==}
+    engines: {node: '>= 4.0.0'}
+
   aggregate-error@3.1.0:
     resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
     engines: {node: '>=8'}
 
+  ajv-errors@1.0.1:
+    resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==}
+    peerDependencies:
+      ajv: '>=5.0.0'
+
   ajv-formats@2.1.1:
     resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
     peerDependencies:
@@ -3443,6 +3902,9 @@ packages:
   ajv@6.12.6:
     resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
 
+  ajv@6.9.1:
+    resolution: {integrity: sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==}
+
   ajv@8.17.1:
     resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
 
@@ -3455,6 +3917,16 @@ packages:
     resolution: {integrity: sha512-iNC6BGvipaalFfDfDnXUje8GUlW5asj0cTMsZJwO/0rhsyLx1L7GZFAY8wW+eQ6AM4Yge2p5GSE5hrBlfSD90Q==}
     engines: {node: '>= 14.0.0'}
 
+  ali-oss@6.23.0:
+    resolution: {integrity: sha512-FipRmyd16Pr/tEey/YaaQ/24Pc3HEpLM9S1DRakEuXlSLXNIJnu1oJtHM53eVYpvW3dXapSjrip3xylZUTIZVQ==}
+    engines: {node: '>=8'}
+
+  amp-message@0.1.2:
+    resolution: {integrity: sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg==}
+
+  amp@0.3.1:
+    resolution: {integrity: sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw==}
+
   anser@1.4.10:
     resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==}
 
@@ -3481,6 +3953,10 @@ packages:
     engines: {'0': node >= 0.8.0}
     hasBin: true
 
+  ansi-regex@2.1.1:
+    resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==}
+    engines: {node: '>=0.10.0'}
+
   ansi-regex@3.0.1:
     resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==}
     engines: {node: '>=4'}
@@ -3497,6 +3973,10 @@ packages:
     resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
     engines: {node: '>=12'}
 
+  ansi-styles@2.2.1:
+    resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
+    engines: {node: '>=0.10.0'}
+
   ansi-styles@3.2.1:
     resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
     engines: {node: '>=4'}
@@ -3519,6 +3999,9 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
 
+  any-promise@1.3.0:
+    resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+
   anymatch@2.0.0:
     resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==}
 
@@ -3526,9 +4009,22 @@ packages:
     resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
     engines: {node: '>= 8'}
 
+  app-root-path@3.1.0:
+    resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==}
+    engines: {node: '>= 6.0.0'}
+
   appdirsjs@1.2.7:
     resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==}
 
+  append-field@1.0.0:
+    resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==}
+
+  aproba@1.2.0:
+    resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==}
+
+  arg@4.1.3:
+    resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+
   arg@5.0.2:
     resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
 
@@ -3628,6 +4124,9 @@ packages:
   asap@2.0.6:
     resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
 
+  asn1.js@4.10.1:
+    resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==}
+
   asn1@0.2.6:
     resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
 
@@ -3635,6 +4134,9 @@ packages:
     resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
     engines: {node: '>=0.8'}
 
+  assert@1.5.1:
+    resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==}
+
   assign-symbols@1.0.0:
     resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==}
     engines: {node: '>=0.10.0'}
@@ -3642,6 +4144,10 @@ packages:
   ast-types-flow@0.0.8:
     resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
 
+  ast-types@0.13.4:
+    resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
+    engines: {node: '>=4'}
+
   ast-types@0.15.2:
     resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==}
     engines: {node: '>=4'}
@@ -3658,12 +4164,18 @@ packages:
     resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
     hasBin: true
 
+  async-each@1.0.6:
+    resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==}
+
   async-limiter@1.0.1:
     resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==}
 
   async-validator@1.11.5:
     resolution: {integrity: sha512-XNtCsMAeAH1pdLMEg1z8/Bb3a8cdCbui9QbJATRFHHHW5kT6+NPI3zSVQUXgikTFITzsg+kYY5NTWhM2Orwt9w==}
 
+  async@2.6.4:
+    resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==}
+
   async@3.2.6:
     resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
 
@@ -3704,6 +4216,10 @@ packages:
     resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==}
     engines: {node: '>=4'}
 
+  axios@0.19.2:
+    resolution: {integrity: sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==}
+    deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410
+
   axios@0.23.0:
     resolution: {integrity: sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==}
 
@@ -3714,6 +4230,9 @@ packages:
     resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
     engines: {node: '>= 0.4'}
 
+  babel-code-frame@6.26.0:
+    resolution: {integrity: sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==}
+
   babel-core@7.0.0-bridge.0:
     resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==}
     peerDependencies:
@@ -3795,15 +4314,26 @@ packages:
     resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
     engines: {node: '>=0.10.0'}
 
+  basic-ftp@5.3.1:
+    resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==}
+    engines: {node: '>=10.0.0'}
+
   batch@0.6.1:
     resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==}
 
   bcrypt-pbkdf@1.0.2:
     resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
 
+  bcryptjs@2.4.3:
+    resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==}
+
   big.js@5.2.2:
     resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
 
+  binary-extensions@1.13.1:
+    resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==}
+    engines: {node: '>=0.10.0'}
+
   binary-extensions@2.3.0:
     resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
     engines: {node: '>=8'}
@@ -3814,6 +4344,27 @@ packages:
   bl@4.1.0:
     resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
 
+  blessed@0.1.81:
+    resolution: {integrity: sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==}
+    engines: {node: '>= 0.8.0'}
+    hasBin: true
+
+  bluebird@3.7.2:
+    resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
+
+  bn.js@4.12.3:
+    resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==}
+
+  bn.js@5.2.3:
+    resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==}
+
+  bodec@0.1.0:
+    resolution: {integrity: sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==}
+
+  body-parser@1.19.0:
+    resolution: {integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==}
+    engines: {node: '>= 0.8'}
+
   body-parser@1.20.3:
     resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
     engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -3828,6 +4379,12 @@ packages:
   boolbase@1.0.0:
     resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
 
+  bowser@1.9.4:
+    resolution: {integrity: sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==}
+
+  bowser@2.9.0:
+    resolution: {integrity: sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==}
+
   boxen@6.2.1:
     resolution: {integrity: sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==}
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -3850,12 +4407,35 @@ packages:
     resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
     engines: {node: '>=8'}
 
+  brorand@1.1.0:
+    resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==}
+
   browser-process-hrtime@1.0.0:
     resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==}
 
   browser-resolve@1.11.3:
     resolution: {integrity: sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==}
 
+  browserify-aes@1.2.0:
+    resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==}
+
+  browserify-cipher@1.0.1:
+    resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==}
+
+  browserify-des@1.0.2:
+    resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==}
+
+  browserify-rsa@4.1.1:
+    resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==}
+    engines: {node: '>= 0.10'}
+
+  browserify-sign@4.2.5:
+    resolution: {integrity: sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==}
+    engines: {node: '>= 0.10'}
+
+  browserify-zlib@0.2.0:
+    resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==}
+
   browserslist@4.23.3:
     resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==}
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -3873,27 +4453,54 @@ packages:
   bser@2.1.1:
     resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
 
+  buffer-equal-constant-time@1.0.1:
+    resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
+
   buffer-from@1.1.2:
     resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
 
+  buffer-xor@1.0.3:
+    resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==}
+
+  buffer@4.9.2:
+    resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==}
+
   buffer@5.7.1:
     resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
 
   buffer@6.0.3:
     resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
 
+  builtin-modules@1.1.1:
+    resolution: {integrity: sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==}
+    engines: {node: '>=0.10.0'}
+
   builtin-modules@3.3.0:
     resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
     engines: {node: '>=6'}
 
+  builtin-status-codes@3.0.0:
+    resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==}
+
+  busboy@0.2.14:
+    resolution: {integrity: sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==}
+    engines: {node: '>=0.8.0'}
+
   bytes@3.0.0:
     resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
     engines: {node: '>= 0.8'}
 
+  bytes@3.1.0:
+    resolution: {integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==}
+    engines: {node: '>= 0.8'}
+
   bytes@3.1.2:
     resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
     engines: {node: '>= 0.8'}
 
+  cacache@12.0.4:
+    resolution: {integrity: sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==}
+
   cache-base@1.0.1:
     resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
     engines: {node: '>=0.10.0'}
@@ -3914,6 +4521,10 @@ packages:
     resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
     engines: {node: '>= 0.4'}
 
+  call-bind@1.0.9:
+    resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==}
+    engines: {node: '>= 0.4'}
+
   call-bound@1.0.4:
     resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
     engines: {node: '>= 0.4'}
@@ -3960,6 +4571,9 @@ packages:
     resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==}
     engines: {node: '>=14.16'}
 
+  camelize@1.0.0:
+    resolution: {integrity: sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==}
+
   caniuse-api@3.0.0:
     resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
 
@@ -3976,10 +4590,18 @@ packages:
   ccount@2.0.1:
     resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
 
+  chalk@1.1.3:
+    resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
+    engines: {node: '>=0.10.0'}
+
   chalk@2.4.2:
     resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
     engines: {node: '>=4'}
 
+  chalk@3.0.0:
+    resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
+    engines: {node: '>=8'}
+
   chalk@4.1.2:
     resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
     engines: {node: '>=10'}
@@ -4004,9 +4626,15 @@ packages:
   character-reference-invalid@2.0.1:
     resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
 
+  chardet@0.7.0:
+    resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
+
   chardet@2.1.0:
     resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==}
 
+  charm@0.1.2:
+    resolution: {integrity: sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ==}
+
   cheerio-select@2.1.0:
     resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
 
@@ -4014,6 +4642,12 @@ packages:
     resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
     engines: {node: '>= 6'}
 
+  chokidar@2.0.4:
+    resolution: {integrity: sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==}
+
+  chokidar@2.1.8:
+    resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==}
+
   chokidar@3.6.0:
     resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
     engines: {node: '>= 8.10.0'}
@@ -4022,6 +4656,9 @@ packages:
     resolution: {integrity: sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==}
     engines: {node: '>= 14.16.0'}
 
+  chownr@1.1.4:
+    resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+
   chrome-launcher@0.15.2:
     resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==}
     engines: {node: '>=12.13.0'}
@@ -4041,10 +4678,20 @@ packages:
     resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
     engines: {node: '>=8'}
 
+  cipher-base@1.0.7:
+    resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==}
+    engines: {node: '>= 0.10'}
+
+  class-transformer@0.2.3:
+    resolution: {integrity: sha512-qsP+0xoavpOlJHuYsQJsN58HXSl8Jvveo+T37rEvCEeRfMWoytAyR0Ua/YsFgpM6AZYZ/og2PJwArwzJl1aXtQ==}
+
   class-utils@0.3.6:
     resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
     engines: {node: '>=0.10.0'}
 
+  class-validator@0.13.2:
+    resolution: {integrity: sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==}
+
   classnames@2.5.1:
     resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
 
@@ -4066,6 +4713,13 @@ packages:
     resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
     engines: {node: '>=10'}
 
+  cli-color@2.0.0:
+    resolution: {integrity: sha512-a0VZ8LeraW0jTuCkuAGMNufareGHhyZU9z8OGsW0gXd1hZGi1SRuNRXdbGkraBBKnhyUhyebFWnRbp+dIn0f0A==}
+
+  cli-cursor@2.1.0:
+    resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==}
+    engines: {node: '>=4'}
+
   cli-cursor@3.1.0:
     resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
     engines: {node: '>=8'}
@@ -4074,14 +4728,27 @@ packages:
     resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==}
     engines: {node: '>=18'}
 
+  cli-highlight@2.1.11:
+    resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==}
+    engines: {node: '>=8.0.0', npm: '>=5.0.0'}
+    hasBin: true
+
   cli-spinners@2.9.2:
     resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
     engines: {node: '>=6'}
 
+  cli-table3@0.5.1:
+    resolution: {integrity: sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==}
+    engines: {node: '>=6'}
+
   cli-table3@0.6.5:
     resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==}
     engines: {node: 10.* || >= 12.*}
 
+  cli-tableau@2.0.1:
+    resolution: {integrity: sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==}
+    engines: {node: '>=8.10.0'}
+
   cli-truncate@2.1.0:
     resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
     engines: {node: '>=8'}
@@ -4090,6 +4757,9 @@ packages:
     resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
 
+  cli-width@2.2.1:
+    resolution: {integrity: sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==}
+
   cli-width@3.0.0:
     resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
     engines: {node: '>= 10'}
@@ -4155,6 +4825,10 @@ packages:
   colorette@2.0.20:
     resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
 
+  colors@1.4.0:
+    resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
+    engines: {node: '>=0.1.90'}
+
   combine-promises@1.2.0:
     resolution: {integrity: sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==}
     engines: {node: '>=10'}
@@ -4177,9 +4851,16 @@ packages:
     resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
     engines: {node: '>=18'}
 
+  commander@2.15.1:
+    resolution: {integrity: sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==}
+
   commander@2.20.3:
     resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
 
+  commander@4.1.1:
+    resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+    engines: {node: '>= 6'}
+
   commander@5.1.0:
     resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
     engines: {node: '>= 6'}
@@ -4232,6 +4913,10 @@ packages:
   concat-map@0.0.1:
     resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
 
+  concat-stream@1.6.2:
+    resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
+    engines: {'0': node >= 0.8}
+
   concurrently@7.6.0:
     resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==}
     engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0}
@@ -4252,14 +4937,27 @@ packages:
     resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==}
     engines: {node: '>= 0.10.0'}
 
+  consola@2.15.3:
+    resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==}
+
   consola@3.4.0:
     resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==}
     engines: {node: ^14.18.0 || >=16.10.0}
 
+  console-browserify@1.2.0:
+    resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==}
+
+  constants-browserify@1.0.0:
+    resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==}
+
   content-disposition@0.5.2:
     resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==}
     engines: {node: '>= 0.6'}
 
+  content-disposition@0.5.3:
+    resolution: {integrity: sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==}
+    engines: {node: '>= 0.6'}
+
   content-disposition@0.5.4:
     resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
     engines: {node: '>= 0.6'}
@@ -4268,6 +4966,10 @@ packages:
     resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
     engines: {node: '>= 0.6'}
 
+  content-security-policy-builder@2.1.0:
+    resolution: {integrity: sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==}
+    engines: {node: '>=4.0.0'}
+
   content-type@1.0.5:
     resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
     engines: {node: '>= 0.6'}
@@ -4352,13 +5054,24 @@ packages:
     resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
     engines: {node: '>=6.6.0'}
 
+  cookie@0.4.0:
+    resolution: {integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==}
+    engines: {node: '>= 0.6'}
+
   cookie@0.7.1:
     resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
     engines: {node: '>= 0.6'}
 
+  cookiejar@2.1.4:
+    resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}
+
   copy-anything@2.0.6:
     resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
 
+  copy-concurrently@1.0.5:
+    resolution: {integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==}
+    deprecated: This package is no longer supported.
+
   copy-descriptor@0.1.1:
     resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==}
     engines: {node: '>=0.10.0'}
@@ -4370,12 +5083,19 @@ packages:
   copy-to-clipboard@3.3.3:
     resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==}
 
+  copy-to@2.0.1:
+    resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==}
+
   copy-webpack-plugin@11.0.0:
     resolution: {integrity: sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==}
     engines: {node: '>= 14.15.0'}
     peerDependencies:
       webpack: ^5.1.0
 
+  copyfiles@2.2.0:
+    resolution: {integrity: sha512-iJbHJI+8OKqsq+4JF0rqgRkZzo++jqO6Wf4FUU1JM41cJF6JcY5968XyF4tm3Kkm7ZOMrqlljdm8N9oyY5raGw==}
+    hasBin: true
+
   core-js-compat@3.38.1:
     resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==}
 
@@ -4402,6 +5122,10 @@ packages:
   core-util-is@1.0.3:
     resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
 
+  cors@2.8.5:
+    resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+    engines: {node: '>= 0.10'}
+
   cosmiconfig@5.2.1:
     resolution: {integrity: sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==}
     engines: {node: '>=4'}
@@ -4432,9 +5156,21 @@ packages:
       typescript:
         optional: true
 
+  create-ecdh@4.0.4:
+    resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==}
+
+  create-hash@1.2.0:
+    resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==}
+
+  create-hmac@1.1.7:
+    resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==}
+
   create-react-class@15.7.0:
     resolution: {integrity: sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==}
 
+  croner@4.1.97:
+    resolution: {integrity: sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==}
+
   cross-env@7.0.3:
     resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
     engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
@@ -4452,6 +5188,10 @@ packages:
     resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
     engines: {node: '>= 8'}
 
+  crypto-browserify@3.12.1:
+    resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==}
+    engines: {node: '>= 0.10'}
+
   crypto-random-string@2.0.0:
     resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
     engines: {node: '>=8'}
@@ -4590,9 +5330,19 @@ packages:
   csstype@3.1.3:
     resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
+  culvert@0.1.2:
+    resolution: {integrity: sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==}
+
   cxs@6.2.0:
     resolution: {integrity: sha512-RGatb1BUwVMBzV8DRo9Kapc55bdGfAxMcukVk+ZzE3Ts8xaTve0GVz730kBDxjhEBU2LK+RPuAcjZb00Q3O24w==}
 
+  cyclist@1.0.2:
+    resolution: {integrity: sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==}
+
+  d@1.0.2:
+    resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
+    engines: {node: '>=0.12'}
+
   damerau-levenshtein@1.0.8:
     resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
 
@@ -4604,10 +5354,17 @@ packages:
     resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
     engines: {node: '>=0.10'}
 
+  dasherize@2.0.0:
+    resolution: {integrity: sha512-APql/TZ6FdLEpf2z7/X2a2zyqK8juYtqaSVqxw9mYoQ64CXkfU15AeLh8pUszT8+fnYjgm6t0aIYpWKJbnLkuA==}
+
   data-uri-to-buffer@4.0.1:
     resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
     engines: {node: '>= 12'}
 
+  data-uri-to-buffer@6.0.2:
+    resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==}
+    engines: {node: '>= 14'}
+
   data-urls@1.1.0:
     resolution: {integrity: sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==}
 
@@ -4627,12 +5384,22 @@ packages:
     resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
     engines: {node: '>=0.11'}
 
+  date-format@4.0.14:
+    resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==}
+    engines: {node: '>=4.0'}
+
+  dateformat@2.2.0:
+    resolution: {integrity: sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==}
+
   dateformat@3.0.3:
     resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==}
 
   dayjs@1.11.13:
     resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
 
+  dayjs@1.8.36:
+    resolution: {integrity: sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==}
+
   debounce@1.2.1:
     resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==}
 
@@ -4644,6 +5411,14 @@ packages:
       supports-color:
         optional: true
 
+  debug@3.1.0:
+    resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
   debug@3.2.7:
     resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
     peerDependencies:
@@ -4708,6 +5483,10 @@ packages:
     resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==}
     engines: {node: '>= 10'}
 
+  default-user-agent@1.0.0:
+    resolution: {integrity: sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==}
+    engines: {node: '>= 0.10.0'}
+
   defaults@1.0.4:
     resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
 
@@ -4739,6 +5518,10 @@ packages:
     resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==}
     engines: {node: '>=0.10.0'}
 
+  degenerator@5.0.1:
+    resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==}
+    engines: {node: '>= 14'}
+
   del@4.1.1:
     resolution: {integrity: sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==}
     engines: {node: '>=6'}
@@ -4770,6 +5553,12 @@ packages:
     resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
     engines: {node: '>=6'}
 
+  des.js@1.1.0:
+    resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==}
+
+  destroy@1.0.4:
+    resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==}
+
   destroy@1.2.0:
     resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
     engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -4794,6 +5583,10 @@ packages:
   devlop@1.1.0:
     resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
 
+  dicer@0.2.5:
+    resolution: {integrity: sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==}
+    engines: {node: '>=0.8.0'}
+
   didyoumean@1.2.2:
     resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
 
@@ -4801,6 +5594,17 @@ packages:
     resolution: {integrity: sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==}
     engines: {node: '>= 6'}
 
+  diff@4.0.4:
+    resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
+    engines: {node: '>=0.3.1'}
+
+  diffie-hellman@5.0.3:
+    resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==}
+
+  digest-header@1.1.0:
+    resolution: {integrity: sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg==}
+    engines: {node: '>= 8.0.0'}
+
   dir-glob@3.0.1:
     resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
     engines: {node: '>=8'}
@@ -4844,6 +5648,10 @@ packages:
   dom-serializer@2.0.0:
     resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
 
+  domain-browser@1.2.0:
+    resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==}
+    engines: {node: '>=0.4', npm: '>=1.2'}
+
   domelementtype@2.3.0:
     resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
 
@@ -4865,6 +5673,10 @@ packages:
   domutils@3.2.2:
     resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
 
+  dont-sniff-mimetype@1.1.0:
+    resolution: {integrity: sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug==}
+    engines: {node: '>=4.0.0'}
+
   dot-case@3.0.4:
     resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
 
@@ -4876,6 +5688,9 @@ packages:
     resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==}
     engines: {node: '>=10'}
 
+  dotenv-expand@5.1.0:
+    resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==}
+
   dotenv@16.6.1:
     resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
     engines: {node: '>=12'}
@@ -4884,6 +5699,10 @@ packages:
     resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
     engines: {node: '>=12'}
 
+  dotenv@8.2.0:
+    resolution: {integrity: sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==}
+    engines: {node: '>=8'}
+
   dotenv@8.6.0:
     resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
     engines: {node: '>=10'}
@@ -4901,12 +5720,18 @@ packages:
   duplexer@0.1.2:
     resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
 
+  duplexify@3.7.1:
+    resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
+
   eastasianwidth@0.2.0:
     resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
 
   ecc-jsbn@0.1.2:
     resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
 
+  ecdsa-sig-formatter@1.0.11:
+    resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
+
   echarts-for-react@3.0.2:
     resolution: {integrity: sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==}
     peerDependencies:
@@ -4930,6 +5755,9 @@ packages:
   electron-to-chromium@1.5.27:
     resolution: {integrity: sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==}
 
+  elliptic@6.6.1:
+    resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==}
+
   emoji-regex@10.6.0:
     resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
 
@@ -4966,6 +5794,14 @@ packages:
   end-of-stream@1.4.4:
     resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
 
+  end-or-error@1.0.1:
+    resolution: {integrity: sha512-OclLMSug+k2A0JKuf494im25ANRBVW8qsjmwbgX7lQ8P82H21PQ1PWkoYwb9y5yMBS69BPlwtzdIFClo3+7kOQ==}
+    engines: {node: '>= 0.11.14'}
+
+  enhanced-resolve@4.5.0:
+    resolution: {integrity: sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==}
+    engines: {node: '>=6.9.0'}
+
   enhanced-resolve@5.17.1:
     resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==}
     engines: {node: '>=10.13.0'}
@@ -5056,9 +5892,23 @@ packages:
     resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
     engines: {node: '>= 0.4'}
 
+  es5-ext@0.10.64:
+    resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
+    engines: {node: '>=0.10'}
+
+  es6-iterator@2.0.3:
+    resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
+
   es6-promise@3.3.1:
     resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
 
+  es6-symbol@3.1.4:
+    resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
+    engines: {node: '>=0.12'}
+
+  es6-weak-map@2.0.3:
+    resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==}
+
   esast-util-from-estree@2.0.0:
     resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==}
 
@@ -5097,6 +5947,11 @@ packages:
     engines: {node: '>=4.0'}
     hasBin: true
 
+  escodegen@2.1.0:
+    resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
+    engines: {node: '>=6.0'}
+    hasBin: true
+
   eslint-config-next@12.1.0:
     resolution: {integrity: sha512-tBhuUgoDITcdcM7xFvensi9I5WTI4dnvH4ETGRg1U8ZKpXrZsWQFdOKIDzR3RLP5HR3xXrLviaMM4c3zVoE/pA==}
     peerDependencies:
@@ -5188,6 +6043,10 @@ packages:
     peerDependencies:
       eslint: '>=5.0.0'
 
+  eslint-scope@4.0.3:
+    resolution: {integrity: sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==}
+    engines: {node: '>=4.0.0'}
+
   eslint-scope@5.1.1:
     resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
     engines: {node: '>=8.0.0'}
@@ -5224,6 +6083,12 @@ packages:
     deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
     hasBin: true
 
+  eslint@8.57.1:
+    resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
+    hasBin: true
+
   eslint@9.36.0:
     resolution: {integrity: sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -5234,6 +6099,10 @@ packages:
       jiti:
         optional: true
 
+  esniff@2.0.1:
+    resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
+    engines: {node: '>=0.10'}
+
   espree@10.4.0:
     resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -5306,10 +6175,22 @@ packages:
     resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==}
     engines: {node: '>= 0.8'}
 
+  event-emitter@0.3.5:
+    resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
+
   event-target-shim@5.0.1:
     resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
     engines: {node: '>=6'}
 
+  eventemitter2@0.4.14:
+    resolution: {integrity: sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==}
+
+  eventemitter2@5.0.1:
+    resolution: {integrity: sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==}
+
+  eventemitter2@6.4.9:
+    resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==}
+
   eventemitter3@4.0.7:
     resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
 
@@ -5317,6 +6198,9 @@ packages:
     resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
     engines: {node: '>=0.8.x'}
 
+  evp_bytestokey@1.0.3:
+    resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==}
+
   exec-sh@0.3.6:
     resolution: {integrity: sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==}
 
@@ -5343,6 +6227,13 @@ packages:
   exponential-backoff@3.1.1:
     resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
 
+  express-rate-limit@5.5.1:
+    resolution: {integrity: sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==}
+
+  express@4.17.1:
+    resolution: {integrity: sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==}
+    engines: {node: '>= 0.10.0'}
+
   express@4.21.2:
     resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
     engines: {node: '>= 0.10.0'}
@@ -5351,6 +6242,9 @@ packages:
     resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
     engines: {node: '>= 18'}
 
+  ext@1.7.0:
+    resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
+
   extend-shallow@2.0.1:
     resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
     engines: {node: '>=0.10.0'}
@@ -5362,14 +6256,24 @@ packages:
   extend@3.0.2:
     resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
 
+  external-editor@3.1.0:
+    resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
+    engines: {node: '>=4'}
+
   extglob@2.0.4:
     resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==}
     engines: {node: '>=0.10.0'}
 
+  extrareqp2@1.0.0:
+    resolution: {integrity: sha512-Gum0g1QYb6wpPJCVypWP3bbIuaibcFiJcpuPM10YSXp/tzqi84x9PJageob+eN4xVRIOto4wjSGNLyMD54D2xA==}
+
   extsprintf@1.3.0:
     resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
     engines: {'0': node >=0.6.0}
 
+  fast-deep-equal@2.0.1:
+    resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
+
   fast-deep-equal@3.1.3:
     resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
 
@@ -5380,6 +6284,12 @@ packages:
     resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
     engines: {node: '>=8.6.0'}
 
+  fast-json-patch@3.1.1:
+    resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==}
+
+  fast-json-stable-stringify@2.0.0:
+    resolution: {integrity: sha512-eIgZvM9C3P05kg0qxfqaVU6Tma4QedCPIByQOcemV0vju8ot3cS2DpHi4m2G2JvbSMI152rjfLX0p1pkSdyPlQ==}
+
   fast-json-stable-stringify@2.1.0:
     resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
 
@@ -5412,6 +6322,13 @@ packages:
   fbjs@0.8.18:
     resolution: {integrity: sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==}
 
+  fclone@1.0.11:
+    resolution: {integrity: sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw==}
+
+  feature-policy@0.3.0:
+    resolution: {integrity: sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==}
+    engines: {node: '>=4.0.0'}
+
   feed@4.2.2:
     resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==}
     engines: {node: '>=0.4.0'}
@@ -5420,6 +6337,14 @@ packages:
     resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
     engines: {node: ^12.20 || >= 14.13}
 
+  figgy-pudding@3.5.2:
+    resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==}
+    deprecated: This module is no longer supported.
+
+  figures@2.0.0:
+    resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==}
+    engines: {node: '>=4'}
+
   figures@3.2.0:
     resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
     engines: {node: '>=8'}
@@ -5522,6 +6447,9 @@ packages:
     resolution: {integrity: sha512-WHRizzSrWFTcKo7cVcbP3wzZVhzsoYxoWqbnH4z+JXGqrjVmnsld6kBZWVlB200PwD5ur8r+HV3KUDxv3cHhOQ==}
     engines: {node: '>=0.4.0'}
 
+  flush-write-stream@1.1.1:
+    resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==}
+
   follow-redirects@1.15.9:
     resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
     engines: {node: '>=4.0'}
@@ -5531,9 +6459,17 @@ packages:
       debug:
         optional: true
 
+  follow-redirects@1.5.10:
+    resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==}
+    engines: {node: '>=4.0'}
+
   for-each@0.3.3:
     resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
 
+  for-each@0.3.5:
+    resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
+    engines: {node: '>= 0.4'}
+
   for-in@1.0.2:
     resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==}
     engines: {node: '>=0.10.0'}
@@ -5541,6 +6477,20 @@ packages:
   forever-agent@0.6.1:
     resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
 
+  fork-ts-checker-webpack-plugin@4.0.3:
+    resolution: {integrity: sha512-5hGeMYKg817Hp6rvdc2EOS/T/Cq0JW9LLJDZtVUPlNIojIuP7YbOAdrHEk4Irw1097YQUr56kWIiYhqNPzfNzQ==}
+    engines: {node: '>=6.11.5', yarn: '>=1.0.0'}
+    peerDependencies:
+      eslint: '>= 6'
+      typescript: '>= 2.7'
+      vue-template-compiler: '*'
+      webpack: '>= 4'
+    peerDependenciesMeta:
+      eslint:
+        optional: true
+      vue-template-compiler:
+        optional: true
+
   fork-ts-checker-webpack-plugin@6.5.3:
     resolution: {integrity: sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==}
     engines: {node: '>=10', yarn: '>=1.0.0'}
@@ -5575,6 +6525,13 @@ packages:
     resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
     engines: {node: '>=12.20.0'}
 
+  formidable@1.2.6:
+    resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==}
+    deprecated: 'Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau'
+
+  formstream@1.5.2:
+    resolution: {integrity: sha512-NASf0lgxC1AyKNXQIrXTEYkiX99LhCEXTkiGObXAkpBui86a4u8FjH1o2bGb3PpqI3kafC+yw4zWeK6l6VHTgg==}
+
   forwarded@0.2.0:
     resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
     engines: {node: '>= 0.6'}
@@ -5594,6 +6551,9 @@ packages:
     resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
     engines: {node: '>= 0.8'}
 
+  from2@2.3.0:
+    resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==}
+
   fs-extra@10.1.0:
     resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
     engines: {node: '>=12'}
@@ -5613,6 +6573,10 @@ packages:
   fs-monkey@1.0.6:
     resolution: {integrity: sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==}
 
+  fs-write-stream-atomic@1.0.10:
+    resolution: {integrity: sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==}
+    deprecated: This package is no longer supported.
+
   fs.realpath@1.0.0:
     resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
 
@@ -5675,6 +6639,9 @@ packages:
     resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
     engines: {node: '>= 0.4'}
 
+  get-ready@1.0.0:
+    resolution: {integrity: sha512-mFXCZPJIlcYcth+N8267+mghfYN9h3EhsDa6JSnbA3Wrhh/XFpuowviFcsDeYZtKspQyWyJqfs4O6P8CHeTwzw==}
+
   get-stream@4.1.0:
     resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==}
     engines: {node: '>=6'}
@@ -5687,6 +6654,10 @@ packages:
     resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
     engines: {node: '>= 0.4'}
 
+  get-uri@6.0.5:
+    resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==}
+    engines: {node: '>= 14'}
+
   get-value@2.0.6:
     resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==}
     engines: {node: '>=0.10.0'}
@@ -5694,6 +6665,14 @@ packages:
   getpass@0.1.7:
     resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
 
+  git-node-fs@1.0.0:
+    resolution: {integrity: sha512-bLQypt14llVXBg0S0u8q8HmU7g9p3ysH+NvVlae5vILuUvs759665HvmR5+wb04KjHyjFcDRxdYb4kyNnluMUQ==}
+    peerDependencies:
+      js-git: ^0.7.8
+    peerDependenciesMeta:
+      js-git:
+        optional: true
+
   git-raw-commits@3.0.0:
     resolution: {integrity: sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==}
     engines: {node: '>=14'}
@@ -5708,6 +6687,9 @@ packages:
     engines: {node: '>=14'}
     hasBin: true
 
+  git-sha1@0.1.2:
+    resolution: {integrity: sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg==}
+
   gitconfiglocal@1.0.0:
     resolution: {integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==}
 
@@ -5717,6 +6699,9 @@ packages:
   github-slugger@1.5.0:
     resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==}
 
+  glob-parent@3.1.0:
+    resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==}
+
   glob-parent@5.1.2:
     resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
     engines: {node: '>= 6'}
@@ -5828,6 +6813,10 @@ packages:
     resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
     engines: {node: '>=6'}
 
+  has-ansi@2.0.0:
+    resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==}
+    engines: {node: '>=0.10.0'}
+
   has-bigints@1.0.2:
     resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
 
@@ -5878,6 +6867,17 @@ packages:
     resolution: {integrity: sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==}
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
 
+  hash-base@3.0.5:
+    resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==}
+    engines: {node: '>= 0.10'}
+
+  hash-base@3.1.2:
+    resolution: {integrity: sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==}
+    engines: {node: '>= 0.8'}
+
+  hash.js@1.1.7:
+    resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==}
+
   hasown@2.0.2:
     resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
     engines: {node: '>= 0.4'}
@@ -5910,6 +6910,18 @@ packages:
     resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
     hasBin: true
 
+  helmet-crossdomain@0.4.0:
+    resolution: {integrity: sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==}
+    engines: {node: '>=4.0.0'}
+
+  helmet-csp@2.10.0:
+    resolution: {integrity: sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w==}
+    engines: {node: '>=4.0.0'}
+
+  helmet@3.23.3:
+    resolution: {integrity: sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA==}
+    engines: {node: '>=4.0.0'}
+
   hermes-estree@0.22.0:
     resolution: {integrity: sha512-FLBt5X9OfA8BERUdc6aZS36Xz3rRuB0Y/mfocSADWEJfomc1xfene33GdyAmtTkKTBXTN/EgAy+rjTKkkZJHlw==}
 
@@ -5922,6 +6934,13 @@ packages:
   hermes-parser@0.23.1:
     resolution: {integrity: sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==}
 
+  hide-powered-by@1.1.0:
+    resolution: {integrity: sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==}
+    engines: {node: '>=4.0.0'}
+
+  highlight.js@10.7.3:
+    resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
+
   highlight.js@9.18.5:
     resolution: {integrity: sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==}
     deprecated: Support has ended for 9.x series. Upgrade to @latest
@@ -5929,6 +6948,9 @@ packages:
   history@4.10.1:
     resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==}
 
+  hmac-drbg@1.0.1:
+    resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==}
+
   hoist-non-react-statics@3.3.2:
     resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
 
@@ -5942,6 +6964,13 @@ packages:
   hpack.js@2.1.6:
     resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==}
 
+  hpkp@2.0.0:
+    resolution: {integrity: sha512-TaZpC6cO/k3DFsjfzz1LnOobbVSq+J+7WpJxrVtN4L+8+BPQj8iBDRB2Dx49613N+e7/+ZSQ9ra+xZm7Blf4wg==}
+
+  hsts@2.2.0:
+    resolution: {integrity: sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==}
+    engines: {node: '>=4.0.0'}
+
   html-encoding-sniffer@1.0.2:
     resolution: {integrity: sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==}
 
@@ -5996,6 +7025,14 @@ packages:
     resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==}
     engines: {node: '>= 0.6'}
 
+  http-errors@1.7.2:
+    resolution: {integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==}
+    engines: {node: '>= 0.6'}
+
+  http-errors@1.7.3:
+    resolution: {integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==}
+    engines: {node: '>= 0.6'}
+
   http-errors@2.0.0:
     resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
     engines: {node: '>= 0.8'}
@@ -6003,6 +7040,10 @@ packages:
   http-parser-js@0.5.9:
     resolution: {integrity: sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==}
 
+  http-proxy-agent@7.0.2:
+    resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+    engines: {node: '>= 14'}
+
   http-proxy-middleware@2.0.7:
     resolution: {integrity: sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==}
     engines: {node: '>=12.0.0'}
@@ -6027,10 +7068,20 @@ packages:
     resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==}
     engines: {node: '>=10.19.0'}
 
+  https-browserify@1.0.0:
+    resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==}
+
+  https-proxy-agent@7.0.6:
+    resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+    engines: {node: '>= 14'}
+
   human-signals@2.1.0:
     resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
     engines: {node: '>=10.17.0'}
 
+  humanize-ms@1.2.1:
+    resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
+
   husky@7.0.4:
     resolution: {integrity: sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==}
     engines: {node: '>=12'}
@@ -6064,6 +7115,9 @@ packages:
   ieee754@1.2.1:
     resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
 
+  iferr@0.1.5:
+    resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==}
+
   ignore@5.3.2:
     resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
     engines: {node: '>= 4'}
@@ -6113,6 +7167,9 @@ packages:
     resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
     engines: {node: '>=8'}
 
+  infer-owner@1.0.4:
+    resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
+
   infima@0.2.0-alpha.45:
     resolution: {integrity: sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==}
     engines: {node: '>=12'}
@@ -6137,6 +7194,14 @@ packages:
   inline-style-parser@0.2.4:
     resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
 
+  inquirer@6.2.1:
+    resolution: {integrity: sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==}
+    engines: {node: '>=6.0.0'}
+
+  inquirer@7.0.4:
+    resolution: {integrity: sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==}
+    engines: {node: '>=6.0.0'}
+
   inquirer@8.2.7:
     resolution: {integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==}
     engines: {node: '>=12.0.0'}
@@ -6155,6 +7220,10 @@ packages:
   invariant@2.2.4:
     resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
 
+  ip-address@10.2.0:
+    resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==}
+    engines: {node: '>= 12'}
+
   ipaddr.js@1.9.1:
     resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
     engines: {node: '>= 0.10'}
@@ -6191,6 +7260,10 @@ packages:
   is-bigint@1.0.4:
     resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
 
+  is-binary-path@1.0.1:
+    resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==}
+    engines: {node: '>=0.10.0'}
+
   is-binary-path@2.1.0:
     resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
     engines: {node: '>=8'}
@@ -6214,6 +7287,9 @@ packages:
     resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
     hasBin: true
 
+  is-class-hotfix@0.0.6:
+    resolution: {integrity: sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==}
+
   is-core-module@2.15.1:
     resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
     engines: {node: '>= 0.4'}
@@ -6285,6 +7361,10 @@ packages:
     resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
     engines: {node: '>= 0.4'}
 
+  is-glob@3.1.0:
+    resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==}
+    engines: {node: '>=0.10.0'}
+
   is-glob@4.0.3:
     resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
     engines: {node: '>=0.10.0'}
@@ -6371,6 +7451,9 @@ packages:
     resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
     engines: {node: '>=0.10.0'}
 
+  is-promise@2.2.2:
+    resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
+
   is-promise@4.0.0:
     resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
 
@@ -6417,10 +7500,17 @@ packages:
     resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==}
     engines: {node: '>=0.10.0'}
 
+  is-type-of@1.4.0:
+    resolution: {integrity: sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==}
+
   is-typed-array@1.1.13:
     resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
     engines: {node: '>= 0.4'}
 
+  is-typed-array@1.1.15:
+    resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
+    engines: {node: '>= 0.4'}
+
   is-typedarray@1.0.0:
     resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
 
@@ -6512,6 +7602,10 @@ packages:
     resolution: {integrity: sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==}
     engines: {node: '>=6'}
 
+  iterare@1.2.0:
+    resolution: {integrity: sha512-RxMV9p/UzdK0Iplnd8mVgRvNdXlsTOiuDrqMRnDi3wIhbT+JP4xDquAX9ay13R3CH72NBzQ91KWe0+C168QAyQ==}
+    engines: {node: '>=6'}
+
   iterator.prototype@1.1.2:
     resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
 
@@ -6688,6 +7782,15 @@ packages:
   joi@17.13.3:
     resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
 
+  js-base64@2.6.4:
+    resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
+
+  js-git@0.7.8:
+    resolution: {integrity: sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA==}
+
+  js-tokens@3.0.2:
+    resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==}
+
   js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
 
@@ -6786,14 +7889,37 @@ packages:
     resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
     engines: {node: '>=0.10.0'}
 
+  jsonwebtoken@8.5.1:
+    resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==}
+    engines: {node: '>=4', npm: '>=1.4.28'}
+
+  jsonwebtoken@9.0.3:
+    resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==}
+    engines: {node: '>=12', npm: '>=6'}
+
   jsprim@1.4.2:
     resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
     engines: {node: '>=0.6.0'}
 
+  jstoxml@2.2.9:
+    resolution: {integrity: sha512-OYWlK0j+roh+eyaMROlNbS5cd5R25Y+IUpdl7cNdB8HNrkgwQzIS7L9MegxOiWNBj9dQhA/yAxiMwCC5mwNoBw==}
+
   jsx-ast-utils@3.3.5:
     resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
     engines: {node: '>=4.0'}
 
+  jwa@1.4.2:
+    resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==}
+
+  jwa@2.0.1:
+    resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==}
+
+  jws@3.2.3:
+    resolution: {integrity: sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==}
+
+  jws@4.0.1:
+    resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
+
   keyv@4.5.4:
     resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
 
@@ -6834,6 +7960,10 @@ packages:
   launch-editor@2.10.0:
     resolution: {integrity: sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==}
 
+  lazy@1.0.11:
+    resolution: {integrity: sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==}
+    engines: {node: '>=0.2.0'}
+
   left-pad@1.3.0:
     resolution: {integrity: sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==}
     deprecated: use String.prototype.padStart()
@@ -6866,6 +7996,9 @@ packages:
     resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
     engines: {node: '>= 0.8.0'}
 
+  libphonenumber-js@1.13.2:
+    resolution: {integrity: sha512-S3kmBrptp3yRTm83NUcHy9g1vbwiWMzI8WvY22+koBJ6zkRteLnedBL2VX0MIAGwx2yiyxX4J85pceZyQ6ffgg==}
+
   lighthouse-logger@1.4.2:
     resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==}
 
@@ -6898,10 +8031,18 @@ packages:
     resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
     engines: {node: '>=4'}
 
+  loader-runner@2.4.0:
+    resolution: {integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==}
+    engines: {node: '>=4.3.0 <5.0.0 || >=5.10'}
+
   loader-runner@4.3.0:
     resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
     engines: {node: '>=6.11.5'}
 
+  loader-utils@1.4.2:
+    resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==}
+    engines: {node: '>=4.0.0'}
+
   loader-utils@2.0.4:
     resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==}
     engines: {node: '>=8.9.0'}
@@ -6939,21 +8080,55 @@ packages:
   lodash.debounce@4.0.8:
     resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
 
+  lodash.get@4.4.2:
+    resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
+    deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
+
+  lodash.has@4.5.2:
+    resolution: {integrity: sha512-rnYUdIo6xRCJnQmbVFEwcxF144erlD+M3YcJUVesflU9paQaE8p+fJDcIQrlMYbxoANFL+AB9hZrzSBBk5PL+g==}
+
+  lodash.includes@4.3.0:
+    resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
+
+  lodash.isboolean@3.0.3:
+    resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
+
+  lodash.isinteger@4.0.4:
+    resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
+
   lodash.ismatch@4.4.0:
     resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==}
 
+  lodash.isnumber@3.0.3:
+    resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
+
+  lodash.isplainobject@4.0.6:
+    resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+
+  lodash.isstring@4.0.1:
+    resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
+
   lodash.memoize@4.1.2:
     resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
 
   lodash.merge@4.6.2:
     resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
 
+  lodash.once@4.1.1:
+    resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
+
+  lodash.set@4.3.2:
+    resolution: {integrity: sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==}
+
   lodash.sortby@4.7.0:
     resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
 
   lodash.throttle@4.1.1:
     resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
 
+  lodash.toarray@4.4.0:
+    resolution: {integrity: sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==}
+
   lodash.uniq@4.5.0:
     resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
 
@@ -6963,6 +8138,10 @@ packages:
   lodash@4.17.21:
     resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
 
+  log-symbols@3.0.0:
+    resolution: {integrity: sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==}
+    engines: {node: '>=8'}
+
   log-symbols@4.1.0:
     resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
     engines: {node: '>=10'}
@@ -6975,6 +8154,10 @@ packages:
     resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
     engines: {node: '>=10'}
 
+  log4js@6.9.1:
+    resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==}
+    engines: {node: '>=8.0'}
+
   logkitty@0.7.1:
     resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==}
     hasBin: true
@@ -7010,6 +8193,9 @@ packages:
     resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
     engines: {node: '>=12'}
 
+  lru-queue@0.1.0:
+    resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==}
+
   lru.min@1.1.1:
     resolution: {integrity: sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==}
     engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'}
@@ -7022,6 +8208,10 @@ packages:
     resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
     hasBin: true
 
+  macos-release@2.5.1:
+    resolution: {integrity: sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==}
+    engines: {node: '>=6'}
+
   magic-string@0.25.9:
     resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
 
@@ -7039,6 +8229,9 @@ packages:
   makeerror@1.0.12:
     resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
 
+  mamacro@0.0.3:
+    resolution: {integrity: sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==}
+
   map-cache@0.2.2:
     resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
     engines: {node: '>=0.10.0'}
@@ -7065,6 +8258,11 @@ packages:
   markdown-table@3.0.4:
     resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
 
+  marked@0.8.2:
+    resolution: {integrity: sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==}
+    engines: {node: '>= 8.16.2'}
+    hasBin: true
+
   marky@1.2.5:
     resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==}
 
@@ -7072,6 +8270,9 @@ packages:
     resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
     engines: {node: '>= 0.4'}
 
+  md5.js@1.3.5:
+    resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==}
+
   mdast-util-directive@3.1.0:
     resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==}
 
@@ -7147,10 +8348,24 @@ packages:
   memoize-one@5.2.1:
     resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
 
+  memoizee@0.4.17:
+    resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==}
+    engines: {node: '>=0.12'}
+
+  memory-fs@0.4.1:
+    resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==}
+
+  memory-fs@0.5.0:
+    resolution: {integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==}
+    engines: {node: '>=4.3.0 <5.0.0 || >=5.10'}
+
   meow@8.1.2:
     resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==}
     engines: {node: '>=10'}
 
+  merge-descriptors@1.0.1:
+    resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
+
   merge-descriptors@1.0.3:
     resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
 
@@ -7227,6 +8442,9 @@ packages:
     engines: {node: '>=18'}
     hasBin: true
 
+  microevent.ts@0.1.1:
+    resolution: {integrity: sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==}
+
   micromark-core-commonmark@2.0.3:
     resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
 
@@ -7358,6 +8576,10 @@ packages:
     resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
     engines: {node: '>=8.6'}
 
+  miller-rabin@4.0.1:
+    resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==}
+    hasBin: true
+
   mime-db@1.33.0:
     resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==}
     engines: {node: '>= 0.6'}
@@ -7366,10 +8588,6 @@ packages:
     resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
     engines: {node: '>= 0.6'}
 
-  mime-db@1.53.0:
-    resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==}
-    engines: {node: '>= 0.6'}
-
   mime-db@1.54.0:
     resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
     engines: {node: '>= 0.6'}
@@ -7396,6 +8614,10 @@ packages:
     engines: {node: '>=4.0.0'}
     hasBin: true
 
+  mimic-fn@1.2.0:
+    resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==}
+    engines: {node: '>=4'}
+
   mimic-fn@2.1.0:
     resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
     engines: {node: '>=6'}
@@ -7425,6 +8647,9 @@ packages:
   minimalistic-assert@1.0.1:
     resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
 
+  minimalistic-crypto-utils@1.0.1:
+    resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==}
+
   minimatch@3.1.2:
     resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
 
@@ -7436,9 +8661,16 @@ packages:
     resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
     engines: {node: '>= 6'}
 
+  minimist@1.2.0:
+    resolution: {integrity: sha512-7Wl+Jz+IGWuSdgsQEJ4JunV0si/iMhg42MnQQG6h1R6TNeVenp4U9x5CC5v/gYqz/fENLQITAWXidNtVL0NNbw==}
+
   minimist@1.2.8:
     resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
 
+  mississippi@3.0.0:
+    resolution: {integrity: sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==}
+    engines: {node: '>=4.0.0'}
+
   mixin-deep@1.3.2:
     resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
     engines: {node: '>=0.10.0'}
@@ -7456,9 +8688,16 @@ packages:
     resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==}
     engines: {node: '>=0.10.0'}
 
+  module-details-from-path@1.0.4:
+    resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==}
+
   monaco-editor@0.52.0:
     resolution: {integrity: sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==}
 
+  move-concurrently@1.0.1:
+    resolution: {integrity: sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==}
+    deprecated: This package is no longer supported.
+
   mrmime@2.0.1:
     resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
     engines: {node: '>=10'}
@@ -7466,13 +8705,24 @@ packages:
   ms@2.0.0:
     resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
 
+  ms@2.1.1:
+    resolution: {integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==}
+
   ms@2.1.3:
     resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
 
+  multer@1.4.2:
+    resolution: {integrity: sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==}
+    engines: {node: '>= 0.10.0'}
+    deprecated: Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10.
+
   multicast-dns@7.2.5:
     resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==}
     hasBin: true
 
+  mute-stream@0.0.7:
+    resolution: {integrity: sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==}
+
   mute-stream@0.0.8:
     resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
 
@@ -7486,6 +8736,9 @@ packages:
     peerDependencies:
       '@types/node': '>= 8'
 
+  mz@2.7.0:
+    resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+
   named-placeholders@1.1.3:
     resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==}
     engines: {node: '>=12.0.0'}
@@ -7517,6 +8770,11 @@ packages:
   natural-compare@1.4.0:
     resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
 
+  needle@2.4.0:
+    resolution: {integrity: sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==}
+    engines: {node: '>= 4.4.x'}
+    hasBin: true
+
   needle@3.3.1:
     resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==}
     engines: {node: '>= 4.4.x'}
@@ -7533,6 +8791,10 @@ packages:
   neo-async@2.6.2:
     resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
 
+  netmask@2.1.1:
+    resolution: {integrity: sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==}
+    engines: {node: '>= 0.4.0'}
+
   next-compose-plugins@2.2.1:
     resolution: {integrity: sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg==}
 
@@ -7571,6 +8833,12 @@ packages:
     peerDependencies:
       next: '*'
 
+  next-tick@1.1.0:
+    resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
+
+  next-transpile-modules@6.4.1:
+    resolution: {integrity: sha512-trUMkm+bkjMci7mXSOQkF3apEY18K6YuaeG4mkLwiQtDdsmdVXzopNyZGc2nJq8OwHYDgJr1QlsBQuQb/2vXlw==}
+
   next-with-less@2.0.5:
     resolution: {integrity: sha512-1MJDcgFOPucFPCMXV7rTqcWiLI2nLSBi8bA6msvkiNLhYyZMXaFl4MkyYf7eOEUUEtA/c5eD0grPhbcDkrKqPQ==}
     peerDependencies:
@@ -7602,6 +8870,10 @@ packages:
   no-case@3.0.4:
     resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
 
+  nocache@2.1.0:
+    resolution: {integrity: sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==}
+    engines: {node: '>=4.0.0'}
+
   nocache@3.0.4:
     resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==}
     engines: {node: '>=12.0.0'}
@@ -7618,6 +8890,9 @@ packages:
     engines: {node: '>=10.5.0'}
     deprecated: Use your platform's native DOMException instead
 
+  node-emoji@1.10.0:
+    resolution: {integrity: sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==}
+
   node-emoji@1.11.0:
     resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==}
 
@@ -7649,9 +8924,20 @@ packages:
     resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
     engines: {node: '>= 6.13.0'}
 
+  node-hex@1.0.1:
+    resolution: {integrity: sha512-iwpZdvW6Umz12ICmu9IYPRxg0tOLGmU3Tq2tKetejCj3oZd7b2nUXwP3a7QA5M9glWy8wlPS1G3RwM/CdsUbdQ==}
+    engines: {node: '>=8.0.0'}
+
   node-int64@0.4.0:
     resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
 
+  node-ip2region@1.0.2:
+    resolution: {integrity: sha512-tH/A46cbCSeE+G0w8cwPeQDV3EdVp5D900VLgDbjhC4bH7SKVPBOarpjH1He6QvWFBOam48lIroKTAyVUPC3CA==}
+    engines: {node: '>=6.0.0'}
+
+  node-libs-browser@2.2.1:
+    resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==}
+
   node-notifier@5.4.5:
     resolution: {integrity: sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==}
 
@@ -7668,8 +8954,15 @@ packages:
     resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==}
     engines: {node: '>=0.12.0'}
 
-  normalize-package-data@2.5.0:
-    resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
+  nodemailer@6.10.1:
+    resolution: {integrity: sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==}
+    engines: {node: '>=6.0.0'}
+
+  noms@0.0.0:
+    resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==}
+
+  normalize-package-data@2.5.0:
+    resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
 
   normalize-package-data@3.0.3:
     resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==}
@@ -7702,9 +8995,18 @@ packages:
   nprogress@0.2.0:
     resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
 
+  nssocket@0.6.0:
+    resolution: {integrity: sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==}
+    engines: {node: '>= 0.10.x'}
+
   nth-check@2.1.1:
     resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
 
+  nuid@1.1.6:
+    resolution: {integrity: sha512-Eb3CPCupYscP1/S1FQcO5nxtu6l/F3k0MQ69h7f5osnsemVk5pkc8/5AyalVT+NCfra9M71U8POqF6EZa6IHvg==}
+    engines: {node: '>= 8.16.0'}
+    deprecated: 'Package deprecated. Use @nats-io/nuid instead: https://www.npmjs.com/package/@nats-io/nuid'
+
   null-loader@4.0.1:
     resolution: {integrity: sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==}
     engines: {node: '>= 10.13.0'}
@@ -7748,6 +9050,10 @@ packages:
     resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==}
     engines: {node: '>=0.10.0'}
 
+  object-hash@2.0.3:
+    resolution: {integrity: sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==}
+    engines: {node: '>= 6'}
+
   object-inspect@1.13.2:
     resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==}
     engines: {node: '>= 0.4'}
@@ -7820,6 +9126,10 @@ packages:
   once@1.4.0:
     resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
 
+  onetime@2.0.1:
+    resolution: {integrity: sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==}
+    engines: {node: '>=4'}
+
   onetime@5.1.2:
     resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
     engines: {node: '>=6'}
@@ -7844,6 +9154,9 @@ packages:
     resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
     hasBin: true
 
+  optional@0.1.4:
+    resolution: {integrity: sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==}
+
   optionator@0.8.3:
     resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==}
     engines: {node: '>= 0.8.0'}
@@ -7852,6 +9165,10 @@ packages:
     resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
     engines: {node: '>= 0.8.0'}
 
+  ora@4.0.3:
+    resolution: {integrity: sha512-fnDebVFyz309A73cqCipVL1fBZewq4vwgSHfxh43vVy31mbyoQ8sCH3Oeaog/owYOs/lLlGVPCISQonTneg6Pg==}
+    engines: {node: '>=8'}
+
   ora@5.4.1:
     resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
     engines: {node: '>=10'}
@@ -7860,6 +9177,27 @@ packages:
     resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==}
     engines: {node: '>=18'}
 
+  os-browserify@0.3.0:
+    resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==}
+
+  os-name@1.0.3:
+    resolution: {integrity: sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==}
+    engines: {node: '>=0.10.0'}
+    hasBin: true
+
+  os-name@3.1.0:
+    resolution: {integrity: sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==}
+    engines: {node: '>=6'}
+
+  os-tmpdir@1.0.2:
+    resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
+    engines: {node: '>=0.10.0'}
+
+  osx-release@1.1.0:
+    resolution: {integrity: sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==}
+    engines: {node: '>=0.10.0'}
+    hasBin: true
+
   p-cancelable@3.0.0:
     resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==}
     engines: {node: '>=12.20'}
@@ -7932,10 +9270,27 @@ packages:
     resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
     engines: {node: '>=6'}
 
+  pac-proxy-agent@7.2.0:
+    resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==}
+    engines: {node: '>= 14'}
+
+  pac-resolver@7.0.1:
+    resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==}
+    engines: {node: '>= 14'}
+
   package-json@8.1.1:
     resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==}
     engines: {node: '>=14.16'}
 
+  pako@0.2.9:
+    resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
+
+  pako@1.0.11:
+    resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
+
+  parallel-transform@1.2.0:
+    resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==}
+
   param-case@3.0.4:
     resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
 
@@ -7943,6 +9298,10 @@ packages:
     resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
     engines: {node: '>=6'}
 
+  parse-asn1@5.1.9:
+    resolution: {integrity: sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==}
+    engines: {node: '>= 0.10'}
+
   parse-entities@4.0.2:
     resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
 
@@ -7961,12 +9320,21 @@ packages:
   parse-numeric-range@1.3.0:
     resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==}
 
+  parse5-htmlparser2-tree-adapter@6.0.1:
+    resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==}
+
   parse5-htmlparser2-tree-adapter@7.1.0:
     resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==}
 
   parse5@4.0.0:
     resolution: {integrity: sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==}
 
+  parse5@5.1.1:
+    resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==}
+
+  parse5@6.0.1:
+    resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
+
   parse5@7.2.1:
     resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==}
 
@@ -7981,6 +9349,23 @@ packages:
     resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
     engines: {node: '>=0.10.0'}
 
+  passport-jwt@4.0.1:
+    resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==}
+
+  passport-strategy@1.0.0:
+    resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==}
+    engines: {node: '>= 0.4.0'}
+
+  passport@0.4.1:
+    resolution: {integrity: sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==}
+    engines: {node: '>= 0.4.0'}
+
+  path-browserify@0.0.1:
+    resolution: {integrity: sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==}
+
+  path-dirname@1.0.2:
+    resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==}
+
   path-exists@3.0.0:
     resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
     engines: {node: '>=4'}
@@ -8014,12 +9399,18 @@ packages:
   path-to-regexp@0.1.12:
     resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}
 
+  path-to-regexp@0.1.7:
+    resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
+
   path-to-regexp@1.9.0:
     resolution: {integrity: sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==}
 
   path-to-regexp@2.4.0:
     resolution: {integrity: sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==}
 
+  path-to-regexp@3.2.0:
+    resolution: {integrity: sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==}
+
   path-to-regexp@3.3.0:
     resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==}
 
@@ -8034,6 +9425,16 @@ packages:
     resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
     engines: {node: '>=8'}
 
+  pause-stream@0.0.11:
+    resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==}
+
+  pause@0.0.1:
+    resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==}
+
+  pbkdf2@3.1.5:
+    resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==}
+    engines: {node: '>= 0.10'}
+
   performance-now@0.2.0:
     resolution: {integrity: sha512-YHk5ez1hmMR5LOkb9iJkLKqoBlL7WD5M8ljC75ZfzXriuBIVNuecaXuU7e+hOwyqf24Wxhh7Vxgt7Hnw9288Tg==}
 
@@ -8052,6 +9453,14 @@ packages:
     engines: {node: '>=0.10'}
     hasBin: true
 
+  pidusage@2.0.21:
+    resolution: {integrity: sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==}
+    engines: {node: '>=8'}
+
+  pidusage@3.0.2:
+    resolution: {integrity: sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==}
+    engines: {node: '>=10'}
+
   pify@2.3.0:
     resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
     engines: {node: '>=0.10.0'}
@@ -8092,6 +9501,32 @@ packages:
     resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==}
     engines: {node: '>=8'}
 
+  platform@1.3.6:
+    resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==}
+
+  pm2-axon-rpc@0.7.1:
+    resolution: {integrity: sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw==}
+    engines: {node: '>=5'}
+
+  pm2-axon@4.0.1:
+    resolution: {integrity: sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg==}
+    engines: {node: '>=5'}
+
+  pm2-deploy@1.0.2:
+    resolution: {integrity: sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==}
+    engines: {node: '>=4.0.0'}
+
+  pm2-multimeter@0.1.2:
+    resolution: {integrity: sha512-S+wT6XfyKfd7SJIBqRgOctGxaBzUOmVQzTAS+cg04TsEUObJVreha7lvCfX8zzGVr871XwCSnHUU7DQQ5xEsfA==}
+
+  pm2-sysmonit@1.2.8:
+    resolution: {integrity: sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==}
+
+  pm2@5.4.3:
+    resolution: {integrity: sha512-4/I1htIHzZk1Y67UgOCo4F1cJtas1kSds31N8zN0PybO230id1nigyjGuGFzUnGmUFPmrJ0On22fO1ChFlp7VQ==}
+    engines: {node: '>=12.0.0'}
+    hasBin: true
+
   pn@1.1.0:
     resolution: {integrity: sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==}
 
@@ -8513,6 +9948,11 @@ packages:
     resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
     engines: {node: '>=6.0.0'}
 
+  prettier@1.19.1:
+    resolution: {integrity: sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==}
+    engines: {node: '>=4'}
+    hasBin: true
+
   prettier@2.7.1:
     resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==}
     engines: {node: '>=10.13.0'}
@@ -8562,12 +10002,27 @@ packages:
   process-nextick-args@2.0.1:
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
 
+  process@0.11.10:
+    resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
+    engines: {node: '>= 0.6.0'}
+
+  promise-inflight@1.0.1:
+    resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
+    peerDependencies:
+      bluebird: '*'
+    peerDependenciesMeta:
+      bluebird:
+        optional: true
+
   promise@7.3.1:
     resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==}
 
   promise@8.3.0:
     resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==}
 
+  promptly@2.2.0:
+    resolution: {integrity: sha512-aC9j+BZsRSSzEsXBNBwDnAxujdx19HycZoKgRgzWnS8eOHg1asuf9heuLprfbe739zY3IdUQx+Egv6Jn135WHA==}
+
   prompts@2.4.2:
     resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
     engines: {node: '>= 6'}
@@ -8588,6 +10043,10 @@ packages:
     resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
     engines: {node: '>= 0.10'}
 
+  proxy-agent@6.3.1:
+    resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==}
+    engines: {node: '>= 14'}
+
   proxy-from-env@1.1.0:
     resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
 
@@ -8597,9 +10056,21 @@ packages:
   psl@1.9.0:
     resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
 
+  public-encrypt@4.0.3:
+    resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==}
+
+  pump@2.0.1:
+    resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==}
+
   pump@3.0.2:
     resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
 
+  pumpify@1.5.1:
+    resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==}
+
+  punycode@1.4.1:
+    resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==}
+
   punycode@2.3.1:
     resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
     engines: {node: '>=6'}
@@ -8624,6 +10095,14 @@ packages:
     resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
     engines: {node: '>=0.6'}
 
+  qs@6.7.0:
+    resolution: {integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==}
+    engines: {node: '>=0.6'}
+
+  querystring-es3@0.2.1:
+    resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==}
+    engines: {node: '>=0.4.x'}
+
   queue-microtask@1.2.3:
     resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
 
@@ -8644,6 +10123,9 @@ packages:
   randombytes@2.1.0:
     resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
 
+  randomfill@1.0.4:
+    resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==}
+
   range-parser@1.2.0:
     resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==}
     engines: {node: '>= 0.6'}
@@ -8652,6 +10134,10 @@ packages:
     resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
     engines: {node: '>= 0.6'}
 
+  raw-body@2.4.0:
+    resolution: {integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==}
+    engines: {node: '>= 0.8'}
+
   raw-body@2.5.2:
     resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
     engines: {node: '>= 0.8'}
@@ -9129,6 +10615,16 @@ packages:
     resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
     engines: {node: '>=8'}
 
+  read@1.0.7:
+    resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==}
+    engines: {node: '>=0.8'}
+
+  readable-stream@1.0.34:
+    resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==}
+
+  readable-stream@1.1.14:
+    resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==}
+
   readable-stream@2.3.8:
     resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
 
@@ -9136,6 +10632,10 @@ packages:
     resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
     engines: {node: '>= 6'}
 
+  readdirp@2.2.1:
+    resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==}
+    engines: {node: '>=0.10'}
+
   readdirp@3.6.0:
     resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
     engines: {node: '>=8.10.0'}
@@ -9182,6 +10682,13 @@ packages:
     resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
     engines: {node: '>=8'}
 
+  referrer-policy@1.2.0:
+    resolution: {integrity: sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==}
+    engines: {node: '>=4.0.0'}
+
+  reflect-metadata@0.1.14:
+    resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==}
+
   reflect.getprototypeof@1.0.6:
     resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
     engines: {node: '>= 0.4'}
@@ -9322,6 +10829,10 @@ packages:
     resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
     engines: {node: '>=0.10.0'}
 
+  require-in-the-middle@5.2.0:
+    resolution: {integrity: sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==}
+    engines: {node: '>=6'}
+
   require-like@0.1.2:
     resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==}
 
@@ -9371,6 +10882,10 @@ packages:
     resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==}
     engines: {node: '>=14.16'}
 
+  restore-cursor@2.0.0:
+    resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==}
+    engines: {node: '>=4'}
+
   restore-cursor@3.1.0:
     resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
     engines: {node: '>=8'}
@@ -9404,11 +10919,20 @@ packages:
     deprecated: Rimraf versions prior to v4 are no longer supported
     hasBin: true
 
+  rimraf@3.0.1:
+    resolution: {integrity: sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw==}
+    deprecated: Rimraf versions prior to v4 are no longer supported
+    hasBin: true
+
   rimraf@3.0.2:
     resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
     deprecated: Rimraf versions prior to v4 are no longer supported
     hasBin: true
 
+  ripemd160@2.0.3:
+    resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==}
+    engines: {node: '>= 0.8'}
+
   rollup-plugin-terser@7.0.2:
     resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
     deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
@@ -9440,6 +10964,20 @@ packages:
   run-parallel@1.2.0:
     resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
 
+  run-queue@1.0.3:
+    resolution: {integrity: sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==}
+
+  run-series@1.1.9:
+    resolution: {integrity: sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==}
+
+  rxjs@6.3.3:
+    resolution: {integrity: sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==}
+    engines: {npm: '>=2.0.0'}
+
+  rxjs@6.6.7:
+    resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==}
+    engines: {npm: '>=2.0.0'}
+
   rxjs@7.8.1:
     resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
 
@@ -9517,6 +11055,10 @@ packages:
   scheduler@0.25.0:
     resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
 
+  schema-utils@1.0.0:
+    resolution: {integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==}
+    engines: {node: '>= 4'}
+
   schema-utils@2.7.0:
     resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==}
     engines: {node: '>= 8.9.0'}
@@ -9536,6 +11078,9 @@ packages:
   scroll-into-view-if-needed@3.1.0:
     resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==}
 
+  sdk-base@2.0.1:
+    resolution: {integrity: sha512-eeG26wRwhtwYuKGCDM3LixCaxY27Pa/5lK4rLKhQa7HBjJ3U3Y+f81MMZQRsDw/8SC2Dao/83yJTXJ8aULuN8Q==}
+
   search-insights@2.17.3:
     resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==}
 
@@ -9543,6 +11088,10 @@ packages:
     resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
     engines: {node: '>=4'}
 
+  segment@0.1.3:
+    resolution: {integrity: sha512-4Kjk38q0ykMIK5a+uo2MjTM2EECJaLLQOkdptceiYHTFZU/iciWXiFiGTG8Or/cfO2RqjlLw/s6rqijxAFSKFQ==}
+    engines: {node: '>= 0.4.0'}
+
   select-hose@2.0.0:
     resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==}
 
@@ -9562,11 +11111,20 @@ packages:
     resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
     hasBin: true
 
+  semver@7.5.4:
+    resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
+    engines: {node: '>=10'}
+    hasBin: true
+
   semver@7.6.3:
     resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
     engines: {node: '>=10'}
     hasBin: true
 
+  send@0.17.1:
+    resolution: {integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==}
+    engines: {node: '>= 0.8.0'}
+
   send@0.19.0:
     resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
     engines: {node: '>= 0.8.0'}
@@ -9595,6 +11153,10 @@ packages:
     resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==}
     engines: {node: '>= 0.8.0'}
 
+  serve-static@1.14.1:
+    resolution: {integrity: sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==}
+    engines: {node: '>= 0.8.0'}
+
   serve-static@1.16.2:
     resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
     engines: {node: '>= 0.8.0'}
@@ -9624,9 +11186,17 @@ packages:
   setprototypeof@1.1.0:
     resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==}
 
+  setprototypeof@1.1.1:
+    resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==}
+
   setprototypeof@1.2.0:
     resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
 
+  sha.js@2.4.12:
+    resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==}
+    engines: {node: '>= 0.10'}
+    hasBin: true
+
   shallow-clone@3.0.1:
     resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
     engines: {node: '>=8'}
@@ -9661,6 +11231,9 @@ packages:
   shellwords@0.1.1:
     resolution: {integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==}
 
+  shimmer@1.2.1:
+    resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==}
+
   should-equal@2.0.0:
     resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==}
 
@@ -9757,6 +11330,10 @@ packages:
     resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
     engines: {node: '>=12'}
 
+  smart-buffer@4.2.0:
+    resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
+    engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
+
   snake-case@3.0.4:
     resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
 
@@ -9775,6 +11352,14 @@ packages:
   sockjs@0.3.24:
     resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==}
 
+  socks-proxy-agent@8.0.5:
+    resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==}
+    engines: {node: '>= 14'}
+
+  socks@2.8.9:
+    resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==}
+    engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
+
   sort-css-media-queries@2.2.0:
     resolution: {integrity: sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==}
     engines: {node: '>= 6.3.0'}
@@ -9805,6 +11390,10 @@ packages:
     resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
     engines: {node: '>=0.10.0'}
 
+  source-map@0.7.3:
+    resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==}
+    engines: {node: '>= 8'}
+
   source-map@0.7.4:
     resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
     engines: {node: '>= 8'}
@@ -9856,6 +11445,9 @@ packages:
   sprintf-js@1.0.3:
     resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
 
+  sprintf-js@1.1.2:
+    resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
+
   sql-escaper@1.3.3:
     resolution: {integrity: sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==}
     engines: {bun: '>=1.0.0', deno: '>=2.0.0', node: '>=12.0.0'}
@@ -9873,6 +11465,9 @@ packages:
     engines: {node: '>=0.10.0'}
     hasBin: true
 
+  ssri@6.0.2:
+    resolution: {integrity: sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==}
+
   stack-utils@1.0.5:
     resolution: {integrity: sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==}
     engines: {node: '>=8'}
@@ -9918,6 +11513,33 @@ packages:
     resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
     engines: {node: '>= 0.4'}
 
+  stream-browserify@2.0.2:
+    resolution: {integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==}
+
+  stream-each@1.2.3:
+    resolution: {integrity: sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==}
+
+  stream-http@2.8.2:
+    resolution: {integrity: sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==}
+
+  stream-http@2.8.3:
+    resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==}
+
+  stream-shift@1.0.3:
+    resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==}
+
+  stream-wormhole@1.1.0:
+    resolution: {integrity: sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==}
+    engines: {node: '>=4.0.0'}
+
+  streamroller@3.1.5:
+    resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==}
+    engines: {node: '>=8.0'}
+
+  streamsearch@0.1.2:
+    resolution: {integrity: sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==}
+    engines: {node: '>=0.8.0'}
+
   string-argv@0.3.2:
     resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
     engines: {node: '>=0.6.19'}
@@ -9929,6 +11551,10 @@ packages:
     resolution: {integrity: sha512-Qka42GGrS8Mm3SZ+7cH8UXiIWI867/b/Z/feQSpQx/rbfB8UGknGEZVaUQMOUVj+soY6NpWAxily63HI1OckVQ==}
     engines: {node: '>=4'}
 
+  string-width@2.1.1:
+    resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==}
+    engines: {node: '>=4'}
+
   string-width@3.1.0:
     resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==}
     engines: {node: '>=6'}
@@ -9966,6 +11592,9 @@ packages:
     resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
     engines: {node: '>= 0.4'}
 
+  string_decoder@0.10.31:
+    resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==}
+
   string_decoder@1.1.1:
     resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
 
@@ -9979,6 +11608,10 @@ packages:
     resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==}
     engines: {node: '>=4'}
 
+  strip-ansi@3.0.1:
+    resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==}
+    engines: {node: '>=0.10.0'}
+
   strip-ansi@4.0.0:
     resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==}
     engines: {node: '>=4'}
@@ -10062,6 +11695,20 @@ packages:
     resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==}
     deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
 
+  superagent@3.8.3:
+    resolution: {integrity: sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==}
+    engines: {node: '>= 4.0'}
+    deprecated: Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net
+
+  supertest@4.0.2:
+    resolution: {integrity: sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ==}
+    engines: {node: '>=6.0.0'}
+    deprecated: Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net
+
+  supports-color@2.0.0:
+    resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==}
+    engines: {node: '>=0.8.0'}
+
   supports-color@5.5.0:
     resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
     engines: {node: '>=4'}
@@ -10102,10 +11749,22 @@ packages:
   swagger-schema-official@2.0.0-bab6bed:
     resolution: {integrity: sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==}
 
+  swagger-themes@1.4.3:
+    resolution: {integrity: sha512-1G0CqJC1IBbNxkAOyJoREd9hfwXH1R6+3GOFxLhQho2w2i+AbaJqkF4mTJhkce4yhaEMUXvv4KKu1YO/qpe6nQ==}
+
   swagger-typescript-api@12.0.4:
     resolution: {integrity: sha512-04ZxlJzu3g15TupfPhS0Yk0jzV/MM23WU4uuOl2vSi4yHrxEwnkIsoBkP084ec61q4vr2FHcI3DKxC+Mt1u10Q==}
     hasBin: true
 
+  swagger-ui-dist@5.32.6:
+    resolution: {integrity: sha512-75ttZNaYCLoFPnozPZcTUU6mS3wKT8l7WLjU5zJSHFeJa23i5vtnze6IiCl4jDMPeQTXVXIgovq4M11NNfQvSA==}
+
+  swagger-ui-express@4.6.3:
+    resolution: {integrity: sha512-CDje4PndhTD2HkgyKH3pab+LKspDeB/NhPN2OF1j+piYIamQqBYwAXWESOT1Yju2xFg51bRW9sUng2WxDjzArw==}
+    engines: {node: '>= v0.10.32'}
+    peerDependencies:
+      express: '>=4.0.0 || >=5.0.0-beta'
+
   swagger2openapi@7.0.8:
     resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==}
     hasBin: true
@@ -10115,9 +11774,19 @@ packages:
     peerDependencies:
       react: ^16.11.0 || ^17.0.0 || ^18.0.0
 
+  symbol-observable@1.2.0:
+    resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==}
+    engines: {node: '>=0.10.0'}
+
   symbol-tree@3.2.4:
     resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
 
+  systeminformation@5.31.6:
+    resolution: {integrity: sha512-Uv2b2uGGM6ns+26czgW2cYRabYdnswM0ddSOOlryHOaelzsmDSet1iM/NT7VOYxW8x/BW+HkY+b1Ve2pLTSGSA==}
+    engines: {node: '>=8.0.0'}
+    os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android]
+    hasBin: true
+
   tapable@1.1.3:
     resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==}
     engines: {node: '>=6'}
@@ -10126,6 +11795,10 @@ packages:
     resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
     engines: {node: '>=6'}
 
+  tapable@2.3.3:
+    resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
+    engines: {node: '>=6'}
+
   temp-dir@2.0.0:
     resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
     engines: {node: '>=8'}
@@ -10142,6 +11815,12 @@ packages:
     resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==}
     engines: {node: '>=10'}
 
+  terser-webpack-plugin@1.4.6:
+    resolution: {integrity: sha512-2lBVf/VMVIddjSn3GqbT90GvIJ/eYXJkt8cTzU7NbjKqK8fwv18Ftr4PlbF46b/e88743iZFL5Dtr/rC4hjIeA==}
+    engines: {node: '>= 6.9.0'}
+    peerDependencies:
+      webpack: ^4.0.0
+
   terser-webpack-plugin@5.3.10:
     resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==}
     engines: {node: '>= 10.13.0'}
@@ -10174,6 +11853,11 @@ packages:
       uglify-js:
         optional: true
 
+  terser@4.8.1:
+    resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+
   terser@5.33.0:
     resolution: {integrity: sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==}
     engines: {node: '>=10'}
@@ -10190,6 +11874,13 @@ packages:
   text-table@0.2.0:
     resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
 
+  thenify-all@1.6.0:
+    resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+    engines: {node: '>=0.8'}
+
+  thenify@3.3.1:
+    resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+
   three@0.168.0:
     resolution: {integrity: sha512-6m6jXtDwMJEK/GGMbAOTSAmxNdzKvvBzgd7q8bE/7Tr6m7PaBh5kKLrN7faWtlglXbzj7sVba48Idwx+NRsZXw==}
 
@@ -10212,15 +11903,34 @@ packages:
   thunky@1.1.0:
     resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==}
 
+  timers-browserify@2.0.12:
+    resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==}
+    engines: {node: '>=0.6.0'}
+
+  timers-ext@0.1.8:
+    resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==}
+    engines: {node: '>=0.12'}
+
   tiny-invariant@1.3.3:
     resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
 
   tiny-warning@1.0.3:
     resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
 
+  tmp@0.0.33:
+    resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
+    engines: {node: '>=0.6.0'}
+
   tmpl@1.0.5:
     resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
 
+  to-arraybuffer@1.0.1:
+    resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==}
+
+  to-buffer@1.2.2:
+    resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==}
+    engines: {node: '>= 0.4'}
+
   to-object-path@0.3.0:
     resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==}
     engines: {node: '>=0.10.0'}
@@ -10240,6 +11950,10 @@ packages:
   toggle-selection@1.0.6:
     resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==}
 
+  toidentifier@1.0.0:
+    resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==}
+    engines: {node: '>=0.6'}
+
   toidentifier@1.0.1:
     resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
     engines: {node: '>=0.6'}
@@ -10279,33 +11993,80 @@ packages:
     peerDependencies:
       jest: '>=24 <25'
 
+  ts-loader@6.2.2:
+    resolution: {integrity: sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ==}
+    engines: {node: '>=8.6'}
+    peerDependencies:
+      typescript: '*'
+
+  ts-node@8.10.2:
+    resolution: {integrity: sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+    peerDependencies:
+      typescript: '>=2.7'
+
+  tsconfig-paths-webpack-plugin@3.2.0:
+    resolution: {integrity: sha512-S/gOOPOkV8rIL4LurZ1vUdYCVgo15iX9ZMJ6wx6w2OgcpT/G4wMyHB6WM+xheSqGMrWKuxFul+aXpCju3wmj/g==}
+
   tsconfig-paths-webpack-plugin@3.5.2:
     resolution: {integrity: sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==}
 
   tsconfig-paths@3.15.0:
     resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
 
+  tsconfig-paths@3.9.0:
+    resolution: {integrity: sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==}
+
+  tslib@1.11.1:
+    resolution: {integrity: sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==}
+
   tslib@1.14.1:
     resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
 
+  tslib@1.9.3:
+    resolution: {integrity: sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==}
+
   tslib@2.3.0:
     resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
 
   tslib@2.7.0:
     resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
 
+  tslint@5.20.1:
+    resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==}
+    engines: {node: '>=4.8.0'}
+    hasBin: true
+    peerDependencies:
+      typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev'
+
+  tsutils@2.29.0:
+    resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==}
+    peerDependencies:
+      typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev'
+
   tsutils@3.21.0:
     resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
     engines: {node: '>= 6'}
     peerDependencies:
       typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
 
+  tty-browserify@0.0.0:
+    resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==}
+
   tunnel-agent@0.6.0:
     resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
 
+  tv4@1.3.0:
+    resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==}
+    engines: {node: '>= 0.8.0'}
+
   tweetnacl@0.14.5:
     resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
 
+  tx2@1.0.5:
+    resolution: {integrity: sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==}
+
   type-check@0.3.2:
     resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==}
     engines: {node: '>= 0.8.0'}
@@ -10362,10 +12123,17 @@ packages:
     resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
     engines: {node: '>= 0.6'}
 
+  type@2.7.3:
+    resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
+
   typed-array-buffer@1.0.2:
     resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
     engines: {node: '>= 0.4'}
 
+  typed-array-buffer@1.0.3:
+    resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
+    engines: {node: '>= 0.4'}
+
   typed-array-byte-length@1.0.1:
     resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
     engines: {node: '>= 0.4'}
@@ -10381,6 +12149,65 @@ packages:
   typedarray-to-buffer@3.1.5:
     resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
 
+  typedarray@0.0.6:
+    resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
+
+  typeorm@0.2.45:
+    resolution: {integrity: sha512-c0rCO8VMJ3ER7JQ73xfk0zDnVv0WDjpsP6Q1m6CVKul7DB9iVdWLRjPzc8v2eaeBuomsbZ2+gTaYr8k1gm3bYA==}
+    hasBin: true
+    peerDependencies:
+      '@sap/hana-client': ^2.11.14
+      better-sqlite3: ^7.1.2
+      hdb-pool: ^0.1.6
+      ioredis: ^4.28.3
+      mongodb: ^3.6.0
+      mssql: ^6.3.1
+      mysql2: ^2.2.5
+      oracledb: ^5.1.0
+      pg: ^8.5.1
+      pg-native: ^3.0.0
+      pg-query-stream: ^4.0.0
+      redis: ^3.1.1
+      sql.js: ^1.4.0
+      sqlite3: ^5.0.2
+      typeorm-aurora-data-api-driver: ^2.0.0
+    peerDependenciesMeta:
+      '@sap/hana-client':
+        optional: true
+      better-sqlite3:
+        optional: true
+      hdb-pool:
+        optional: true
+      ioredis:
+        optional: true
+      mongodb:
+        optional: true
+      mssql:
+        optional: true
+      mysql2:
+        optional: true
+      oracledb:
+        optional: true
+      pg:
+        optional: true
+      pg-native:
+        optional: true
+      pg-query-stream:
+        optional: true
+      redis:
+        optional: true
+      sql.js:
+        optional: true
+      sqlite3:
+        optional: true
+      typeorm-aurora-data-api-driver:
+        optional: true
+
+  typescript@3.9.10:
+    resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==}
+    engines: {node: '>=4.2.0'}
+    hasBin: true
+
   typescript@4.1.6:
     resolution: {integrity: sha512-pxnwLxeb/Z5SP80JDRzVjh58KsM6jZHRAOtTpS7sXLS4ogXNKC9ANxHHZqLLeVHZN35jCtI4JdmLLbLiC1kBow==}
     engines: {node: '>=4.2.0'}
@@ -10416,6 +12243,10 @@ packages:
   undici-types@7.12.0:
     resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==}
 
+  unescape@1.0.1:
+    resolution: {integrity: sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==}
+    engines: {node: '>=0.10.0'}
+
   unicode-canonical-property-names-ecmascript@2.0.1:
     resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==}
     engines: {node: '>=4'}
@@ -10443,6 +12274,12 @@ packages:
     resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
     engines: {node: '>=0.10.0'}
 
+  unique-filename@1.1.1:
+    resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==}
+
+  unique-slug@2.0.2:
+    resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==}
+
   unique-string@2.0.0:
     resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
     engines: {node: '>=8'}
@@ -10522,6 +12359,19 @@ packages:
       file-loader:
         optional: true
 
+  url@0.11.4:
+    resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==}
+    engines: {node: '>= 0.4'}
+
+  urllib@2.44.0:
+    resolution: {integrity: sha512-zRCJqdfYllRDA9bXUtx+vccyRqtJPKsw85f44zH7zPD28PIvjMqIgw9VwoTLV7xTBWZsbebUFVHU5ghQcWku2A==}
+    engines: {node: '>= 0.10.0'}
+    peerDependencies:
+      proxy-agent: ^5.0.0
+    peerDependenciesMeta:
+      proxy-agent:
+        optional: true
+
   use-intl@1.5.1:
     resolution: {integrity: sha512-GVqDf8NjeAxCrHGi3ZiofCmqUyX9gRnC9WNhwl5XLPLZ8b5g2zycGlRP1KxmKvQMu7l3asXZM7ALnj+Ls764iw==}
     engines: {node: '>=10'}
@@ -10548,6 +12398,12 @@ packages:
   util.promisify@1.1.2:
     resolution: {integrity: sha512-PBdZ03m1kBnQ5cjjO0ZvJMJS+QsbyIcFwi4hY4U76OQsCO9JrOYjbCFgIF76ccFg9xnJo7ZHPkqyj1GqmdS7MA==}
 
+  util@0.10.4:
+    resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==}
+
+  util@0.11.1:
+    resolution: {integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==}
+
   utila@0.4.0:
     resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==}
 
@@ -10555,6 +12411,10 @@ packages:
     resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
     engines: {node: '>= 4'}
 
+  utility@1.18.0:
+    resolution: {integrity: sha512-PYxZDA+6QtvRvm//++aGdmKG/cI07jNwbROz0Ql+VzFV1+Z0Dy55NI4zZ7RHc9KKpBePNFwoErqIuqQv/cjiTA==}
+    engines: {node: '>= 0.12.0'}
+
   utils-merge@1.0.1:
     resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
     engines: {node: '>= 0.4.0'}
@@ -10564,8 +12424,19 @@ packages:
     deprecated: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
     hasBin: true
 
+  uuid@7.0.1:
+    resolution: {integrity: sha512-yqjRXZzSJm9Dbl84H2VDHpM3zMjzSJQ+hn6C4zqd5ilW+7P4ZmLEEqwho9LjP+tGuZlF4xrHQXT0h9QZUS/pWA==}
+    deprecated: uuid@10 and below is no longer supported.  For ESM codebases, update to uuid@latest.  For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
+    hasBin: true
+
+  uuid@7.0.3:
+    resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==}
+    deprecated: uuid@10 and below is no longer supported.  For ESM codebases, update to uuid@latest.  For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
+    hasBin: true
+
   uuid@8.3.2:
     resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+    deprecated: uuid@10 and below is no longer supported.  For ESM codebases, update to uuid@latest.  For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
     hasBin: true
 
   v8-compile-cache@2.4.0:
@@ -10574,6 +12445,10 @@ packages:
   validate-npm-package-license@3.0.4:
     resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
 
+  validator@13.15.35:
+    resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==}
+    engines: {node: '>= 0.10'}
+
   value-equal@1.0.1:
     resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==}
 
@@ -10597,9 +12472,16 @@ packages:
   viewerjs@1.11.6:
     resolution: {integrity: sha512-TlhdSp2oEOLFXvEp4psKaeTjR5zBjTRcM/sHUN8PkV1UWuY8HKC8n7GaVdW5Xqnwdr/F1OmzLik1QwDjI4w/nw==}
 
+  vizion@2.2.1:
+    resolution: {integrity: sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==}
+    engines: {node: '>=4.0'}
+
   vlq@1.0.1:
     resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==}
 
+  vm-browserify@1.1.2:
+    resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==}
+
   w3c-hr-time@1.0.2:
     resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
     deprecated: Use your platform's native performance.now() and performance.timeOrigin.
@@ -10610,6 +12492,12 @@ packages:
   warning@4.0.3:
     resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
 
+  watchpack-chokidar2@2.0.1:
+    resolution: {integrity: sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==}
+
+  watchpack@1.7.5:
+    resolution: {integrity: sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==}
+
   watchpack@2.4.2:
     resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==}
     engines: {node: '>=10.13.0'}
@@ -10665,6 +12553,9 @@ packages:
     resolution: {integrity: sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==}
     engines: {node: '>=18.0.0'}
 
+  webpack-node-externals@1.7.2:
+    resolution: {integrity: sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==}
+
   webpack-sources@1.4.3:
     resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==}
 
@@ -10672,6 +12563,19 @@ packages:
     resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
     engines: {node: '>=10.13.0'}
 
+  webpack@4.41.5:
+    resolution: {integrity: sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw==}
+    engines: {node: '>=6.11.5'}
+    hasBin: true
+    peerDependencies:
+      webpack-cli: '*'
+      webpack-command: '*'
+    peerDependenciesMeta:
+      webpack-cli:
+        optional: true
+      webpack-command:
+        optional: true
+
   webpack@5.98.0:
     resolution: {integrity: sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==}
     engines: {node: '>=10.13.0'}
@@ -10732,6 +12636,10 @@ packages:
     resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==}
     engines: {node: '>= 0.4'}
 
+  which-typed-array@1.1.20:
+    resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==}
+    engines: {node: '>= 0.4'}
+
   which@1.3.1:
     resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
     hasBin: true
@@ -10748,6 +12656,14 @@ packages:
   wildcard@2.0.1:
     resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==}
 
+  win-release@1.1.1:
+    resolution: {integrity: sha512-iCRnKVvGxOQdsKhcQId2PXV1vV3J/sDPXKA4Oe9+Eti2nb2ESEsYHRYls/UjoUW3bIc5ZDO8dTH50A/5iVN+bw==}
+    engines: {node: '>=0.10.0'}
+
+  windows-release@3.3.3:
+    resolution: {integrity: sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==}
+    engines: {node: '>=6'}
+
   word-wrap@1.2.5:
     resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
     engines: {node: '>=0.10.0'}
@@ -10812,6 +12728,12 @@ packages:
   workbox-window@6.6.0:
     resolution: {integrity: sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==}
 
+  worker-farm@1.7.0:
+    resolution: {integrity: sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==}
+
+  worker-rpc@0.1.1:
+    resolution: {integrity: sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==}
+
   wrap-ansi@5.1.0:
     resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==}
     engines: {node: '>=6'}
@@ -10886,6 +12808,10 @@ packages:
       utf-8-validate:
         optional: true
 
+  x-xss-protection@1.3.0:
+    resolution: {integrity: sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==}
+    engines: {node: '>=4.0.0'}
+
   xdg-basedir@5.1.0:
     resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==}
     engines: {node: '>=12'}
@@ -10897,9 +12823,21 @@ packages:
   xml-name-validator@3.0.0:
     resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==}
 
+  xml2js@0.4.23:
+    resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==}
+    engines: {node: '>=4.0.0'}
+
+  xml2js@0.6.2:
+    resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==}
+    engines: {node: '>=4.0.0'}
+
   xml@1.0.1:
     resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==}
 
+  xmlbuilder@11.0.1:
+    resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
+    engines: {node: '>=4.0'}
+
   xtend@4.0.2:
     resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
     engines: {node: '>=0.4'}
@@ -10965,6 +12903,10 @@ packages:
     resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
     engines: {node: '>=12'}
 
+  yn@3.1.1:
+    resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
+    engines: {node: '>=6'}
+
   yocto-queue@0.1.0:
     resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
     engines: {node: '>=10'}
@@ -10976,6 +12918,12 @@ packages:
   zdog@1.1.3:
     resolution: {integrity: sha512-raRj6r0gPzopFm5XWBJZr/NuV4EEnT4iE+U3dp5FV5pCb588Gmm3zLIp/j9yqqcMiHH8VNQlerLTgOqL7krh6w==}
 
+  zen-observable-ts@1.1.0:
+    resolution: {integrity: sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==}
+
+  zen-observable@0.8.15:
+    resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==}
+
   zrender@5.6.1:
     resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
 
@@ -11107,6 +13055,35 @@ snapshots:
       '@jridgewell/gen-mapping': 0.3.5
       '@jridgewell/trace-mapping': 0.3.25
 
+  '@angular-devkit/core@7.3.8':
+    dependencies:
+      ajv: 6.9.1
+      chokidar: 2.0.4
+      fast-json-stable-stringify: 2.0.0
+      rxjs: 6.3.3
+      source-map: 0.7.3
+    transitivePeerDependencies:
+      - supports-color
+
+  '@angular-devkit/schematics-cli@0.13.8':
+    dependencies:
+      '@angular-devkit/core': 7.3.8
+      '@angular-devkit/schematics': 7.3.8
+      '@schematics/schematics': 0.13.8
+      inquirer: 6.2.1
+      minimist: 1.2.0
+      rxjs: 6.3.3
+      symbol-observable: 1.2.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@angular-devkit/schematics@7.3.8':
+    dependencies:
+      '@angular-devkit/core': 7.3.8
+      rxjs: 6.3.3
+    transitivePeerDependencies:
+      - supports-color
+
   '@ant-design/colors@6.0.0':
     dependencies:
       '@ctrl/tinycolor': 3.6.1
@@ -11267,11 +13244,6 @@ snapshots:
       jsonpointer: 5.0.1
       leven: 3.1.0
 
-  '@babel/code-frame@7.24.7':
-    dependencies:
-      '@babel/highlight': 7.24.7
-      picocolors: 1.1.1
-
   '@babel/code-frame@7.26.2':
     dependencies:
       '@babel/helper-validator-identifier': 7.27.1
@@ -11285,7 +13257,7 @@ snapshots:
   '@babel/core@7.25.2':
     dependencies:
       '@ampproject/remapping': 2.3.0
-      '@babel/code-frame': 7.24.7
+      '@babel/code-frame': 7.26.2
       '@babel/generator': 7.25.6
       '@babel/helper-compilation-targets': 7.25.2
       '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
@@ -11624,8 +13596,6 @@ snapshots:
 
   '@babel/helper-string-parser@7.27.1': {}
 
-  '@babel/helper-validator-identifier@7.25.9': {}
-
   '@babel/helper-validator-identifier@7.27.1': {}
 
   '@babel/helper-validator-option@7.24.8': {}
@@ -11658,13 +13628,6 @@ snapshots:
       '@babel/template': 7.26.9
       '@babel/types': 7.28.4
 
-  '@babel/highlight@7.24.7':
-    dependencies:
-      '@babel/helper-validator-identifier': 7.25.9
-      chalk: 2.4.2
-      js-tokens: 4.0.0
-      picocolors: 1.1.1
-
   '@babel/parser@7.25.6':
     dependencies:
       '@babel/types': 7.28.4
@@ -14540,6 +16503,16 @@ snapshots:
       eslint: 8.11.0
       eslint-visitor-keys: 3.4.3
 
+  '@eslint-community/eslint-utils@4.4.0(eslint@8.57.1)':
+    dependencies:
+      eslint: 8.57.1
+      eslint-visitor-keys: 3.4.3
+
+  '@eslint-community/eslint-utils@4.9.0(eslint@8.57.1)':
+    dependencies:
+      eslint: 8.57.1
+      eslint-visitor-keys: 3.4.3
+
   '@eslint-community/eslint-utils@4.9.0(eslint@9.36.0(jiti@1.21.7))':
     dependencies:
       eslint: 9.36.0(jiti@1.21.7)
@@ -14577,6 +16550,20 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@eslint/eslintrc@2.1.4':
+    dependencies:
+      ajv: 6.12.6
+      debug: 4.4.3
+      espree: 9.6.1
+      globals: 13.24.0
+      ignore: 5.3.2
+      import-fresh: 3.3.0
+      js-yaml: 4.1.0
+      minimatch: 3.1.2
+      strip-json-comments: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+
   '@eslint/eslintrc@3.3.1':
     dependencies:
       ajv: 6.12.6
@@ -14591,6 +16578,8 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@eslint/js@8.57.1': {}
+
   '@eslint/js@9.36.0': {}
 
   '@eslint/object-schema@2.1.6': {}
@@ -14651,6 +16640,14 @@ snapshots:
       '@humanfs/core': 0.19.1
       '@humanwhocodes/retry': 0.4.3
 
+  '@humanwhocodes/config-array@0.13.0':
+    dependencies:
+      '@humanwhocodes/object-schema': 2.0.3
+      debug: 4.4.3
+      minimatch: 3.1.2
+    transitivePeerDependencies:
+      - supports-color
+
   '@humanwhocodes/config-array@0.9.5':
     dependencies:
       '@humanwhocodes/object-schema': 1.2.1
@@ -14663,14 +16660,23 @@ snapshots:
 
   '@humanwhocodes/object-schema@1.2.1': {}
 
+  '@humanwhocodes/object-schema@2.0.3': {}
+
   '@humanwhocodes/retry@0.4.3': {}
 
   '@hutson/parse-repository-url@3.0.2': {}
 
+  '@inquirer/external-editor@1.0.2(@types/node@12.20.55)':
+    dependencies:
+      chardet: 2.1.0
+      iconv-lite: 0.7.2
+    optionalDependencies:
+      '@types/node': 12.20.55
+
   '@inquirer/external-editor@1.0.2(@types/node@24.5.2)':
     dependencies:
       chardet: 2.1.0
-      iconv-lite: 0.7.0
+      iconv-lite: 0.7.2
     optionalDependencies:
       '@types/node': 24.5.2
 
@@ -14925,6 +16931,152 @@ snapshots:
       react: 17.0.2
       react-dom: 17.0.2(react@17.0.2)
 
+  '@nestjs/cli@6.14.2(eslint@8.57.1)':
+    dependencies:
+      '@angular-devkit/core': 7.3.8
+      '@angular-devkit/schematics': 7.3.8
+      '@angular-devkit/schematics-cli': 0.13.8
+      '@nestjs/schematics': 6.9.4(typescript@3.9.10)
+      '@types/webpack': 4.41.5
+      chalk: 2.4.2
+      cli-table3: 0.5.1
+      commander: 4.1.1
+      copyfiles: 2.2.0
+      fork-ts-checker-webpack-plugin: 4.0.3(eslint@8.57.1)(typescript@3.9.10)(webpack@4.41.5)
+      inquirer: 7.0.4
+      node-emoji: 1.10.0
+      ora: 4.0.3
+      os-name: 3.1.0
+      rimraf: 3.0.1
+      tree-kill: 1.2.2
+      tsconfig-paths: 3.9.0
+      tsconfig-paths-webpack-plugin: 3.2.0
+      typescript: 3.9.10
+      webpack: 4.41.5
+      webpack-node-externals: 1.7.2
+    transitivePeerDependencies:
+      - eslint
+      - supports-color
+      - vue-template-compiler
+      - webpack-cli
+      - webpack-command
+
+  '@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)':
+    dependencies:
+      axios: 0.19.2
+      cli-color: 2.0.0
+      reflect-metadata: 0.1.14
+      rxjs: 6.6.7
+      tslib: 1.11.1
+      uuid: 7.0.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@nestjs/config@0.6.3(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(reflect-metadata@0.1.14)(rxjs@6.6.7)':
+    dependencies:
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      dotenv: 8.2.0
+      dotenv-expand: 5.1.0
+      lodash.get: 4.4.2
+      lodash.has: 4.5.2
+      lodash.set: 4.3.2
+      reflect-metadata: 0.1.14
+      rxjs: 6.6.7
+      uuid: 8.3.2
+
+  '@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)':
+    dependencies:
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nuxtjs/opencollective': 0.2.2(encoding@0.1.13)
+      fast-safe-stringify: 2.0.7
+      iterare: 1.2.0
+      object-hash: 2.0.3
+      path-to-regexp: 3.2.0
+      reflect-metadata: 0.1.14
+      rxjs: 6.6.7
+      tslib: 1.11.1
+      uuid: 7.0.1
+    transitivePeerDependencies:
+      - encoding
+
+  '@nestjs/jwt@6.1.2(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))':
+    dependencies:
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@types/jsonwebtoken': 8.3.7
+      jsonwebtoken: 8.5.1
+
+  '@nestjs/mapped-types@0.4.1(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(class-transformer@0.2.3)(class-validator@0.13.2)(reflect-metadata@0.1.14)':
+    dependencies:
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      class-transformer: 0.2.3
+      class-validator: 0.13.2
+      reflect-metadata: 0.1.14
+
+  '@nestjs/passport@6.2.0(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(passport@0.4.1)':
+    dependencies:
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      passport: 0.4.1
+
+  '@nestjs/platform-express@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))':
+    dependencies:
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nestjs/core': 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      body-parser: 1.19.0
+      cors: 2.8.5
+      express: 4.17.1
+      multer: 1.4.2
+      tslib: 1.11.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@nestjs/schematics@6.9.4(typescript@3.9.10)':
+    dependencies:
+      '@angular-devkit/core': 7.3.8
+      '@angular-devkit/schematics': 7.3.8
+      fs-extra: 8.1.0
+      typescript: 3.9.10
+    transitivePeerDependencies:
+      - supports-color
+
+  '@nestjs/schematics@6.9.4(typescript@4.1.6)':
+    dependencies:
+      '@angular-devkit/core': 7.3.8
+      '@angular-devkit/schematics': 7.3.8
+      fs-extra: 8.1.0
+      typescript: 4.1.6
+    transitivePeerDependencies:
+      - supports-color
+
+  '@nestjs/swagger@4.8.2(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))(class-transformer@0.2.3)(class-validator@0.13.2)(reflect-metadata@0.1.14)(swagger-ui-express@4.6.3(express@4.21.2))':
+    dependencies:
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nestjs/core': 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nestjs/mapped-types': 0.4.1(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(class-transformer@0.2.3)(class-validator@0.13.2)(reflect-metadata@0.1.14)
+      lodash: 4.17.21
+      path-to-regexp: 3.2.0
+      reflect-metadata: 0.1.14
+    optionalDependencies:
+      swagger-ui-express: 4.6.3(express@4.21.2)
+    transitivePeerDependencies:
+      - class-transformer
+      - class-validator
+
+  '@nestjs/testing@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))':
+    dependencies:
+      optional: 0.1.4
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nestjs/core': 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      tslib: 1.11.1
+
+  '@nestjs/typeorm@6.3.4(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(@nestjs/core@6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7))(reflect-metadata@0.1.14)(rxjs@6.6.7)(typeorm@0.2.45(mysql2@3.22.3(@types/node@12.20.55)))':
+    dependencies:
+      '@nestjs/common': 6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      '@nestjs/core': 6.11.11(@nestjs/common@6.11.11(reflect-metadata@0.1.14)(rxjs@6.6.7))(encoding@0.1.13)(reflect-metadata@0.1.14)(rxjs@6.6.7)
+      reflect-metadata: 0.1.14
+      rxjs: 6.6.7
+      typeorm: 0.2.45(mysql2@3.22.3(@types/node@12.20.55))
+      uuid: 7.0.3
+
   '@next/env@12.3.4': {}
 
   '@next/eslint-plugin-next@12.1.0':
@@ -14982,6 +17134,65 @@ snapshots:
       '@nodelib/fs.scandir': 2.1.5
       fastq: 1.17.1
 
+  '@nuxtjs/opencollective@0.2.2(encoding@0.1.13)':
+    dependencies:
+      chalk: 2.4.2
+      consola: 2.15.3
+      node-fetch: 2.7.0(encoding@0.1.13)
+    transitivePeerDependencies:
+      - encoding
+
+  '@pm2/agent@2.0.4':
+    dependencies:
+      async: 3.2.6
+      chalk: 3.0.0
+      dayjs: 1.8.36
+      debug: 4.3.7(supports-color@9.4.0)
+      eventemitter2: 5.0.1
+      fast-json-patch: 3.1.1
+      fclone: 1.0.11
+      nssocket: 0.6.0
+      pm2-axon: 4.0.1
+      pm2-axon-rpc: 0.7.1
+      proxy-agent: 6.3.1
+      semver: 7.5.4
+      ws: 7.5.10
+    transitivePeerDependencies:
+      - bufferutil
+      - supports-color
+      - utf-8-validate
+
+  '@pm2/io@6.0.1':
+    dependencies:
+      async: 2.6.4
+      debug: 4.3.7(supports-color@9.4.0)
+      eventemitter2: 6.4.9
+      require-in-the-middle: 5.2.0
+      semver: 7.5.4
+      shimmer: 1.2.1
+      signal-exit: 3.0.7
+      tslib: 1.9.3
+    transitivePeerDependencies:
+      - supports-color
+
+  '@pm2/js-api@0.8.0':
+    dependencies:
+      async: 2.6.4
+      debug: 4.3.7(supports-color@9.4.0)
+      eventemitter2: 6.4.9
+      extrareqp2: 1.0.0(debug@4.3.7)
+      ws: 7.5.10
+    transitivePeerDependencies:
+      - bufferutil
+      - supports-color
+      - utf-8-validate
+
+  '@pm2/pm2-version-check@1.0.4':
+    dependencies:
+      debug: 4.4.3
+    transitivePeerDependencies:
+      - supports-color
+
   '@pnpm/config.env-replace@1.1.0': {}
 
   '@pnpm/network.ca-file@1.0.2':
@@ -15461,6 +17672,15 @@ snapshots:
 
   '@rushstack/eslint-patch@1.10.4': {}
 
+  '@scarf/scarf@1.4.0': {}
+
+  '@schematics/schematics@0.13.8':
+    dependencies:
+      '@angular-devkit/core': 7.3.8
+      '@angular-devkit/schematics': 7.3.8
+    transitivePeerDependencies:
+      - supports-color
+
   '@sideway/address@4.1.5':
     dependencies:
       '@hapi/hoek': 9.3.0
@@ -15499,6 +17719,8 @@ snapshots:
       micromark-util-character: 1.2.0
       micromark-util-symbol: 1.1.0
 
+  '@sqltools/formatter@1.2.5': {}
+
   '@surma/rollup-plugin-off-main-thread@2.2.3':
     dependencies:
       ejs: 3.1.10
@@ -15636,12 +17858,18 @@ snapshots:
     optionalDependencies:
       '@types/react': 17.0.42
 
+  '@tootallnate/quickjs-emscripten@0.23.0': {}
+
   '@trysound/sax@0.2.0': {}
 
   '@types/acorn@4.0.6':
     dependencies:
       '@types/estree': 1.0.6
 
+  '@types/anymatch@3.0.4':
+    dependencies:
+      anymatch: 3.1.3
+
   '@types/aria-query@5.0.4': {}
 
   '@types/babel__core@7.20.5':
@@ -15683,6 +17911,8 @@ snapshots:
     dependencies:
       '@types/node': 17.0.22
 
+  '@types/cookiejar@2.1.5': {}
+
   '@types/debounce@1.2.4': {}
 
   '@types/debug@4.1.12':
@@ -15771,12 +18001,18 @@ snapshots:
 
   '@types/json5@0.0.29': {}
 
+  '@types/jsonwebtoken@8.3.7':
+    dependencies:
+      '@types/node': 17.0.22
+
   '@types/mdast@4.0.4':
     dependencies:
       '@types/unist': 3.0.3
 
   '@types/mdx@2.0.13': {}
 
+  '@types/methods@1.1.4': {}
+
   '@types/mime@1.3.5': {}
 
   '@types/minimatch@5.1.2': {}
@@ -15789,6 +18025,8 @@ snapshots:
     dependencies:
       '@types/node': 17.0.22
 
+  '@types/node@12.20.55': {}
+
   '@types/node@17.0.22': {}
 
   '@types/node@24.5.2':
@@ -15875,18 +18113,54 @@ snapshots:
     dependencies:
       '@types/node': 17.0.22
 
+  '@types/source-list-map@0.1.6': {}
+
   '@types/stack-utils@1.0.1': {}
 
   '@types/stack-utils@2.0.3': {}
 
+  '@types/superagent@8.1.9':
+    dependencies:
+      '@types/cookiejar': 2.1.5
+      '@types/methods': 1.1.4
+      '@types/node': 17.0.22
+      form-data: 4.0.4
+
+  '@types/supertest@2.0.16':
+    dependencies:
+      '@types/superagent': 8.1.9
+
   '@types/swagger-schema-official@2.0.22': {}
 
+  '@types/tapable@2.3.0':
+    dependencies:
+      tapable: 2.3.3
+
   '@types/trusted-types@2.0.7': {}
 
+  '@types/uglify-js@3.17.5':
+    dependencies:
+      source-map: 0.6.1
+
   '@types/unist@2.0.11': {}
 
   '@types/unist@3.0.3': {}
 
+  '@types/webpack-sources@3.2.3':
+    dependencies:
+      '@types/node': 17.0.22
+      '@types/source-list-map': 0.1.6
+      source-map: 0.7.4
+
+  '@types/webpack@4.41.5':
+    dependencies:
+      '@types/anymatch': 3.0.4
+      '@types/node': 17.0.22
+      '@types/tapable': 2.3.0
+      '@types/uglify-js': 3.17.5
+      '@types/webpack-sources': 3.2.3
+      source-map: 0.6.1
+
   '@types/webxr@0.5.20': {}
 
   '@types/ws@8.5.14':
@@ -15907,6 +18181,8 @@ snapshots:
     dependencies:
       '@types/yargs-parser': 21.0.3
 
+  '@types/zen-observable@0.8.3': {}
+
   '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint@8.11.0)(typescript@4.6.2)':
     dependencies:
       '@eslint-community/regexpp': 4.11.1
@@ -15926,6 +18202,25 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1)(typescript@4.1.6)':
+    dependencies:
+      '@eslint-community/regexpp': 4.11.1
+      '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.1.6)
+      '@typescript-eslint/scope-manager': 5.62.0
+      '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@4.1.6)
+      '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.1.6)
+      debug: 4.3.7(supports-color@9.4.0)
+      eslint: 8.57.1
+      graphemer: 1.4.0
+      ignore: 5.3.2
+      natural-compare-lite: 1.4.0
+      semver: 7.6.3
+      tsutils: 3.21.0(typescript@4.1.6)
+    optionalDependencies:
+      typescript: 4.1.6
+    transitivePeerDependencies:
+      - supports-color
+
   '@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2)':
     dependencies:
       '@typescript-eslint/scope-manager': 5.62.0
@@ -15938,6 +18233,18 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6)':
+    dependencies:
+      '@typescript-eslint/scope-manager': 5.62.0
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.1.6)
+      debug: 4.3.7(supports-color@9.4.0)
+      eslint: 8.57.1
+    optionalDependencies:
+      typescript: 4.1.6
+    transitivePeerDependencies:
+      - supports-color
+
   '@typescript-eslint/scope-manager@5.62.0':
     dependencies:
       '@typescript-eslint/types': 5.62.0
@@ -15955,8 +18262,34 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@4.1.6)':
+    dependencies:
+      '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.1.6)
+      '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.1.6)
+      debug: 4.4.3
+      eslint: 8.57.1
+      tsutils: 3.21.0(typescript@4.1.6)
+    optionalDependencies:
+      typescript: 4.1.6
+    transitivePeerDependencies:
+      - supports-color
+
   '@typescript-eslint/types@5.62.0': {}
 
+  '@typescript-eslint/typescript-estree@5.62.0(typescript@4.1.6)':
+    dependencies:
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/visitor-keys': 5.62.0
+      debug: 4.4.3
+      globby: 11.1.0
+      is-glob: 4.0.3
+      semver: 7.6.3
+      tsutils: 3.21.0(typescript@4.1.6)
+    optionalDependencies:
+      typescript: 4.1.6
+    transitivePeerDependencies:
+      - supports-color
+
   '@typescript-eslint/typescript-estree@5.62.0(typescript@4.6.2)':
     dependencies:
       '@typescript-eslint/types': 5.62.0
@@ -15986,14 +18319,29 @@ snapshots:
       - supports-color
       - typescript
 
-  '@typescript-eslint/visitor-keys@5.62.0':
+  '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@4.1.6)':
     dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1)
+      '@types/json-schema': 7.0.15
+      '@types/semver': 7.5.8
+      '@typescript-eslint/scope-manager': 5.62.0
       '@typescript-eslint/types': 5.62.0
-      eslint-visitor-keys: 3.4.3
-
-  '@umijs/route-utils@4.0.1': {}
-
-  '@umijs/use-params@1.0.9(react@17.0.2)':
+      '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.1.6)
+      eslint: 8.57.1
+      eslint-scope: 5.1.1
+      semver: 7.6.3
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+
+  '@typescript-eslint/visitor-keys@5.62.0':
+    dependencies:
+      '@typescript-eslint/types': 5.62.0
+      eslint-visitor-keys: 3.4.3
+
+  '@umijs/route-utils@4.0.1': {}
+
+  '@umijs/use-params@1.0.9(react@17.0.2)':
     dependencies:
       react: 17.0.2
 
@@ -16004,12 +18352,35 @@ snapshots:
       '@webassemblyjs/helper-numbers': 1.13.2
       '@webassemblyjs/helper-wasm-bytecode': 1.13.2
 
+  '@webassemblyjs/ast@1.8.5':
+    dependencies:
+      '@webassemblyjs/helper-module-context': 1.8.5
+      '@webassemblyjs/helper-wasm-bytecode': 1.8.5
+      '@webassemblyjs/wast-parser': 1.8.5
+
   '@webassemblyjs/floating-point-hex-parser@1.13.2': {}
 
+  '@webassemblyjs/floating-point-hex-parser@1.8.5': {}
+
   '@webassemblyjs/helper-api-error@1.13.2': {}
 
+  '@webassemblyjs/helper-api-error@1.8.5': {}
+
   '@webassemblyjs/helper-buffer@1.14.1': {}
 
+  '@webassemblyjs/helper-buffer@1.8.5': {}
+
+  '@webassemblyjs/helper-code-frame@1.8.5':
+    dependencies:
+      '@webassemblyjs/wast-printer': 1.8.5
+
+  '@webassemblyjs/helper-fsm@1.8.5': {}
+
+  '@webassemblyjs/helper-module-context@1.8.5':
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      mamacro: 0.0.3
+
   '@webassemblyjs/helper-numbers@1.13.2':
     dependencies:
       '@webassemblyjs/floating-point-hex-parser': 1.13.2
@@ -16018,6 +18389,8 @@ snapshots:
 
   '@webassemblyjs/helper-wasm-bytecode@1.13.2': {}
 
+  '@webassemblyjs/helper-wasm-bytecode@1.8.5': {}
+
   '@webassemblyjs/helper-wasm-section@1.14.1':
     dependencies:
       '@webassemblyjs/ast': 1.14.1
@@ -16025,16 +18398,33 @@ snapshots:
       '@webassemblyjs/helper-wasm-bytecode': 1.13.2
       '@webassemblyjs/wasm-gen': 1.14.1
 
+  '@webassemblyjs/helper-wasm-section@1.8.5':
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      '@webassemblyjs/helper-buffer': 1.8.5
+      '@webassemblyjs/helper-wasm-bytecode': 1.8.5
+      '@webassemblyjs/wasm-gen': 1.8.5
+
   '@webassemblyjs/ieee754@1.13.2':
     dependencies:
       '@xtuc/ieee754': 1.2.0
 
+  '@webassemblyjs/ieee754@1.8.5':
+    dependencies:
+      '@xtuc/ieee754': 1.2.0
+
   '@webassemblyjs/leb128@1.13.2':
     dependencies:
       '@xtuc/long': 4.2.2
 
+  '@webassemblyjs/leb128@1.8.5':
+    dependencies:
+      '@xtuc/long': 4.2.2
+
   '@webassemblyjs/utf8@1.13.2': {}
 
+  '@webassemblyjs/utf8@1.8.5': {}
+
   '@webassemblyjs/wasm-edit@1.14.1':
     dependencies:
       '@webassemblyjs/ast': 1.14.1
@@ -16046,6 +18436,17 @@ snapshots:
       '@webassemblyjs/wasm-parser': 1.14.1
       '@webassemblyjs/wast-printer': 1.14.1
 
+  '@webassemblyjs/wasm-edit@1.8.5':
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      '@webassemblyjs/helper-buffer': 1.8.5
+      '@webassemblyjs/helper-wasm-bytecode': 1.8.5
+      '@webassemblyjs/helper-wasm-section': 1.8.5
+      '@webassemblyjs/wasm-gen': 1.8.5
+      '@webassemblyjs/wasm-opt': 1.8.5
+      '@webassemblyjs/wasm-parser': 1.8.5
+      '@webassemblyjs/wast-printer': 1.8.5
+
   '@webassemblyjs/wasm-gen@1.14.1':
     dependencies:
       '@webassemblyjs/ast': 1.14.1
@@ -16054,6 +18455,14 @@ snapshots:
       '@webassemblyjs/leb128': 1.13.2
       '@webassemblyjs/utf8': 1.13.2
 
+  '@webassemblyjs/wasm-gen@1.8.5':
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      '@webassemblyjs/helper-wasm-bytecode': 1.8.5
+      '@webassemblyjs/ieee754': 1.8.5
+      '@webassemblyjs/leb128': 1.8.5
+      '@webassemblyjs/utf8': 1.8.5
+
   '@webassemblyjs/wasm-opt@1.14.1':
     dependencies:
       '@webassemblyjs/ast': 1.14.1
@@ -16061,6 +18470,13 @@ snapshots:
       '@webassemblyjs/wasm-gen': 1.14.1
       '@webassemblyjs/wasm-parser': 1.14.1
 
+  '@webassemblyjs/wasm-opt@1.8.5':
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      '@webassemblyjs/helper-buffer': 1.8.5
+      '@webassemblyjs/wasm-gen': 1.8.5
+      '@webassemblyjs/wasm-parser': 1.8.5
+
   '@webassemblyjs/wasm-parser@1.14.1':
     dependencies:
       '@webassemblyjs/ast': 1.14.1
@@ -16070,11 +18486,35 @@ snapshots:
       '@webassemblyjs/leb128': 1.13.2
       '@webassemblyjs/utf8': 1.13.2
 
+  '@webassemblyjs/wasm-parser@1.8.5':
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      '@webassemblyjs/helper-api-error': 1.8.5
+      '@webassemblyjs/helper-wasm-bytecode': 1.8.5
+      '@webassemblyjs/ieee754': 1.8.5
+      '@webassemblyjs/leb128': 1.8.5
+      '@webassemblyjs/utf8': 1.8.5
+
+  '@webassemblyjs/wast-parser@1.8.5':
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      '@webassemblyjs/floating-point-hex-parser': 1.8.5
+      '@webassemblyjs/helper-api-error': 1.8.5
+      '@webassemblyjs/helper-code-frame': 1.8.5
+      '@webassemblyjs/helper-fsm': 1.8.5
+      '@xtuc/long': 4.2.2
+
   '@webassemblyjs/wast-printer@1.14.1':
     dependencies:
       '@webassemblyjs/ast': 1.14.1
       '@xtuc/long': 4.2.2
 
+  '@webassemblyjs/wast-printer@1.8.5':
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      '@webassemblyjs/wast-parser': 1.8.5
+      '@xtuc/long': 4.2.2
+
   '@xtuc/ieee754@1.2.0': {}
 
   '@xtuc/long@4.2.2': {}
@@ -16121,7 +18561,7 @@ snapshots:
 
   acorn-walk@8.3.4:
     dependencies:
-      acorn: 8.14.0
+      acorn: 8.15.0
 
   acorn@5.7.4: {}
 
@@ -16141,11 +18581,21 @@ snapshots:
 
   address@1.2.2: {}
 
+  agent-base@7.1.4: {}
+
+  agentkeepalive@3.5.3:
+    dependencies:
+      humanize-ms: 1.2.1
+
   aggregate-error@3.1.0:
     dependencies:
       clean-stack: 2.2.0
       indent-string: 4.0.0
 
+  ajv-errors@1.0.1(ajv@6.12.6):
+    dependencies:
+      ajv: 6.12.6
+
   ajv-formats@2.1.1(ajv@8.17.1):
     optionalDependencies:
       ajv: 8.17.1
@@ -16166,6 +18616,13 @@ snapshots:
       json-schema-traverse: 0.4.1
       uri-js: 4.4.1
 
+  ajv@6.9.1:
+    dependencies:
+      fast-deep-equal: 2.0.1
+      fast-json-stable-stringify: 2.1.0
+      json-schema-traverse: 0.4.1
+      uri-js: 4.4.1
+
   ajv@8.17.1:
     dependencies:
       fast-deep-equal: 3.1.3
@@ -16194,14 +18651,50 @@ snapshots:
       '@algolia/requester-fetch': 5.20.3
       '@algolia/requester-node-http': 5.20.3
 
+  ali-oss@6.23.0:
+    dependencies:
+      address: 1.2.2
+      agentkeepalive: 3.5.3
+      bowser: 1.9.4
+      copy-to: 2.0.1
+      dateformat: 2.2.0
+      debug: 4.4.3
+      destroy: 1.2.0
+      end-or-error: 1.0.1
+      get-ready: 1.0.0
+      humanize-ms: 1.2.1
+      is-type-of: 1.4.0
+      js-base64: 2.6.4
+      jstoxml: 2.2.9
+      lodash: 4.17.21
+      merge-descriptors: 1.0.3
+      mime: 2.6.0
+      platform: 1.3.6
+      pump: 3.0.2
+      qs: 6.14.0
+      sdk-base: 2.0.1
+      stream-http: 2.8.2
+      stream-wormhole: 1.1.0
+      urllib: 2.44.0
+      utility: 1.18.0
+      xml2js: 0.6.2
+    transitivePeerDependencies:
+      - proxy-agent
+      - supports-color
+
+  amp-message@0.1.2:
+    dependencies:
+      amp: 0.3.1
+
+  amp@0.3.1: {}
+
   anser@1.4.10: {}
 
   ansi-align@3.0.1:
     dependencies:
       string-width: 4.2.3
 
-  ansi-colors@4.1.3:
-    optional: true
+  ansi-colors@4.1.3: {}
 
   ansi-escapes@3.2.0: {}
 
@@ -16217,6 +18710,8 @@ snapshots:
 
   ansi-html-community@0.0.8: {}
 
+  ansi-regex@2.1.1: {}
+
   ansi-regex@3.0.1: {}
 
   ansi-regex@4.1.1: {}
@@ -16225,6 +18720,8 @@ snapshots:
 
   ansi-regex@6.0.1: {}
 
+  ansi-styles@2.2.1: {}
+
   ansi-styles@3.2.1:
     dependencies:
       color-convert: 1.9.3
@@ -16295,6 +18792,8 @@ snapshots:
       - luxon
       - moment
 
+  any-promise@1.3.0: {}
+
   anymatch@2.0.0:
     dependencies:
       micromatch: 3.1.10
@@ -16307,8 +18806,16 @@ snapshots:
       normalize-path: 3.0.0
       picomatch: 2.3.1
 
+  app-root-path@3.1.0: {}
+
   appdirsjs@1.2.7: {}
 
+  append-field@1.0.0: {}
+
+  aproba@1.2.0: {}
+
+  arg@4.1.3: {}
+
   arg@5.0.2: {}
 
   argparse@1.0.10:
@@ -16428,16 +18935,31 @@ snapshots:
 
   asap@2.0.6: {}
 
+  asn1.js@4.10.1:
+    dependencies:
+      bn.js: 4.12.3
+      inherits: 2.0.4
+      minimalistic-assert: 1.0.1
+
   asn1@0.2.6:
     dependencies:
       safer-buffer: 2.1.2
 
   assert-plus@1.0.0: {}
 
+  assert@1.5.1:
+    dependencies:
+      object.assign: 4.1.5
+      util: 0.10.4
+
   assign-symbols@1.0.0: {}
 
   ast-types-flow@0.0.8: {}
 
+  ast-types@0.13.4:
+    dependencies:
+      tslib: 2.7.0
+
   ast-types@0.15.2:
     dependencies:
       tslib: 2.7.0
@@ -16448,10 +18970,16 @@ snapshots:
 
   astring@1.9.0: {}
 
+  async-each@1.0.6: {}
+
   async-limiter@1.0.1: {}
 
   async-validator@1.11.5: {}
 
+  async@2.6.4:
+    dependencies:
+      lodash: 4.17.21
+
   async@3.2.6: {}
 
   asynckit@0.4.0: {}
@@ -16482,15 +19010,21 @@ snapshots:
 
   axe-core@4.10.0: {}
 
+  axios@0.19.2:
+    dependencies:
+      follow-redirects: 1.5.10
+    transitivePeerDependencies:
+      - supports-color
+
   axios@0.23.0:
     dependencies:
-      follow-redirects: 1.15.9
+      follow-redirects: 1.15.9(debug@4.3.7)
     transitivePeerDependencies:
       - debug
 
   axios@1.12.2:
     dependencies:
-      follow-redirects: 1.15.9
+      follow-redirects: 1.15.9(debug@4.3.7)
       form-data: 4.0.4
       proxy-from-env: 1.1.0
     transitivePeerDependencies:
@@ -16498,6 +19032,12 @@ snapshots:
 
   axobject-query@4.1.0: {}
 
+  babel-code-frame@6.26.0:
+    dependencies:
+      chalk: 1.1.3
+      esutils: 2.0.3
+      js-tokens: 3.0.2
+
   babel-core@7.0.0-bridge.0(@babel/core@7.26.9):
     dependencies:
       '@babel/core': 7.26.9
@@ -16645,14 +19185,20 @@ snapshots:
       mixin-deep: 1.3.2
       pascalcase: 0.1.1
 
+  basic-ftp@5.3.1: {}
+
   batch@0.6.1: {}
 
   bcrypt-pbkdf@1.0.2:
     dependencies:
       tweetnacl: 0.14.5
 
+  bcryptjs@2.4.3: {}
+
   big.js@5.2.2: {}
 
+  binary-extensions@1.13.1: {}
+
   binary-extensions@2.3.0: {}
 
   bindings@1.5.0:
@@ -16666,6 +19212,31 @@ snapshots:
       inherits: 2.0.4
       readable-stream: 3.6.2
 
+  blessed@0.1.81: {}
+
+  bluebird@3.7.2: {}
+
+  bn.js@4.12.3: {}
+
+  bn.js@5.2.3: {}
+
+  bodec@0.1.0: {}
+
+  body-parser@1.19.0:
+    dependencies:
+      bytes: 3.1.0
+      content-type: 1.0.5
+      debug: 2.6.9
+      depd: 1.1.2
+      http-errors: 1.7.2
+      iconv-lite: 0.4.24
+      on-finished: 2.3.0
+      qs: 6.7.0
+      raw-body: 2.4.0
+      type-is: 1.6.18
+    transitivePeerDependencies:
+      - supports-color
+
   body-parser@1.20.3:
     dependencies:
       bytes: 3.1.2
@@ -16704,6 +19275,10 @@ snapshots:
 
   boolbase@1.0.0: {}
 
+  bowser@1.9.4: {}
+
+  bowser@2.9.0: {}
+
   boxen@6.2.1:
     dependencies:
       ansi-align: 3.0.1
@@ -16754,12 +19329,58 @@ snapshots:
     dependencies:
       fill-range: 7.1.1
 
+  brorand@1.1.0: {}
+
   browser-process-hrtime@1.0.0: {}
 
   browser-resolve@1.11.3:
     dependencies:
       resolve: 1.1.7
 
+  browserify-aes@1.2.0:
+    dependencies:
+      buffer-xor: 1.0.3
+      cipher-base: 1.0.7
+      create-hash: 1.2.0
+      evp_bytestokey: 1.0.3
+      inherits: 2.0.4
+      safe-buffer: 5.2.1
+
+  browserify-cipher@1.0.1:
+    dependencies:
+      browserify-aes: 1.2.0
+      browserify-des: 1.0.2
+      evp_bytestokey: 1.0.3
+
+  browserify-des@1.0.2:
+    dependencies:
+      cipher-base: 1.0.7
+      des.js: 1.1.0
+      inherits: 2.0.4
+      safe-buffer: 5.2.1
+
+  browserify-rsa@4.1.1:
+    dependencies:
+      bn.js: 5.2.3
+      randombytes: 2.1.0
+      safe-buffer: 5.2.1
+
+  browserify-sign@4.2.5:
+    dependencies:
+      bn.js: 5.2.3
+      browserify-rsa: 4.1.1
+      create-hash: 1.2.0
+      create-hmac: 1.1.7
+      elliptic: 6.6.1
+      inherits: 2.0.4
+      parse-asn1: 5.1.9
+      readable-stream: 2.3.8
+      safe-buffer: 5.2.1
+
+  browserify-zlib@0.2.0:
+    dependencies:
+      pako: 1.0.11
+
   browserslist@4.23.3:
     dependencies:
       caniuse-lite: 1.0.30001701
@@ -16782,8 +19403,18 @@ snapshots:
     dependencies:
       node-int64: 0.4.0
 
+  buffer-equal-constant-time@1.0.1: {}
+
   buffer-from@1.1.2: {}
 
+  buffer-xor@1.0.3: {}
+
+  buffer@4.9.2:
+    dependencies:
+      base64-js: 1.5.1
+      ieee754: 1.2.1
+      isarray: 1.0.0
+
   buffer@5.7.1:
     dependencies:
       base64-js: 1.5.1
@@ -16794,12 +19425,41 @@ snapshots:
       base64-js: 1.5.1
       ieee754: 1.2.1
 
+  builtin-modules@1.1.1: {}
+
   builtin-modules@3.3.0: {}
 
+  builtin-status-codes@3.0.0: {}
+
+  busboy@0.2.14:
+    dependencies:
+      dicer: 0.2.5
+      readable-stream: 1.1.14
+
   bytes@3.0.0: {}
 
+  bytes@3.1.0: {}
+
   bytes@3.1.2: {}
 
+  cacache@12.0.4:
+    dependencies:
+      bluebird: 3.7.2
+      chownr: 1.1.4
+      figgy-pudding: 3.5.2
+      glob: 7.2.3
+      graceful-fs: 4.2.11
+      infer-owner: 1.0.4
+      lru-cache: 5.1.1
+      mississippi: 3.0.0
+      mkdirp: 0.5.6
+      move-concurrently: 1.0.1
+      promise-inflight: 1.0.1(bluebird@3.7.2)
+      rimraf: 2.7.1
+      ssri: 6.0.2
+      unique-filename: 1.1.1
+      y18n: 4.0.3
+
   cache-base@1.0.1:
     dependencies:
       collection-visit: 1.0.0
@@ -16837,6 +19497,13 @@ snapshots:
       get-intrinsic: 1.2.4
       set-function-length: 1.2.2
 
+  call-bind@1.0.9:
+    dependencies:
+      call-bind-apply-helpers: 1.0.2
+      es-define-property: 1.0.1
+      get-intrinsic: 1.3.0
+      set-function-length: 1.2.2
+
   call-bound@1.0.4:
     dependencies:
       call-bind-apply-helpers: 1.0.2
@@ -16875,6 +19542,8 @@ snapshots:
 
   camelcase@7.0.1: {}
 
+  camelize@1.0.0: {}
+
   caniuse-api@3.0.0:
     dependencies:
       browserslist: 4.23.3
@@ -16892,12 +19561,25 @@ snapshots:
 
   ccount@2.0.1: {}
 
+  chalk@1.1.3:
+    dependencies:
+      ansi-styles: 2.2.1
+      escape-string-regexp: 1.0.5
+      has-ansi: 2.0.0
+      strip-ansi: 3.0.1
+      supports-color: 2.0.0
+
   chalk@2.4.2:
     dependencies:
       ansi-styles: 3.2.1
       escape-string-regexp: 1.0.5
       supports-color: 5.5.0
 
+  chalk@3.0.0:
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
+
   chalk@4.1.2:
     dependencies:
       ansi-styles: 4.3.0
@@ -16915,8 +19597,12 @@ snapshots:
 
   character-reference-invalid@2.0.1: {}
 
+  chardet@0.7.0: {}
+
   chardet@2.1.0: {}
 
+  charm@0.1.2: {}
+
   cheerio-select@2.1.0:
     dependencies:
       boolbase: 1.0.0
@@ -16936,6 +19622,44 @@ snapshots:
       parse5: 7.2.1
       parse5-htmlparser2-tree-adapter: 7.1.0
 
+  chokidar@2.0.4:
+    dependencies:
+      anymatch: 2.0.0
+      async-each: 1.0.6
+      braces: 2.3.2
+      glob-parent: 3.1.0
+      inherits: 2.0.4
+      is-binary-path: 1.0.1
+      is-glob: 4.0.3
+      lodash.debounce: 4.0.8
+      normalize-path: 2.1.1
+      path-is-absolute: 1.0.1
+      readdirp: 2.2.1
+      upath: 1.2.0
+    optionalDependencies:
+      fsevents: 1.2.13
+    transitivePeerDependencies:
+      - supports-color
+
+  chokidar@2.1.8:
+    dependencies:
+      anymatch: 2.0.0
+      async-each: 1.0.6
+      braces: 2.3.2
+      glob-parent: 3.1.0
+      inherits: 2.0.4
+      is-binary-path: 1.0.1
+      is-glob: 4.0.3
+      normalize-path: 3.0.0
+      path-is-absolute: 1.0.1
+      readdirp: 2.2.1
+      upath: 1.2.0
+    optionalDependencies:
+      fsevents: 1.2.13
+    transitivePeerDependencies:
+      - supports-color
+    optional: true
+
   chokidar@3.6.0:
     dependencies:
       anymatch: 3.1.3
@@ -16952,6 +19676,8 @@ snapshots:
     dependencies:
       readdirp: 4.0.1
 
+  chownr@1.1.4: {}
+
   chrome-launcher@0.15.2:
     dependencies:
       '@types/node': 17.0.22
@@ -16978,6 +19704,14 @@ snapshots:
 
   ci-info@3.9.0: {}
 
+  cipher-base@1.0.7:
+    dependencies:
+      inherits: 2.0.4
+      safe-buffer: 5.2.1
+      to-buffer: 1.2.2
+
+  class-transformer@0.2.3: {}
+
   class-utils@0.3.6:
     dependencies:
       arr-union: 3.1.0
@@ -16985,6 +19719,11 @@ snapshots:
       isobject: 3.0.1
       static-extend: 0.1.2
 
+  class-validator@0.13.2:
+    dependencies:
+      libphonenumber-js: 1.13.2
+      validator: 13.15.35
+
   classnames@2.5.1: {}
 
   clean-css@5.3.3:
@@ -17000,6 +19739,19 @@ snapshots:
 
   cli-boxes@3.0.0: {}
 
+  cli-color@2.0.0:
+    dependencies:
+      ansi-regex: 2.1.1
+      d: 1.0.2
+      es5-ext: 0.10.64
+      es6-iterator: 2.0.3
+      memoizee: 0.4.17
+      timers-ext: 0.1.8
+
+  cli-cursor@2.1.0:
+    dependencies:
+      restore-cursor: 2.0.0
+
   cli-cursor@3.1.0:
     dependencies:
       restore-cursor: 3.1.0
@@ -17008,14 +19760,34 @@ snapshots:
     dependencies:
       restore-cursor: 5.1.0
 
+  cli-highlight@2.1.11:
+    dependencies:
+      chalk: 4.1.2
+      highlight.js: 10.7.3
+      mz: 2.7.0
+      parse5: 5.1.1
+      parse5-htmlparser2-tree-adapter: 6.0.1
+      yargs: 16.2.0
+
   cli-spinners@2.9.2: {}
 
+  cli-table3@0.5.1:
+    dependencies:
+      object-assign: 4.1.1
+      string-width: 2.1.1
+    optionalDependencies:
+      colors: 1.4.0
+
   cli-table3@0.6.5:
     dependencies:
       string-width: 4.2.3
     optionalDependencies:
       '@colors/colors': 1.5.0
 
+  cli-tableau@2.0.1:
+    dependencies:
+      chalk: 3.0.0
+
   cli-truncate@2.1.0:
     dependencies:
       slice-ansi: 3.0.0
@@ -17026,6 +19798,8 @@ snapshots:
       slice-ansi: 5.0.0
       string-width: 5.1.2
 
+  cli-width@2.2.1: {}
+
   cli-width@3.0.0: {}
 
   client-only@0.0.1: {}
@@ -17091,6 +19865,9 @@ snapshots:
 
   colorette@2.0.20: {}
 
+  colors@1.4.0:
+    optional: true
+
   combine-promises@1.2.0: {}
 
   combined-stream@1.0.8:
@@ -17105,8 +19882,12 @@ snapshots:
 
   commander@13.1.0: {}
 
+  commander@2.15.1: {}
+
   commander@2.20.3: {}
 
+  commander@4.1.1: {}
+
   commander@5.1.0: {}
 
   commander@7.2.0: {}
@@ -17136,7 +19917,7 @@ snapshots:
 
   compressible@2.0.18:
     dependencies:
-      mime-db: 1.53.0
+      mime-db: 1.54.0
 
   compression@1.7.4:
     dependencies:
@@ -17154,6 +19935,13 @@ snapshots:
 
   concat-map@0.0.1: {}
 
+  concat-stream@1.6.2:
+    dependencies:
+      buffer-from: 1.1.2
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+      typedarray: 0.0.6
+
   concurrently@7.6.0:
     dependencies:
       chalk: 4.1.2
@@ -17190,10 +19978,20 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  consola@2.15.3: {}
+
   consola@3.4.0: {}
 
+  console-browserify@1.2.0: {}
+
+  constants-browserify@1.0.0: {}
+
   content-disposition@0.5.2: {}
 
+  content-disposition@0.5.3:
+    dependencies:
+      safe-buffer: 5.1.2
+
   content-disposition@0.5.4:
     dependencies:
       safe-buffer: 5.2.1
@@ -17202,6 +20000,8 @@ snapshots:
     dependencies:
       safe-buffer: 5.2.1
 
+  content-security-policy-builder@2.1.0: {}
+
   content-type@1.0.5: {}
 
   conventional-changelog-angular@6.0.0:
@@ -17295,20 +20095,35 @@ snapshots:
 
   cookie-signature@1.2.2: {}
 
+  cookie@0.4.0: {}
+
   cookie@0.7.1: {}
 
+  cookiejar@2.1.4: {}
+
   copy-anything@2.0.6:
     dependencies:
       is-what: 3.14.1
 
-  copy-descriptor@0.1.1: {}
-
+  copy-concurrently@1.0.5:
+    dependencies:
+      aproba: 1.2.0
+      fs-write-stream-atomic: 1.0.10
+      iferr: 0.1.5
+      mkdirp: 0.5.6
+      rimraf: 2.7.1
+      run-queue: 1.0.3
+
+  copy-descriptor@0.1.1: {}
+
   copy-text-to-clipboard@3.2.0: {}
 
   copy-to-clipboard@3.3.3:
     dependencies:
       toggle-selection: 1.0.6
 
+  copy-to@2.0.1: {}
+
   copy-webpack-plugin@11.0.0(webpack@5.98.0):
     dependencies:
       fast-glob: 3.3.2
@@ -17319,6 +20134,15 @@ snapshots:
       serialize-javascript: 6.0.2
       webpack: 5.98.0
 
+  copyfiles@2.2.0:
+    dependencies:
+      glob: 7.2.3
+      minimatch: 3.1.2
+      mkdirp: 0.5.6
+      noms: 0.0.0
+      through2: 2.0.5
+      yargs: 13.3.2
+
   core-js-compat@3.38.1:
     dependencies:
       browserslist: 4.23.3
@@ -17339,6 +20163,11 @@ snapshots:
 
   core-util-is@1.0.3: {}
 
+  cors@2.8.5:
+    dependencies:
+      object-assign: 4.1.1
+      vary: 1.1.2
+
   cosmiconfig@5.2.1:
     dependencies:
       import-fresh: 2.0.0
@@ -17380,11 +20209,35 @@ snapshots:
     optionalDependencies:
       typescript: 4.6.2
 
+  create-ecdh@4.0.4:
+    dependencies:
+      bn.js: 4.12.3
+      elliptic: 6.6.1
+
+  create-hash@1.2.0:
+    dependencies:
+      cipher-base: 1.0.7
+      inherits: 2.0.4
+      md5.js: 1.3.5
+      ripemd160: 2.0.3
+      sha.js: 2.4.12
+
+  create-hmac@1.1.7:
+    dependencies:
+      cipher-base: 1.0.7
+      create-hash: 1.2.0
+      inherits: 2.0.4
+      ripemd160: 2.0.3
+      safe-buffer: 5.2.1
+      sha.js: 2.4.12
+
   create-react-class@15.7.0:
     dependencies:
       loose-envify: 1.4.0
       object-assign: 4.1.1
 
+  croner@4.1.97: {}
+
   cross-env@7.0.3:
     dependencies:
       cross-spawn: 7.0.3
@@ -17409,6 +20262,21 @@ snapshots:
       shebang-command: 2.0.0
       which: 2.0.2
 
+  crypto-browserify@3.12.1:
+    dependencies:
+      browserify-cipher: 1.0.1
+      browserify-sign: 4.2.5
+      create-ecdh: 4.0.4
+      create-hash: 1.2.0
+      create-hmac: 1.1.7
+      diffie-hellman: 5.0.3
+      hash-base: 3.0.5
+      inherits: 2.0.4
+      pbkdf2: 3.1.5
+      public-encrypt: 4.0.3
+      randombytes: 2.1.0
+      randomfill: 1.0.4
+
   crypto-random-string@2.0.0: {}
 
   crypto-random-string@4.0.0:
@@ -17566,8 +20434,17 @@ snapshots:
 
   csstype@3.1.3: {}
 
+  culvert@0.1.2: {}
+
   cxs@6.2.0: {}
 
+  cyclist@1.0.2: {}
+
+  d@1.0.2:
+    dependencies:
+      es5-ext: 0.10.64
+      type: 2.7.3
+
   damerau-levenshtein@1.0.8: {}
 
   dargs@7.0.0: {}
@@ -17576,8 +20453,12 @@ snapshots:
     dependencies:
       assert-plus: 1.0.0
 
+  dasherize@2.0.0: {}
+
   data-uri-to-buffer@4.0.1: {}
 
+  data-uri-to-buffer@6.0.2: {}
+
   data-urls@1.1.0:
     dependencies:
       abab: 2.0.6
@@ -17606,16 +20487,26 @@ snapshots:
     dependencies:
       '@babel/runtime': 7.25.6
 
+  date-format@4.0.14: {}
+
+  dateformat@2.2.0: {}
+
   dateformat@3.0.3: {}
 
   dayjs@1.11.13: {}
 
+  dayjs@1.8.36: {}
+
   debounce@1.2.1: {}
 
   debug@2.6.9:
     dependencies:
       ms: 2.0.0
 
+  debug@3.1.0:
+    dependencies:
+      ms: 2.0.0
+
   debug@3.2.7:
     dependencies:
       ms: 2.1.3
@@ -17678,6 +20569,10 @@ snapshots:
     dependencies:
       execa: 5.1.1
 
+  default-user-agent@1.0.0:
+    dependencies:
+      os-name: 1.0.3
+
   defaults@1.0.4:
     dependencies:
       clone: 1.0.4
@@ -17711,6 +20606,12 @@ snapshots:
       is-descriptor: 1.0.3
       isobject: 3.0.1
 
+  degenerator@5.0.1:
+    dependencies:
+      ast-types: 0.13.4
+      escodegen: 2.1.0
+      esprima: 4.0.1
+
   del@4.1.1:
     dependencies:
       '@types/glob': 7.2.0
@@ -17744,6 +20645,13 @@ snapshots:
 
   dequal@2.0.3: {}
 
+  des.js@1.1.0:
+    dependencies:
+      inherits: 2.0.4
+      minimalistic-assert: 1.0.1
+
+  destroy@1.0.4: {}
+
   destroy@1.2.0: {}
 
   detect-newline@2.1.0: {}
@@ -17768,10 +20676,25 @@ snapshots:
     dependencies:
       dequal: 2.0.3
 
+  dicer@0.2.5:
+    dependencies:
+      readable-stream: 1.1.14
+      streamsearch: 0.1.2
+
   didyoumean@1.2.2: {}
 
   diff-sequences@24.9.0: {}
 
+  diff@4.0.4: {}
+
+  diffie-hellman@5.0.3:
+    dependencies:
+      bn.js: 4.12.3
+      miller-rabin: 4.0.1
+      randombytes: 2.1.0
+
+  digest-header@1.1.0: {}
+
   dir-glob@3.0.1:
     dependencies:
       path-type: 4.0.0
@@ -17825,6 +20748,8 @@ snapshots:
       domhandler: 5.0.3
       entities: 4.5.0
 
+  domain-browser@1.2.0: {}
+
   domelementtype@2.3.0: {}
 
   domexception@1.0.1:
@@ -17851,6 +20776,8 @@ snapshots:
       domelementtype: 2.3.0
       domhandler: 5.0.3
 
+  dont-sniff-mimetype@1.1.0: {}
+
   dot-case@3.0.4:
     dependencies:
       no-case: 3.0.4
@@ -17864,10 +20791,14 @@ snapshots:
     dependencies:
       is-obj: 2.0.0
 
+  dotenv-expand@5.1.0: {}
+
   dotenv@16.6.1: {}
 
   dotenv@17.2.3: {}
 
+  dotenv@8.2.0: {}
+
   dotenv@8.6.0: {}
 
   draft-js@0.10.5(react-dom@17.0.2(react@17.0.2))(react@17.0.2):
@@ -17886,6 +20817,13 @@ snapshots:
 
   duplexer@0.1.2: {}
 
+  duplexify@3.7.1:
+    dependencies:
+      end-of-stream: 1.4.4
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+      stream-shift: 1.0.3
+
   eastasianwidth@0.2.0: {}
 
   ecc-jsbn@0.1.2:
@@ -17893,6 +20831,10 @@ snapshots:
       jsbn: 0.1.1
       safer-buffer: 2.1.2
 
+  ecdsa-sig-formatter@1.0.11:
+    dependencies:
+      safe-buffer: 5.2.1
+
   echarts-for-react@3.0.2(echarts@5.6.0)(react@17.0.2):
     dependencies:
       echarts: 5.6.0
@@ -17915,6 +20857,16 @@ snapshots:
 
   electron-to-chromium@1.5.27: {}
 
+  elliptic@6.6.1:
+    dependencies:
+      bn.js: 4.12.3
+      brorand: 1.1.0
+      hash.js: 1.1.7
+      hmac-drbg: 1.0.1
+      inherits: 2.0.4
+      minimalistic-assert: 1.0.1
+      minimalistic-crypto-utils: 1.0.1
+
   emoji-regex@10.6.0: {}
 
   emoji-regex@7.0.3: {}
@@ -17941,6 +20893,14 @@ snapshots:
     dependencies:
       once: 1.4.0
 
+  end-or-error@1.0.1: {}
+
+  enhanced-resolve@4.5.0:
+    dependencies:
+      graceful-fs: 4.2.11
+      memory-fs: 0.5.0
+      tapable: 1.1.3
+
   enhanced-resolve@5.17.1:
     dependencies:
       graceful-fs: 4.2.11
@@ -17949,7 +20909,6 @@ snapshots:
   enquirer@2.3.6:
     dependencies:
       ansi-colors: 4.1.3
-    optional: true
 
   entities@2.2.0: {}
 
@@ -17962,7 +20921,6 @@ snapshots:
   errno@0.1.8:
     dependencies:
       prr: 1.0.1
-    optional: true
 
   error-ex@1.3.2:
     dependencies:
@@ -18098,8 +21056,33 @@ snapshots:
       is-date-object: 1.0.5
       is-symbol: 1.0.4
 
+  es5-ext@0.10.64:
+    dependencies:
+      es6-iterator: 2.0.3
+      es6-symbol: 3.1.4
+      esniff: 2.0.1
+      next-tick: 1.1.0
+
+  es6-iterator@2.0.3:
+    dependencies:
+      d: 1.0.2
+      es5-ext: 0.10.64
+      es6-symbol: 3.1.4
+
   es6-promise@3.3.1: {}
 
+  es6-symbol@3.1.4:
+    dependencies:
+      d: 1.0.2
+      ext: 1.7.0
+
+  es6-weak-map@2.0.3:
+    dependencies:
+      d: 1.0.2
+      es5-ext: 0.10.64
+      es6-iterator: 2.0.3
+      es6-symbol: 3.1.4
+
   esast-util-from-estree@2.0.0:
     dependencies:
       '@types/estree-jsx': 1.0.5
@@ -18137,6 +21120,14 @@ snapshots:
     optionalDependencies:
       source-map: 0.6.1
 
+  escodegen@2.1.0:
+    dependencies:
+      esprima: 4.0.1
+      estraverse: 5.3.0
+      esutils: 2.0.3
+    optionalDependencies:
+      source-map: 0.6.1
+
   eslint-config-next@12.1.0(eslint@8.11.0)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(typescript@4.6.2):
     dependencies:
       '@next/eslint-plugin-next': 12.1.0
@@ -18160,6 +21151,10 @@ snapshots:
     dependencies:
       eslint: 8.11.0
 
+  eslint-config-prettier@8.10.0(eslint@8.57.1):
+    dependencies:
+      eslint: 8.57.1
+
   eslint-import-resolver-node@0.3.9:
     dependencies:
       debug: 3.2.7
@@ -18172,7 +21167,7 @@ snapshots:
     dependencies:
       debug: 4.4.3
       eslint: 8.11.0
-      eslint-plugin-import: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint-import-resolver-typescript@2.7.1)(eslint@8.11.0)
+      eslint-plugin-import: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint@8.11.0)
       glob: 7.2.3
       is-glob: 4.0.3
       resolve: 1.22.8
@@ -18191,6 +21186,16 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  eslint-module-utils@2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1):
+    dependencies:
+      debug: 3.2.7
+    optionalDependencies:
+      '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.1.6)
+      eslint: 8.57.1
+      eslint-import-resolver-node: 0.3.9
+    transitivePeerDependencies:
+      - supports-color
+
   eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint-import-resolver-typescript@2.7.1)(eslint@8.11.0):
     dependencies:
       '@rtsao/scc': 1.1.0
@@ -18219,6 +21224,62 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
+  eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint@8.11.0):
+    dependencies:
+      '@rtsao/scc': 1.1.0
+      array-includes: 3.1.8
+      array.prototype.findlastindex: 1.2.5
+      array.prototype.flat: 1.3.2
+      array.prototype.flatmap: 1.3.2
+      debug: 3.2.7
+      doctrine: 2.1.0
+      eslint: 8.11.0
+      eslint-import-resolver-node: 0.3.9
+      eslint-module-utils: 2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@2.7.1)(eslint@8.11.0)
+      hasown: 2.0.2
+      is-core-module: 2.15.1
+      is-glob: 4.0.3
+      minimatch: 3.1.2
+      object.fromentries: 2.0.8
+      object.groupby: 1.0.3
+      object.values: 1.2.0
+      semver: 6.3.1
+      tsconfig-paths: 3.15.0
+    optionalDependencies:
+      '@typescript-eslint/parser': 5.62.0(eslint@8.11.0)(typescript@4.6.2)
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+
+  eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1):
+    dependencies:
+      '@rtsao/scc': 1.1.0
+      array-includes: 3.1.8
+      array.prototype.findlastindex: 1.2.5
+      array.prototype.flat: 1.3.2
+      array.prototype.flatmap: 1.3.2
+      debug: 3.2.7
+      doctrine: 2.1.0
+      eslint: 8.57.1
+      eslint-import-resolver-node: 0.3.9
+      eslint-module-utils: 2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1)
+      hasown: 2.0.2
+      is-core-module: 2.15.1
+      is-glob: 4.0.3
+      minimatch: 3.1.2
+      object.fromentries: 2.0.8
+      object.groupby: 1.0.3
+      object.values: 1.2.0
+      semver: 6.3.1
+      tsconfig-paths: 3.15.0
+    optionalDependencies:
+      '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.1.6)
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+
   eslint-plugin-jsx-a11y@6.10.0(eslint@8.11.0):
     dependencies:
       aria-query: 5.1.3
@@ -18247,6 +21308,14 @@ snapshots:
     optionalDependencies:
       eslint-config-prettier: 8.10.0(eslint@8.11.0)
 
+  eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@1.19.1):
+    dependencies:
+      eslint: 8.57.1
+      prettier: 1.19.1
+      prettier-linter-helpers: 1.0.0
+    optionalDependencies:
+      eslint-config-prettier: 8.10.0(eslint@8.57.1)
+
   eslint-plugin-react-hooks@4.6.2(eslint@8.11.0):
     dependencies:
       eslint: 8.11.0
@@ -18277,6 +21346,15 @@ snapshots:
     dependencies:
       eslint: 8.11.0
 
+  eslint-plugin-simple-import-sort@7.0.0(eslint@8.57.1):
+    dependencies:
+      eslint: 8.57.1
+
+  eslint-scope@4.0.3:
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 4.3.0
+
   eslint-scope@5.1.1:
     dependencies:
       esrecurse: 4.3.0
@@ -18343,6 +21421,49 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  eslint@8.57.1:
+    dependencies:
+      '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1)
+      '@eslint-community/regexpp': 4.12.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.6
+      chalk: 4.1.2
+      cross-spawn: 7.0.6
+      debug: 4.4.3
+      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.6.0
+      esutils: 2.0.3
+      fast-deep-equal: 3.1.3
+      file-entry-cache: 6.0.1
+      find-up: 5.0.0
+      glob-parent: 6.0.2
+      globals: 13.24.0
+      graphemer: 1.4.0
+      ignore: 5.3.2
+      imurmurhash: 0.1.4
+      is-glob: 4.0.3
+      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.4
+      strip-ansi: 6.0.1
+      text-table: 0.2.0
+    transitivePeerDependencies:
+      - supports-color
+
   eslint@9.36.0(jiti@1.21.7):
     dependencies:
       '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@1.21.7))
@@ -18385,6 +21506,13 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  esniff@2.0.1:
+    dependencies:
+      d: 1.0.2
+      es5-ext: 0.10.64
+      event-emitter: 0.3.5
+      type: 2.7.3
+
   espree@10.4.0:
     dependencies:
       acorn: 8.15.0
@@ -18461,12 +21589,28 @@ snapshots:
       '@types/node': 17.0.22
       require-like: 0.1.2
 
+  event-emitter@0.3.5:
+    dependencies:
+      d: 1.0.2
+      es5-ext: 0.10.64
+
   event-target-shim@5.0.1: {}
 
+  eventemitter2@0.4.14: {}
+
+  eventemitter2@5.0.1: {}
+
+  eventemitter2@6.4.9: {}
+
   eventemitter3@4.0.7: {}
 
   events@3.3.0: {}
 
+  evp_bytestokey@1.0.3:
+    dependencies:
+      md5.js: 1.3.5
+      safe-buffer: 5.2.1
+
   exec-sh@0.3.6: {}
 
   execa@1.0.0:
@@ -18481,7 +21625,7 @@ snapshots:
 
   execa@5.1.1:
     dependencies:
-      cross-spawn: 7.0.3
+      cross-spawn: 7.0.6
       get-stream: 6.0.1
       human-signals: 2.1.0
       is-stream: 2.0.1
@@ -18518,6 +21662,43 @@ snapshots:
 
   exponential-backoff@3.1.1: {}
 
+  express-rate-limit@5.5.1: {}
+
+  express@4.17.1:
+    dependencies:
+      accepts: 1.3.8
+      array-flatten: 1.1.1
+      body-parser: 1.19.0
+      content-disposition: 0.5.3
+      content-type: 1.0.5
+      cookie: 0.4.0
+      cookie-signature: 1.0.6
+      debug: 2.6.9
+      depd: 1.1.2
+      encodeurl: 1.0.2
+      escape-html: 1.0.3
+      etag: 1.8.1
+      finalhandler: 1.1.2
+      fresh: 0.5.2
+      merge-descriptors: 1.0.1
+      methods: 1.1.2
+      on-finished: 2.3.0
+      parseurl: 1.3.3
+      path-to-regexp: 0.1.7
+      proxy-addr: 2.0.7
+      qs: 6.7.0
+      range-parser: 1.2.1
+      safe-buffer: 5.1.2
+      send: 0.17.1
+      serve-static: 1.14.1
+      setprototypeof: 1.1.1
+      statuses: 1.5.0
+      type-is: 1.6.18
+      utils-merge: 1.0.1
+      vary: 1.1.2
+    transitivePeerDependencies:
+      - supports-color
+
   express@4.21.2:
     dependencies:
       accepts: 1.3.8
@@ -18586,6 +21767,10 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  ext@1.7.0:
+    dependencies:
+      type: 2.7.3
+
   extend-shallow@2.0.1:
     dependencies:
       is-extendable: 0.1.1
@@ -18597,6 +21782,12 @@ snapshots:
 
   extend@3.0.2: {}
 
+  external-editor@3.1.0:
+    dependencies:
+      chardet: 0.7.0
+      iconv-lite: 0.4.24
+      tmp: 0.0.33
+
   extglob@2.0.4:
     dependencies:
       array-unique: 0.3.2
@@ -18610,8 +21801,16 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  extrareqp2@1.0.0(debug@4.3.7):
+    dependencies:
+      follow-redirects: 1.15.9(debug@4.3.7)
+    transitivePeerDependencies:
+      - debug
+
   extsprintf@1.3.0: {}
 
+  fast-deep-equal@2.0.1: {}
+
   fast-deep-equal@3.1.3: {}
 
   fast-diff@1.3.0: {}
@@ -18624,6 +21823,10 @@ snapshots:
       merge2: 1.4.1
       micromatch: 4.0.8
 
+  fast-json-patch@3.1.1: {}
+
+  fast-json-stable-stringify@2.0.0: {}
+
   fast-json-stable-stringify@2.1.0: {}
 
   fast-levenshtein@2.0.6: {}
@@ -18662,6 +21865,10 @@ snapshots:
       setimmediate: 1.0.5
       ua-parser-js: 0.7.39
 
+  fclone@1.0.11: {}
+
+  feature-policy@0.3.0: {}
+
   feed@4.2.2:
     dependencies:
       xml-js: 1.6.11
@@ -18671,6 +21878,12 @@ snapshots:
       node-domexception: 1.0.0
       web-streams-polyfill: 3.3.3
 
+  figgy-pudding@3.5.2: {}
+
+  figures@2.0.0:
+    dependencies:
+      escape-string-regexp: 1.0.5
+
   figures@3.2.0:
     dependencies:
       escape-string-regexp: 1.0.5
@@ -18803,19 +22016,52 @@ snapshots:
 
   flow-parser@0.246.0: {}
 
-  follow-redirects@1.15.9: {}
+  flush-write-stream@1.1.1:
+    dependencies:
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+
+  follow-redirects@1.15.9(debug@4.3.7):
+    optionalDependencies:
+      debug: 4.3.7(supports-color@9.4.0)
+
+  follow-redirects@1.5.10:
+    dependencies:
+      debug: 3.1.0
+    transitivePeerDependencies:
+      - supports-color
 
   for-each@0.3.3:
     dependencies:
       is-callable: 1.2.7
 
+  for-each@0.3.5:
+    dependencies:
+      is-callable: 1.2.7
+
   for-in@1.0.2: {}
 
   forever-agent@0.6.1: {}
 
+  fork-ts-checker-webpack-plugin@4.0.3(eslint@8.57.1)(typescript@3.9.10)(webpack@4.41.5):
+    dependencies:
+      babel-code-frame: 6.26.0
+      chalk: 2.4.2
+      micromatch: 3.1.10
+      minimatch: 3.1.2
+      semver: 5.7.2
+      tapable: 1.1.3
+      typescript: 3.9.10
+      webpack: 4.41.5
+      worker-rpc: 0.1.1
+    optionalDependencies:
+      eslint: 8.57.1
+    transitivePeerDependencies:
+      - supports-color
+
   fork-ts-checker-webpack-plugin@6.5.3(eslint@9.36.0(jiti@1.21.7))(typescript@5.6.3)(webpack@5.98.0):
     dependencies:
-      '@babel/code-frame': 7.24.7
+      '@babel/code-frame': 7.26.2
       '@types/json-schema': 7.0.15
       chalk: 4.1.2
       chokidar: 3.6.0
@@ -18851,9 +22097,18 @@ snapshots:
 
   format@0.2.2: {}
 
-  formdata-polyfill@4.0.10:
+  formdata-polyfill@4.0.10:
+    dependencies:
+      fetch-blob: 3.2.0
+
+  formidable@1.2.6: {}
+
+  formstream@1.5.2:
     dependencies:
-      fetch-blob: 3.2.0
+      destroy: 1.2.0
+      mime: 2.6.0
+      node-hex: 1.0.1
+      pause-stream: 0.0.11
 
   forwarded@0.2.0: {}
 
@@ -18867,6 +22122,11 @@ snapshots:
 
   fresh@2.0.0: {}
 
+  from2@2.3.0:
+    dependencies:
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+
   fs-extra@10.1.0:
     dependencies:
       graceful-fs: 4.2.11
@@ -18894,6 +22154,13 @@ snapshots:
 
   fs-monkey@1.0.6: {}
 
+  fs-write-stream-atomic@1.0.10:
+    dependencies:
+      graceful-fs: 4.2.11
+      iferr: 0.1.5
+      imurmurhash: 0.1.4
+      readable-stream: 2.3.8
+
   fs.realpath@1.0.0: {}
 
   fsevents@1.2.13:
@@ -18963,6 +22230,8 @@ snapshots:
       dunder-proto: 1.0.1
       es-object-atoms: 1.1.1
 
+  get-ready@1.0.0: {}
+
   get-stream@4.1.0:
     dependencies:
       pump: 3.0.2
@@ -18975,12 +22244,24 @@ snapshots:
       es-errors: 1.3.0
       get-intrinsic: 1.2.4
 
+  get-uri@6.0.5:
+    dependencies:
+      basic-ftp: 5.3.1
+      data-uri-to-buffer: 6.0.2
+      debug: 4.4.3
+    transitivePeerDependencies:
+      - supports-color
+
   get-value@2.0.6: {}
 
   getpass@0.1.7:
     dependencies:
       assert-plus: 1.0.0
 
+  git-node-fs@1.0.0(js-git@0.7.8):
+    optionalDependencies:
+      js-git: 0.7.8
+
   git-raw-commits@3.0.0:
     dependencies:
       dargs: 7.0.0
@@ -18997,6 +22278,8 @@ snapshots:
       meow: 8.1.2
       semver: 7.6.3
 
+  git-sha1@0.1.2: {}
+
   gitconfiglocal@1.0.0:
     dependencies:
       ini: 1.3.8
@@ -19005,6 +22288,11 @@ snapshots:
 
   github-slugger@1.5.0: {}
 
+  glob-parent@3.1.0:
+    dependencies:
+      is-glob: 3.1.0
+      path-dirname: 1.0.2
+
   glob-parent@5.1.2:
     dependencies:
       is-glob: 4.0.3
@@ -19144,6 +22432,10 @@ snapshots:
 
   hard-rejection@2.1.0: {}
 
+  has-ansi@2.0.0:
+    dependencies:
+      ansi-regex: 2.1.1
+
   has-bigints@1.0.2: {}
 
   has-flag@3.0.0: {}
@@ -19185,6 +22477,23 @@ snapshots:
 
   has-yarn@3.0.0: {}
 
+  hash-base@3.0.5:
+    dependencies:
+      inherits: 2.0.4
+      safe-buffer: 5.2.1
+
+  hash-base@3.1.2:
+    dependencies:
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+      safe-buffer: 5.2.1
+      to-buffer: 1.2.2
+
+  hash.js@1.1.7:
+    dependencies:
+      inherits: 2.0.4
+      minimalistic-assert: 1.0.1
+
   hasown@2.0.2:
     dependencies:
       function-bind: 1.1.2
@@ -19285,6 +22594,29 @@ snapshots:
 
   he@1.2.0: {}
 
+  helmet-crossdomain@0.4.0: {}
+
+  helmet-csp@2.10.0:
+    dependencies:
+      bowser: 2.9.0
+      camelize: 1.0.0
+      content-security-policy-builder: 2.1.0
+      dasherize: 2.0.0
+
+  helmet@3.23.3:
+    dependencies:
+      depd: 2.0.0
+      dont-sniff-mimetype: 1.1.0
+      feature-policy: 0.3.0
+      helmet-crossdomain: 0.4.0
+      helmet-csp: 2.10.0
+      hide-powered-by: 1.1.0
+      hpkp: 2.0.0
+      hsts: 2.2.0
+      nocache: 2.1.0
+      referrer-policy: 1.2.0
+      x-xss-protection: 1.3.0
+
   hermes-estree@0.22.0: {}
 
   hermes-estree@0.23.1: {}
@@ -19297,6 +22629,10 @@ snapshots:
     dependencies:
       hermes-estree: 0.23.1
 
+  hide-powered-by@1.1.0: {}
+
+  highlight.js@10.7.3: {}
+
   highlight.js@9.18.5: {}
 
   history@4.10.1:
@@ -19308,6 +22644,12 @@ snapshots:
       tiny-warning: 1.0.3
       value-equal: 1.0.1
 
+  hmac-drbg@1.0.1:
+    dependencies:
+      hash.js: 1.1.7
+      minimalistic-assert: 1.0.1
+      minimalistic-crypto-utils: 1.0.1
+
   hoist-non-react-statics@3.3.2:
     dependencies:
       react-is: 16.13.1
@@ -19325,6 +22667,12 @@ snapshots:
       readable-stream: 2.3.8
       wbuf: 1.7.3
 
+  hpkp@2.0.0: {}
+
+  hsts@2.2.0:
+    dependencies:
+      depd: 2.0.0
+
   html-encoding-sniffer@1.0.2:
     dependencies:
       whatwg-encoding: 1.0.5
@@ -19392,6 +22740,22 @@ snapshots:
       setprototypeof: 1.1.0
       statuses: 1.5.0
 
+  http-errors@1.7.2:
+    dependencies:
+      depd: 1.1.2
+      inherits: 2.0.3
+      setprototypeof: 1.1.1
+      statuses: 1.5.0
+      toidentifier: 1.0.0
+
+  http-errors@1.7.3:
+    dependencies:
+      depd: 1.1.2
+      inherits: 2.0.4
+      setprototypeof: 1.1.1
+      statuses: 1.5.0
+      toidentifier: 1.0.0
+
   http-errors@2.0.0:
     dependencies:
       depd: 2.0.0
@@ -19402,6 +22766,13 @@ snapshots:
 
   http-parser-js@0.5.9: {}
 
+  http-proxy-agent@7.0.2:
+    dependencies:
+      agent-base: 7.1.4
+      debug: 4.4.3
+    transitivePeerDependencies:
+      - supports-color
+
   http-proxy-middleware@2.0.7(@types/express@4.17.18):
     dependencies:
       '@types/http-proxy': 1.17.16
@@ -19417,7 +22788,7 @@ snapshots:
   http-proxy@1.18.1:
     dependencies:
       eventemitter3: 4.0.7
-      follow-redirects: 1.15.9
+      follow-redirects: 1.15.9(debug@4.3.7)
       requires-port: 1.0.0
     transitivePeerDependencies:
       - debug
@@ -19435,8 +22806,21 @@ snapshots:
       quick-lru: 5.1.1
       resolve-alpn: 1.2.1
 
+  https-browserify@1.0.0: {}
+
+  https-proxy-agent@7.0.6:
+    dependencies:
+      agent-base: 7.1.4
+      debug: 4.4.3
+    transitivePeerDependencies:
+      - supports-color
+
   human-signals@2.1.0: {}
 
+  humanize-ms@1.2.1:
+    dependencies:
+      ms: 2.1.3
+
   husky@7.0.4: {}
 
   iconv-lite@0.4.24:
@@ -19463,6 +22847,8 @@ snapshots:
 
   ieee754@1.2.1: {}
 
+  iferr@0.1.5: {}
+
   ignore@5.3.2: {}
 
   image-size@0.5.5:
@@ -19499,6 +22885,8 @@ snapshots:
 
   indent-string@4.0.0: {}
 
+  infer-owner@1.0.4: {}
+
   infima@0.2.0-alpha.45: {}
 
   inflight@1.0.6:
@@ -19516,6 +22904,58 @@ snapshots:
 
   inline-style-parser@0.2.4: {}
 
+  inquirer@6.2.1:
+    dependencies:
+      ansi-escapes: 3.2.0
+      chalk: 2.4.2
+      cli-cursor: 2.1.0
+      cli-width: 2.2.1
+      external-editor: 3.1.0
+      figures: 2.0.0
+      lodash: 4.17.21
+      mute-stream: 0.0.7
+      run-async: 2.4.1
+      rxjs: 6.6.7
+      string-width: 2.1.1
+      strip-ansi: 5.2.0
+      through: 2.3.8
+
+  inquirer@7.0.4:
+    dependencies:
+      ansi-escapes: 4.3.2
+      chalk: 2.4.2
+      cli-cursor: 3.1.0
+      cli-width: 2.2.1
+      external-editor: 3.1.0
+      figures: 3.2.0
+      lodash: 4.17.21
+      mute-stream: 0.0.8
+      run-async: 2.4.1
+      rxjs: 6.6.7
+      string-width: 4.2.3
+      strip-ansi: 5.2.0
+      through: 2.3.8
+
+  inquirer@8.2.7(@types/node@12.20.55):
+    dependencies:
+      '@inquirer/external-editor': 1.0.2(@types/node@12.20.55)
+      ansi-escapes: 4.3.2
+      chalk: 4.1.2
+      cli-cursor: 3.1.0
+      cli-width: 3.0.0
+      figures: 3.2.0
+      lodash: 4.17.21
+      mute-stream: 0.0.8
+      ora: 5.4.1
+      run-async: 2.4.1
+      rxjs: 7.8.1
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+      through: 2.3.8
+      wrap-ansi: 6.2.0
+    transitivePeerDependencies:
+      - '@types/node'
+
   inquirer@8.2.7(@types/node@24.5.2):
     dependencies:
       '@inquirer/external-editor': 1.0.2(@types/node@24.5.2)
@@ -19555,6 +22995,8 @@ snapshots:
     dependencies:
       loose-envify: 1.4.0
 
+  ip-address@10.2.0: {}
+
   ipaddr.js@1.9.1: {}
 
   ipaddr.js@2.2.0: {}
@@ -19590,6 +23032,10 @@ snapshots:
     dependencies:
       has-bigints: 1.0.2
 
+  is-binary-path@1.0.1:
+    dependencies:
+      binary-extensions: 1.13.1
+
   is-binary-path@2.1.0:
     dependencies:
       binary-extensions: 2.3.0
@@ -19611,6 +23057,8 @@ snapshots:
     dependencies:
       ci-info: 3.9.0
 
+  is-class-hotfix@0.0.6: {}
+
   is-core-module@2.15.1:
     dependencies:
       hasown: 2.0.2
@@ -19667,6 +23115,10 @@ snapshots:
     dependencies:
       has-tostringtag: 1.0.2
 
+  is-glob@3.1.0:
+    dependencies:
+      is-extglob: 2.1.1
+
   is-glob@4.0.3:
     dependencies:
       is-extglob: 2.1.1
@@ -19726,6 +23178,8 @@ snapshots:
     dependencies:
       isobject: 3.0.1
 
+  is-promise@2.2.2: {}
+
   is-promise@4.0.0: {}
 
   is-property@1.0.2: {}
@@ -19761,10 +23215,20 @@ snapshots:
     dependencies:
       text-extensions: 1.9.0
 
+  is-type-of@1.4.0:
+    dependencies:
+      core-util-is: 1.0.3
+      is-class-hotfix: 0.0.6
+      isstream: 0.1.2
+
   is-typed-array@1.1.13:
     dependencies:
       which-typed-array: 1.1.15
 
+  is-typed-array@1.1.15:
+    dependencies:
+      which-typed-array: 1.1.20
+
   is-typedarray@1.0.0: {}
 
   is-unicode-supported@0.1.0: {}
@@ -19851,6 +23315,8 @@ snapshots:
     dependencies:
       html-escaper: 2.0.2
 
+  iterare@1.2.0: {}
+
   iterator.prototype@1.1.2:
     dependencies:
       define-properties: 1.2.1
@@ -20263,6 +23729,17 @@ snapshots:
       '@sideway/formula': 3.0.1
       '@sideway/pinpoint': 2.0.0
 
+  js-base64@2.6.4: {}
+
+  js-git@0.7.8:
+    dependencies:
+      bodec: 0.1.0
+      culvert: 0.1.2
+      git-sha1: 0.1.2
+      pako: 0.2.9
+
+  js-tokens@3.0.2: {}
+
   js-tokens@4.0.0: {}
 
   js-yaml@3.14.1:
@@ -20385,6 +23862,32 @@ snapshots:
 
   jsonpointer@5.0.1: {}
 
+  jsonwebtoken@8.5.1:
+    dependencies:
+      jws: 3.2.3
+      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.1.1
+      ms: 2.1.3
+      semver: 5.7.2
+
+  jsonwebtoken@9.0.3:
+    dependencies:
+      jws: 4.0.1
+      lodash.includes: 4.3.0
+      lodash.isboolean: 3.0.3
+      lodash.isinteger: 4.0.4
+      lodash.isnumber: 3.0.3
+      lodash.isplainobject: 4.0.6
+      lodash.isstring: 4.0.1
+      lodash.once: 4.1.1
+      ms: 2.1.3
+      semver: 7.6.3
+
   jsprim@1.4.2:
     dependencies:
       assert-plus: 1.0.0
@@ -20392,6 +23895,8 @@ snapshots:
       json-schema: 0.4.0
       verror: 1.10.0
 
+  jstoxml@2.2.9: {}
+
   jsx-ast-utils@3.3.5:
     dependencies:
       array-includes: 3.1.8
@@ -20399,6 +23904,28 @@ snapshots:
       object.assign: 4.1.5
       object.values: 1.2.0
 
+  jwa@1.4.2:
+    dependencies:
+      buffer-equal-constant-time: 1.0.1
+      ecdsa-sig-formatter: 1.0.11
+      safe-buffer: 5.2.1
+
+  jwa@2.0.1:
+    dependencies:
+      buffer-equal-constant-time: 1.0.1
+      ecdsa-sig-formatter: 1.0.11
+      safe-buffer: 5.2.1
+
+  jws@3.2.3:
+    dependencies:
+      jwa: 1.4.2
+      safe-buffer: 5.2.1
+
+  jws@4.0.1:
+    dependencies:
+      jwa: 2.0.1
+      safe-buffer: 5.2.1
+
   keyv@4.5.4:
     dependencies:
       json-buffer: 3.0.1
@@ -20434,6 +23961,8 @@ snapshots:
       picocolors: 1.1.1
       shell-quote: 1.8.1
 
+  lazy@1.0.11: {}
+
   left-pad@1.3.0: {}
 
   less-loader@10.2.0(less@4.2.0)(webpack@5.98.0):
@@ -20472,6 +24001,8 @@ snapshots:
       prelude-ls: 1.2.1
       type-check: 0.4.0
 
+  libphonenumber-js@1.13.2: {}
+
   lighthouse-logger@1.4.2:
     dependencies:
       debug: 2.6.9
@@ -20524,8 +24055,16 @@ snapshots:
       pify: 3.0.0
       strip-bom: 3.0.0
 
+  loader-runner@2.4.0: {}
+
   loader-runner@4.3.0: {}
 
+  loader-utils@1.4.2:
+    dependencies:
+      big.js: 5.2.2
+      emojis-list: 3.0.0
+      json5: 1.0.2
+
   loader-utils@2.0.4:
     dependencies:
       big.js: 5.2.2
@@ -20562,22 +24101,48 @@ snapshots:
 
   lodash.debounce@4.0.8: {}
 
+  lodash.get@4.4.2: {}
+
+  lodash.has@4.5.2: {}
+
+  lodash.includes@4.3.0: {}
+
+  lodash.isboolean@3.0.3: {}
+
+  lodash.isinteger@4.0.4: {}
+
   lodash.ismatch@4.4.0: {}
 
+  lodash.isnumber@3.0.3: {}
+
+  lodash.isplainobject@4.0.6: {}
+
+  lodash.isstring@4.0.1: {}
+
   lodash.memoize@4.1.2: {}
 
   lodash.merge@4.6.2: {}
 
+  lodash.once@4.1.1: {}
+
+  lodash.set@4.3.2: {}
+
   lodash.sortby@4.7.0: {}
 
   lodash.throttle@4.1.1: {}
 
+  lodash.toarray@4.4.0: {}
+
   lodash.uniq@4.5.0: {}
 
   lodash.upperfirst@4.3.1: {}
 
   lodash@4.17.21: {}
 
+  log-symbols@3.0.0:
+    dependencies:
+      chalk: 2.4.2
+
   log-symbols@4.1.0:
     dependencies:
       chalk: 4.1.2
@@ -20595,6 +24160,16 @@ snapshots:
       slice-ansi: 4.0.0
       wrap-ansi: 6.2.0
 
+  log4js@6.9.1:
+    dependencies:
+      date-format: 4.0.14
+      debug: 4.4.3
+      flatted: 3.3.1
+      rfdc: 1.4.1
+      streamroller: 3.1.5
+    transitivePeerDependencies:
+      - supports-color
+
   logkitty@0.7.1:
     dependencies:
       ansi-fragments: 0.2.1
@@ -20627,12 +24202,18 @@ snapshots:
 
   lru-cache@7.18.3: {}
 
+  lru-queue@0.1.0:
+    dependencies:
+      es5-ext: 0.10.64
+
   lru.min@1.1.1: {}
 
   lru.min@1.1.4: {}
 
   lz-string@1.5.0: {}
 
+  macos-release@2.5.1: {}
+
   magic-string@0.25.9:
     dependencies:
       sourcemap-codec: 1.4.8
@@ -20652,6 +24233,8 @@ snapshots:
     dependencies:
       tmpl: 1.0.5
 
+  mamacro@0.0.3: {}
+
   map-cache@0.2.2: {}
 
   map-obj@1.0.1: {}
@@ -20670,10 +24253,18 @@ snapshots:
 
   markdown-table@3.0.4: {}
 
+  marked@0.8.2: {}
+
   marky@1.2.5: {}
 
   math-intrinsics@1.1.0: {}
 
+  md5.js@1.3.5:
+    dependencies:
+      hash-base: 3.0.5
+      inherits: 2.0.4
+      safe-buffer: 5.2.1
+
   mdast-util-directive@3.1.0:
     dependencies:
       '@types/mdast': 4.0.4
@@ -20876,6 +24467,27 @@ snapshots:
 
   memoize-one@5.2.1: {}
 
+  memoizee@0.4.17:
+    dependencies:
+      d: 1.0.2
+      es5-ext: 0.10.64
+      es6-weak-map: 2.0.3
+      event-emitter: 0.3.5
+      is-promise: 2.2.2
+      lru-queue: 0.1.0
+      next-tick: 1.1.0
+      timers-ext: 0.1.8
+
+  memory-fs@0.4.1:
+    dependencies:
+      errno: 0.1.8
+      readable-stream: 2.3.8
+
+  memory-fs@0.5.0:
+    dependencies:
+      errno: 0.1.8
+      readable-stream: 2.3.8
+
   meow@8.1.2:
     dependencies:
       '@types/minimist': 1.2.5
@@ -20890,6 +24502,8 @@ snapshots:
       type-fest: 0.18.1
       yargs-parser: 20.2.9
 
+  merge-descriptors@1.0.1: {}
+
   merge-descriptors@1.0.3: {}
 
   merge-descriptors@2.0.0: {}
@@ -21078,6 +24692,8 @@ snapshots:
       - supports-color
       - utf-8-validate
 
+  microevent.ts@0.1.1: {}
+
   micromark-core-commonmark@2.0.3:
     dependencies:
       decode-named-character-reference: 1.0.2
@@ -21398,12 +25014,15 @@ snapshots:
       braces: 3.0.3
       picomatch: 2.3.1
 
+  miller-rabin@4.0.1:
+    dependencies:
+      bn.js: 4.12.3
+      brorand: 1.1.0
+
   mime-db@1.33.0: {}
 
   mime-db@1.52.0: {}
 
-  mime-db@1.53.0: {}
-
   mime-db@1.54.0: {}
 
   mime-types@2.1.18:
@@ -21422,6 +25041,8 @@ snapshots:
 
   mime@2.6.0: {}
 
+  mimic-fn@1.2.0: {}
+
   mimic-fn@2.1.0: {}
 
   mimic-function@5.0.1: {}
@@ -21440,6 +25061,8 @@ snapshots:
 
   minimalistic-assert@1.0.1: {}
 
+  minimalistic-crypto-utils@1.0.1: {}
+
   minimatch@3.1.2:
     dependencies:
       brace-expansion: 1.1.11
@@ -21454,8 +25077,23 @@ snapshots:
       is-plain-obj: 1.1.0
       kind-of: 6.0.3
 
+  minimist@1.2.0: {}
+
   minimist@1.2.8: {}
 
+  mississippi@3.0.0:
+    dependencies:
+      concat-stream: 1.6.2
+      duplexify: 3.7.1
+      end-of-stream: 1.4.4
+      flush-write-stream: 1.1.1
+      from2: 2.3.0
+      parallel-transform: 1.2.0
+      pump: 3.0.2
+      pumpify: 1.5.1
+      stream-each: 1.2.3
+      through2: 2.0.5
+
   mixin-deep@1.3.2:
     dependencies:
       for-in: 1.0.2
@@ -21469,19 +25107,45 @@ snapshots:
 
   modify-values@1.0.1: {}
 
+  module-details-from-path@1.0.4: {}
+
   monaco-editor@0.52.0: {}
 
+  move-concurrently@1.0.1:
+    dependencies:
+      aproba: 1.2.0
+      copy-concurrently: 1.0.5
+      fs-write-stream-atomic: 1.0.10
+      mkdirp: 0.5.6
+      rimraf: 2.7.1
+      run-queue: 1.0.3
+
   mrmime@2.0.1: {}
 
   ms@2.0.0: {}
 
+  ms@2.1.1: {}
+
   ms@2.1.3: {}
 
+  multer@1.4.2:
+    dependencies:
+      append-field: 1.0.0
+      busboy: 0.2.14
+      concat-stream: 1.6.2
+      mkdirp: 0.5.6
+      object-assign: 4.1.1
+      on-finished: 2.4.1
+      type-is: 1.6.18
+      xtend: 4.0.2
+
   multicast-dns@7.2.5:
     dependencies:
       dns-packet: 5.6.1
       thunky: 1.1.0
 
+  mute-stream@0.0.7: {}
+
   mute-stream@0.0.8: {}
 
   mysql2@3.12.0:
@@ -21496,6 +25160,18 @@ snapshots:
       seq-queue: 0.0.5
       sqlstring: 2.3.3
 
+  mysql2@3.22.3(@types/node@12.20.55):
+    dependencies:
+      '@types/node': 12.20.55
+      aws-ssl-profiles: 1.1.2
+      denque: 2.1.0
+      generate-function: 2.3.1
+      iconv-lite: 0.7.2
+      long: 5.3.2
+      lru.min: 1.1.4
+      named-placeholders: 1.1.6
+      sql-escaper: 1.3.3
+
   mysql2@3.22.3(@types/node@24.5.2):
     dependencies:
       '@types/node': 24.5.2
@@ -21508,6 +25184,12 @@ snapshots:
       named-placeholders: 1.1.6
       sql-escaper: 1.3.3
 
+  mz@2.7.0:
+    dependencies:
+      any-promise: 1.3.0
+      object-assign: 4.1.1
+      thenify-all: 1.6.0
+
   named-placeholders@1.1.3:
     dependencies:
       lru-cache: 7.18.3
@@ -21543,6 +25225,14 @@ snapshots:
 
   natural-compare@1.4.0: {}
 
+  needle@2.4.0:
+    dependencies:
+      debug: 3.2.7
+      iconv-lite: 0.4.24
+      sax: 1.4.1
+    transitivePeerDependencies:
+      - supports-color
+
   needle@3.3.1:
     dependencies:
       iconv-lite: 0.6.3
@@ -21555,6 +25245,8 @@ snapshots:
 
   neo-async@2.6.2: {}
 
+  netmask@2.1.1: {}
+
   next-compose-plugins@2.2.1: {}
 
   next-fonts@1.5.1(webpack@5.98.0):
@@ -21606,6 +25298,13 @@ snapshots:
       minimist: 1.2.8
       next: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
 
+  next-tick@1.1.0: {}
+
+  next-transpile-modules@6.4.1:
+    dependencies:
+      enhanced-resolve: 5.17.1
+      escalade: 3.2.0
+
   next-with-less@2.0.5(less-loader@10.2.0(less@4.2.0)(webpack@5.98.0))(less@4.2.0)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)):
     dependencies:
       clone-deep: 4.0.1
@@ -21678,6 +25377,8 @@ snapshots:
       lower-case: 2.0.2
       tslib: 2.7.0
 
+  nocache@2.1.0: {}
+
   nocache@3.0.4: {}
 
   node-abort-controller@3.1.1: {}
@@ -21688,6 +25389,10 @@ snapshots:
 
   node-domexception@1.0.0: {}
 
+  node-emoji@1.10.0:
+    dependencies:
+      lodash.toarray: 4.4.0
+
   node-emoji@1.11.0:
     dependencies:
       lodash: 4.17.21
@@ -21722,8 +25427,38 @@ snapshots:
 
   node-forge@1.3.1: {}
 
+  node-hex@1.0.1: {}
+
   node-int64@0.4.0: {}
 
+  node-ip2region@1.0.2: {}
+
+  node-libs-browser@2.2.1:
+    dependencies:
+      assert: 1.5.1
+      browserify-zlib: 0.2.0
+      buffer: 4.9.2
+      console-browserify: 1.2.0
+      constants-browserify: 1.0.0
+      crypto-browserify: 3.12.1
+      domain-browser: 1.2.0
+      events: 3.3.0
+      https-browserify: 1.0.0
+      os-browserify: 0.3.0
+      path-browserify: 0.0.1
+      process: 0.11.10
+      punycode: 1.4.1
+      querystring-es3: 0.2.1
+      readable-stream: 2.3.8
+      stream-browserify: 2.0.2
+      stream-http: 2.8.3
+      string_decoder: 1.3.0
+      timers-browserify: 2.0.12
+      tty-browserify: 0.0.0
+      url: 0.11.4
+      util: 0.11.1
+      vm-browserify: 1.1.2
+
   node-notifier@5.4.5:
     dependencies:
       growly: 1.3.0
@@ -21742,6 +25477,13 @@ snapshots:
 
   node-stream-zip@1.15.0: {}
 
+  nodemailer@6.10.1: {}
+
+  noms@0.0.0:
+    dependencies:
+      inherits: 2.0.4
+      readable-stream: 1.0.34
+
   normalize-package-data@2.5.0:
     dependencies:
       hosted-git-info: 2.8.9
@@ -21776,10 +25518,17 @@ snapshots:
 
   nprogress@0.2.0: {}
 
+  nssocket@0.6.0:
+    dependencies:
+      eventemitter2: 0.4.14
+      lazy: 1.0.11
+
   nth-check@2.1.1:
     dependencies:
       boolbase: 1.0.0
 
+  nuid@1.1.6: {}
+
   null-loader@4.0.1(webpack@5.98.0):
     dependencies:
       loader-utils: 2.0.4
@@ -21835,6 +25584,8 @@ snapshots:
       define-property: 0.2.5
       kind-of: 3.2.2
 
+  object-hash@2.0.3: {}
+
   object-inspect@1.13.2: {}
 
   object-inspect@1.13.4: {}
@@ -21918,6 +25669,10 @@ snapshots:
     dependencies:
       wrappy: 1.0.2
 
+  onetime@2.0.1:
+    dependencies:
+      mimic-fn: 1.2.0
+
   onetime@5.1.2:
     dependencies:
       mimic-fn: 2.1.0
@@ -21943,6 +25698,8 @@ snapshots:
 
   opener@1.5.2: {}
 
+  optional@0.1.4: {}
+
   optionator@0.8.3:
     dependencies:
       deep-is: 0.1.4
@@ -21961,6 +25718,17 @@ snapshots:
       type-check: 0.4.0
       word-wrap: 1.2.5
 
+  ora@4.0.3:
+    dependencies:
+      chalk: 3.0.0
+      cli-cursor: 3.1.0
+      cli-spinners: 2.9.2
+      is-interactive: 1.0.0
+      log-symbols: 3.0.0
+      mute-stream: 0.0.8
+      strip-ansi: 6.0.1
+      wcwidth: 1.0.1
+
   ora@5.4.1:
     dependencies:
       bl: 4.1.0
@@ -21985,6 +25753,24 @@ snapshots:
       string-width: 7.2.0
       strip-ansi: 7.1.0
 
+  os-browserify@0.3.0: {}
+
+  os-name@1.0.3:
+    dependencies:
+      osx-release: 1.1.0
+      win-release: 1.1.1
+
+  os-name@3.1.0:
+    dependencies:
+      macos-release: 2.5.1
+      windows-release: 3.3.3
+
+  os-tmpdir@1.0.2: {}
+
+  osx-release@1.1.0:
+    dependencies:
+      minimist: 1.2.8
+
   p-cancelable@3.0.0: {}
 
   p-each-series@1.0.0:
@@ -22046,6 +25832,24 @@ snapshots:
 
   p-try@2.2.0: {}
 
+  pac-proxy-agent@7.2.0:
+    dependencies:
+      '@tootallnate/quickjs-emscripten': 0.23.0
+      agent-base: 7.1.4
+      debug: 4.4.3
+      get-uri: 6.0.5
+      http-proxy-agent: 7.0.2
+      https-proxy-agent: 7.0.6
+      pac-resolver: 7.0.1
+      socks-proxy-agent: 8.0.5
+    transitivePeerDependencies:
+      - supports-color
+
+  pac-resolver@7.0.1:
+    dependencies:
+      degenerator: 5.0.1
+      netmask: 2.1.1
+
   package-json@8.1.1:
     dependencies:
       got: 12.6.1
@@ -22053,6 +25857,16 @@ snapshots:
       registry-url: 6.0.1
       semver: 7.6.3
 
+  pako@0.2.9: {}
+
+  pako@1.0.11: {}
+
+  parallel-transform@1.2.0:
+    dependencies:
+      cyclist: 1.0.2
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+
   param-case@3.0.4:
     dependencies:
       dot-case: 3.0.4
@@ -22062,6 +25876,14 @@ snapshots:
     dependencies:
       callsites: 3.1.0
 
+  parse-asn1@5.1.9:
+    dependencies:
+      asn1.js: 4.10.1
+      browserify-aes: 1.2.0
+      evp_bytestokey: 1.0.3
+      pbkdf2: 3.1.5
+      safe-buffer: 5.2.1
+
   parse-entities@4.0.2:
     dependencies:
       '@types/unist': 2.0.11
@@ -22088,6 +25910,10 @@ snapshots:
 
   parse-numeric-range@1.3.0: {}
 
+  parse5-htmlparser2-tree-adapter@6.0.1:
+    dependencies:
+      parse5: 6.0.1
+
   parse5-htmlparser2-tree-adapter@7.1.0:
     dependencies:
       domhandler: 5.0.3
@@ -22095,6 +25921,10 @@ snapshots:
 
   parse5@4.0.0: {}
 
+  parse5@5.1.1: {}
+
+  parse5@6.0.1: {}
+
   parse5@7.2.1:
     dependencies:
       entities: 4.5.0
@@ -22108,6 +25938,22 @@ snapshots:
 
   pascalcase@0.1.1: {}
 
+  passport-jwt@4.0.1:
+    dependencies:
+      jsonwebtoken: 9.0.3
+      passport-strategy: 1.0.0
+
+  passport-strategy@1.0.0: {}
+
+  passport@0.4.1:
+    dependencies:
+      passport-strategy: 1.0.0
+      pause: 0.0.1
+
+  path-browserify@0.0.1: {}
+
+  path-dirname@1.0.2: {}
+
   path-exists@3.0.0: {}
 
   path-exists@4.0.0: {}
@@ -22126,12 +25972,16 @@ snapshots:
 
   path-to-regexp@0.1.12: {}
 
+  path-to-regexp@0.1.7: {}
+
   path-to-regexp@1.9.0:
     dependencies:
       isarray: 0.0.1
 
   path-to-regexp@2.4.0: {}
 
+  path-to-regexp@3.2.0: {}
+
   path-to-regexp@3.3.0: {}
 
   path-to-regexp@8.3.0: {}
@@ -22142,6 +25992,21 @@ snapshots:
 
   path-type@4.0.0: {}
 
+  pause-stream@0.0.11:
+    dependencies:
+      through: 2.3.8
+
+  pause@0.0.1: {}
+
+  pbkdf2@3.1.5:
+    dependencies:
+      create-hash: 1.2.0
+      create-hmac: 1.1.7
+      ripemd160: 2.0.3
+      safe-buffer: 5.2.1
+      sha.js: 2.4.12
+      to-buffer: 1.2.2
+
   performance-now@0.2.0: {}
 
   performance-now@2.1.0: {}
@@ -22152,6 +26017,15 @@ snapshots:
 
   pidtree@0.5.0: {}
 
+  pidusage@2.0.21:
+    dependencies:
+      safe-buffer: 5.2.1
+    optional: true
+
+  pidusage@3.0.2:
+    dependencies:
+      safe-buffer: 5.2.1
+
   pify@2.3.0: {}
 
   pify@3.0.0: {}
@@ -22182,6 +26056,81 @@ snapshots:
     dependencies:
       find-up: 3.0.0
 
+  platform@1.3.6: {}
+
+  pm2-axon-rpc@0.7.1:
+    dependencies:
+      debug: 4.4.3
+    transitivePeerDependencies:
+      - supports-color
+
+  pm2-axon@4.0.1:
+    dependencies:
+      amp: 0.3.1
+      amp-message: 0.1.2
+      debug: 4.4.3
+      escape-string-regexp: 4.0.0
+    transitivePeerDependencies:
+      - supports-color
+
+  pm2-deploy@1.0.2:
+    dependencies:
+      run-series: 1.1.9
+      tv4: 1.3.0
+
+  pm2-multimeter@0.1.2:
+    dependencies:
+      charm: 0.1.2
+
+  pm2-sysmonit@1.2.8:
+    dependencies:
+      async: 3.2.6
+      debug: 4.4.3
+      pidusage: 2.0.21
+      systeminformation: 5.31.6
+      tx2: 1.0.5
+    transitivePeerDependencies:
+      - supports-color
+    optional: true
+
+  pm2@5.4.3:
+    dependencies:
+      '@pm2/agent': 2.0.4
+      '@pm2/io': 6.0.1
+      '@pm2/js-api': 0.8.0
+      '@pm2/pm2-version-check': 1.0.4
+      async: 3.2.6
+      blessed: 0.1.81
+      chalk: 3.0.0
+      chokidar: 3.6.0
+      cli-tableau: 2.0.1
+      commander: 2.15.1
+      croner: 4.1.97
+      dayjs: 1.11.13
+      debug: 4.4.3
+      enquirer: 2.3.6
+      eventemitter2: 5.0.1
+      fclone: 1.0.11
+      js-yaml: 4.1.0
+      mkdirp: 1.0.4
+      needle: 2.4.0
+      pidusage: 3.0.2
+      pm2-axon: 4.0.1
+      pm2-axon-rpc: 0.7.1
+      pm2-deploy: 1.0.2
+      pm2-multimeter: 0.1.2
+      promptly: 2.2.0
+      semver: 7.6.3
+      source-map-support: 0.5.21
+      sprintf-js: 1.1.2
+      vizion: 2.2.1
+    optionalDependencies:
+      pm2-sysmonit: 1.2.8
+    transitivePeerDependencies:
+      - bufferutil
+      - supports-color
+      - utf-8-validate
+
   pn@1.1.0: {}
 
   posix-character-classes@0.1.1: {}
@@ -22637,6 +26586,8 @@ snapshots:
     dependencies:
       fast-diff: 1.3.0
 
+  prettier@1.19.1: {}
+
   prettier@2.7.1: {}
 
   prettier@2.8.8: {}
@@ -22686,6 +26637,12 @@ snapshots:
 
   process-nextick-args@2.0.1: {}
 
+  process@0.11.10: {}
+
+  promise-inflight@1.0.1(bluebird@3.7.2):
+    optionalDependencies:
+      bluebird: 3.7.2
+
   promise@7.3.1:
     dependencies:
       asap: 2.0.6
@@ -22694,6 +26651,10 @@ snapshots:
     dependencies:
       asap: 2.0.6
 
+  promptly@2.2.0:
+    dependencies:
+      read: 1.0.7
+
   prompts@2.4.2:
     dependencies:
       kleur: 3.0.3
@@ -22716,18 +26677,52 @@ snapshots:
       forwarded: 0.2.0
       ipaddr.js: 1.9.1
 
+  proxy-agent@6.3.1:
+    dependencies:
+      agent-base: 7.1.4
+      debug: 4.4.3
+      http-proxy-agent: 7.0.2
+      https-proxy-agent: 7.0.6
+      lru-cache: 7.18.3
+      pac-proxy-agent: 7.2.0
+      proxy-from-env: 1.1.0
+      socks-proxy-agent: 8.0.5
+    transitivePeerDependencies:
+      - supports-color
+
   proxy-from-env@1.1.0: {}
 
-  prr@1.0.1:
-    optional: true
+  prr@1.0.1: {}
 
   psl@1.9.0: {}
 
+  public-encrypt@4.0.3:
+    dependencies:
+      bn.js: 4.12.3
+      browserify-rsa: 4.1.1
+      create-hash: 1.2.0
+      parse-asn1: 5.1.9
+      randombytes: 2.1.0
+      safe-buffer: 5.2.1
+
+  pump@2.0.1:
+    dependencies:
+      end-of-stream: 1.4.4
+      once: 1.4.0
+
   pump@3.0.2:
     dependencies:
       end-of-stream: 1.4.4
       once: 1.4.0
 
+  pumpify@1.5.1:
+    dependencies:
+      duplexify: 3.7.1
+      inherits: 2.0.4
+      pump: 2.0.1
+
+  punycode@1.4.1: {}
+
   punycode@2.3.1: {}
 
   pupa@3.1.0:
@@ -22738,7 +26733,7 @@ snapshots:
 
   qs@6.13.0:
     dependencies:
-      side-channel: 1.0.6
+      side-channel: 1.1.0
 
   qs@6.14.0:
     dependencies:
@@ -22746,6 +26741,10 @@ snapshots:
 
   qs@6.5.3: {}
 
+  qs@6.7.0: {}
+
+  querystring-es3@0.2.1: {}
+
   queue-microtask@1.2.3: {}
 
   queue@6.0.2:
@@ -22764,10 +26763,22 @@ snapshots:
     dependencies:
       safe-buffer: 5.2.1
 
+  randomfill@1.0.4:
+    dependencies:
+      randombytes: 2.1.0
+      safe-buffer: 5.2.1
+
   range-parser@1.2.0: {}
 
   range-parser@1.2.1: {}
 
+  raw-body@2.4.0:
+    dependencies:
+      bytes: 3.1.0
+      http-errors: 1.7.2
+      iconv-lite: 0.4.24
+      unpipe: 1.0.0
+
   raw-body@2.5.2:
     dependencies:
       bytes: 3.1.2
@@ -23185,11 +27196,11 @@ snapshots:
 
   react-dev-utils@12.0.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.6.3)(webpack@5.98.0):
     dependencies:
-      '@babel/code-frame': 7.24.7
+      '@babel/code-frame': 7.26.2
       address: 1.2.2
       browserslist: 4.23.3
       chalk: 4.1.2
-      cross-spawn: 7.0.3
+      cross-spawn: 7.0.6
       detect-port-alt: 1.1.6
       escape-string-regexp: 4.0.0
       filesize: 8.0.7
@@ -23492,6 +27503,24 @@ snapshots:
       parse-json: 5.2.0
       type-fest: 0.6.0
 
+  read@1.0.7:
+    dependencies:
+      mute-stream: 0.0.8
+
+  readable-stream@1.0.34:
+    dependencies:
+      core-util-is: 1.0.3
+      inherits: 2.0.4
+      isarray: 0.0.1
+      string_decoder: 0.10.31
+
+  readable-stream@1.1.14:
+    dependencies:
+      core-util-is: 1.0.3
+      inherits: 2.0.4
+      isarray: 0.0.1
+      string_decoder: 0.10.31
+
   readable-stream@2.3.8:
     dependencies:
       core-util-is: 1.0.3
@@ -23508,6 +27537,14 @@ snapshots:
       string_decoder: 1.3.0
       util-deprecate: 1.0.2
 
+  readdirp@2.2.1:
+    dependencies:
+      graceful-fs: 4.2.11
+      micromatch: 3.1.10
+      readable-stream: 2.3.8
+    transitivePeerDependencies:
+      - supports-color
+
   readdirp@3.6.0:
     dependencies:
       picomatch: 2.3.1
@@ -23572,6 +27609,10 @@ snapshots:
       indent-string: 4.0.0
       strip-indent: 3.0.0
 
+  referrer-policy@1.2.0: {}
+
+  reflect-metadata@0.1.14: {}
+
   reflect.getprototypeof@1.0.6:
     dependencies:
       call-bind: 1.0.7
@@ -23786,6 +27827,14 @@ snapshots:
 
   require-from-string@2.0.2: {}
 
+  require-in-the-middle@5.2.0:
+    dependencies:
+      debug: 4.4.3
+      module-details-from-path: 1.0.4
+      resolve: 1.22.8
+    transitivePeerDependencies:
+      - supports-color
+
   require-like@0.1.2: {}
 
   require-main-filename@2.0.0: {}
@@ -23826,6 +27875,11 @@ snapshots:
     dependencies:
       lowercase-keys: 3.0.0
 
+  restore-cursor@2.0.0:
+    dependencies:
+      onetime: 2.0.1
+      signal-exit: 3.0.7
+
   restore-cursor@3.1.0:
     dependencies:
       onetime: 5.1.2
@@ -23852,13 +27906,22 @@ snapshots:
     dependencies:
       glob: 7.2.3
 
+  rimraf@3.0.1:
+    dependencies:
+      glob: 7.2.3
+
   rimraf@3.0.2:
     dependencies:
       glob: 7.2.3
 
+  ripemd160@2.0.3:
+    dependencies:
+      hash-base: 3.1.2
+      inherits: 2.0.4
+
   rollup-plugin-terser@7.0.2(rollup@2.79.1):
     dependencies:
-      '@babel/code-frame': 7.24.7
+      '@babel/code-frame': 7.26.2
       jest-worker: 26.6.2
       rollup: 2.79.1
       serialize-javascript: 4.0.0
@@ -23893,6 +27956,20 @@ snapshots:
     dependencies:
       queue-microtask: 1.2.3
 
+  run-queue@1.0.3:
+    dependencies:
+      aproba: 1.2.0
+
+  run-series@1.1.9: {}
+
+  rxjs@6.3.3:
+    dependencies:
+      tslib: 1.14.1
+
+  rxjs@6.6.7:
+    dependencies:
+      tslib: 1.14.1
+
   rxjs@7.8.1:
     dependencies:
       tslib: 2.7.0
@@ -23970,6 +28047,12 @@ snapshots:
 
   scheduler@0.25.0: {}
 
+  schema-utils@1.0.0:
+    dependencies:
+      ajv: 6.12.6
+      ajv-errors: 1.0.1(ajv@6.12.6)
+      ajv-keywords: 3.5.2(ajv@6.12.6)
+
   schema-utils@2.7.0:
     dependencies:
       '@types/json-schema': 7.0.15
@@ -23999,6 +28082,10 @@ snapshots:
     dependencies:
       compute-scroll-into-view: 3.1.0
 
+  sdk-base@2.0.1:
+    dependencies:
+      get-ready: 1.0.0
+
   search-insights@2.17.3: {}
 
   section-matter@1.0.0:
@@ -24006,6 +28093,8 @@ snapshots:
       extend-shallow: 2.0.1
       kind-of: 6.0.3
 
+  segment@0.1.3: {}
+
   select-hose@2.0.0: {}
 
   selfsigned@2.4.1:
@@ -24021,8 +28110,30 @@ snapshots:
 
   semver@6.3.1: {}
 
+  semver@7.5.4:
+    dependencies:
+      lru-cache: 6.0.0
+
   semver@7.6.3: {}
 
+  send@0.17.1:
+    dependencies:
+      debug: 2.6.9
+      depd: 1.1.2
+      destroy: 1.0.4
+      encodeurl: 1.0.2
+      escape-html: 1.0.3
+      etag: 1.8.1
+      fresh: 0.5.2
+      http-errors: 1.7.3
+      mime: 1.6.0
+      ms: 2.1.1
+      on-finished: 2.3.0
+      range-parser: 1.2.1
+      statuses: 1.5.0
+    transitivePeerDependencies:
+      - supports-color
+
   send@0.19.0:
     dependencies:
       debug: 2.6.9
@@ -24091,6 +28202,15 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  serve-static@1.14.1:
+    dependencies:
+      encodeurl: 1.0.2
+      escape-html: 1.0.3
+      parseurl: 1.3.3
+      send: 0.17.1
+    transitivePeerDependencies:
+      - supports-color
+
   serve-static@1.16.2:
     dependencies:
       encodeurl: 2.0.0
@@ -24138,8 +28258,16 @@ snapshots:
 
   setprototypeof@1.1.0: {}
 
+  setprototypeof@1.1.1: {}
+
   setprototypeof@1.2.0: {}
 
+  sha.js@2.4.12:
+    dependencies:
+      inherits: 2.0.4
+      safe-buffer: 5.2.1
+      to-buffer: 1.2.2
+
   shallow-clone@3.0.1:
     dependencies:
       kind-of: 6.0.3
@@ -24168,6 +28296,8 @@ snapshots:
 
   shellwords@0.1.1: {}
 
+  shimmer@1.2.1: {}
+
   should-equal@2.0.0:
     dependencies:
       should-type: 1.4.0
@@ -24287,6 +28417,8 @@ snapshots:
       ansi-styles: 6.2.1
       is-fullwidth-code-point: 4.0.0
 
+  smart-buffer@4.2.0: {}
+
   snake-case@3.0.4:
     dependencies:
       dot-case: 3.0.4
@@ -24321,6 +28453,19 @@ snapshots:
       uuid: 8.3.2
       websocket-driver: 0.7.4
 
+  socks-proxy-agent@8.0.5:
+    dependencies:
+      agent-base: 7.1.4
+      debug: 4.4.3
+      socks: 2.8.9
+    transitivePeerDependencies:
+      - supports-color
+
+  socks@2.8.9:
+    dependencies:
+      ip-address: 10.2.0
+      smart-buffer: 4.2.0
+
   sort-css-media-queries@2.2.0: {}
 
   source-list-map@2.0.1: {}
@@ -24346,6 +28491,8 @@ snapshots:
 
   source-map@0.6.1: {}
 
+  source-map@0.7.3: {}
+
   source-map@0.7.4: {}
 
   source-map@0.8.0-beta.0:
@@ -24407,6 +28554,8 @@ snapshots:
 
   sprintf-js@1.0.3: {}
 
+  sprintf-js@1.1.2: {}
+
   sql-escaper@1.3.3: {}
 
   sqlstring@2.3.3: {}
@@ -24425,6 +28574,10 @@ snapshots:
       safer-buffer: 2.1.2
       tweetnacl: 0.14.5
 
+  ssri@6.0.2:
+    dependencies:
+      figgy-pudding: 3.5.2
+
   stack-utils@1.0.5:
     dependencies:
       escape-string-regexp: 2.0.0
@@ -24460,6 +28613,46 @@ snapshots:
     dependencies:
       internal-slot: 1.0.7
 
+  stream-browserify@2.0.2:
+    dependencies:
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+
+  stream-each@1.2.3:
+    dependencies:
+      end-of-stream: 1.4.4
+      stream-shift: 1.0.3
+
+  stream-http@2.8.2:
+    dependencies:
+      builtin-status-codes: 3.0.0
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+      to-arraybuffer: 1.0.1
+      xtend: 4.0.2
+
+  stream-http@2.8.3:
+    dependencies:
+      builtin-status-codes: 3.0.0
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+      to-arraybuffer: 1.0.1
+      xtend: 4.0.2
+
+  stream-shift@1.0.3: {}
+
+  stream-wormhole@1.1.0: {}
+
+  streamroller@3.1.5:
+    dependencies:
+      date-format: 4.0.14
+      debug: 4.4.3
+      fs-extra: 8.1.0
+    transitivePeerDependencies:
+      - supports-color
+
+  streamsearch@0.1.2: {}
+
   string-argv@0.3.2: {}
 
   string-convert@0.2.1: {}
@@ -24469,6 +28662,11 @@ snapshots:
       astral-regex: 1.0.0
       strip-ansi: 4.0.0
 
+  string-width@2.1.1:
+    dependencies:
+      is-fullwidth-code-point: 2.0.0
+      strip-ansi: 4.0.0
+
   string-width@3.1.0:
     dependencies:
       emoji-regex: 7.0.3
@@ -24537,6 +28735,8 @@ snapshots:
       define-properties: 1.2.1
       es-object-atoms: 1.0.0
 
+  string_decoder@0.10.31: {}
+
   string_decoder@1.1.1:
     dependencies:
       safe-buffer: 5.1.2
@@ -24556,6 +28756,10 @@ snapshots:
       is-obj: 1.0.1
       is-regexp: 1.0.0
 
+  strip-ansi@3.0.1:
+    dependencies:
+      ansi-regex: 2.1.1
+
   strip-ansi@4.0.0:
     dependencies:
       ansi-regex: 3.0.1
@@ -24622,6 +28826,30 @@ snapshots:
 
   sudo-prompt@9.2.1: {}
 
+  superagent@3.8.3:
+    dependencies:
+      component-emitter: 1.3.1
+      cookiejar: 2.1.4
+      debug: 3.2.7
+      extend: 3.0.2
+      form-data: 2.3.3
+      formidable: 1.2.6
+      methods: 1.1.2
+      mime: 1.6.0
+      qs: 6.14.0
+      readable-stream: 2.3.8
+    transitivePeerDependencies:
+      - supports-color
+
+  supertest@4.0.2:
+    dependencies:
+      methods: 1.1.2
+      superagent: 3.8.3
+    transitivePeerDependencies:
+      - supports-color
+
+  supports-color@2.0.0: {}
+
   supports-color@5.5.0:
     dependencies:
       has-flag: 3.0.0
@@ -24660,6 +28888,8 @@ snapshots:
 
   swagger-schema-official@2.0.0-bab6bed: {}
 
+  swagger-themes@1.4.3: {}
+
   swagger-typescript-api@12.0.4(encoding@0.1.13):
     dependencies:
       '@types/swagger-schema-official': 2.0.22
@@ -24679,6 +28909,15 @@ snapshots:
     transitivePeerDependencies:
       - encoding
 
+  swagger-ui-dist@5.32.6:
+    dependencies:
+      '@scarf/scarf': 1.4.0
+
+  swagger-ui-express@4.6.3(express@4.21.2):
+    dependencies:
+      express: 4.21.2
+      swagger-ui-dist: 5.32.6
+
   swagger2openapi@7.0.8(encoding@0.1.13):
     dependencies:
       call-me-maybe: 1.0.2
@@ -24701,12 +28940,19 @@ snapshots:
       react: 17.0.2
       use-sync-external-store: 1.2.2(react@17.0.2)
 
+  symbol-observable@1.2.0: {}
+
   symbol-tree@3.2.4: {}
 
+  systeminformation@5.31.6:
+    optional: true
+
   tapable@1.1.3: {}
 
   tapable@2.2.1: {}
 
+  tapable@2.3.3: {}
+
   temp-dir@2.0.0: {}
 
   temp@0.8.4:
@@ -24725,6 +28971,19 @@ snapshots:
       type-fest: 0.16.0
       unique-string: 2.0.0
 
+  terser-webpack-plugin@1.4.6(webpack@4.41.5):
+    dependencies:
+      cacache: 12.0.4
+      find-cache-dir: 2.1.0
+      is-wsl: 1.1.0
+      schema-utils: 1.0.0
+      serialize-javascript: 4.0.0
+      source-map: 0.6.1
+      terser: 4.8.1
+      webpack: 4.41.5
+      webpack-sources: 1.4.3
+      worker-farm: 1.7.0
+
   terser-webpack-plugin@5.3.10(webpack@5.98.0):
     dependencies:
       '@jridgewell/trace-mapping': 0.3.25
@@ -24743,6 +29002,13 @@ snapshots:
       terser: 5.33.0
       webpack: 5.98.0
 
+  terser@4.8.1:
+    dependencies:
+      acorn: 8.15.0
+      commander: 2.20.3
+      source-map: 0.6.1
+      source-map-support: 0.5.21
+
   terser@5.33.0:
     dependencies:
       '@jridgewell/source-map': 0.3.6
@@ -24761,6 +29027,14 @@ snapshots:
 
   text-table@0.2.0: {}
 
+  thenify-all@1.6.0:
+    dependencies:
+      thenify: 3.3.1
+
+  thenify@3.3.1:
+    dependencies:
+      any-promise: 1.3.0
+
   three@0.168.0: {}
 
   throat@4.1.0: {}
@@ -24778,12 +29052,33 @@ snapshots:
 
   thunky@1.1.0: {}
 
+  timers-browserify@2.0.12:
+    dependencies:
+      setimmediate: 1.0.5
+
+  timers-ext@0.1.8:
+    dependencies:
+      es5-ext: 0.10.64
+      next-tick: 1.1.0
+
   tiny-invariant@1.3.3: {}
 
   tiny-warning@1.0.3: {}
 
+  tmp@0.0.33:
+    dependencies:
+      os-tmpdir: 1.0.2
+
   tmpl@1.0.5: {}
 
+  to-arraybuffer@1.0.1: {}
+
+  to-buffer@1.2.2:
+    dependencies:
+      isarray: 2.0.5
+      safe-buffer: 5.2.1
+      typed-array-buffer: 1.0.3
+
   to-object-path@0.3.0:
     dependencies:
       kind-of: 3.2.2
@@ -24806,6 +29101,8 @@ snapshots:
 
   toggle-selection@1.0.6: {}
 
+  toidentifier@1.0.0: {}
+
   toidentifier@1.0.1: {}
 
   totalist@3.0.1: {}
@@ -24843,6 +29140,30 @@ snapshots:
       semver: 5.7.2
       yargs-parser: 10.1.0
 
+  ts-loader@6.2.2(typescript@4.1.6):
+    dependencies:
+      chalk: 2.4.2
+      enhanced-resolve: 4.5.0
+      loader-utils: 1.4.2
+      micromatch: 4.0.8
+      semver: 6.3.1
+      typescript: 4.1.6
+
+  ts-node@8.10.2(typescript@4.1.6):
+    dependencies:
+      arg: 4.1.3
+      diff: 4.0.4
+      make-error: 1.3.6
+      source-map-support: 0.5.21
+      typescript: 4.1.6
+      yn: 3.1.1
+
+  tsconfig-paths-webpack-plugin@3.2.0:
+    dependencies:
+      chalk: 2.4.2
+      enhanced-resolve: 4.5.0
+      tsconfig-paths: 3.15.0
+
   tsconfig-paths-webpack-plugin@3.5.2:
     dependencies:
       chalk: 4.1.2
@@ -24856,23 +29177,70 @@ snapshots:
       minimist: 1.2.8
       strip-bom: 3.0.0
 
+  tsconfig-paths@3.9.0:
+    dependencies:
+      '@types/json5': 0.0.29
+      json5: 1.0.2
+      minimist: 1.2.8
+      strip-bom: 3.0.0
+
+  tslib@1.11.1: {}
+
   tslib@1.14.1: {}
 
+  tslib@1.9.3: {}
+
   tslib@2.3.0: {}
 
   tslib@2.7.0: {}
 
+  tslint@5.20.1(typescript@4.1.6):
+    dependencies:
+      '@babel/code-frame': 7.26.2
+      builtin-modules: 1.1.1
+      chalk: 2.4.2
+      commander: 2.20.3
+      diff: 4.0.4
+      glob: 7.2.3
+      js-yaml: 3.14.1
+      minimatch: 3.1.2
+      mkdirp: 0.5.6
+      resolve: 1.22.8
+      semver: 5.7.2
+      tslib: 1.14.1
+      tsutils: 2.29.0(typescript@4.1.6)
+      typescript: 4.1.6
+
+  tsutils@2.29.0(typescript@4.1.6):
+    dependencies:
+      tslib: 1.14.1
+      typescript: 4.1.6
+
+  tsutils@3.21.0(typescript@4.1.6):
+    dependencies:
+      tslib: 1.14.1
+      typescript: 4.1.6
+
   tsutils@3.21.0(typescript@4.6.2):
     dependencies:
       tslib: 1.14.1
       typescript: 4.6.2
 
+  tty-browserify@0.0.0: {}
+
   tunnel-agent@0.6.0:
     dependencies:
       safe-buffer: 5.2.1
 
+  tv4@1.3.0: {}
+
   tweetnacl@0.14.5: {}
 
+  tx2@1.0.5:
+    dependencies:
+      json-stringify-safe: 5.0.1
+    optional: true
+
   type-check@0.3.2:
     dependencies:
       prelude-ls: 1.1.2
@@ -24912,12 +29280,20 @@ snapshots:
       media-typer: 1.1.0
       mime-types: 3.0.1
 
+  type@2.7.3: {}
+
   typed-array-buffer@1.0.2:
     dependencies:
       call-bind: 1.0.7
       es-errors: 1.3.0
       is-typed-array: 1.1.13
 
+  typed-array-buffer@1.0.3:
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      is-typed-array: 1.1.15
+
   typed-array-byte-length@1.0.1:
     dependencies:
       call-bind: 1.0.7
@@ -24948,6 +29324,34 @@ snapshots:
     dependencies:
       is-typedarray: 1.0.0
 
+  typedarray@0.0.6: {}
+
+  typeorm@0.2.45(mysql2@3.22.3(@types/node@12.20.55)):
+    dependencies:
+      '@sqltools/formatter': 1.2.5
+      app-root-path: 3.1.0
+      buffer: 6.0.3
+      chalk: 4.1.2
+      cli-highlight: 2.1.11
+      debug: 4.4.3
+      dotenv: 8.6.0
+      glob: 7.2.3
+      js-yaml: 4.1.0
+      mkdirp: 1.0.4
+      reflect-metadata: 0.1.14
+      sha.js: 2.4.12
+      tslib: 2.7.0
+      uuid: 8.3.2
+      xml2js: 0.4.23
+      yargs: 17.7.2
+      zen-observable-ts: 1.1.0
+    optionalDependencies:
+      mysql2: 3.22.3(@types/node@12.20.55)
+    transitivePeerDependencies:
+      - supports-color
+
+  typescript@3.9.10: {}
+
   typescript@4.1.6: {}
 
   typescript@4.6.2: {}
@@ -24970,6 +29374,10 @@ snapshots:
 
   undici-types@7.12.0: {}
 
+  unescape@1.0.1:
+    dependencies:
+      extend-shallow: 2.0.1
+
   unicode-canonical-property-names-ecmascript@2.0.1: {}
 
   unicode-emoji-modifier-base@1.0.0: {}
@@ -25000,6 +29408,14 @@ snapshots:
       is-extendable: 0.1.1
       set-value: 2.0.1
 
+  unique-filename@1.1.1:
+    dependencies:
+      unique-slug: 2.0.2
+
+  unique-slug@2.0.2:
+    dependencies:
+      imurmurhash: 0.1.4
+
   unique-string@2.0.0:
     dependencies:
       crypto-random-string: 2.0.0
@@ -25092,6 +29508,26 @@ snapshots:
     optionalDependencies:
       file-loader: 6.2.0(webpack@5.98.0)
 
+  url@0.11.4:
+    dependencies:
+      punycode: 1.4.1
+      qs: 6.14.0
+
+  urllib@2.44.0:
+    dependencies:
+      any-promise: 1.3.0
+      content-type: 1.0.5
+      default-user-agent: 1.0.0
+      digest-header: 1.1.0
+      ee-first: 1.1.1
+      formstream: 1.5.2
+      humanize-ms: 1.2.1
+      iconv-lite: 0.6.3
+      pump: 3.0.2
+      qs: 6.14.0
+      statuses: 1.5.0
+      utility: 1.18.0
+
   use-intl@1.5.1(react@17.0.2):
     dependencies:
       intl-messageformat: 9.13.0
@@ -25119,14 +29555,34 @@ snapshots:
       object.getownpropertydescriptors: 2.1.8
       safe-array-concat: 1.1.2
 
+  util@0.10.4:
+    dependencies:
+      inherits: 2.0.3
+
+  util@0.11.1:
+    dependencies:
+      inherits: 2.0.3
+
   utila@0.4.0: {}
 
   utility-types@3.11.0: {}
 
+  utility@1.18.0:
+    dependencies:
+      copy-to: 2.0.1
+      escape-html: 1.0.3
+      mkdirp: 0.5.6
+      mz: 2.7.0
+      unescape: 1.0.1
+
   utils-merge@1.0.1: {}
 
   uuid@3.4.0: {}
 
+  uuid@7.0.1: {}
+
+  uuid@7.0.3: {}
+
   uuid@8.3.2: {}
 
   v8-compile-cache@2.4.0: {}
@@ -25136,6 +29592,8 @@ snapshots:
       spdx-correct: 3.2.0
       spdx-expression-parse: 3.0.1
 
+  validator@13.15.35: {}
+
   value-equal@1.0.1: {}
 
   vary@1.1.2: {}
@@ -25163,8 +29621,17 @@ snapshots:
 
   viewerjs@1.11.6: {}
 
+  vizion@2.2.1:
+    dependencies:
+      async: 2.6.4
+      git-node-fs: 1.0.0(js-git@0.7.8)
+      ini: 1.3.8
+      js-git: 0.7.8
+
   vlq@1.0.1: {}
 
+  vm-browserify@1.1.2: {}
+
   w3c-hr-time@1.0.2:
     dependencies:
       browser-process-hrtime: 1.0.0
@@ -25177,6 +29644,23 @@ snapshots:
     dependencies:
       loose-envify: 1.4.0
 
+  watchpack-chokidar2@2.0.1:
+    dependencies:
+      chokidar: 2.1.8
+    transitivePeerDependencies:
+      - supports-color
+    optional: true
+
+  watchpack@1.7.5:
+    dependencies:
+      graceful-fs: 4.2.11
+      neo-async: 2.6.2
+    optionalDependencies:
+      chokidar: 3.6.0
+      watchpack-chokidar2: 2.0.1
+    transitivePeerDependencies:
+      - supports-color
+
   watchpack@2.4.2:
     dependencies:
       glob-to-regexp: 0.4.1
@@ -25277,6 +29761,8 @@ snapshots:
       flat: 5.0.2
       wildcard: 2.0.1
 
+  webpack-node-externals@1.7.2: {}
+
   webpack-sources@1.4.3:
     dependencies:
       source-list-map: 2.0.1
@@ -25284,6 +29770,34 @@ snapshots:
 
   webpack-sources@3.2.3: {}
 
+  webpack@4.41.5:
+    dependencies:
+      '@webassemblyjs/ast': 1.8.5
+      '@webassemblyjs/helper-module-context': 1.8.5
+      '@webassemblyjs/wasm-edit': 1.8.5
+      '@webassemblyjs/wasm-parser': 1.8.5
+      acorn: 6.4.2
+      ajv: 6.12.6
+      ajv-keywords: 3.5.2(ajv@6.12.6)
+      chrome-trace-event: 1.0.4
+      enhanced-resolve: 4.5.0
+      eslint-scope: 4.0.3
+      json-parse-better-errors: 1.0.2
+      loader-runner: 2.4.0
+      loader-utils: 1.4.2
+      memory-fs: 0.4.1
+      micromatch: 3.1.10
+      mkdirp: 0.5.6
+      neo-async: 2.6.2
+      node-libs-browser: 2.2.1
+      schema-utils: 1.0.0
+      tapable: 1.1.3
+      terser-webpack-plugin: 1.4.6(webpack@4.41.5)
+      watchpack: 1.7.5
+      webpack-sources: 1.4.3
+    transitivePeerDependencies:
+      - supports-color
+
   webpack@5.98.0:
     dependencies:
       '@types/eslint-scope': 3.7.7
@@ -25399,6 +29913,16 @@ snapshots:
       gopd: 1.0.1
       has-tostringtag: 1.0.2
 
+  which-typed-array@1.1.20:
+    dependencies:
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.9
+      call-bound: 1.0.4
+      for-each: 0.3.5
+      get-proto: 1.0.1
+      gopd: 1.2.0
+      has-tostringtag: 1.0.2
+
   which@1.3.1:
     dependencies:
       isexe: 2.0.0
@@ -25413,6 +29937,14 @@ snapshots:
 
   wildcard@2.0.1: {}
 
+  win-release@1.1.1:
+    dependencies:
+      semver: 5.7.2
+
+  windows-release@3.3.3:
+    dependencies:
+      execa: 1.0.0
+
   word-wrap@1.2.5: {}
 
   wordwrap@1.0.0: {}
@@ -25542,6 +30074,14 @@ snapshots:
       '@types/trusted-types': 2.0.7
       workbox-core: 6.6.0
 
+  worker-farm@1.7.0:
+    dependencies:
+      errno: 0.1.8
+
+  worker-rpc@0.1.1:
+    dependencies:
+      microevent.ts: 0.1.1
+
   wrap-ansi@5.1.0:
     dependencies:
       ansi-styles: 3.2.1
@@ -25599,6 +30139,8 @@ snapshots:
 
   ws@8.18.1: {}
 
+  x-xss-protection@1.3.0: {}
+
   xdg-basedir@5.1.0: {}
 
   xml-js@1.6.11:
@@ -25607,8 +30149,20 @@ snapshots:
 
   xml-name-validator@3.0.0: {}
 
+  xml2js@0.4.23:
+    dependencies:
+      sax: 1.4.1
+      xmlbuilder: 11.0.1
+
+  xml2js@0.6.2:
+    dependencies:
+      sax: 1.4.1
+      xmlbuilder: 11.0.1
+
   xml@1.0.1: {}
 
+  xmlbuilder@11.0.1: {}
+
   xtend@4.0.2: {}
 
   y18n@4.0.3: {}
@@ -25707,12 +30261,21 @@ snapshots:
       y18n: 5.0.8
       yargs-parser: 21.1.1
 
+  yn@3.1.1: {}
+
   yocto-queue@0.1.0: {}
 
   yocto-queue@1.1.1: {}
 
   zdog@1.1.3: {}
 
+  zen-observable-ts@1.1.0:
+    dependencies:
+      '@types/zen-observable': 0.8.3
+      zen-observable: 0.8.15
+
+  zen-observable@0.8.15: {}
+
   zrender@5.6.1:
     dependencies:
       tslib: 2.3.0
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index b44048d..7725ede 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,4 +1,6 @@
 packages:
+  # 后端 API
+  - 'server'
   # 客户端
   - 'client'
   # 文档
diff --git a/scripts/bundled-server-path.js b/scripts/bundled-server-path.js
index d924534..d2bdf6e 100644
--- a/scripts/bundled-server-path.js
+++ b/scripts/bundled-server-path.js
@@ -1,8 +1,22 @@
 /**
- * Resolve paths to the Nest server bundled inside @fecommunity/reactpress-cli.
+ * Resolve ReactPress API server paths.
+ * Monorepo: prefer ./server when Nest source exists; otherwise fall back to CLI bundle.
  */
+const fs = require('fs');
 const path = require('path');
 
+function getMonorepoRoot() {
+  return path.resolve(__dirname, '..');
+}
+
+function getMonorepoServerDir() {
+  return path.join(getMonorepoRoot(), 'server');
+}
+
+function hasMonorepoServerSource() {
+  return fs.existsSync(path.join(getMonorepoServerDir(), 'src', 'main.ts'));
+}
+
 function getCliPackageRoot() {
   return path.dirname(require.resolve('@fecommunity/reactpress-cli/package.json'));
 }
@@ -11,27 +25,46 @@ function getBundledServerDir() {
   return path.join(getCliPackageRoot(), 'server');
 }
 
-function getBundledServerBin() {
-  return path.join(getBundledServerDir(), 'bin', 'reactpress-server.js');
+function getServerDir() {
+  if (hasMonorepoServerSource()) {
+    return getMonorepoServerDir();
+  }
+  return getBundledServerDir();
 }
 
-function getBundledSwaggerPath() {
-  return path.join(getBundledServerDir(), 'public', 'swagger.json');
+function getServerBin() {
+  return path.join(getServerDir(), 'bin', 'reactpress-server.js');
 }
 
-function getBundledServerMain() {
-  return path.join(getBundledServerDir(), 'dist', 'main.js');
+function getSwaggerPath() {
+  return path.join(getServerDir(), 'public', 'swagger.json');
 }
 
-function getMonorepoRoot() {
-  return path.resolve(__dirname, '..');
+function getServerMain() {
+  return path.join(getServerDir(), 'dist', 'main.js');
+}
+
+function isUsingMonorepoServer() {
+  return hasMonorepoServerSource();
 }
 
+// Legacy export names
+const getBundledServerBin = getServerBin;
+const getBundledSwaggerPath = getSwaggerPath;
+const getBundledServerMain = getServerMain;
+
 module.exports = {
+  getMonorepoRoot,
+  getMonorepoServerDir,
+  hasMonorepoServerSource,
+  isUsingMonorepoServer,
   getCliPackageRoot,
   getBundledServerDir,
+  getServerDir,
+  getServerBin,
+  getSwaggerPath,
+  getServerMain,
   getBundledServerBin,
   getBundledSwaggerPath,
   getBundledServerMain,
-  getMonorepoRoot,
 };
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
index 40f38e7..763c8b4 100755
--- a/scripts/deploy.sh
+++ b/scripts/deploy.sh
@@ -1,59 +1,44 @@
 #!/bin/bash
 
-# Exit on any error
+# ReactPress production deploy (monorepo: server + client on host with PM2)
 set -e
 
-# Logging function
 log() {
-    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
+  echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
 }
 
-# Error handling
 error_exit() {
-    log "ERROR: $1"
-    exit 1
+  log "ERROR: $1"
+  exit 1
 }
 
-# Check if repository is already cloned
-if [ ! -d ".git" ]; then
-    log "Cloning repository..."
-    # Assuming the script is in the root of the repo, this would be adjusted based on actual needs
-    # For now, we'll assume the script is run from within the repo
-    log "WARNING: This script should be run from within the cloned repository"
-else
-    log "Repository already cloned, proceeding with update..."
-fi
-
-log "Starting deployment process..."
+log "Starting deployment..."
 
-# Update code
-log "Updating code from repository..."
-git checkout master || error_exit "Failed to checkout master branch"
-git pull || error_exit "Failed to pull latest changes"
+if [ ! -f "package.json" ]; then
+  error_exit "Run this script from the repository root"
+fi
 
-# Install dependencies
 log "Installing dependencies..."
-pnpm install || error_exit "Failed to install dependencies"
+pnpm install || error_exit "pnpm install failed"
 
-# Build all packages using the unified build command
-log "Building all packages..."
-pnpm run build || error_exit "Failed to build packages"
+log "Building toolkit, server, and client..."
+pnpm run build || error_exit "pnpm build failed"
 
-# Kill existing PM2 processes
-log "Stopping existing PM2 processes..."
-pm2 kill || log "No existing PM2 processes found"
+log "Stopping existing ReactPress PM2 apps (if any)..."
+pm2 delete reactpress-server 2>/dev/null || true
+pm2 delete @fecommunity/reactpress-server 2>/dev/null || true
+pm2 delete @fecommunity/reactpress-client 2>/dev/null || true
+pm2 delete reactpress-client 2>/dev/null || true
 
-# Start services with PM2
-log "Starting services with PM2..."
-pnpm run pm2 || error_exit "Failed to start services with PM2"
+log "Starting API and client with PM2..."
+pnpm run pm2 || error_exit "Failed to start PM2 processes"
 
-# Set up PM2 startup script
-log "Setting up PM2 startup script..."
-pm2 startup || log "Failed to setup PM2 startup script"
-pm2 save || error_exit "Failed to save PM2 configuration"
+log "Saving PM2 process list..."
+pm2 save || log "WARN: pm2 save failed (run pm2 startup manually if needed)"
 
-log "Deployment completed successfully!"
-log "Frontend available at http://localhost:3001"
-log "Backend API available at http://localhost:3002"
+log "Deployment completed."
+log "  Client: http://localhost:3001"
+log "  API:    http://localhost:3002"
+log "  Status: pnpm run status"
 
-exit 0
\ No newline at end of file
+exit 0
diff --git a/scripts/docker-dev.js b/scripts/docker-dev.js
index 1ef8fda..6a846db 100755
--- a/scripts/docker-dev.js
+++ b/scripts/docker-dev.js
@@ -128,7 +128,7 @@ switch (command) {
           }
           
           console.log('[ReactPress] Toolkit built successfully.');
-          console.log('[ReactPress] Starting client and API (reactpress-cli) in development mode...');
+          console.log('[ReactPress] Starting client and API (monorepo server/) in development mode...');
           console.log('[ReactPress] Access your application at: http://localhost:8080');
           
           // 执行并发命令
diff --git a/scripts/reactpress-api-dev.js b/scripts/reactpress-api-dev.js
index 1ec9a68..766df6f 100644
--- a/scripts/reactpress-api-dev.js
+++ b/scripts/reactpress-api-dev.js
@@ -1,13 +1,16 @@
 #!/usr/bin/env node
 
 /**
- * Development API: ensure config, start via reactpress-cli, keep process alive for concurrently.
+ * Development API: Nest watch (monorepo server) or reactpress-cli fallback.
  */
 
-const { spawnSync } = require('child_process');
+const { spawn, spawnSync } = require('child_process');
 const path = require('path');
 const fs = require('fs');
-const { getMonorepoRoot } = require('./bundled-server-path');
+const {
+  getMonorepoRoot,
+  isUsingMonorepoServer,
+} = require('./bundled-server-path');
 
 const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
 const configPath = path.join(projectRoot, '.reactpress', 'config.json');
@@ -25,25 +28,48 @@ if (!fs.existsSync(configPath)) {
   }
 }
 
-const start = spawnSync('pnpm', ['exec', 'reactpress-cli', 'start'], {
-  cwd: projectRoot,
-  stdio: 'inherit',
-});
+let apiChild;
 
-if (start.status !== 0) {
-  process.exit(start.status ?? 1);
+function stopApi() {
+  if (apiChild && !apiChild.killed) {
+    apiChild.kill('SIGTERM');
+  }
+  if (!isUsingMonorepoServer()) {
+    spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], {
+      cwd: projectRoot,
+      stdio: 'inherit',
+    });
+  }
 }
 
-console.log('[reactpress] API 已由 reactpress-cli 启动。按 Ctrl+C 停止 API 与前端。');
-console.log('[reactpress] 单独停止 API: pnpm exec reactpress-cli stop');
-
-process.stdin.resume();
-
-function stopApi() {
-  spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], {
+if (isUsingMonorepoServer()) {
+  console.log('[reactpress] 开发模式: server/ (nest start --watch)');
+  apiChild = spawn('pnpm', ['run', '--dir', './server', 'dev'], {
+    cwd: projectRoot,
+    stdio: 'inherit',
+    shell: true,
+    env: {
+      ...process.env,
+      REACTPRESS_ORIGINAL_CWD: projectRoot,
+    },
+  });
+} else {
+  console.log('[reactpress] 开发模式: reactpress-cli(未找到 server/src)');
+  const start = spawnSync('pnpm', ['exec', 'reactpress-cli', 'start'], {
     cwd: projectRoot,
     stdio: 'inherit',
   });
+  if (start.status !== 0) {
+    process.exit(start.status ?? 1);
+  }
+  console.log('[reactpress] API 已由 reactpress-cli 启动。');
+  process.stdin.resume();
+}
+
+if (apiChild) {
+  apiChild.on('close', (code) => {
+    process.exit(code ?? 0);
+  });
 }
 
 process.on('SIGINT', () => {
@@ -55,3 +81,8 @@ process.on('SIGTERM', () => {
   stopApi();
   process.exit(0);
 });
+
+if (apiChild) {
+  console.log('[reactpress] 按 Ctrl+C 停止 API 与前端。');
+  console.log('[reactpress] 单独停止 API: pnpm run stop');
+}
diff --git a/scripts/reactpress-api-lifecycle.js b/scripts/reactpress-api-lifecycle.js
new file mode 100644
index 0000000..9efc43b
--- /dev/null
+++ b/scripts/reactpress-api-lifecycle.js
@@ -0,0 +1,257 @@
+#!/usr/bin/env node
+
+/**
+ * API lifecycle for monorepo: start / stop / restart / status (local server package).
+ * Init and Docker DB still use reactpress-cli when needed.
+ */
+
+const { spawn, spawnSync } = require('child_process');
+const fs = require('fs');
+const http = require('http');
+const path = require('path');
+const {
+  getMonorepoRoot,
+  getServerBin,
+  getServerDir,
+  isUsingMonorepoServer,
+} = require('./bundled-server-path');
+
+const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
+const pidFile = path.join(projectRoot, '.reactpress', 'server.pid');
+const configPath = path.join(projectRoot, '.reactpress', 'config.json');
+
+process.env.REACTPRESS_ORIGINAL_CWD = projectRoot;
+
+function loadServerSiteUrl() {
+  const envPath = path.join(projectRoot, '.env');
+  try {
+    const content = fs.readFileSync(envPath, 'utf8');
+    const match = content.match(/^SERVER_SITE_URL=(.+)$/m);
+    if (match) {
+      return match[1].trim().replace(/^['"]|['"]$/g, '');
+    }
+  } catch {
+    // ignore
+  }
+  return 'http://localhost:3002';
+}
+
+function ensureConfig() {
+  if (fs.existsSync(configPath)) {
+    return true;
+  }
+  console.warn('[reactpress] 未找到 .reactpress/config.json,正在执行 reactpress-cli init …');
+  const init = spawnSync('pnpm', ['exec', 'reactpress-cli', 'init', '.'], {
+    cwd: projectRoot,
+    stdio: 'inherit',
+  });
+  return init.status === 0;
+}
+
+function readPid() {
+  try {
+    const raw = fs.readFileSync(pidFile, 'utf8').trim();
+    const pid = Number.parseInt(raw, 10);
+    return Number.isFinite(pid) ? pid : null;
+  } catch {
+    return null;
+  }
+}
+
+function isProcessRunning(pid) {
+  if (!pid) return false;
+  try {
+    process.kill(pid, 0);
+    return true;
+  } catch {
+    return false;
+  }
+}
+
+function clearPidFile() {
+  if (fs.existsSync(pidFile)) {
+    fs.unlinkSync(pidFile);
+  }
+}
+
+function writePid(pid) {
+  fs.mkdirSync(path.dirname(pidFile), { recursive: true });
+  fs.writeFileSync(pidFile, String(pid));
+}
+
+function stopApi() {
+  const pid = readPid();
+  if (pid && isProcessRunning(pid)) {
+    try {
+      process.kill(pid, 'SIGTERM');
+      console.log(`[reactpress] 已停止 API 进程 (pid ${pid})`);
+    } catch (err) {
+      console.warn(`[reactpress] 停止 pid ${pid} 失败:`, err.message);
+    }
+  }
+  clearPidFile();
+}
+
+function isApiResponding(url, timeoutMs = 2000) {
+  return new Promise((resolve) => {
+    let parsed;
+    try {
+      parsed = new URL(url);
+    } catch {
+      resolve(false);
+      return;
+    }
+    const port = parsed.port || (parsed.protocol === 'https:' ? 443 : 80);
+    const req = http.request(
+      {
+        hostname: parsed.hostname,
+        port,
+        path: parsed.pathname || '/',
+        method: 'GET',
+        timeout: timeoutMs,
+      },
+      (res) => resolve(res.statusCode > 0)
+    );
+    req.on('timeout', () => {
+      req.destroy();
+      resolve(false);
+    });
+    req.on('error', () => resolve(false));
+    req.end();
+  });
+}
+
+async function waitForApi(url, timeoutMs = 120_000) {
+  const deadline = Date.now() + timeoutMs;
+  while (Date.now() < deadline) {
+    if (await isApiResponding(url)) {
+      return true;
+    }
+    await new Promise((r) => setTimeout(r, 500));
+  }
+  return false;
+}
+
+function startApi({ wait = true } = {}) {
+  if (!ensureConfig()) {
+    process.exit(1);
+  }
+
+  const existing = readPid();
+  if (existing && isProcessRunning(existing)) {
+    console.log(`[reactpress] API 已在运行 (pid ${existing})`);
+    return 0;
+  }
+  clearPidFile();
+
+  if (!isUsingMonorepoServer()) {
+    console.warn('[reactpress] 未检测到 server/src,回退到 reactpress-cli start');
+    const start = spawnSync('pnpm', ['exec', 'reactpress-cli', 'start'], {
+      cwd: projectRoot,
+      stdio: 'inherit',
+    });
+    return start.status ?? 1;
+  }
+
+  console.log('[reactpress] 正在启动本地 API (server/)…');
+  const child = spawn(process.execPath, [getServerBin()], {
+    cwd: getServerDir(),
+    detached: true,
+    stdio: 'ignore',
+    env: {
+      ...process.env,
+      REACTPRESS_ORIGINAL_CWD: projectRoot,
+    },
+  });
+
+  child.unref();
+  writePid(child.pid);
+  console.log(`[reactpress] API 已后台启动 (pid ${child.pid})`);
+
+  if (!wait) {
+    return 0;
+  }
+
+  const serverUrl = loadServerSiteUrl();
+  return waitForApi(serverUrl).then((ready) => {
+    if (!ready) {
+      console.error(`[reactpress] API 在 120s 内未就绪: ${serverUrl}`);
+      return 1;
+    }
+    console.log(`[reactpress] API 已就绪: ${serverUrl}`);
+    return 0;
+  });
+}
+
+async function statusApi() {
+  const pid = readPid();
+  const serverUrl = loadServerSiteUrl();
+  const httpOk = await isApiResponding(serverUrl);
+
+  console.log('[reactpress] API 状态');
+  console.log(`  来源: ${isUsingMonorepoServer() ? 'monorepo server/' : 'reactpress-cli bundle'}`);
+  console.log(`  PID 文件: ${pidFile}`);
+  console.log(`  记录 PID: ${pid ?? '(无)'}`);
+  console.log(`  进程存活: ${pid ? (isProcessRunning(pid) ? '是' : '否') : '—'}`);
+  console.log(`  HTTP (${serverUrl}): ${httpOk ? '可访问' : '不可访问'}`);
+}
+
+const command = process.argv[2] || 'start';
+
+async function main() {
+  switch (command) {
+    case 'start': {
+      const code = await startApi({ wait: true });
+      process.exit(typeof code === 'number' ? code : 0);
+      break;
+    }
+    case 'start:bg': {
+      const code = await startApi({ wait: false });
+      process.exit(typeof code === 'number' ? code : 0);
+      break;
+    }
+    case 'stop':
+      stopApi();
+      if (!isUsingMonorepoServer()) {
+        spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], {
+          cwd: projectRoot,
+          stdio: 'inherit',
+        });
+      }
+      break;
+    case 'restart':
+      stopApi();
+      if (!isUsingMonorepoServer()) {
+        spawnSync('pnpm', ['exec', 'reactpress-cli', 'restart'], {
+          cwd: projectRoot,
+          stdio: 'inherit',
+        });
+        break;
+      }
+      {
+        const code = await startApi({ wait: true });
+        process.exit(code ?? 0);
+      }
+      break;
+    case 'status':
+      await statusApi();
+      break;
+    default:
+      console.log(`
+用法: node scripts/reactpress-api-lifecycle.js 
+
+命令:
+  start      启动 API 并等待就绪(默认)
+  start:bg   后台启动,不等待 HTTP
+  stop       停止 API
+  restart    重启 API
+  status     查看 API 状态
+`);
+      process.exit(1);
+  }
+}
+
+main().catch((err) => {
+  console.error('[reactpress]', err);
+  process.exit(1);
+});
diff --git a/scripts/reactpress-api-pm2.js b/scripts/reactpress-api-pm2.js
index 725fb26..a54f445 100644
--- a/scripts/reactpress-api-pm2.js
+++ b/scripts/reactpress-api-pm2.js
@@ -1,17 +1,21 @@
 #!/usr/bin/env node
 
 /**
- * Start bundled API with PM2 (production).
+ * Start API with PM2 (monorepo server or CLI bundle).
  */
 
 const { spawn } = require('child_process');
-const { getBundledServerBin, getBundledServerDir, getMonorepoRoot } = require('./bundled-server-path');
+const {
+  getServerBin,
+  getServerDir,
+  getMonorepoRoot,
+} = require('./bundled-server-path');
 
 const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
 
-const child = spawn(process.execPath, [getBundledServerBin(), '--pm2'], {
+const child = spawn(process.execPath, [getServerBin(), '--pm2'], {
   stdio: 'inherit',
-  cwd: getBundledServerDir(),
+  cwd: getServerDir(),
   env: {
     ...process.env,
     REACTPRESS_ORIGINAL_CWD: projectRoot,
@@ -19,7 +23,7 @@ const child = spawn(process.execPath, [getBundledServerBin(), '--pm2'], {
 });
 
 child.on('error', (error) => {
-  console.error('[reactpress] Failed to start API with PM2:', error);
+  console.error('[reactpress] PM2 启动 API 失败:', error);
   process.exit(1);
 });
 
diff --git a/scripts/reactpress-cli.js b/scripts/reactpress-cli.js
index 65e732a..04479ff 100755
--- a/scripts/reactpress-cli.js
+++ b/scripts/reactpress-cli.js
@@ -2,7 +2,7 @@
 
 /**
  * ReactPress CLI — unified entry for monorepo development.
- * API lifecycle is delegated to @fecommunity/reactpress-cli; client stays local.
+ * API: local server/ package; init / Docker DB: reactpress-cli.
  */
 
 const { Command } = require('commander');
@@ -29,6 +29,10 @@ function runReactpressCli(args, options = {}) {
   }
 }
 
+function runLifecycle(command, extraArgs = []) {
+  spawnNodeScript(path.join(rootDir, 'scripts', 'reactpress-api-lifecycle.js'), [command, ...extraArgs]);
+}
+
 function spawnNodeScript(scriptPath, args = [], options = {}) {
   const child = spawn(process.execPath, [scriptPath, ...args], {
     stdio: 'inherit',
@@ -46,39 +50,34 @@ function spawnNodeScript(scriptPath, args = [], options = {}) {
   child.on('close', (code) => process.exit(code ?? 0));
 }
 
-const serverCmd = program.command('server').description('Manage the ReactPress API (via reactpress-cli)');
+const serverCmd = program.command('server').description('Manage the ReactPress API (monorepo server/)');
 
 serverCmd
   .command('start')
-  .description('Start the API server (reactpress-cli start, or --pm2 for production)')
+  .description('Start the API server (local server/ or --pm2 for production)')
   .option('--pm2', 'Start API with PM2 process manager')
   .action((options) => {
     if (options.pm2) {
       spawnNodeScript(path.join(rootDir, 'scripts', 'reactpress-api-pm2.js'));
       return;
     }
-    runReactpressCli(['start']);
+    runLifecycle('start');
   });
 
 serverCmd
   .command('stop')
   .description('Stop the API server')
-  .option('--database', 'Also stop embedded database container')
-  .action((options) => {
-    const args = ['stop'];
-    if (options.database) args.push('--database');
-    runReactpressCli(args);
-  });
+  .action(() => runLifecycle('stop'));
 
 serverCmd
   .command('restart')
   .description('Restart the API server')
-  .action(() => runReactpressCli(['restart']));
+  .action(() => runLifecycle('restart'));
 
 serverCmd
   .command('status')
-  .description('Show API and database status')
-  .action(() => runReactpressCli(['status']));
+  .description('Show API status')
+  .action(() => runLifecycle('status'));
 
 const clientCmd = program.command('client').description('Manage the ReactPress client');
 
@@ -94,7 +93,7 @@ clientCmd
 
 program
   .command('init')
-  .description('Initialize ReactPress in the current project (delegates to reactpress-cli)')
+  .description('Initialize ReactPress (.reactpress/config.json + .env via reactpress-cli)')
   .argument('[directory]', 'Project directory', '.')
   .option('-f, --force', 'Overwrite existing configuration')
   .action((directory, options) => {
@@ -109,13 +108,13 @@ program.version(packageJson.version);
 program.on('--help', () => {
   console.log('');
   console.log('Examples:');
-  console.log('  $ reactpress init .              # Initialize .reactpress/config.json + .env');
-  console.log('  $ reactpress server start        # Start API (reactpress-cli start)');
-  console.log('  $ reactpress server start --pm2  # Start API with PM2');
-  console.log('  $ reactpress client start        # Start Next.js client');
-  console.log('  $ pnpm dev                       # Build toolkit + API + client');
+  console.log('  $ reactpress init .              # .reactpress/config.json + .env');
+  console.log('  $ reactpress server start        # Local Nest API (server/)');
+  console.log('  $ reactpress server start --pm2  # PM2 production API');
+  console.log('  $ reactpress client start        # Next.js client');
+  console.log('  $ pnpm dev                       # toolkit + API + client');
   console.log('');
-  console.log('API backend: @fecommunity/reactpress-cli bundled Nest server.');
+  console.log('API backend: monorepo server/ (NestJS). Init/DB: @fecommunity/reactpress-cli.');
 });
 
 program.parse(process.argv);
diff --git a/scripts/reactpress-publish.js b/scripts/reactpress-publish.js
index 9302967..5d5c1ae 100644
--- a/scripts/reactpress-publish.js
+++ b/scripts/reactpress-publish.js
@@ -14,9 +14,14 @@ const packages = [
     path: '.',
     description: 'Main ReactPress package'
   },
+  {
+    name: '@fecommunity/reactpress-server',
+    path: 'server',
+    description: 'NestJS backend API'
+  },
   {
     name: '@fecommunity/reactpress-client',
-    path: 'client', 
+    path: 'client',
     description: 'Frontend application package'
   },
   {
diff --git a/server/.eslintrc.js b/server/.eslintrc.js
new file mode 100644
index 0000000..60a15ad
--- /dev/null
+++ b/server/.eslintrc.js
@@ -0,0 +1,25 @@
+module.exports = {
+  parser: '@typescript-eslint/parser',
+  plugins: ['@typescript-eslint', 'simple-import-sort', 'prettier'],
+  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
+  root: true,
+  env: {
+    node: true,
+    jest: true,
+  },
+  settings: {
+    'import/resolver': {
+      node: {
+        paths: ['src'],
+        extensions: ['.js', '.jsx', '.ts', '.tsx'],
+      },
+    },
+  },
+  rules: {
+    '@typescript-eslint/interface-name-prefix': 'off',
+    '@typescript-eslint/explicit-function-return-type': 'off',
+    '@typescript-eslint/no-explicit-any': 'off',
+    'simple-import-sort/imports': 'error',
+    'simple-import-sort/exports': 'error',
+  },
+};
diff --git a/server/Dockerfile b/server/Dockerfile
new file mode 100644
index 0000000..acb938e
--- /dev/null
+++ b/server/Dockerfile
@@ -0,0 +1,38 @@
+# Use Node.js 18 as the base image
+FROM node:18-alpine
+
+# Set working directory
+WORKDIR /app
+
+# Install pnpm globally
+RUN npm install -g pnpm
+
+# Copy ALL files from the project root
+COPY . .
+
+# Debug: Show what files were copied
+RUN echo "=== Files in /app ===" && ls -la
+RUN echo "=== pnpm-lock.yaml exists? ===" && test -f pnpm-lock.yaml && echo "YES" || echo "NO"
+RUN echo "=== pnpm-workspace.yaml exists? ===" && test -f pnpm-workspace.yaml && echo "YES" || echo "NO"
+RUN echo "=== server/package.json exists? ===" && test -f server/package.json && echo "YES" || echo "NO"
+
+# Install dependencies - ALWAYS use --no-frozen-lockfile to avoid issues
+RUN pnpm install --no-frozen-lockfile
+
+# Build the server application
+WORKDIR /app/server
+RUN pnpm run build
+
+# Expose port
+EXPOSE 3002
+
+# Create a non-root user
+RUN addgroup -g 1001 -S nodejs && \
+    adduser -S nestjs -u 1001
+
+# Change ownership of the app directory
+RUN chown -R nestjs:nodejs /app
+USER nestjs
+
+# Start the application
+CMD ["pnpm", "run", "start"]
\ No newline at end of file
diff --git a/server/LICENSE b/server/LICENSE
new file mode 100644
index 0000000..fc16eb7
--- /dev/null
+++ b/server/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 FECommunity
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/server/README.md b/server/README.md
new file mode 100644
index 0000000..728dc01
--- /dev/null
+++ b/server/README.md
@@ -0,0 +1,366 @@
+# @fecommunity/reactpress-server
+
+ReactPress Server - NestJS 10 backend API for ReactPress CMS with simple installation.
+
+[![NPM Version](https://img.shields.io/npm/v/@fecommunity/reactpress-server.svg)](https://www.npmjs.com/package/@fecommunity/reactpress-server)
+[![License](https://img.shields.io/npm/l/@fecommunity/reactpress-server.svg)](https://github.com/fecommunity/reactpress/blob/master/server/LICENSE)
+[![Node Version](https://img.shields.io/node/v/@fecommunity/reactpress-server.svg)](https://nodejs.org)
+[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
+[![NestJS](https://img.shields.io/badge/NestJS-10-red)](https://nestjs.com/)
+
+## Overview
+
+ReactPress Server is a backend API built with NestJS 10 that powers the ReactPress CMS platform. It provides RESTful APIs for content management, user authentication, media handling, and more. With its simple installation process, it offers a smooth setup experience.
+
+The server is built with a modular architecture following NestJS best practices, making it extensible and maintainable. It automatically generates OpenAPI/Swagger documentation that powers the [ReactPress Toolkit](../toolkit).
+
+## Quick Start
+
+### Installation & Setup
+
+```bash
+# Regular startup
+npx @fecommunity/reactpress-server
+
+# PM2 startup for production
+npx @fecommunity/reactpress-server --pm2
+```
+
+That's it! The command will automatically:
+
+1. **Auto-detect** if configuration exists
+2. **Launch installation wizard** in your browser if no configuration found
+3. **Start the server** immediately after installation
+4. **Open API documentation** at `http://localhost:3002/api`
+
+## Features
+
+- 🚀 **Simple Installation** - No complex CLI parameters needed
+- 🔧 **Auto-Configuration** - Generates `.env` files automatically
+- 🔌 **Database Setup** - Creates MySQL database with migrations
+- 🎯 **Seamless Flow** - From installation to running server
+- 📖 **Auto-Documentation** - Swagger API docs available immediately
+- ⚡ **PM2 Support** - Optional PM2 process management
+- 🔐 **Security** - JWT with refresh token rotation, rate limiting
+- 🛡️ **Protection** - Helmet.js, CSRF protection, input validation
+- 📱 **Responsive APIs** - Mobile-friendly RESTful endpoints
+- 🌐 **Globalization** - Multi-language support
+- 📊 **Analytics Tracking** - Built-in view and visitor analytics
+- 🔄 **Data Synchronization** - Scheduled tasks and webhook support
+
+## Requirements
+
+- Node.js >= 18.20.4
+- MySQL 8.0+ or PostgreSQL 13+
+- npm or pnpm package manager
+
+## Usage Scenarios
+
+### Standalone API Server
+Perfect for:
+- Headless CMS implementation
+- Mobile app backend
+- Microservices architecture
+- Custom frontend integration
+- Enterprise API gateway
+
+### Full ReactPress Stack
+Use with ReactPress client for complete CMS solution:
+```bash
+# Start server
+npx @fecommunity/reactpress-server
+
+# In another terminal, start client
+npx @fecommunity/reactpress-client
+```
+
+## API Modules
+
+ReactPress Server provides comprehensive API modules:
+
+- **Article Management** - Create, read, update, delete articles with versioning
+- **User Authentication** - Registration, login, password management, 2FA
+- **Comment System** - Comment moderation and management with spam detection
+- **Media Management** - File upload and management (local/S3/Cloudinary)
+- **Category & Tag** - Content organization systems with hierarchy
+- **Page Management** - Custom page creation with templates
+- **Settings** - System configuration management with environment overrides
+- **SMTP** - Email sending capabilities with template system
+- **Search** - Full-text search functionality with Elasticsearch integration
+- **Analytics** - Visitor and view tracking with export capabilities
+- **Webhooks** - Event-driven integrations with external services
+- **Scheduled Tasks** - Cron jobs for automated operations
+
+## PM2 Support
+
+ReactPress server supports PM2 process management for production deployments:
+
+```bash
+# Start with PM2
+npx @fecommunity/reactpress-server --pm2
+```
+
+PM2 features:
+- Automatic process restart on crash
+- Memory monitoring
+- Log management with rotation
+- Process management
+- Health checks
+
+## Configuration
+
+The installation wizard will create a `.env` file with:
+
+```env
+# Database Configuration (Production)
+DB_HOST=prod-db.cluster-xyz.amazonaws.com
+DB_PORT=3306
+DB_USER=reactpress_user
+DB_PASSWD=secure_password_here
+DB_DATABASE=reactpress_prod
+DB_SSL=true
+
+# Site URLs (Production)
+CLIENT_SITE_URL=https://yourdomain.com
+SERVER_SITE_URL=https://api.yourdomain.com
+
+# Security Settings (Production)
+JWT_SECRET=your-very-secure-jwt-secret-here
+JWT_EXPIRES_IN=24h
+JWT_REFRESH_EXPIRES_IN=7d
+
+# SMTP Configuration (Production)
+SMTP_HOST=email-smtp.us-east-1.amazonaws.com
+SMTP_PORT=587
+SMTP_USER=your_smtp_username
+SMTP_PASS=your_smtp_password
+SMTP_FROM=noreply@yourdomain.com
+
+# Cloud Storage (Optional)
+S3_ACCESS_KEY_ID=your_aws_access_key
+S3_SECRET_ACCESS_KEY=your_aws_secret_key
+S3_BUCKET_NAME=your_bucket_name
+S3_REGION=us-east-1
+```
+
+## API Documentation
+
+Once running, visit `http://localhost:3002/api` for:
+- Interactive Swagger documentation
+- API endpoint explorer
+- Authentication examples
+- Response schemas
+- Request/response validation
+- Code generation for multiple languages
+
+## Development
+
+```bash
+# Clone repository
+git clone https://github.com/fecommunity/reactpress.git
+cd reactpress/server
+
+# Install dependencies
+pnpm install
+
+# Start development server with hot reload
+pnpm run dev
+
+# Start with PM2 (development)
+pnpm run pm2:start
+
+# Build for production
+pnpm run build
+
+# Run tests
+pnpm run test
+
+# Run tests with coverage
+pnpm run test:cov
+
+# Run end-to-end tests
+pnpm run test:e2e
+```
+
+## Project Structure
+
+```
+server/
+├── src/
+│   ├── modules/          # Feature modules
+│   │   ├── article/      # Article management
+│   │   ├── auth/         # Authentication
+│   │   ├── user/         # User management
+│   │   └── ...           # Other modules
+│   ├── common/           # Shared utilities and decorators
+│   ├── filters/          # Exception filters
+│   ├── interceptors/     # Request/response interceptors
+│   ├── guards/           # Authentication guards
+│   ├── pipes/            # Data transformation pipes
+│   ├── logger/           # Logging utilities
+│   └── utils/            # Utility functions
+├── public/               # Static assets
+│   └── swagger/          # Swagger documentation
+├── dist/                 # Compiled output
+└── bin/                  # CLI entry points
+```
+
+## Environment Variables
+
+| Variable | Description | Default |
+|----------|-------------|---------|
+| `DB_HOST` | Database host | `127.0.0.1` |
+| `DB_PORT` | Database port | `3306` |
+| `DB_USER` | Database username | - |
+| `DB_PASSWD` | Database password | - |
+| `DB_DATABASE` | Database name | `reactpress` |
+| `SERVER_PORT` | Server port | `3002` |
+| `JWT_SECRET` | JWT secret key | - |
+| `CLIENT_SITE_URL` | Client site URL | `http://localhost:3001` |
+| `SERVER_SITE_URL` | Server site URL | `http://localhost:3002` |
+| `SMTP_HOST` | SMTP server host | - |
+| `SMTP_PORT` | SMTP server port | - |
+| `SMTP_USER` | SMTP username | - |
+| `SMTP_PASS` | SMTP password | - |
+
+## CLI Commands
+
+```bash
+# Show help
+npx @fecommunity/reactpress-server --help
+
+# Start server
+npx @fecommunity/reactpress-server
+
+# Start with PM2
+npx @fecommunity/reactpress-server --pm2
+
+# Specify port
+npx @fecommunity/reactpress-server --port 3002
+
+# Enable verbose logging
+npx @fecommunity/reactpress-server --verbose
+
+# Run database migrations
+npx @fecommunity/reactpress-server --migrate
+
+# Seed database with sample data
+npx @fecommunity/reactpress-server --seed
+```
+
+## Integration with ReactPress Toolkit
+
+The server automatically generates the OpenAPI specification that powers the ReactPress Toolkit:
+
+```typescript
+// The toolkit is automatically generated from this server's API
+import { api, types } from '@fecommunity/reactpress-toolkit';
+
+// All API endpoints are strongly typed
+const articles: types.IArticle[] = await api.article.findAll();
+```
+
+## Database Schema
+
+ReactPress uses MySQL/PostgreSQL with the following key tables:
+- `users` - User accounts and profiles with 2FA support
+- `articles` - Blog posts and content with versioning
+- `categories` - Content categorization with hierarchy
+- `tags` - Content tagging system
+- `comments` - Reader comments and discussions with moderation
+- `files` - Media file management
+- `settings` - System configuration with environment overrides
+- `views` - Analytics and tracking
+- `webhooks` - Event-driven integrations
+- `scheduled_tasks` - Automated operations
+
+## Security Features
+
+- **JWT Authentication** - Secure token-based authentication with refresh rotation
+- **Rate Limiting** - Adaptive throttling to prevent abuse
+- **Input Validation** - Sanitize all user inputs with Zod schema validation
+- **Helmet.js** - Secure HTTP headers
+- **CSRF Protection** - Prevent cross-site request forgery
+- **SQL Injection Prevention** - Through TypeORM parameterized queries
+- **CORS Configuration** - Controlled cross-origin resource sharing
+- **Data Encryption** - At-rest encryption for sensitive data
+- **Audit Logging** - Comprehensive activity tracking
+
+## Performance Optimization
+
+- **Database Indexing** - Optimized queries with proper indexing
+- **Connection Pooling** - Efficient database connection management
+- **Caching** - Redis integration for frequently accessed data
+- **Compression** - Gzip compression for API responses
+- **Pagination** - Efficient data retrieval for large datasets
+- **Query Optimization** - TypeORM query builder for complex operations
+- **Background Jobs** - Queue system for long-running tasks
+
+## Testing
+
+```bash
+# Run unit tests
+pnpm run test
+
+# Run integration tests
+pnpm run test:integration
+
+# Run end-to-end tests
+pnpm run test:e2e
+
+# Run tests with coverage
+pnpm run test:cov
+
+# Run linting
+pnpm run lint
+
+# Run formatting
+pnpm run format
+
+# Run type checking
+pnpm run type-check
+```
+
+## Deployment
+
+### Production Deployment with PM2
+
+```
+# Start server with PM2
+npx @fecommunity/reactpress-server --pm2
+
+# Or build and start manually
+pnpm run build
+pnpm run start:prod
+```
+
+## Monitoring & Logging
+
+- **Structured Logging** - JSON-formatted logs for easy parsing
+- **Error Tracking** - Comprehensive error reporting with context
+- **Performance Metrics** - Response time and throughput monitoring
+- **Health Checks** - API endpoint for service status
+- **Alerting** - Basic alerting capabilities
+
+## Support
+
+- 📖 [Documentation](https://github.com/fecommunity/reactpress)
+- 🐛 [Issues](https://github.com/fecommunity/reactpress/issues)
+- 💬 [Discussions](https://github.com/fecommunity/reactpress/discussions)
+- 📧 [Support](mailto:support@reactpress.dev)
+
+## Contributing
+
+1. Fork the repository
+2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
+3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
+4. Push to the branch (`git push origin feature/AmazingFeature`)
+5. Open a pull request
+
+## License
+
+MIT License - see [LICENSE](LICENSE) file for details.
+
+---
+
+Built with ❤️ by [FECommunity](https://github.com/fecommunity)
\ No newline at end of file
diff --git a/server/bin/reactpress-server.js b/server/bin/reactpress-server.js
new file mode 100755
index 0000000..c6121a1
--- /dev/null
+++ b/server/bin/reactpress-server.js
@@ -0,0 +1,203 @@
+#!/usr/bin/env node
+
+/**
+ * ReactPress Server CLI Entry Point
+ * This script allows starting the ReactPress server via npx
+ * Supports both regular and PM2 startup modes
+ */
+
+const path = require('path');
+const fs = require('fs');
+const { spawn, spawnSync } = require('child_process');
+
+// Capture the original working directory where npx was executed
+// BUT prioritize the REACTPRESS_ORIGINAL_CWD environment variable if it exists
+// This ensures consistency when running via pnpm dev from root directory
+const originalCwd = process.env.REACTPRESS_ORIGINAL_CWD || process.cwd();
+
+// Get command line arguments
+const args = process.argv.slice(2);
+const usePM2 = args.includes('--pm2');
+const showHelp = args.includes('--help') || args.includes('-h');
+
+// Show help if requested
+if (showHelp) {
+  console.log(`
+ReactPress Server - NestJS-based backend API for ReactPress CMS
+
+Usage:
+  reactpress-server [options]
+  (通常由 reactpress-cli start 调用)
+
+Options:
+  --pm2        Start server with PM2 process manager
+  --help, -h   Show this help message
+
+Examples:
+  node bin/reactpress-server.js          # Start server normally
+  node bin/reactpress-server.js --pm2    # Start server with PM2
+  `);
+  process.exit(0);
+}
+
+// Get the directory where this script is located
+const binDir = __dirname;
+const serverDir = path.join(binDir, '..');
+const distPath = path.join(serverDir, 'dist', 'main.js');
+const ecosystemPath = path.join(serverDir, 'ecosystem.config.js');
+
+// Function to check if PM2 is installed
+function isPM2Installed() {
+  try {
+    require.resolve('pm2');
+    return true;
+  } catch (e) {
+    // Check if PM2 is installed globally
+    try {
+      spawnSync('pm2', ['--version'], { stdio: 'ignore' });
+      return true;
+    } catch (e) {
+      return false;
+    }
+  }
+}
+
+// Function to install PM2
+function installPM2() {
+  console.log('[ReactPress Server] Installing PM2...');
+  const installResult = spawnSync('npm', ['install', 'pm2', '--no-save'], {
+    stdio: 'inherit',
+    cwd: serverDir
+  });
+  
+  if (installResult.status !== 0) {
+    console.error('[ReactPress Server] Failed to install PM2');
+    return false;
+  }
+  
+  return true;
+}
+
+// Function to start with PM2
+function startWithPM2() {
+  // Check if PM2 is installed
+  if (!isPM2Installed()) {
+    // Try to install PM2
+    if (!installPM2()) {
+      console.error('[ReactPress Server] Cannot start with PM2');
+      process.exit(1);
+    }
+  }
+  
+  // Check if the server is built
+  if (!fs.existsSync(distPath)) {
+    console.log('[ReactPress Server] Server not built yet. Building...');
+    
+    // Try to build the server
+    const buildResult = spawnSync('npm', ['run', 'build'], {
+      stdio: 'inherit',
+      cwd: serverDir
+    });
+    
+    if (buildResult.status !== 0) {
+      console.error('[ReactPress Server] Failed to build server');
+      process.exit(1);
+    }
+  }
+  
+  console.log('[ReactPress Server] Starting with PM2...');
+  
+  // Use ecosystem.config.js if it exists, otherwise use direct command
+  let pm2Command = 'pm2';
+  try {
+    // Try to resolve PM2 path
+    pm2Command = path.join(serverDir, 'node_modules', '.bin', 'pm2');
+    if (!fs.existsSync(pm2Command)) {
+      pm2Command = 'pm2';
+    }
+  } catch (e) {
+    pm2Command = 'pm2';
+  }
+  
+  // Check if ecosystem.config.js exists
+  if (fs.existsSync(ecosystemPath)) {
+    const pm2 = spawn(pm2Command, ['start', ecosystemPath], {
+      stdio: 'inherit',
+      cwd: serverDir
+    });
+    
+    pm2.on('close', (code) => {
+      console.log(`[ReactPress Server] PM2 process exited with code ${code}`);
+      process.exit(code);
+    });
+    
+    pm2.on('error', (error) => {
+      console.error('[ReactPress Server] Failed to start with PM2:', error);
+      process.exit(1);
+    });
+  } else {
+    // Fallback to direct start
+    const pm2 = spawn(pm2Command, ['start', distPath, '--name', 'reactpress-server'], {
+      stdio: 'inherit',
+      cwd: serverDir
+    });
+    
+    pm2.on('close', (code) => {
+      console.log(`[ReactPress Server] PM2 process exited with code ${code}`);
+      process.exit(code);
+    });
+    
+    pm2.on('error', (error) => {
+      console.error('[ReactPress Server] Failed to start with PM2:', error);
+      process.exit(1);
+    });
+  }
+}
+
+// Function to start with regular Node.js
+function startWithNode() {
+  // Check if the server is built
+  if (!fs.existsSync(distPath)) {
+    console.log('[ReactPress Server] Server not built yet. Building...');
+    
+    // Try to build the server
+    const buildResult = spawnSync('npm', ['run', 'build'], {
+      stdio: 'inherit',
+      cwd: serverDir
+    });
+    
+    if (buildResult.status !== 0) {
+      console.error('[ReactPress Server] Failed to build server');
+      process.exit(1);
+    }
+  }
+
+  // ONLY set the environment variable if it's not already set
+  // This preserves the value set by set-env.js when running pnpm dev from root
+  if (!process.env.REACTPRESS_ORIGINAL_CWD) {
+    process.env.REACTPRESS_ORIGINAL_CWD = originalCwd;
+  } else {
+    console.log(`[ReactPress Server] Using existing REACTPRESS_ORIGINAL_CWD: ${process.env.REACTPRESS_ORIGINAL_CWD}`);
+  }
+
+  // Change to the server directory
+  process.chdir(serverDir);
+
+  // Set environment variables
+  process.env.NODE_ENV = process.env.NODE_ENV || 'production';
+
+  // Import and run the server
+  try {
+    require(distPath);
+  } catch (error) {
+    console.error('[ReactPress Server] Failed to start server:', error);
+    process.exit(1);
+  }
+}
+
+// Main execution
+if (usePM2) {
+  startWithPM2();
+} else {
+  startWithNode();
+}
diff --git a/server/ecosystem.config.js b/server/ecosystem.config.js
new file mode 100644
index 0000000..6a90515
--- /dev/null
+++ b/server/ecosystem.config.js
@@ -0,0 +1,18 @@
+module.exports = {
+  apps: [
+    {
+      name: 'reactpress-server',
+      script: './dist/main.js',
+      instances: 1,
+      autorestart: true,
+      watch: false,
+      max_memory_restart: '1G',
+      env: {
+        NODE_ENV: 'production',
+      },
+      env_development: {
+        NODE_ENV: 'development',
+      },
+    },
+  ],
+};
\ No newline at end of file
diff --git a/server/nest-cli.json b/server/nest-cli.json
new file mode 100644
index 0000000..56167b3
--- /dev/null
+++ b/server/nest-cli.json
@@ -0,0 +1,4 @@
+{
+  "collection": "@nestjs/schematics",
+  "sourceRoot": "src"
+}
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 0000000..f91da54
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,149 @@
+{
+  "name": "@fecommunity/reactpress-server",
+  "version": "1.0.0-beta.16",
+  "description": "ReactPress Server - NestJS-based backend API for ReactPress CMS",
+  "author": "fecommunity",
+  "license": "MIT",
+  "main": "dist/main.js",
+  "types": "dist/index.d.ts",
+  "bin": {
+    "reactpress-server": "./bin/reactpress-server.js"
+  },
+  "files": [
+    "dist/**/*",
+    "public/**/*",
+    "bin/**/*",
+    "README.md",
+    "LICENSE"
+  ],
+  "keywords": [
+    "reactpress",
+    "server",
+    "nestjs",
+    "cms",
+    "blog",
+    "api",
+    "typescript"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/fecommunity/reactpress.git",
+    "directory": "server"
+  },
+  "engines": {
+    "node": ">=16.5.0"
+  },
+  "scripts": {
+    "prebuild": "rimraf dist",
+    "build": "nest build && npm run copy-assets",
+    "copy-assets": "cp -r public dist/ 2>/dev/null || true",
+    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
+    "dev": "nest start --watch",
+    "debug": "nest start --debug --watch",
+    "start": "cross-env NODE_ENV=production node dist/main",
+    "pm2": "pm2 start npm --name @fecommunity/reactpress-server -- start",
+    "lint": "tslint -p tsconfig.json -c tslint.json",
+    "test": "jest",
+    "test:watch": "jest --watch",
+    "test:cov": "jest --coverage",
+    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
+    "test:e2e": "jest --config ./test/jest-e2e.json",
+    "prepublishOnly": "npm run build",
+    "pm2:start": "pm2 start dist/main.js --name reactpress-server",
+    "pm2:stop": "pm2 stop reactpress-server",
+    "pm2:restart": "pm2 restart reactpress-server",
+    "pm2:delete": "pm2 delete reactpress-server",
+    "pm2:logs": "pm2 logs reactpress-server",
+    "pm2:status": "pm2 status reactpress-server",
+    "generate:swagger": "ts-node src/generate-swagger.ts"
+  },
+  "dependencies": {
+    "@fecommunity/reactpress-toolkit": "workspace:*",
+    "@nestjs/cli": "^6.9.0",
+    "@nestjs/common": "^6.7.2",
+    "@nestjs/config": "^0.6.3",
+    "@nestjs/core": "^6.7.2",
+    "@nestjs/jwt": "^6.1.1",
+    "@nestjs/passport": "^6.1.1",
+    "@nestjs/platform-express": "^6.11.5",
+    "@nestjs/swagger": "^4.8.2",
+    "@nestjs/typeorm": "^6.3.4",
+    "@types/express-serve-static-core": "^4.19.5",
+    "ali-oss": "^6.5.1",
+    "axios": "^0.23.0",
+    "bcryptjs": "^2.4.3",
+    "body-parser": "^1.19.0",
+    "chalk": "^4.1.2",
+    "class-transformer": "^0.2.3",
+    "commander": "^9.4.1",
+    "compression": "^1.7.4",
+    "cross-env": "^7.0.3",
+    "date-fns": "^2.17.0",
+    "deepmerge": "^4.2.2",
+    "dotenv": "^8.2.0",
+    "express": "^4.18.2",
+    "express-rate-limit": "^5.0.0",
+    "fs-extra": "^10.0.0",
+    "helmet": "^3.21.2",
+    "highlight.js": "^9.18.0",
+    "inquirer": "^8.2.4",
+    "lodash": "^4.17.21",
+    "log4js": "^6.1.0",
+    "marked": "^0.8.0",
+    "mysql2": "^3.12.0",
+    "node-ip2region": "^1.0.2",
+    "nodemailer": "^6.4.2",
+    "nuid": "^1.1.0",
+    "open": "^8.2.1",
+    "passport": "^0.4.1",
+    "passport-jwt": "^4.0.0",
+    "pm2": "^5.2.0",
+    "reflect-metadata": "^0.1.13",
+    "rimraf": "^3.0.0",
+    "rxjs": "^6.5.3",
+    "segment": "^0.1.3",
+    "swagger-themes": "^1.4.3",
+    "swagger-ui-express": "^4.1.6",
+    "typeorm": "^0.2.45",
+    "ua-parser-js": "^0.7.28"
+  },
+  "devDependencies": {
+    "@nestjs/schematics": "^6.7.0",
+    "@nestjs/testing": "^6.7.1",
+    "@types/express": "4.17.18",
+    "@types/jest": "^24.0.18",
+    "@types/node": "^12.7.5",
+    "@types/supertest": "^2.0.8",
+    "@typescript-eslint/eslint-plugin": "^5.21.0",
+    "@typescript-eslint/parser": "^5.21.0",
+    "eslint": "^8.15.0",
+    "eslint-config-prettier": "^8.5.0",
+    "eslint-plugin-import": "^2.26.0",
+    "eslint-plugin-prettier": "^4.0.0",
+    "eslint-plugin-simple-import-sort": "^7.0.0",
+    "jest": "^24.9.0",
+    "next-transpile-modules": "^6.3.0",
+    "prettier": "^1.18.2",
+    "supertest": "^4.0.2",
+    "ts-jest": "^24.1.0",
+    "ts-loader": "^6.1.1",
+    "ts-node": "^8.4.1",
+    "tsconfig-paths": "^3.9.0",
+    "tslint": "^5.20.0",
+    "typescript": "~4.1.6"
+  },
+  "jest": {
+    "moduleFileExtensions": [
+      "js",
+      "json",
+      "ts"
+    ],
+    "rootDir": "src",
+    "testRegex": ".spec.ts$",
+    "transform": {
+      "^.+\\.(t|j)s$": "ts-jest"
+    },
+    "coverageDirectory": "../coverage",
+    "testEnvironment": "node"
+  }
+}
diff --git a/server/public/favicon.png b/server/public/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..521edf80e7dfb357e0bb99f8659aad49b04430b8
GIT binary patch
literal 33057
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

oLluaFg!lf8R;7G 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 FV1m^A{DS}h literal 0 HcmV?d00001 diff --git a/server/public/index.html b/server/public/index.html new file mode 100644 index 0000000..4c285e3 --- /dev/null +++ b/server/public/index.html @@ -0,0 +1,439 @@ + + + + + + ReactPress › Installation + + + +

+ + +
+
+
+ +
+ +
+

Database Connection Information

+ +
+ You should have this information available from your web hosting provider. If you don't have it, contact them before continuing. +
+ + + + + + + + + + + + + + + + + + + + + + +
+ +

Usually "localhost" or "127.0.0.1"

+
+ +

Default MySQL port is 3306

+
+ +

Your MySQL username

+
+ +

Your MySQL password

+
+ +

The name of the database you want to use with ReactPress

+
+ +
+ +

+ +

+
+ + +
+

Site Information

+ +
+ Please provide the following information. Don't worry, you can always change these settings later. +
+ + + + + + + + + + +
+ +

The URL where your ReactPress frontend will be accessible

+
+ +

The URL where your ReactPress API server will run

+
+ +
+ +

+ +

+
+ + +
+

🎉 Installation Complete!

+ +
+

ReactPress has been installed successfully!

+
+ +

Your ReactPress server configuration has been saved. You can:

+ +
    +
  • Close this browser window
  • +
  • Restart the server by running npx @fecommunity/reactpress-server in your terminal
  • +
  • Access your admin panel at http://localhost:3001/admin (when client is running)
  • +
+ + +
+

Waiting for server to start...

+
+ +
+ + +
+ +
+ Note: To start the server with your new configuration, run npx @fecommunity/reactpress-server in your terminal. +
+
+
+ + +
+ + + + \ No newline at end of file diff --git a/server/public/swagger/custom.css b/server/public/swagger/custom.css new file mode 100644 index 0000000..fee918b --- /dev/null +++ b/server/public/swagger/custom.css @@ -0,0 +1,11 @@ +.swagger-ui div.topbar { + display: none !important; + padding: 0 !important; +} + + +.swagger-ui .scheme-container { + display: none !important; + margin: 0 !important; + padding: 0 !important; +} \ No newline at end of file diff --git a/server/src/app.module.ts b/server/src/app.module.ts new file mode 100644 index 0000000..8cb3919 --- /dev/null +++ b/server/src/app.module.ts @@ -0,0 +1,82 @@ +// 配置文件 +import { config } from '@fecommunity/reactpress-toolkit'; +import { Module } from '@nestjs/common'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { Article } from './modules/article/article.entity'; +// 文章模块 +import { ArticleModule } from './modules/article/article.module'; +// 鉴权模块 +import { AuthModule } from './modules/auth/auth.module'; +import { Category } from './modules/category/category.entity'; +// 分类模块 +import { CategoryModule } from './modules/category/category.module'; +import { Comment } from './modules/comment/comment.entity'; +// 评论模块 +import { CommentModule } from './modules/comment/comment.module'; +import { File } from './modules/file/file.entity'; +// 文件模块 +import { FileModule } from './modules/file/file.module'; +import { Knowledge } from './modules/knowledge/knowledge.entity'; +// 知识库模块 +import { KnowledgeModule } from './modules/knowledge/knowledge.module'; +import { Page } from './modules/page/page.entity'; +// 页面模块 +import { PageModule } from './modules/page/page.module'; +// 搜索模块 +import { Search } from './modules/search/search.entity'; +import { SearchModule } from './modules/search/search.module'; +import { Setting } from './modules/setting/setting.entity'; +// 系统模块 +import { SettingModule } from './modules/setting/setting.module'; +import { SMTP } from './modules/smtp/smtp.entity'; +// 邮件模块 +import { SMTPModule } from './modules/smtp/smtp.module'; +import { Tag } from './modules/tag/tag.entity'; +// 标签模块 +import { TagModule } from './modules/tag/tag.module'; +import { User } from './modules/user/user.entity'; +// 用户模块 +import { UserModule } from './modules/user/user.module'; +import { View } from './modules/view/view.entity'; +// 访问统计模块 +import { ViewModule } from './modules/view/view.module'; + +@Module({ + imports: [ + ConfigModule.forRoot({ isGlobal: true, envFilePath: [config.file] }), + TypeOrmModule.forRootAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: async (configService: ConfigService) => ({ + type: 'mysql', + entities: [User, File, Knowledge, Article, Category, Tag, Comment, Setting, SMTP, Page, View, Search], + host: configService.get('DB_HOST', '0.0.0.0'), + port: configService.get('DB_PORT', 3306), + username: configService.get('DB_USER', 'root'), + password: configService.get('DB_PASSWD', 'root'), + database: configService.get('DB_DATABASE', 'reactpress'), + charset: 'utf8mb4', + timezone: '+08:00', + synchronize: true, + }), + }), + UserModule, + FileModule, + TagModule, + ArticleModule, + KnowledgeModule, + CategoryModule, + CommentModule, + SettingModule, + SMTPModule, + AuthModule, + PageModule, + ViewModule, + SearchModule, + ], + controllers: [], + providers: [], +}) +export class AppModule {} \ No newline at end of file diff --git a/server/src/filters/http-exception.filter.ts b/server/src/filters/http-exception.filter.ts new file mode 100644 index 0000000..16a08aa --- /dev/null +++ b/server/src/filters/http-exception.filter.ts @@ -0,0 +1,28 @@ +import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common'; + +import { errorLogger } from '../logger'; + +@Catch(HttpException) +export class HttpExceptionFilter implements ExceptionFilter { + catch(exception: HttpException, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + const url = request.originalUrl; // 请求路由 + const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; + const msg = exception.message.message || exception.message; // 错误信息 + const errorResponse = { + statusCode: status, + msg, + success: false, + data: null, + }; + + // 设置返回的状态码、请求头、发送错误信息 + response.status(status); + response.header('Content-Type', 'application/json; charset=utf-8'); + response.send(errorResponse); + errorLogger.error(url, errorResponse); + } +} diff --git a/server/src/generate-swagger.ts b/server/src/generate-swagger.ts new file mode 100644 index 0000000..43674db --- /dev/null +++ b/server/src/generate-swagger.ts @@ -0,0 +1,95 @@ +import { NestFactory } from '@nestjs/core'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import { existsSync, unlinkSync, writeFileSync } from 'fs'; +import { join } from 'path'; +import { AppModule } from './app.module'; + +async function generateSwaggerJson() { + let app; + try { + console.log('🚀 Starting Swagger JSON generation...'); + + // 创建应用实例,但不初始化数据库连接 + app = await NestFactory.createApplicationContext(AppModule, { + logger: ['error', 'warn'], // 只记录错误和警告 + }); + + // 获取配置服务 + const configService = app.get('ConfigService'); + const apiPrefix = configService.get('SERVER_API_PREFIX', '/api'); + + console.log('📝 Configuring Swagger documentation...'); + + // 增强版 Swagger 配置 + const swaggerConfig = new DocumentBuilder() + .setTitle('ReactPress API Documentation') + .setDescription('Comprehensive API documentation for ReactPress - A modern content management system built with NestJS') + .setVersion('2.0') + .setContact('ReactPress Team', 'https://github.com/fecommunity/reactpress', 'admin@gaoredu.com') + .setLicense('MIT', 'https://github.com/fecommunity/reactpress/blob/main/LICENSE') + .addServer(configService.get('SERVER_SITE_URL', 'http://localhost:3002'), 'API Server') + .build(); + + // 创建 Swagger 文档 + console.log('🔨 Generating Swagger document...'); + const document = SwaggerModule.createDocument(app, swaggerConfig); + + // 写入文件 + const outputPath = join(__dirname, '../public/swagger.json'); + + // 确保 public 目录存在 + const publicDir = join(__dirname, '../public'); + if (!existsSync(publicDir)) { + console.log('📁 Creating public directory...'); + require('fs').mkdirSync(publicDir, { recursive: true }); + } + + // 如果文件已经存在,就覆盖掉 + if (existsSync(outputPath)) { + console.log('🗑️ Removing existing swagger.json file...'); + unlinkSync(outputPath); + } + + console.log('💾 Writing Swagger JSON to file...'); + writeFileSync(outputPath, JSON.stringify(document, null, 2)); + + console.log(`✅ Success! Swagger JSON generated at: ${outputPath}`); + + // 直接退出进程,避免关闭应用时的数据库连接错误 + console.log('🎉 Swagger generation process completed successfully'); + process.exit(0); + + } catch (error) { + console.error('❌ Error during Swagger generation:', error.message); + + // 检查是否已有现有的 swagger.json 文件 + const existingPath = join(__dirname, '../public/swagger.json'); + if (existsSync(existingPath)) { + console.log('ℹ️ Using existing swagger.json file'); + console.log('🎉 Swagger generation process completed successfully'); + process.exit(0); + } else { + console.error('❌ No existing swagger.json file found'); + process.exit(1); + } + } finally { + // 不尝试关闭应用,直接退出进程 + // 这样可以避免数据库连接池错误 + } +} + +// 运行生成函数 +generateSwaggerJson().catch(e => { + console.error('💥 Unhandled error in generateSwaggerJson:', e.message); + + // 检查是否已有现有的 swagger.json 文件 + const existingPath = join(__dirname, '../public/swagger.json'); + if (existsSync(existingPath)) { + console.log('ℹ️ Using existing swagger.json file'); + console.log('🎉 Swagger generation process completed successfully'); + process.exit(0); + } else { + console.error('❌ No existing swagger.json file found'); + process.exit(1); + } +}); \ No newline at end of file diff --git a/server/src/interceptors/transform.interceptor.ts b/server/src/interceptors/transform.interceptor.ts new file mode 100644 index 0000000..4e34786 --- /dev/null +++ b/server/src/interceptors/transform.interceptor.ts @@ -0,0 +1,33 @@ +import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { responseLogger } from '../logger'; + +interface Response { + data: T; +} + +@Injectable() +export class TransformInterceptor implements NestInterceptor> { + intercept(context: ExecutionContext, next: CallHandler): Observable> { + return next.handle().pipe( + map((data) => { + const ctx = context.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + const statusCode = response.statusCode; + const url = request.originalUrl; + const res = { + statusCode, + msg: null, + success: true, + data, + }; + responseLogger.info(url, res); + return res; + }) + ); + } +} diff --git a/server/src/logger/index.ts b/server/src/logger/index.ts new file mode 100644 index 0000000..319c734 --- /dev/null +++ b/server/src/logger/index.ts @@ -0,0 +1,47 @@ +import * as fs from 'fs-extra'; +import * as log4js from 'log4js'; +import { join } from 'path'; + +const LOG_DIR_NAME = '../../logs'; + +fs.ensureDirSync(join(__dirname, LOG_DIR_NAME)); +void ['request', 'response', 'error'].forEach((t) => { + fs.ensureDirSync(join(__dirname, LOG_DIR_NAME, t)); +}); + +const resolvePath = (dir, filename) => join(__dirname, LOG_DIR_NAME, dir, filename); + +const commonCinfig = { + type: 'dateFile', + pattern: '-yyyy-MM-dd.log', + alwaysIncludePattern: true, +}; + +log4js.configure({ + appenders: { + request: { + ...commonCinfig, + filename: resolvePath('request', 'request.log'), + category: 'request', + }, + response: { + ...commonCinfig, + filename: resolvePath('response', 'response.log'), + category: 'response', + }, + error: { + ...commonCinfig, + filename: resolvePath('error', 'error.log'), + category: 'error', + }, + }, + categories: { + default: { appenders: ['request'], level: 'info' }, + response: { appenders: ['response'], level: 'info' }, + error: { appenders: ['error'], level: 'info' }, + }, +}); + +export const requestLogger = log4js.getLogger('request'); +export const responseLogger = log4js.getLogger('response'); +export const errorLogger = log4js.getLogger('error'); diff --git a/server/src/main.ts b/server/src/main.ts new file mode 100644 index 0000000..f6fad2b --- /dev/null +++ b/server/src/main.ts @@ -0,0 +1,346 @@ +import * as fs from 'fs'; +import { join, dirname } from 'path'; +import * as express from 'express'; +import * as bodyParser from 'body-parser'; +import * as open from 'open'; +import * as net from 'net'; + +// 全局状态管理 +declare global { + var installationServer: any; + var installationPort: number; + var isInstalling: boolean; +} + +const INSTALLATION_PORT = 3002; +const MAX_PORT_ATTEMPTS = 10; + +// 服务器状态跟踪 +interface ServerState { + server: any; + isClosing: boolean; + isListening: boolean; +} + +const serverState: ServerState = { + server: null, + isClosing: false, + isListening: false +}; + +// 增强的端口检测函数 +const checkPort = (port: number): Promise => { + return new Promise((resolve) => { + const server = net.createServer(); + server.once('error', (err: any) => { + if (err.code === 'EADDRINUSE') { + resolve(false); + } else { + resolve(false); + } + }); + server.once('listening', () => { + server.once('close', () => resolve(true)).close(); + }); + server.listen(port); + }); +}; + +// 获取可用端口 +const findAvailablePort = async (startPort: number): Promise => { + for (let port = startPort; port < startPort + MAX_PORT_ATTEMPTS; port++) { + if (await checkPort(port)) { + return port; + } + } + throw new Error(`No available ports found in range ${startPort}-${startPort + MAX_PORT_ATTEMPTS - 1}`); +}; + +// 安全关闭服务器 +const safelyCloseServer = async (): Promise => { + if (!serverState.server || serverState.isClosing) { + return; + } + + serverState.isClosing = true; + + return new Promise((resolve) => { + // 检查服务器是否仍在运行 + if (!serverState.isListening) { + serverState.server = null; + serverState.isClosing = false; + resolve(); + return; + } + + // 设置超时 + const timeout = setTimeout(() => { + console.log('[ReactPress] Force closing server due to timeout'); + serverState.server = null; + serverState.isClosing = false; + serverState.isListening = false; + resolve(); + }, 3000); + + // 尝试正常关闭 + serverState.server.close((err: any) => { + clearTimeout(timeout); + + if (err && err.code !== 'ERR_SERVER_NOT_RUNNING') { + console.warn('[ReactPress] Server close warning:', err.message); + } + + serverState.server = null; + serverState.isClosing = false; + serverState.isListening = false; + resolve(); + }); + + // 强制关闭所有连接(如果可用) + if (serverState.server.closeAllConnections) { + serverState.server.closeAllConnections(); + } + }); +}; + +// 启动服务器并跟踪状态 +const startServerWithState = (app: express.Express, port: number): Promise => { + return new Promise((resolve, reject) => { + if (serverState.server) { + reject(new Error('Server is already running')); + return; + } + + const server = app.listen(port, () => { + serverState.server = server; + serverState.isListening = true; + global.installationPort = port; + console.log(`[ReactPress] Installation server running on http://localhost:${port}`); + resolve(); + }); + + server.on('error', (error: any) => { + serverState.isListening = false; + reject(error); + }); + + server.on('close', () => { + serverState.isListening = false; + }); + }); +}; + +// 信号处理 +const setupSignalHandlers = () => { + const shutdown = async (signal: string) => { + console.log(`\n[ReactPress] Received ${signal}, shutting down gracefully...`); + + await safelyCloseServer(); + + process.exit(0); + }; + + process.on('SIGINT', () => shutdown('SIGINT')); + process.on('SIGTERM', () => shutdown('SIGTERM')); + process.on('SIGHUP', () => shutdown('SIGHUP')); +}; + +// 主执行函数 +const main = async () => { + try { + setupSignalHandlers(); + + // 获取项目根目录路径(考虑npm包场景) + const projectRoot = getProjectRoot(); + const envPath = join(projectRoot, '.env'); + + console.log(`[ReactPress] Checking for environment file at: ${envPath}`); + console.log(`[ReactPress] Project root determined to be: ${projectRoot}`); + + if (fs.existsSync(envPath)) { + console.log('[ReactPress] Environment file exists, starting main application'); + await startMainApplication(); + return; + } + + console.log('[ReactPress] Environment file not found, starting installation wizard'); + console.log('[ReactPress] Current working directory:', process.cwd()); + console.log('[ReactPress] __dirname:', __dirname); + + await runInstallationWizard(); + + } catch (error) { + console.error('[ReactPress] Fatal error:', error); + // 确保服务器被正确关闭 + await safelyCloseServer(); + process.exit(1); + } +}; + +// 获取项目根目录路径的函数 +const getProjectRoot = (): string => { + // 优先使用通过环境变量传递的原始工作目录 + // 这是在 bin/reactpress-server.js 中设置的,表示用户执行 npx 命令的目录 + if (process.env.REACTPRESS_ORIGINAL_CWD) { + console.log(`[ReactPress] Using original working directory from npx execution: ${process.env.REACTPRESS_ORIGINAL_CWD}`); + return process.env.REACTPRESS_ORIGINAL_CWD; + } + + // 如果没有设置环境变量,则回退到当前工作目录 + const projectRoot = process.cwd(); + console.log(`[ReactPress] Using current working directory as project root: ${projectRoot}`); + return projectRoot; +}; + +// 安装向导主函数 +const runInstallationWizard = async (): Promise => { + try { + // 查找可用端口 + const port = await findAvailablePort(INSTALLATION_PORT); + + const app = express(); + + // 中间件配置 + app.use(bodyParser.json({ limit: '10mb' })); + app.use(bodyParser.urlencoded({ limit: '10mb', extended: true })); + app.use('/public', express.static(join(__dirname, '../public'))); + + // 路由 + app.get('/', (req, res) => { + res.sendFile(join(__dirname, '../public/index.html')); + }); + + app.post('/test-db', async (req, res) => { + try { + const mysql = await import('mysql2/promise'); + const { host, port, user, password, database } = req.body; + const connection = await mysql.createConnection({ + host: host || 'localhost', + port: parseInt(port) || 3306, + user, + password, + database + }); + await connection.execute('SELECT 1'); + await connection.end(); + res.json({ success: true, message: 'Database connection successful!' }); + } catch (error: any) { + res.status(400).json({ + success: false, + message: `Database connection failed: ${error.message}` + }); + } + }); + + app.post('/install', async (req, res) => { + try { + const { db, site } = req.body; + if (!db || !site) { + return res.status(400).json({ + success: false, + message: 'Missing configuration data' + }); + } + + // 测试数据库连接 + const mysql = await import('mysql2/promise'); + const connection = await mysql.createConnection({ + host: db.host || 'localhost', + port: parseInt(db.port) || 3306, + user: db.user, + password: db.password, + database: db.database + }); + await connection.execute('SELECT 1'); + await connection.end(); + + // 创建环境文件到项目根目录 + const envContent = `# Database Config +DB_HOST=${db.host || '127.0.0.1'} +DB_PORT=${db.port || 3306} +DB_USER=${db.user} +DB_PASSWD=${db.password} +DB_DATABASE=${db.database} + +# Client Config +CLIENT_SITE_URL=${site.clientUrl || 'http://localhost:3001'} + +# Server Config +SERVER_SITE_URL=${site.serverUrl || 'http://localhost:3002'} +`.trim(); + + // 使用项目根目录路径创建.env文件 + const projectRoot = getProjectRoot(); + const envPath = join(projectRoot, '.env'); + fs.writeFileSync(envPath, envContent, 'utf8'); + + res.json({ + success: true, + message: 'Installation completed! Server will restart.', + serverUrl: site.serverUrl || 'http://localhost:3002' + }); + + // 确保响应已发送后再关闭服务器 + res.on('finish', async () => { + try { + console.log('[ReactPress] Installation complete, restarting server...'); + await safelyCloseServer(); + await startMainApplication(); + } catch (error) { + console.error('[ReactPress] Restart error:', error); + } + }); + + } catch (error: any) { + res.status(400).json({ + success: false, + message: `Installation failed: ${error.message}` + }); + } + }); + + // 使用状态跟踪启动服务器 + await startServerWithState(app, port); + + try { + await open(`http://localhost:${port}`); + } catch (error) { + console.log(`[ReactPress] Please visit http://localhost:${port} manually`); + } + + } catch (error) { + console.error('[ReactPress] Installation wizard failed:', error); + // 确保服务器被正确关闭 + await safelyCloseServer(); + throw error; + } +}; + +// 启动主应用 +const startMainApplication = async (): Promise => { + try { + console.log('[ReactPress] Starting main application...'); + + // 确保安装服务器完全关闭 + await safelyCloseServer(); + + // 清除安装状态 + global.isInstalling = false; + + // 延迟启动以确保端口释放 + await new Promise(resolve => setTimeout(resolve, 1000)); + + // 动态导入以避免在安装阶段加载 NestJS + const { bootstrap } = await import('./starter'); + if (typeof bootstrap === 'function') { + await bootstrap(); + } else { + throw new Error('Bootstrap function not found'); + } + } catch (error) { + console.error('[ReactPress] Failed to start main application:', error); + process.exit(1); + } +}; + +main(); \ No newline at end of file diff --git a/server/src/modules/article/article.controller.ts b/server/src/modules/article/article.controller.ts new file mode 100644 index 0000000..0445142 --- /dev/null +++ b/server/src/modules/article/article.controller.ts @@ -0,0 +1,178 @@ +import { + Body, + Controller, + Delete, + Get, + HttpCode, + HttpStatus, + Param, + Patch, + Post, + Query, + Request, + UseGuards, +} from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { User } from '../user/user.entity'; +import { UserService } from '../user/user.service'; +import { Article } from './article.entity'; +import { ArticleService } from './article.service'; + +@ApiTags('Article') +@Controller('article') +@UseGuards(RolesGuard) +export class ArticleController { + constructor( + private readonly articleService: ArticleService, + + private readonly jwtService: JwtService, + private readonly userService: UserService + ) {} + + /** + * 创建文章 + * @param article + */ + @ApiResponse({ status: 200, description: '创建文章', type: [Article] }) + @Post() + @Roles('admin') + @UseGuards(JwtAuthGuard) + create(@Body() article) { + return this.articleService.create(article); + } + + /** + * 获取所有文章 + */ + @Get() + @HttpCode(HttpStatus.OK) + findAll(@Query() queryParams) { + return this.articleService.findAll(queryParams); + } + + /** + * 获取标签下所有文章 + */ + @Get('/category/:id') + @HttpCode(HttpStatus.OK) + findArticlesByCategory(@Param('id') category, @Query() queryParams) { + return this.articleService.findArticlesByCategory(category, queryParams); + } + + /** + * 获取标签下所有文章 + */ + @Get('/tag/:id') + @HttpCode(HttpStatus.OK) + findArticlesByTag(@Param('id') tag, @Query() queryParams) { + return this.articleService.findArticlesByTag(tag, queryParams); + } + + /** + * 获取所有推荐文章 + */ + @Get('/all/recommend') + @HttpCode(HttpStatus.OK) + getRecommendArticles() { + return this.articleService.getRecommendArticles(); + } + + /** + * 获取所有文章归档 + */ + @Get('/archives') + @HttpCode(HttpStatus.OK) + getArchives(): Promise<{ [key: string]: Article[] }> { + return this.articleService.getArchives(); + } + + /** + * 获取相应文章的推荐文章 + */ + @Get('/recommend') + @HttpCode(HttpStatus.OK) + recommend(@Query('articleId') articleId) { + return this.articleService.recommend(articleId); + } + + /** + * 获取指定文章 + * @param id + */ + @Get(':id') + async findById(@Request() req, @Param('id') id, @Query('status') status) { + let token = req.headers.authorization; + + if (/Bearer/.test(token)) { + // 不需要 Bearer,否则验证失败 + token = token.split(' ').pop(); + } + + try { + const tokenUser = this.jwtService.decode(token) as User; + const userId = tokenUser.id; + const exist = await this.userService.findById(userId); + const isAdmin = userId && exist.role === 'admin'; + return this.articleService.findById(id, status, isAdmin); + } catch (e) { + return this.articleService.findById(id, status); + } + } + + /** + * 校验文章密码 + * @param id + * @param article + */ + @Post(':id/checkPassword') + @HttpCode(HttpStatus.OK) + checkPassword(@Param('id') id, @Body() article) { + return this.articleService.checkPassword(id, article); + } + + /** + * 文章访问量 +1 + */ + @Post(':id/views') + @HttpCode(HttpStatus.OK) + updateViewsById(@Param('id') id) { + return this.articleService.updateViewsById(id); + } + + /** + * 文章访问量 +1 + */ + @Post(':id/likes') + @HttpCode(HttpStatus.OK) + updateLikesById(@Param('id') id, @Body('type') type) { + return this.articleService.updateLikesById(id, type); + } + + /** + * 更新文章 + * @param id + * @param article + */ + @Patch(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + @HttpCode(HttpStatus.OK) + updateById(@Param('id') id, @Body() article) { + return this.articleService.updateById(id, article); + } + + /** + * 删除文章 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.articleService.deleteById(id); + } +} diff --git a/server/src/modules/article/article.entity.ts b/server/src/modules/article/article.entity.ts new file mode 100644 index 0000000..7b25d0a --- /dev/null +++ b/server/src/modules/article/article.entity.ts @@ -0,0 +1,103 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { + Column, + CreateDateColumn, + Entity, + JoinTable, + ManyToMany, + ManyToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { Category } from '../category/category.entity'; +import { Tag } from '../tag/tag.entity'; + +@Entity() +export class Article { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column() + title: string; + + @ApiProperty() + @Column({ default: null }) + cover: string; // 封面图 + + @ApiProperty() + @Column({ type: 'text', default: null }) + summary: string; // 摘要,自动生成 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) + content: string; // 原始内容 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) + html: string; // 格式化内容,自动生成 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null }) + toc: string; // 格式化内容索引,自动生成 + + @ApiProperty() + @ManyToOne(() => Category, (category) => category.articles, { cascade: true }) + @JoinTable() + category: Category; + + @ApiProperty() + @ManyToMany(() => Tag, (tag) => tag.articles, { cascade: true }) + @JoinTable() + tags: Array; + + @ApiProperty() + @Column('simple-enum', { enum: ['draft', 'publish'] }) + status: string; // 文章状态 + + @ApiProperty() + @Column({ type: 'int', default: 0 }) + views: number; // 阅读量 + + @ApiProperty() + @Column({ type: 'int', default: 0 }) + likes: number; // 喜欢数 + + @ApiProperty() + @Column({ type: 'boolean', default: false }) + isRecommended: boolean; // 是否推荐到首页 + + @ApiProperty() + @Column({ type: 'text', default: null, select: false }) + password: string; + + @ApiProperty() + @Column({ type: 'boolean', default: false }) + needPassword: boolean; + + @ApiProperty() + @Column({ type: 'boolean', default: true }) + isCommentable: boolean; + + @ApiProperty() + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + publishAt: Date; // 发布日期 + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/article/article.module.ts b/server/src/modules/article/article.module.ts new file mode 100644 index 0000000..ac1ccc7 --- /dev/null +++ b/server/src/modules/article/article.module.ts @@ -0,0 +1,18 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { CategoryModule } from '../category/category.module'; +import { TagModule } from '../tag/tag.module'; +import { UserModule } from '../user/user.module'; +import { ArticleController } from './article.controller'; +import { Article } from './article.entity'; +import { ArticleService } from './article.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Article]), CategoryModule, TagModule, UserModule, AuthModule], + exports: [ArticleService], + providers: [ArticleService], + controllers: [ArticleController], +}) +export class ArticleModule {} diff --git a/server/src/modules/article/article.service.ts b/server/src/modules/article/article.service.ts new file mode 100644 index 0000000..3493129 --- /dev/null +++ b/server/src/modules/article/article.service.ts @@ -0,0 +1,398 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { dateFormat } from '../../utils/date.util'; +import { CategoryService } from '../category/category.service'; +import { TagService } from '../tag/tag.service'; +import { Article } from './article.entity'; +import { extractProtectedArticle } from './article.util'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const Segment = require('segment'); +const segment = new Segment(); +segment.useDefault(); + +@Injectable() +export class ArticleService { + constructor( + @InjectRepository(Article) + private readonly articleRepository: Repository
, + private readonly tagService: TagService, + private readonly categoryService: CategoryService + ) {} + + /** + * 创建文章 + * @param article + */ + async create(article: Partial
): Promise
{ + const { title } = article; + const exist = await this.articleRepository.findOne({ where: { title } }); + + if (exist) { + throw new HttpException('文章标题已存在', HttpStatus.BAD_REQUEST); + } + + let { tags, category, status } = article; // eslint-disable-line prefer-const + + if (status === 'publish') { + Object.assign(article, { + publishAt: dateFormat(), + }); + } + + tags = await this.tagService.findByIds(('' + tags).split(',')); + const existCategory = await this.categoryService.findById(category); + const newArticle = await this.articleRepository.create({ + ...article, + category: existCategory, + tags, + needPassword: !!article.password, + }); + await this.articleRepository.save(newArticle); + return newArticle; + } + + /** + * 获取所有文章 + */ + async findAll(queryParams): Promise<[Article[], number]> { + const query = this.articleRepository + .createQueryBuilder('article') + .leftJoinAndSelect('article.tags', 'tag') + .leftJoinAndSelect('article.category', 'category') + .orderBy('article.publishAt', 'DESC'); + + const { page = 1, pageSize = 12, status, ...otherParams } = queryParams; + + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (status) { + query.andWhere('article.status=:status').setParameter('status', status); + } + + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`article.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + + const [data, total] = await query.getManyAndCount(); + + data.forEach((d) => { + if (d.needPassword) { + extractProtectedArticle(d); + } + }); + + return [data, total]; + } + + /** + * 根据 category 查找文章 + * @param category + * @param queryParams + */ + async findArticlesByCategory(category, queryParams) { + const query = this.articleRepository + .createQueryBuilder('article') + .leftJoinAndSelect('article.category', 'category') + .where('category.value=:value', { value: category }) + .orderBy('article.publishAt', 'DESC'); + + const { page = 1, pageSize = 12, status } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (status) { + query.andWhere('article.status=:status').setParameter('status', status); + } + + const [data, total] = await query.getManyAndCount(); + + data.forEach((d) => { + if (d.needPassword) { + extractProtectedArticle(d); + } + }); + + return [data, total]; + } + + /** + * 根据 tag 查找文章 + * @param tag + * @param queryParams + */ + async findArticlesByTag(tag, queryParams) { + const query = this.articleRepository + .createQueryBuilder('article') + .innerJoinAndSelect('article.tags', 'tag', 'tag.value=:value', { + value: tag, + }) + .orderBy('article.publishAt', 'DESC'); + + const { page = 1, pageSize = 12, status } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (status) { + query.andWhere('article.status=:status').setParameter('status', status); + } + + const [data, total] = await query.getManyAndCount(); + + data.forEach((d) => { + if (d.needPassword) { + extractProtectedArticle(d); + } + }); + + return [data, total]; + } + + /** + * 获取推荐文章 + */ + async getRecommendArticles() { + const data = await this.articleRepository.find({ + where: { isRecommended: true }, + order: { publishAt: 'DESC' }, + }); + + return data.filter((d) => !d.needPassword); + } + + /** + * 获取文章归档 + */ + async getArchives(): Promise<{ [key: string]: Article[] }> { + const data = await this.articleRepository.find({ + where: { status: 'publish' }, + order: { publishAt: 'DESC' }, + }); + const months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; + const ret = {}; + data.forEach((d) => { + const year = new Date(d.publishAt).getFullYear(); + const month = new Date(d.publishAt).getMonth(); + if (d.needPassword) { + extractProtectedArticle(d); + } + if (!ret[year]) { + ret[year] = {}; + } + if (!ret[year][months[month]]) { + ret[year][months[month]] = []; + } + ret[year][months[month]].push(d); + }); + + return ret; + } + + /** + * 校验文章密码是否正确 + * @param id + * @param password + */ + async checkPassword(id, { password }): Promise<{ pass: boolean }> { + const data = await this.articleRepository + .createQueryBuilder('article') + .where('article.id=:id') + .andWhere('article.password=:password') + .setParameter('id', id) + .setParameter('password', password) + .getOne(); + + const pass = !!data; + return pass ? { pass: !!data, ...data } : { pass: false }; + } + + /** + * 获取指定文章信息 + * @param id + */ + async findById(id, status = null, isAdmin = false): Promise
{ + const query = this.articleRepository + .createQueryBuilder('article') + .leftJoinAndSelect('article.category', 'category') + .leftJoinAndSelect('article.tags', 'tags') + .where('article.id=:id') + .orWhere('article.title=:title') + .setParameter('id', id) + .setParameter('title', id); + + if (status) { + query.andWhere('article.status=:status').setParameter('status', status); + } + + const data = await query.getOne(); + + if (data && data.needPassword && !isAdmin) { + extractProtectedArticle(data); + } + + return data; + } + + /** + * 更新指定文章 + * @param id + * @param article + */ + async updateById(id, article: Partial
): Promise
{ + const oldArticle = await this.articleRepository.findOne(id); + let { tags, category, status } = article; // eslint-disable-line prefer-const + + if (tags) { + tags = await this.tagService.findByIds(('' + tags).split(',')); + } + + const existCategory = await this.categoryService.findById(category); + + const newArticle = { + ...article, + views: oldArticle.views, + category: existCategory, + needPassword: !!article.password, + publishAt: oldArticle.status === 'draft' && status === 'publish' ? dateFormat() : oldArticle.publishAt, + }; + + if (tags) { + Object.assign(newArticle, { tags }); + } + + const updatedArticle = await this.articleRepository.merge(oldArticle, newArticle); + return this.articleRepository.save(updatedArticle); + } + + /** + * 更新指定文章阅读量 + 1 + * @param id + * @param article + */ + async updateViewsById(id): Promise
{ + const oldArticle = await this.articleRepository.findOne(id); + const updatedArticle = await this.articleRepository.merge(oldArticle, { + views: oldArticle.views + 1, + }); + return this.articleRepository.save(updatedArticle); + } + + /** + * 更新喜欢数 + * @param id + * @returns + */ + async updateLikesById(id, type): Promise
{ + const oldArticle = await this.articleRepository.findOne(id); + const updatedArticle = await this.articleRepository.merge(oldArticle, { + likes: type === 'like' ? oldArticle.likes + 1 : oldArticle.likes - 1, + }); + return this.articleRepository.save(updatedArticle); + } + + /** + * 删除文章 + * @param id + */ + async deleteById(id) { + const article = await this.articleRepository.findOne(id); + return this.articleRepository.remove(article); + } + + /** + * 关键词搜索文章 + * @param keyword + */ + async search(keyword) { + const res = await this.articleRepository + .createQueryBuilder('article') + .where('article.title LIKE :keyword') + .setParameter('keyword', `%${keyword}%`) + .getMany(); + + return res; + } + + /** + * 推荐文章 + * @param articleId + */ + async recommend(articleId = null) { + const query = this.articleRepository + .createQueryBuilder('article') + .orderBy('article.publishAt', 'DESC') + .leftJoinAndSelect('article.category', 'category') + .leftJoinAndSelect('article.tags', 'tags'); + + if (!articleId) { + query.where('article.status=:status').setParameter('status', 'publish'); + return query.take(6).getMany(); + } + const sub = this.articleRepository + .createQueryBuilder('article') + .orderBy('article.publishAt', 'DESC') + .leftJoinAndSelect('article.category', 'category') + .leftJoinAndSelect('article.tags', 'tags') + .where('article.id=:id') + .setParameter('id', articleId); + const exist = await sub.getOne(); + + if (!exist) { + return query.take(6).getMany(); + } + + const { title, summary } = exist; + + try { + // nodejieba 安装太麻烦 + // const nodejieba = require('nodejieba'); + const kw1 = segment.doSegment(title, { + stripStopword: true, + }); + const kw2 = segment.doSegment(summary, { + stripStopword: true, + }); + + kw1.forEach((kw, i) => { + const paramKey = `title_` + i; + if (i === 0) { + query.where(`article.title LIKE :${paramKey}`); + } else { + query.orWhere(`article.title LIKE :${paramKey}`); + } + query.setParameter(paramKey, `%${kw.w}%`); + }); + + kw2.forEach((kw, i) => { + const paramKey = `summary_` + i; + if (!kw1.length) { + query.where(`article.summary LIKE :${paramKey}`); + } else { + query.orWhere(`article.summary LIKE :${paramKey}`); + } + query.setParameter(paramKey, `%${kw.w}%`); + }); + } catch (e) {} // eslint-disable-line no-empty + + const data = await query.getMany(); + return data.filter((d) => d.id !== articleId && d.status === 'publish'); + } +} diff --git a/server/src/modules/article/article.util.ts b/server/src/modules/article/article.util.ts new file mode 100644 index 0000000..b11a654 --- /dev/null +++ b/server/src/modules/article/article.util.ts @@ -0,0 +1,4 @@ +export const extractProtectedArticle = (article) => { + delete article.content; + delete article.html; +}; diff --git a/server/src/modules/auth/auth.controller.ts b/server/src/modules/auth/auth.controller.ts new file mode 100644 index 0000000..3236367 --- /dev/null +++ b/server/src/modules/auth/auth.controller.ts @@ -0,0 +1,45 @@ +import { + Body, + ClassSerializerInterceptor, + Controller, + HttpCode, + HttpStatus, + Post, + UseGuards, + UseInterceptors, +} from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; + +import { AuthService } from './auth.service'; +import { JwtAuthGuard } from './jwt-auth.guard'; +import { Roles } from './roles.guard'; + +@ApiTags('Auth') +@Controller('auth') +export class AuthController { + constructor(private readonly authService: AuthService) {} + + /** + * 用户登录 + * @param user + */ + @UseInterceptors(ClassSerializerInterceptor) + @Post('login') + @HttpCode(HttpStatus.OK) + async login(@Body() user) { + const res = await this.authService.login(user); + return res; + } + + @Post('admin') + @Roles('admin') + @UseGuards(JwtAuthGuard) + createBook() { + return this.authService.checkAdmin(); + } + + @Post('github') + loginWithGithub(@Body('code') code) { + return this.authService.loginWithGithub(code); + } +} diff --git a/server/src/modules/auth/auth.module.ts b/server/src/modules/auth/auth.module.ts new file mode 100644 index 0000000..ad21d8b --- /dev/null +++ b/server/src/modules/auth/auth.module.ts @@ -0,0 +1,30 @@ +import { forwardRef, Module } from '@nestjs/common'; +import { JwtModule } from '@nestjs/jwt'; +import { PassportModule } from '@nestjs/passport'; + +import { SettingModule } from '../setting/setting.module'; +import { SMTPModule } from '../smtp/smtp.module'; +import { UserModule } from '../user/user.module'; +import { AuthController } from './auth.controller'; +import { AuthService } from './auth.service'; +import { JwtStrategy } from './jwt.strategy'; + +const passModule = PassportModule.register({ defaultStrategy: 'jwt' }); +const jwtModule = JwtModule.register({ + secret: 'reactpress', + signOptions: { expiresIn: '4h' }, +}); + +@Module({ + imports: [ + forwardRef(() => UserModule), + passModule, + jwtModule, + forwardRef(() => SettingModule), + forwardRef(() => SMTPModule), + ], + providers: [AuthService, JwtStrategy], + controllers: [AuthController], + exports: [passModule, jwtModule], +}) +export class AuthModule {} diff --git a/server/src/modules/auth/auth.service.ts b/server/src/modules/auth/auth.service.ts new file mode 100644 index 0000000..0149af6 --- /dev/null +++ b/server/src/modules/auth/auth.service.ts @@ -0,0 +1,119 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; +import axios from 'axios'; + +import { uniqueid } from '../../utils/uniqueid.util'; +import { SettingService } from '../setting/setting.service'; +import { SMTPService } from '../smtp/smtp.service'; +import { User } from '../user/user.entity'; +import { UserService } from '../user/user.service'; + +@Injectable() +export class AuthService { + constructor( + private readonly userService: UserService, + private readonly jwtService: JwtService, + private readonly configService: ConfigService, + private readonly settingService: SettingService, + private readonly smtpService: SMTPService + ) {} + + createToken(user: Partial) { + const accessToken = this.jwtService.sign(user); + return accessToken; + } + + async login(user: Partial) { + const data = await this.userService.login(user); + const token = this.createToken({ + id: data.id, + name: data.name, + email: data.email, + role: data.role, + }); + return Object.assign(data, { token }); + } + + async loginWithoutPasswd(user: Partial) { + const data = await this.userService.loginWithoutPasswd(user); + const token = this.createToken({ + id: data.id, + name: data.name, + email: data.email, + role: data.role, + }); + return Object.assign(data, { token }); + } + + async checkAdmin() { + return true; + } + + async validateUser(payload: User) { + const user = await this.userService.findById(payload.id); + return user; + } + + async loginWithGithub(code) { + if (!code) { + throw new HttpException('请输入Gitub授权码', HttpStatus.BAD_REQUEST); + } + + try { + const tokenResponse = (await axios({ + method: 'post', + url: + 'https://github.com/login/oauth/access_token?' + + `client_id=${this.configService.get('GITHUB_CLIENT_ID')}&` + + `client_secret=${this.configService.get('GITHUB_CLIENT_SECRET')}&` + + `code=${code}`, + headers: { + accept: 'application/json', + }, + })) as any; + const accessToken = tokenResponse.data.access_token; + const result = (await axios({ + method: 'get', + url: `https://api.github.com/user`, + headers: { + accept: 'application/json', + Authorization: `token ${accessToken}`, + }, + })) as any; + + if (result.data.email) { + const user = { + name: result.data.name, + avatar: result.data.avatar_url, + email: result.data.email, + type: 'github', + }; + + const existUser = await this.userService.findByConditions(user); + + if (!existUser) { + const password = `easy-blog_${uniqueid()}_${result.data.email}`; + await this.userService.createUser({ ...user, password }); + const setting = await this.settingService.findAll(true); + const emailMessage = { + from: setting.smtpFromUser, + to: result.data.email, + subject: 'Github 用户登录通知', + html: `您好,您使用了 Github 登录了 reactpress。reactpress 已为您创建用户,用户名称:${result.data.name}, 用户密码:${password},请及时登录系统修改密码`, + }; + this.smtpService.create(emailMessage).catch(() => { + console.log(`通知用户 ${result.data.name}(${result.data.email}),但发送邮件通知失败`); + }); + } + + const res = await this.loginWithoutPasswd(user); + return res; + } else { + throw new HttpException('未获取到您的公开邮件地址,无法使用Github登录', HttpStatus.BAD_REQUEST); + } + } catch (e) { + throw new HttpException(e.message || e, HttpStatus.BAD_REQUEST); + } + } +} diff --git a/server/src/modules/auth/jwt-auth.guard.ts b/server/src/modules/auth/jwt-auth.guard.ts new file mode 100644 index 0000000..3c77b65 --- /dev/null +++ b/server/src/modules/auth/jwt-auth.guard.ts @@ -0,0 +1,18 @@ +import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; + +@Injectable() +export class JwtAuthGuard extends AuthGuard('jwt') { + getRequest(context: ExecutionContext) { + const ctx = context.switchToHttp(); + const request = ctx.getRequest(); + return request; + } + + handleRequest(err, user: User): User { + if (err || !user) { + throw new UnauthorizedException('身份验证失败'); + } + return user; + } +} diff --git a/server/src/modules/auth/jwt.strategy.ts b/server/src/modules/auth/jwt.strategy.ts new file mode 100644 index 0000000..34baa61 --- /dev/null +++ b/server/src/modules/auth/jwt.strategy.ts @@ -0,0 +1,25 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { PassportStrategy } from '@nestjs/passport'; +import { ExtractJwt, Strategy } from 'passport-jwt'; + +import { User } from '../user/user.entity'; +import { AuthService } from './auth.service'; + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor(private readonly authService: AuthService) { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: 'reactpress', + }); + } + + async validate(payload: User) { + const user = await this.authService.validateUser(payload); + + if (!user) { + throw new UnauthorizedException('身份验证失败'); + } + return user; + } +} diff --git a/server/src/modules/auth/roles.guard.ts b/server/src/modules/auth/roles.guard.ts new file mode 100644 index 0000000..ed3ba06 --- /dev/null +++ b/server/src/modules/auth/roles.guard.ts @@ -0,0 +1,34 @@ +import { CanActivate, ExecutionContext, Injectable, SetMetadata } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { JwtService } from '@nestjs/jwt'; + +import { User } from '../user/user.entity'; + +export const Roles = (...roles: string[]) => SetMetadata('roles', roles); + +@Injectable() +export class RolesGuard implements CanActivate { + constructor(private readonly reflector: Reflector, private readonly jwtService: JwtService) {} + + canActivate(context: ExecutionContext): boolean { + const roles = this.reflector.get('roles', context.getHandler()); + if (!roles) { + return true; + } + const request = context.switchToHttp().getRequest(); + + let token = request.headers.authorization; + + if (/Bearer/.test(token)) { + // 不需要 Bearer,否则验证失败 + token = token.split(' ').pop(); + } + + const user = this.jwtService.decode(token) as User; + if (!user) { + return false; + } + const hasRole = roles.some((role) => role === user.role); + return user && user.role && hasRole; + } +} diff --git a/server/src/modules/category/category.controller.ts b/server/src/modules/category/category.controller.ts new file mode 100644 index 0000000..76191bb --- /dev/null +++ b/server/src/modules/category/category.controller.ts @@ -0,0 +1,66 @@ +import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { Category } from './category.entity'; +import { CategoryService } from './category.service'; + +@ApiTags('Category') +@Controller('category') +@UseGuards(RolesGuard) +export class CategoryController { + constructor(private readonly categoryService: CategoryService) {} + + /** + * 添加标签 + * @param category + */ + @ApiResponse({ status: 200, description: '添加分类', type: [Category] }) + @Post() + @Roles('admin') + @UseGuards(JwtAuthGuard) + create(@Body() category) { + return this.categoryService.create(category); + } + + /** + * 获取所有标签 + */ + @Get() + findAll(@Query() queryParams): Promise { + return this.categoryService.findAll(queryParams); + } + + /** + * 获取指定标签 + * @param id + */ + @Get(':id') + findById(@Param('id') id) { + return this.categoryService.findById(id); + } + + /** + * 更新标签 + * @param id + * @param category + */ + @Patch(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + updateById(@Param('id') id, @Body() category) { + return this.categoryService.updateById(id, category); + } + + /** + * 删除标签 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.categoryService.deleteById(id); + } +} diff --git a/server/src/modules/category/category.entity.ts b/server/src/modules/category/category.entity.ts new file mode 100644 index 0000000..35111d9 --- /dev/null +++ b/server/src/modules/category/category.entity.ts @@ -0,0 +1,42 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +import { Article } from '../article/article.entity'; + +@Entity() +export class Category { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column() + label: string; + + @ApiProperty() + @Column() + value: string; + + @ApiProperty() + @OneToMany( + () => Article, + (article) => article.category + ) + articles: Array
; + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/category/category.module.ts b/server/src/modules/category/category.module.ts new file mode 100644 index 0000000..b4d18d5 --- /dev/null +++ b/server/src/modules/category/category.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { CategoryController } from './category.controller'; +import { Category } from './category.entity'; +import { CategoryService } from './category.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Category]), AuthModule], + exports: [CategoryService], + providers: [CategoryService], + controllers: [CategoryController], +}) +export class CategoryModule {} diff --git a/server/src/modules/category/category.service.ts b/server/src/modules/category/category.service.ts new file mode 100644 index 0000000..8439e57 --- /dev/null +++ b/server/src/modules/category/category.service.ts @@ -0,0 +1,104 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { Category } from './category.entity'; + +@Injectable() +export class CategoryService { + constructor( + @InjectRepository(Category) + private readonly categoryRepository: Repository + ) {} + + /** + * 添加分类 + * @param Category + */ + async create(Category: Partial): Promise { + const { label } = Category; + const existCategory = await this.categoryRepository.findOne({ + where: { label }, + }); + + if (existCategory) { + throw new HttpException('分类已存在', HttpStatus.BAD_REQUEST); + } + + const newCategory = await this.categoryRepository.create(Category); + await this.categoryRepository.save(newCategory); + return newCategory; + } + + /** + * 获取所有分类 + */ + async findAll(queryParams): Promise { + const { articleStatus } = queryParams; + const qb = this.categoryRepository.createQueryBuilder('category').orderBy('category.createAt', 'ASC'); + + if (articleStatus) { + qb.leftJoinAndSelect('category.articles', 'articles', 'articles.status=:status', { + status: articleStatus, + }); + } else { + qb.leftJoinAndSelect('category.articles', 'articles'); + } + + const data = await qb.getMany(); + + data.forEach((d) => { + Object.assign(d, { articleCount: d.articles.length }); + delete d.articles; + }); + + return data; + + // return this.categoryRepository.find({ order: { createAt: 'ASC' } }); + } + + /** + * 获取指定分类 + * @param id + */ + async findById(id): Promise { + const data = await this.categoryRepository + .createQueryBuilder('category') + .where('category.id=:id') + .orWhere('category.label=:id') + .orWhere('category.value=:id') + .setParameter('id', id) + .getOne(); + + return data; + } + + async findByIds(ids): Promise> { + return this.categoryRepository.findByIds(ids); + } + + /** + * 更新分类 + * @param id + * @param Category + */ + async updateById(id, category: Partial): Promise { + const oldCategory = await this.categoryRepository.findOne(id); + const updatedCategory = await this.categoryRepository.merge(oldCategory, category); + return this.categoryRepository.save(updatedCategory); + } + + /** + * 删除分类 + * @param id + */ + async deleteById(id) { + try { + const category = await this.categoryRepository.findOne(id); + await this.categoryRepository.remove(category); + return true; + } catch (e) { + throw new HttpException('删除失败,可能存在关联文章', HttpStatus.BAD_REQUEST); + } + } +} diff --git a/server/src/modules/comment/comment.controller.ts b/server/src/modules/comment/comment.controller.ts new file mode 100644 index 0000000..d44e048 --- /dev/null +++ b/server/src/modules/comment/comment.controller.ts @@ -0,0 +1,74 @@ +import { Body, Controller, Delete, Get, Param, Patch, Post, Query, Request, UseGuards } from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { Comment } from './comment.entity'; +import { CommentService } from './comment.service'; + +@ApiTags('Comment') +@Controller('comment') +@UseGuards(RolesGuard) +export class CommentController { + constructor(private readonly commentService: CommentService) {} + + /** + * 创建评论 + * @param comment + */ + @ApiResponse({ status: 200, description: '创建评论', type: [Comment] }) + @Post() + create(@Request() req, @Body() comment) { + const userAgent = req.headers['user-agent']; + return this.commentService.create(userAgent, comment); + } + + /** + * 获取所有评论 + */ + @Get() + findAll(@Query() queryParams) { + return this.commentService.findAll(queryParams); + } + + /** + * 获取指定评论 + * @param id + */ + @Get(':id') + findById(@Param('id') id) { + return this.commentService.findById(id); + } + + /** + * 获取文章或页面评论 + * @param hostId + */ + @Get('host/:hostId') + getArticleComments(@Param('hostId') hostId, @Query() qurey) { + return this.commentService.getArticleComments(hostId, qurey); + } + + /** + * 更新评论 + * @param id + * @param tag + */ + @Patch(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + updateById(@Param('id') id, @Body() data) { + return this.commentService.updateById(id, data); + } + + /** + * 删除评论 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.commentService.deleteById(id); + } +} diff --git a/server/src/modules/comment/comment.entity.ts b/server/src/modules/comment/comment.entity.ts new file mode 100644 index 0000000..bd58c6c --- /dev/null +++ b/server/src/modules/comment/comment.entity.ts @@ -0,0 +1,73 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +@Entity() +export class Comment { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column() + name: string; + + @ApiProperty() + @Column() + email: string; // 联系方式 + + @ApiProperty() + @Column() + avatar: string; + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) // 评论内容 + content: string; + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) // 评论内容 + html: string; + + @ApiProperty() + @Column({ type: 'boolean', default: false }) + pass: boolean; // 是否审核通过 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) + userAgent: string; + + @ApiProperty() + @Column() + hostId: string; // 关联文章或页面 id + + @ApiProperty() + @Column() + url: string; // 关联页面路径,可与 systemUrl 拼接 + + @ApiProperty() + @Column({ default: null }) + parentCommentId: string; // 父级评论 id + + @ApiProperty() + @Column({ default: null }) + replyUserName: string; // 回复评论用户名 + + @ApiProperty() + @Column({ default: null }) + replyUserEmail: string; // 回复评论邮箱 + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/comment/comment.module.ts b/server/src/modules/comment/comment.module.ts new file mode 100644 index 0000000..fe128eb --- /dev/null +++ b/server/src/modules/comment/comment.module.ts @@ -0,0 +1,18 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { ArticleModule } from '../article/article.module'; +import { AuthModule } from '../auth/auth.module'; +import { SettingModule } from '../setting/setting.module'; +import { SMTPModule } from '../smtp/smtp.module'; +import { UserModule } from '../user/user.module'; +import { CommentController } from './comment.controller'; +import { Comment } from './comment.entity'; +import { CommentService } from './comment.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Comment]), AuthModule, ArticleModule, SettingModule, SMTPModule, UserModule], + providers: [CommentService], + controllers: [CommentController], +}) +export class CommentModule {} diff --git a/server/src/modules/comment/comment.service.ts b/server/src/modules/comment/comment.service.ts new file mode 100644 index 0000000..c6ba2a2 --- /dev/null +++ b/server/src/modules/comment/comment.service.ts @@ -0,0 +1,189 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { marked } from '../../utils/markdown.util'; +import { parseUserAgent } from '../../utils/ua.util'; +import { ArticleService } from '../article/article.service'; +import { SettingService } from '../setting/setting.service'; +import { SMTPService } from '../smtp/smtp.service'; +import { UserService } from '../user/user.service'; +import { Comment } from './comment.entity'; +import { getNewCommentHTML, getReplyCommentHTML } from './html'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const url = require('url'); + +@Injectable() +export class CommentService { + constructor( + @InjectRepository(Comment) + private readonly commentRepository: Repository, + private readonly articleService: ArticleService, + private readonly smtpService: SMTPService, + private readonly settingService: SettingService, + private readonly userService: UserService + ) {} + + /** + * 创建评论 + * @param comment + */ + async create(userAgent, comment: Partial & { reply?: string; createByAdmin?: boolean }): Promise { + const { hostId, name, email, content, createByAdmin = false } = comment; + + if (!hostId || !name || !email || !content) { + throw new HttpException('缺失参数', HttpStatus.BAD_REQUEST); + } + + comment.pass = false; + const { text: uaText } = parseUserAgent(userAgent); + comment.userAgent = uaText; + comment.html = marked(content).html; + const newComment = await this.commentRepository.create(comment); + await this.commentRepository.save(comment); + + if (!createByAdmin) { + // 发送通知邮件 + const setting = await this.settingService.findAll(true); + const sendEmail = (adminName, adminEmail) => { + const emailMessage = { + from: setting.smtpFromUser, + to: adminEmail, + subject: '新评论通知', + html: getNewCommentHTML({ ...setting, adminName, comment }), + }; + this.smtpService.create(emailMessage).catch(() => { + console.log('收到新评论,但发送邮件通知失败'); + }); + }; + try { + // 通知所有管理员审核评论 + const [users] = await this.userService.findAll({ role: 'admin' }); + users.forEach((user) => { + if (user.email) { + sendEmail(user.name, user.email); + } + }); + } catch (e) { + console.log(e); + } + } + + return newComment; + } + + /** + * 查询所有评论 + * 额外添加文章信息 + */ + async findAll(queryParams): Promise<[Comment[], number]> { + const query = this.commentRepository.createQueryBuilder('comment').orderBy('comment.createAt', 'DESC'); + + if (typeof queryParams === 'object') { + const { page = 1, pageSize = 12, pass, ...otherParams } = queryParams; + + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (pass) { + query.andWhere('comment.pass=:pass').setParameter('pass', pass); + } + + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`comment.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + } + + return query.getManyAndCount(); + } + + /** + * 获取指定评论 + * @param id + */ + async findById(id): Promise { + return this.commentRepository.findOne(id); + } + + /** + * 获取文章评论 + * @param articleId + */ + async getArticleComments(hostId, queryParams) { + const query = this.commentRepository + .createQueryBuilder('comment') + .where('comment.hostId=:hostId') + .andWhere('comment.pass=:pass') + .andWhere('comment.parentCommentId is NULL') + .orderBy('comment.createAt', 'DESC') + .setParameter('hostId', hostId) + .setParameter('pass', true); + + const subQuery = this.commentRepository + .createQueryBuilder('comment') + .andWhere('comment.pass=:pass') + .andWhere('comment.parentCommentId=:parentCommentId') + .orderBy('comment.createAt', 'ASC') + .setParameter('pass', true); + + const { page = 1, pageSize = 12 } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + const [data, count] = await query.getManyAndCount(); + + for (const item of data) { + const subComments = await subQuery.setParameter('parentCommentId', item.id).getMany(); + Object.assign(item, { children: subComments }); + } + + return [data, count]; + } + + async findByIds(ids): Promise> { + return this.commentRepository.findByIds(ids); + } + + /** + * 更新评论 + * @param id + * @param tag + */ + async updateById(id, data: Partial): Promise { + const old = await this.commentRepository.findOne(id); + const newData = await this.commentRepository.merge(old, data); + + if (newData.pass) { + const { replyUserName, replyUserEmail, url: link } = newData; + const isReply = replyUserName && replyUserEmail; + if (isReply) { + // 发送通知邮件 + try { + const setting = await this.settingService.findAll(true); + const emailMessage = { + from: setting.smtpFromUser, + to: replyUserEmail, + subject: '评论回复通知', + html: getReplyCommentHTML({ + ...setting, + replyUserName, + commentHostUrl: url.resolve(setting.systemUrl, link), + }), + }; + this.smtpService.create(emailMessage).catch(() => { + console.log(`通知用户 ${replyUserName}(${replyUserEmail}),但发送邮件通知失败`); + }); + } catch (e) {} // eslint-disable-line no-empty + } + } + + return this.commentRepository.save(newData); + } + + async deleteById(id) { + const data = await this.commentRepository.findOne(id); + return this.commentRepository.remove(data); + } +} diff --git a/server/src/modules/comment/html.ts b/server/src/modules/comment/html.ts new file mode 100644 index 0000000..13a7a5b --- /dev/null +++ b/server/src/modules/comment/html.ts @@ -0,0 +1,641 @@ +import { dateFormat } from '../../utils/date.util'; + +export const getNewCommentHTML = ({ + systemTitle, + systemUrl, + adminSystemUrl, + adminName, + comment, +}) => { + return ` + + + + + + +
+
+ + + + + + + + + +
+ + + + + + + + + +
+ + + + + + +
+ ${systemTitle} +
+
+ + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + +
+ 新评论通知 +
+

亲爱的${adminName},站点收到新评论:

+

评论人:${comment.name}

+

评论内容:${comment.content}

+
+
+ + + + + + +
+ +
+
+ + + + + + + + + +
+ 此致 +
+ ${systemTitle} 敬上 +
+
+
+
+
+
+
+ `; +}; + +export const getReplyCommentHTML = ({ + systemLogo, + systemTitle, + systemFavicon, + systemUrl, + replyUserName, + commentHostUrl, +}) => { + return ` + + + + + + +
+
+ + + + + + + + + +
+ + + + + + + + + +
+ + + + + + +
+ ${systemTitle} +
+
+ + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + +
+ 评论回复通知 +
+

亲爱的${replyUserName},您的评论已经被他人回复。

+
+
+ + + + + + +
+ +
+
+ + + + + + + + + +
+ 此致 +
+ ${systemTitle} 敬上 +
+
+
+
+
+
+
+ `; +}; diff --git a/server/src/modules/file/file.controller.ts b/server/src/modules/file/file.controller.ts new file mode 100644 index 0000000..9c48cad --- /dev/null +++ b/server/src/modules/file/file.controller.ts @@ -0,0 +1,61 @@ +import { Controller, Delete, Get, Param, Post, Query, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common'; +import { FileInterceptor } from '@nestjs/platform-express'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { File } from './file.entity'; +import { FileService } from './file.service'; + +@ApiTags('File') +@Controller('file') +@UseGuards(RolesGuard) +export class FileController { + constructor(private readonly fileService: FileService) {} + + /** + * 上传文件 + * @param file + */ + @ApiResponse({ status: 200, description: '上传文件', type: [File] }) + @Post('upload') + @UseInterceptors( + FileInterceptor('file', { + limits: { + fieldSize: 5 * 1024 * 1024, // 5MB + }, + }) + ) + @UseGuards(JwtAuthGuard) + uploadFile(@UploadedFile() file, @Query('unique') unique) { + return this.fileService.uploadFile(file, unique); + } + + /** + * 获取所有文件 + */ + @Get() + findAll(@Query() queryParam) { + return this.fileService.findAll(queryParam); + } + + /** + * 获取指定文件 + * @param id + */ + @Get(':id') + findById(@Param('id') id) { + return this.fileService.findById(id); + } + + /** + * 删除文件 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.fileService.deleteById(id); + } +} diff --git a/server/src/modules/file/file.entity.ts b/server/src/modules/file/file.entity.ts new file mode 100644 index 0000000..7ff11e0 --- /dev/null +++ b/server/src/modules/file/file.entity.ts @@ -0,0 +1,37 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm'; + +@Entity() +export class File { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column() + originalname: string; // 文件名 + + @ApiProperty() + @Column() + filename: string; // 文件名 + + @ApiProperty() + @Column() + type: string; // 文件信息 + + @ApiProperty() + @Column() + size: number; // 文件大小 + + @ApiProperty() + @Column() + url: string; + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; +} diff --git a/server/src/modules/file/file.module.ts b/server/src/modules/file/file.module.ts new file mode 100644 index 0000000..f1a909a --- /dev/null +++ b/server/src/modules/file/file.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { SettingModule } from '../setting/setting.module'; +import { FileController } from './file.controller'; +import { File } from './file.entity'; +import { FileService } from './file.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([File]), AuthModule, SettingModule], + controllers: [FileController], + providers: [FileService], +}) +export class FileModule {} diff --git a/server/src/modules/file/file.service.ts b/server/src/modules/file/file.service.ts new file mode 100644 index 0000000..2697148 --- /dev/null +++ b/server/src/modules/file/file.service.ts @@ -0,0 +1,113 @@ +import { HttpException, Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { InjectRepository } from '@nestjs/typeorm'; +import * as path from 'path'; +import { Repository } from 'typeorm'; + +import { dateFormat } from '../../utils/date.util'; +import { Oss } from '../../utils/oss.util'; +import { uniqueid } from '../../utils/uniqueid.util'; +import { LocalUpload } from '../../utils/upload.util'; +import { SettingService } from '../setting/setting.service'; +import { File } from './file.entity'; + +@Injectable() +export class FileService { + private oss: Oss; + private localUpload: LocalUpload; + + constructor( + @InjectRepository(File) + private readonly fileRepository: Repository, + private readonly settingService: SettingService, + private readonly configService: ConfigService + ) { + this.oss = new Oss(this.settingService); + this.localUpload = new LocalUpload(); + } + + /** + * 上传文件 + * @param file + */ + async uploadFile(file, unique): Promise { + const { originalname, mimetype, size, buffer } = file; + const dataFolder = dateFormat(new Date(), 'yyyy-MM-dd'); + const ext = path.extname(originalname); + const filename = +unique === 1 ? `${dataFolder}/${originalname}` : `${dataFolder}/${uniqueid()}.${ext}`; + // 获取oss的配置 + const hasOssConfig = await this.oss.hasOssConfig(); + let url; + if (hasOssConfig) { + // 上传到OSS + url = await this.oss.putFile(filename, buffer); + } else { + // 本地上传 + url = await this.localUpload.putFile(filename, buffer); + // 上传的路径 + const uploadUrl = + this.configService.get('SERVER_PUBLIC_UPLOAD_URL') || `${this.configService.get('SERVER_SITE_URL')}/public/uploads`; + // 最终的地址 + url = `${uploadUrl}/${filename}`; + } + const newFile = await this.fileRepository.create({ + originalname, + filename, + url, + type: mimetype, + size, + }); + await this.fileRepository.save(newFile); + return newFile; + } + + /** + * 获取所有文件 + */ + async findAll(queryParams): Promise<[File[], number]> { + const query = this.fileRepository.createQueryBuilder('file').orderBy('file.createAt', 'DESC'); + + if (typeof queryParams === 'object') { + const { page = 1, pageSize = 12, ...otherParams } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`file.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + } + + return query.getManyAndCount(); + } + + /** + * 获取指定文件 + * @param id + */ + async findById(id): Promise { + return this.fileRepository.findOne(id); + } + + async findByIds(ids): Promise> { + return this.fileRepository.findByIds(ids); + } + + /** + * 删除文件 + * @param id + */ + async deleteById(id) { + const target = await this.fileRepository.findOne(id); + const hasOssConfig = await this.oss.hasOssConfig(); + if (hasOssConfig) { + // 先删除oss的配置 + await this.oss.deleteFile(target.filename); + } else { + // 删除本地的文件 + await this.localUpload.deleteFile(target.filename); + } + return this.fileRepository.remove(target); + } +} diff --git a/server/src/modules/install/install.controller.ts b/server/src/modules/install/install.controller.ts new file mode 100644 index 0000000..42f0bd8 --- /dev/null +++ b/server/src/modules/install/install.controller.ts @@ -0,0 +1,20 @@ +import { Controller, Post, Body, Get, Res, UseGuards } from '@nestjs/common'; +import { InstallService } from './install.service'; +import { Response } from 'express'; +import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger'; + +@ApiTags('install') +@Controller('install') +export class InstallController { + constructor(private readonly installService: InstallService) {} + + @Post('check') + async checkEnvFileExists(): Promise { + return this.installService.checkEnvFileExists() ? 'Environment file exists.' : 'Please configure your database.'; + } + + @Post('configure') + async configureDatabase(@Body() body: { username: string, password: string, database: string }): Promise { + return this.installService.configureDatabase(body).then(() => 'Database configured successfully.'); + } +} \ No newline at end of file diff --git a/server/src/modules/install/install.module.ts b/server/src/modules/install/install.module.ts new file mode 100644 index 0000000..3ee7861 --- /dev/null +++ b/server/src/modules/install/install.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { SettingModule } from '../setting/setting.module'; +import { InstallController } from './install.controller'; +import { InstallService } from './install.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([File]), AuthModule, SettingModule], + controllers: [InstallController], + providers: [InstallService], +}) +export class InstallModule {} diff --git a/server/src/modules/install/install.service.ts b/server/src/modules/install/install.service.ts new file mode 100644 index 0000000..83e41eb --- /dev/null +++ b/server/src/modules/install/install.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@nestjs/common'; +import * as fs from 'fs'; +import * as path from 'path'; +import { createConnection } from 'typeorm'; +import { ConfigService } from '@nestjs/config'; + +@Injectable() +export class InstallService { + private envConfigPath = path.resolve(__dirname, '..', '..', '.env'); + private configService: ConfigService; + + constructor(configService: ConfigService) { + this.configService = configService; + } + + checkEnvFileExists(): boolean { + return fs.existsSync(this.envConfigPath); + } + + async configureDatabase(config: { username: string, password: string, database: string }): Promise { + const connection = await createConnection({ + type: 'mysql', + host: 'localhost', // 这里可以改为从body中获取,但为了简化我们固定为localhost + port: 3306, // 同样,可以改为动态获取 + username: config.username, + password: config.password, + database: config.database, + synchronize: true, // 注意:在生产中不要启用synchronize + logging: false, // 控制台不输出orm日志 + entities: [__dirname + '/../**/*.entity{.ts,.js}'], // 扫描实体位置 + }); + + try { + await connection.connect(); + console.log('Connected to the database'); + + // 写入.env文件 + const envConfigLines = [ + `DB_HOST=localhost`, // 也可以动态写入 + `DB_PORT=3306`, // 同上 + `DB_USERNAME=${config.username}`, + `DB_PASSWORD=${config.password}`, + `DB_NAME=${config.database}`, + ]; + + fs.writeFileSync(this.envConfigPath, envConfigLines.join('\n'), { encoding: 'utf8' }); + } catch (error) { + throw new Error('Failed to connect to the database: ' + error.message); + } finally { + await connection.close(); + } + } +} \ No newline at end of file diff --git a/server/src/modules/knowledge/knowledge.controller.ts b/server/src/modules/knowledge/knowledge.controller.ts new file mode 100644 index 0000000..5f00f9c --- /dev/null +++ b/server/src/modules/knowledge/knowledge.controller.ts @@ -0,0 +1,110 @@ +import { + Body, + Controller, + Delete, + Get, + HttpCode, + HttpStatus, + Param, + Patch, + Post, + Query, + UseGuards, +} from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { Knowledge } from './knowledge.entity'; +import { KnowledgeService } from './knowledge.service'; + +@ApiTags('Knowledge') +@Controller('Knowledge') +@UseGuards(RolesGuard) +export class KnowledgeController { + constructor(private readonly service: KnowledgeService) {} + + /** + * 创建知识库 + * @param data + */ + @ApiResponse({ status: 200, description: '创建知识库', type: [Knowledge] }) + @Post('/book') + @Roles('admin') + @UseGuards(JwtAuthGuard) + createBook(@Body() data) { + return this.service.createKnowledgeBook(data); + } + + /** + * 创建知识库章节 + * @param data + */ + @ApiResponse({ status: 200, description: '创建知识章节', type: [Knowledge] }) + @Post('/chapter') + @Roles('admin') + @UseGuards(JwtAuthGuard) + createChapter(@Body() data) { + return this.service.createKnowledgeChapter(data); + } + + /** + * 删除文章 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.service.deleteById(id); + } + + /** + * 更新知识 + * @param id + * @param data + */ + @Patch(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + @HttpCode(HttpStatus.OK) + updateById(@Param('id') id, @Body() data) { + return this.service.updateById(id, data); + } + + /** + * 获取所有知识库(不包含章节) + */ + @Get() + @HttpCode(HttpStatus.OK) + findAll(@Query() queryParams) { + return this.service.findAll(queryParams); + } + + /** + * 获取章节详情(如果是知识库,会返回所包含的章节) + * @param id + */ + @Get(':id') + async findById(@Param('id') id) { + return this.service.findById(id); + } + + /** + * 文章访问量 +1 + */ + @Post(':id/views') + @HttpCode(HttpStatus.OK) + updateViewsById(@Param('id') id) { + return this.service.updateViewsById(id); + } + + /** + * 文章访问量 +1 + */ + @Post(':id/likes') + @HttpCode(HttpStatus.OK) + updateLikesById(@Param('id') id, @Body('type') type) { + return this.service.updateLikesById(id, type); + } +} diff --git a/server/src/modules/knowledge/knowledge.entity.ts b/server/src/modules/knowledge/knowledge.entity.ts new file mode 100644 index 0000000..b037b17 --- /dev/null +++ b/server/src/modules/knowledge/knowledge.entity.ts @@ -0,0 +1,77 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +@Entity() +export class Knowledge { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column({ default: null }) + parentId: string; // 父级 id,如果该项为空,则是书的封面,不为空则是一个章节 + + @ApiProperty() + @Column({ type: 'int', default: 0 }) + order: number; // 章节排序 + + @ApiProperty() + @Column() + title: string; // 标题 + + @ApiProperty() + @Column({ default: null }) + cover: string; // 封面图 + + @ApiProperty() + @Column({ type: 'text', default: null }) + summary: string; // 摘要,自动生成 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) + content: string; // 原始内容 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) + html: string; // 格式化内容,自动生成 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null }) + toc: string; // 格式化内容索引,自动生成 + + @ApiProperty() + @Column('simple-enum', { enum: ['draft', 'publish'], default: 'draft' }) + status: string; // 文章状态 + + @ApiProperty() + @Column({ type: 'int', default: 0 }) + views: number; // 阅读量 + + @ApiProperty() + @Column({ type: 'int', default: 0 }) + likes: number; // 喜欢数 + + @ApiProperty() + @Column({ type: 'boolean', default: true }) + isCommentable: boolean; + + @ApiProperty() + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + publishAt: Date; // 发布日期 + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/knowledge/knowledge.module.ts b/server/src/modules/knowledge/knowledge.module.ts new file mode 100644 index 0000000..0614723 --- /dev/null +++ b/server/src/modules/knowledge/knowledge.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { KnowledgeController } from './knowledge.controller'; +import { Knowledge } from './knowledge.entity'; +import { KnowledgeService } from './knowledge.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Knowledge]), AuthModule], + exports: [KnowledgeService], + providers: [KnowledgeService], + controllers: [KnowledgeController], +}) +export class KnowledgeModule {} diff --git a/server/src/modules/knowledge/knowledge.service.ts b/server/src/modules/knowledge/knowledge.service.ts new file mode 100644 index 0000000..5770ee0 --- /dev/null +++ b/server/src/modules/knowledge/knowledge.service.ts @@ -0,0 +1,168 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { dateFormat } from '../../utils/date.util'; +import { Knowledge } from './knowledge.entity'; + +@Injectable() +export class KnowledgeService { + constructor( + @InjectRepository(Knowledge) + private readonly repository: Repository + ) {} + + /** + * 新建知识库 + * @param knowledge + */ + async createKnowledgeBook(knowledge: Partial): Promise { + const { title, status, parentId } = knowledge; + + const exist = await this.repository.findOne({ where: { title } }); + if (exist && !parentId) { + // 章节不考虑重名 + throw new HttpException('知识库已存在', HttpStatus.BAD_REQUEST); + } + + if (status === 'publish') { + Object.assign(knowledge, { publishAt: dateFormat() }); + } + + const data = await this.repository.create(knowledge); + await this.repository.save(data); + return data; + } + + /** + * 新建知识章节 + * @param knowledge + */ + async createKnowledgeChapter(knowledges: Partial | Array>): Promise> { + if (!Array.isArray(knowledges)) { + knowledges = [knowledges]; + } + if (knowledges.some((knowledge) => !knowledge.parentId)) { + throw new HttpException('无效的知识库章节', HttpStatus.BAD_REQUEST); + } + const result = []; + for (const knowledge of knowledges) { + result.push(await this.createKnowledgeBook(knowledge)); + } + return result; + } + + /** + * 删除章节 + * @param id + */ + async deleteById(id) { + const data = await this.repository.findOne(id); + if (!data.parentId) { + const query = this.repository + .createQueryBuilder('knowledge') + .where('knowledge.parentId=:parentId') + .setParameter('parentId', data.id); + const children = await query.getMany(); + if (children.length) { + for (const item of children) { + await this.repository.remove(item); + } + } + } + return this.repository.remove(data); + } + + /** + * 更新指定知识 + * @param id + * @param data + */ + async updateById(id, data: Partial): Promise { + const oldData = await this.repository.findOne(id); + const { status } = oldData; + const newData = { + ...data, + views: oldData.views, + publishAt: oldData.status === 'draft' && status === 'publish' ? dateFormat() : oldData.publishAt, + }; + const result = await this.repository.merge(oldData, newData); + await this.repository.save(result); + return result; + } + + /** + * 更新指定文章阅读量 + 1 + * @param id + * @param article + */ + async updateViewsById(id): Promise { + const oldData = await this.repository.findOne(id); + const newData = await this.repository.merge(oldData, { + views: oldData.views + 1, + }); + return this.repository.save(newData); + } + + /** + * 更新喜欢数 + * @param id + * @returns + */ + async updateLikesById(id, type): Promise { + const oldData = await this.repository.findOne(id); + const newData = await this.repository.merge(oldData, { + likes: type === 'like' ? oldData.likes + 1 : oldData.likes - 1, + }); + return this.repository.save(newData); + } + + /** + * 获取所有知识库 + */ + async findAll(queryParams): Promise<[Knowledge[], number]> { + const query = this.repository + .createQueryBuilder('knowledge') + .orderBy('knowledge.publishAt', 'DESC') + .where('knowledge.parentId is :parentId') + .setParameter('parentId', null); + + const { page = 1, pageSize = 12, status, ...otherParams } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + if (status) { + query.andWhere('knowledge.status=:status').setParameter('status', status); + } + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`knowledge.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + const [data, total] = await query.getManyAndCount(); + return [data, total]; + } + + /** + * 获取指定文章信息 + * @param id + */ + async findById(id): Promise> { + const data = (await this.repository.findOne(id)) as Partial; + + if (!data) { + return null; + } + + if (!data.parentId) { + const query = this.repository + .createQueryBuilder('knowledge') + .where('knowledge.parentId=:parentId') + .setParameter('parentId', data.id); + const children = await query.getMany(); + children.sort((a, b) => a.order - b.order); + Object.assign(data, { children: children || [] }); + } + + return data; + } +} diff --git a/server/src/modules/page/page.controller.ts b/server/src/modules/page/page.controller.ts new file mode 100644 index 0000000..968056e --- /dev/null +++ b/server/src/modules/page/page.controller.ts @@ -0,0 +1,87 @@ +import { + Body, + Controller, + Delete, + Get, + HttpCode, + HttpStatus, + Param, + Patch, + Post, + Query, + UseGuards, +} from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { Page } from './page.entity'; +import { PageService } from './page.service'; + +@ApiTags('Page') +@Controller('page') +@UseGuards(RolesGuard) +export class PageController { + constructor(private readonly pageService: PageService) {} + + /** + * 创建页面 + * @param page + */ + @ApiResponse({ status: 200, description: '创建页面', type: [Page] }) + @Post() + @Roles('admin') + @UseGuards(JwtAuthGuard) + create(@Body() page) { + return this.pageService.create(page); + } + + /** + * 获取所有文章 + */ + @Get() + findAll(@Query() queryParams) { + return this.pageService.findAll(queryParams); + } + + /** + * 获取指定页面 + * @param id + */ + @Get(':id') + findById(@Param('id') id) { + return this.pageService.findById(id); + } + + /** + * 更新页面 + * @param id + * @param page + */ + @Patch(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + updateById(@Param('id') id, @Body() page) { + return this.pageService.updateById(id, page); + } + + /** + * 文章访问量 +1 + */ + @Post(':id/views') + @HttpCode(HttpStatus.OK) + updateViewsById(@Param('id') id) { + return this.pageService.updateViewsById(id); + } + + /** + * 删除文章 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.pageService.deleteById(id); + } +} diff --git a/server/src/modules/page/page.entity.ts b/server/src/modules/page/page.entity.ts new file mode 100644 index 0000000..a8a4fb2 --- /dev/null +++ b/server/src/modules/page/page.entity.ts @@ -0,0 +1,65 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +@Entity() +export class Page { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column({ default: null }) + cover: string; // 页面封面 + + @ApiProperty() + @Column() + name: string; // 页面名 + + @ApiProperty() + @Column() + path: string; // 页面路径 + + @ApiProperty() + @Column({ type: 'int', default: 0 }) + order: number; // 顺序 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) + content: string; // 原始内容 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null, charset: 'utf8mb4' }) + html: string; // 格式化内容,自动生成 + + @ApiProperty() + @Column({ type: 'mediumtext', default: null }) + toc: string; // 格式化内容索引,自动生成 + + @ApiProperty() + @Column('simple-enum', { enum: ['draft', 'publish'] }) + status: string; // 页面状态 + + @ApiProperty() + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + publishAt: Date; // 发布日期 + + @ApiProperty() + @Column({ type: 'int', default: 0 }) + views: number; // 阅读量 + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/page/page.module.ts b/server/src/modules/page/page.module.ts new file mode 100644 index 0000000..d6d2209 --- /dev/null +++ b/server/src/modules/page/page.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { PageController } from './page.controller'; +import { Page } from './page.entity'; +import { PageService } from './page.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Page]), AuthModule], + exports: [PageService], + providers: [PageService], + controllers: [PageController], +}) +export class PageModule {} diff --git a/server/src/modules/page/page.service.ts b/server/src/modules/page/page.service.ts new file mode 100644 index 0000000..1863cc4 --- /dev/null +++ b/server/src/modules/page/page.service.ts @@ -0,0 +1,112 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { dateFormat } from '../../utils/date.util'; +import { Page } from './page.entity'; + +@Injectable() +export class PageService { + constructor( + @InjectRepository(Page) + private readonly pageRepository: Repository + ) {} + + /** + * 新建页面 + * @param page + */ + async create(page: Partial): Promise { + const { path } = page; + const exist = await this.pageRepository.findOne({ where: { path } }); + + if (exist) { + throw new HttpException('页面已存在', HttpStatus.BAD_REQUEST); + } + + const newPage = await this.pageRepository.create({ + ...page, + }); + await this.pageRepository.save(newPage); + return newPage; + } + + /** + * 获取所有页面 + */ + async findAll(queryParams): Promise<[Page[], number]> { + const query = this.pageRepository.createQueryBuilder('page').orderBy('publishAt', 'DESC'); + + if (typeof queryParams === 'object') { + const { page = 1, pageSize = 12, status, ...otherParams } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (status) { + query.andWhere('page.status=:status').setParameter('status', status); + } + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`page.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + } + + return query.getManyAndCount(); + } + + /** + * 获取指定页面信息 + * @param id + */ + async findById(id): Promise { + const query = this.pageRepository + .createQueryBuilder('page') + .where('page.id=:id') + .orWhere('page.path=:path') + .setParameter('id', id) + .setParameter('path', id); + + return query.getOne(); + } + + /** + * 更新指定文章阅读量 + 1 + * @param id + * @param article + */ + async updateViewsById(id): Promise { + const old = await this.pageRepository.findOne(id); + const newData = await this.pageRepository.merge(old, { + views: old.views + 1, + }); + return this.pageRepository.save(newData); + } + + /** + * 更新指定页面 + * @param id + * @param article + */ + async updateById(id, page: Partial): Promise { + const old = await this.pageRepository.findOne(id); + const { status } = page; + + const newPage = { + ...page, + publishAt: status === 'publish' ? dateFormat() : old && old.publishAt, + }; + + const updatedPage = await this.pageRepository.merge(old, newPage); + return this.pageRepository.save(updatedPage); + } + + /** + * 删除页面 + * @param id + */ + async deleteById(id) { + const page = await this.pageRepository.findOne(id); + return this.pageRepository.remove(page); + } +} diff --git a/server/src/modules/search/search.controller.ts b/server/src/modules/search/search.controller.ts new file mode 100644 index 0000000..9672f2a --- /dev/null +++ b/server/src/modules/search/search.controller.ts @@ -0,0 +1,43 @@ +import { Controller, Delete, Get, Param, Query, UseGuards } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { SearchService } from './search.service'; + +@ApiTags('Search') +@Controller('search') +@UseGuards(RolesGuard) +export class SearchController { + constructor(private readonly searchService: SearchService) {} + + /** + * 搜索文章 + * @param keyword + */ + @Get('/article') + async searchArticle(@Query('keyword') keyword) { + const data = await this.searchService.searchArticle('article', keyword); + return data; + } + + /** + * 获取搜索记录 + */ + @Get('/') + @UseGuards(JwtAuthGuard) + async findAll(@Query() queryParam) { + return this.searchService.findAll(queryParam); + } + + /** + * 删除文件 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.searchService.deleteById(id); + } +} diff --git a/server/src/modules/search/search.entity.ts b/server/src/modules/search/search.entity.ts new file mode 100644 index 0000000..7f9fc0d --- /dev/null +++ b/server/src/modules/search/search.entity.ts @@ -0,0 +1,37 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +@Entity() +export class Search { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column() + type: string; // 搜索类型 + + @ApiProperty() + @Column() + keyword: string; // 搜索关键词 + + @ApiProperty() + @Column({ default: 1 }) + count: number; + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/search/search.module.ts b/server/src/modules/search/search.module.ts new file mode 100644 index 0000000..8d70955 --- /dev/null +++ b/server/src/modules/search/search.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { ArticleModule } from '../article/article.module'; +import { AuthModule } from '../auth/auth.module'; +import { SearchController } from './search.controller'; +import { Search } from './search.entity'; +import { SearchService } from './search.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Search]), AuthModule, ArticleModule], + providers: [SearchService], + controllers: [SearchController], +}) +export class SearchModule {} diff --git a/server/src/modules/search/search.service.ts b/server/src/modules/search/search.service.ts new file mode 100644 index 0000000..b5c47b8 --- /dev/null +++ b/server/src/modules/search/search.service.ts @@ -0,0 +1,74 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { ArticleService } from '../article/article.service'; +import { Search } from './search.entity'; + +@Injectable() +export class SearchService { + constructor( + @InjectRepository(Search) + private readonly searchRepository: Repository, + private readonly articleService: ArticleService + ) {} + + /** + * 搜素文章 + * @param type + */ + async searchArticle(type, keyword) { + const articles = await this.articleService.search(keyword); + await this.addRecord(type, keyword); + return articles; + } + + async addRecord(type, keyword) { + const exist = await this.searchRepository.findOne({ + where: { type, keyword }, + }); + + if (exist) { + const count = exist.count; + const newData = await this.searchRepository.merge(exist, { + count: count + 1, + }); + await this.searchRepository.save(newData); + return newData; + } + + const newData = await this.searchRepository.create({ type, keyword }); + const d = await this.searchRepository.save(newData); + return d; + } + + /** + * 获取所有搜索记录 + */ + async findAll(queryParams): Promise<[Search[], number]> { + const query = this.searchRepository.createQueryBuilder('search').orderBy('search.updateAt', 'DESC'); + + if (typeof queryParams === 'object') { + const { page = 1, pageSize = 12, ...otherParams } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`search.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + } + + return query.getManyAndCount(); + } + + /** + * 删除搜索记录 + * @param id + */ + async deleteById(id) { + const data = await this.searchRepository.findOne(id); + return this.searchRepository.remove(data); + } +} diff --git a/server/src/modules/setting/setting.constant.ts b/server/src/modules/setting/setting.constant.ts new file mode 100644 index 0000000..1f38e35 --- /dev/null +++ b/server/src/modules/setting/setting.constant.ts @@ -0,0 +1,29 @@ +import { config } from '@fecommunity/reactpress-toolkit'; + +/** + * 国际化配置 + */ +export { messages as i18n } from '@fecommunity/reactpress-toolkit/config'; + +/** + * 全局配置 + */ +export const settings = config.globalSetting; + +export const UNPROTECTED_KEYS = [ + 'i18n', + 'systemUrl', + 'adminSystemUrl', + 'systemTitle', + 'systemSubTitle', + 'systemBg', + 'systemLogo', + 'systemFavicon', + 'systemNoticeInfo', + 'systemFooterInfo', + 'seoKeyword', + 'seoDesc', + 'baiduAnalyticsId', + 'googleAnalyticsId', + 'globalSetting', +]; \ No newline at end of file diff --git a/server/src/modules/setting/setting.controller.ts b/server/src/modules/setting/setting.controller.ts new file mode 100644 index 0000000..f5c2f53 --- /dev/null +++ b/server/src/modules/setting/setting.controller.ts @@ -0,0 +1,57 @@ +import { Body, Controller, HttpCode, HttpStatus, Post, Request, UseGuards } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { User } from '../user/user.entity'; +import { UserService } from '../user/user.service'; +import { Setting } from './setting.entity'; +import { SettingService } from './setting.service'; + +@ApiTags('Setting') +@Controller('setting') +@UseGuards(RolesGuard) +export class SettingController { + constructor( + private readonly settingService: SettingService, + private readonly jwtService: JwtService, + private readonly userService: UserService + ) {} + + /** + * 更新设置 + * @param tag + */ + @ApiResponse({ status: 200, description: '更新设置', type: [Setting] }) + @Post() + @Roles('admin') + @UseGuards(JwtAuthGuard) + update(@Body() setting) { + return this.settingService.update(setting); + } + + /** + * 获取设置 + */ + @Post('/get') + @HttpCode(HttpStatus.OK) + async findAll(@Request() req): Promise { + let token = req.headers.authorization; + + if (/Bearer/.test(token)) { + // 不需要 Bearer,否则验证失败 + token = token.split(' ').pop(); + } + + try { + const tokenUser = this.jwtService.decode(token) as User; + const id = tokenUser.id; + const exist = await this.userService.findById(id); + const isAdmin = id && exist.role === 'admin'; + return this.settingService.findAll(false, isAdmin); + } catch (e) { + return this.settingService.findAll(false, false); + } + } +} diff --git a/server/src/modules/setting/setting.entity.ts b/server/src/modules/setting/setting.entity.ts new file mode 100644 index 0000000..49d500e --- /dev/null +++ b/server/src/modules/setting/setting.entity.ts @@ -0,0 +1,109 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +@Entity() +export class Setting { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column({ type: 'text', default: null }) + i18n: string; // 国际化 + + @ApiProperty() + @Column({ type: 'text', default: null }) + globalSetting: string; // 导航设置 + + @ApiProperty() + @Column({ type: 'text', default: null }) + systemUrl: string; // 系统地址 + + @ApiProperty() + @Column({ type: 'text', default: null }) + systemTitle: string; // 系统标题 + + @ApiProperty() + @Column({ type: 'text', default: null }) + systemSubTitle: string; // 系统副标题 + + @ApiProperty() + @Column({ type: 'text', default: null }) + systemLogo: string; // 系统Logo + + @ApiProperty() + @Column({ type: 'text', default: null }) + systemBg: string; // 全局背景 + + @ApiProperty() + @Column({ type: 'text', default: null }) + systemFavicon: string; // 系统 favicon + + @ApiProperty() + @Column({ type: 'text', default: null }) + systemNoticeInfo: string; // 系统通知信息 + + @ApiProperty() + @Column({ type: 'text', default: null }) + systemFooterInfo: string; // 系统页脚 + + @ApiProperty() + @Column({ type: 'text', default: null }) + adminSystemUrl: string; // 后台系统地址 + + @ApiProperty() + @Column({ type: 'text', default: null }) + baiduAnalyticsId: string; // 百度统计id + + @ApiProperty() + @Column({ type: 'text', default: null }) + googleAnalyticsId: string; // 谷歌分析 id + + @ApiProperty() + @Column({ type: 'text', default: null }) + seoKeyword: string; // SEO 关键词 + + @ApiProperty() + @Column({ type: 'text', default: null }) + seoDesc: string; // SEO 描述 + + @ApiProperty() + @Column({ type: 'text', default: null }) + oss: string; // OSS 上传配置 + + @ApiProperty() + @Column({ type: 'text', default: null }) + smtpHost: string; // SMTP 地址 + + @ApiProperty() + @Column({ type: 'text', default: null }) + smtpPort: string; // SMTP 端口 + + @ApiProperty() + @Column({ type: 'text', default: null }) + smtpUser: string; // SMTP 用户 + + @ApiProperty() + @Column({ type: 'text', default: null }) + smtpPass: string; // SMTP 授权码 + + @ApiProperty() + @Column({ type: 'text', default: null }) + smtpFromUser: string; // SMTP 发件人 + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/setting/setting.module.ts b/server/src/modules/setting/setting.module.ts new file mode 100644 index 0000000..17cf8c3 --- /dev/null +++ b/server/src/modules/setting/setting.module.ts @@ -0,0 +1,16 @@ +import { forwardRef, Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { UserModule } from '../user/user.module'; +import { SettingController } from './setting.controller'; +import { Setting } from './setting.entity'; +import { SettingService } from './setting.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Setting]), forwardRef(() => UserModule), forwardRef(() => AuthModule)], + exports: [SettingService], + providers: [SettingService], + controllers: [SettingController], +}) +export class SettingModule {} diff --git a/server/src/modules/setting/setting.service.ts b/server/src/modules/setting/setting.service.ts new file mode 100644 index 0000000..d0e2d21 --- /dev/null +++ b/server/src/modules/setting/setting.service.ts @@ -0,0 +1,116 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import * as merge from 'deepmerge'; +import { Repository } from 'typeorm'; + +import { i18n, settings, UNPROTECTED_KEYS } from './setting.constant'; +import { Setting } from './setting.entity'; + +@Injectable() +export class SettingService { + constructor( + @InjectRepository(Setting) + private readonly settingRepository: Repository + ) { + this.initI18n(); + this.initGlobalConfig(); + } + + /** + * 初始化时加载 i18n 配置 + */ + async initI18n() { + try { + const items = await this.settingRepository.find(); + const target = (items && items[0]) || ({} as Setting); + + let data = {}; + try { + if (target.i18n) { + data = JSON.parse(target.i18n); + } + } catch (e) { + console.warn('[SettingService] Error parsing i18n from DB:', e); + data = {}; + } + + // Merge default i18n with data from DB + const mergedI18n = merge({}, i18n, data); + + // Only update if there's a change or if it's empty + const mergedI18nString = JSON.stringify(mergedI18n); + if (!target.i18n || target.i18n !== mergedI18nString) { + target.i18n = mergedI18nString; + await this.settingRepository.save(target); + console.log('[SettingService] i18n updated in database'); + } else { + console.log('[SettingService] i18n already up to date'); + } + } catch (error) { + console.error('[SettingService] Error in initI18n:', error); + throw error; + } + } + + /** + * 初始化时加载 nav 配置 + */ + async initGlobalConfig() { + const items = await this.settingRepository.find(); + const target = (items && items[0]) || ({} as Setting); + let data = {}; + try { + if (target.globalSetting) { + data = JSON.parse(target.globalSetting); + } + } catch (e) { + data = {}; + } + const mergedSettings = merge({}, settings, data); + const mergedSettingsString = JSON.stringify(mergedSettings); + + if (!target.globalSetting || target.globalSetting !== mergedSettingsString) { + target.globalSetting = mergedSettingsString; + await this.settingRepository.save(target); + } + } + + /** + * + * 获取系统设置 + * @param user + * @param innerInvoke + * @param isAdmin + */ + async findAll(innerInvoke = false, isAdmin = false): Promise { + const data = await this.settingRepository.find(); + const res = data[0]; + if (!res) { + return {} as Setting; + } + if (innerInvoke || isAdmin) { + return res; + } + const filterRes = UNPROTECTED_KEYS.reduce((a, c) => { + a[c] = res[c]; + return a; + }, {}) as Setting; + + return filterRes; + } + + /** + * 更新系统设置 + * @param id + * @param setting + */ + async update(setting: Partial): Promise { + const old = await this.settingRepository.find(); + + const updatedTag = + old && old[0] + ? await this.settingRepository.merge(old[0], setting) + : await this.settingRepository.create(setting); + return this.settingRepository.save(updatedTag); + } +} \ No newline at end of file diff --git a/server/src/modules/smtp/mail.util.ts b/server/src/modules/smtp/mail.util.ts new file mode 100644 index 0000000..03d37f7 --- /dev/null +++ b/server/src/modules/smtp/mail.util.ts @@ -0,0 +1,31 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const nodemailer = require('nodemailer'); + +export const sendEmail = (message, { host, port, user, pass }) => { + if (!host || !port || !user || !pass) { + console.log('邮箱配置不正确,无法发送邮件'); + return null; + } + + const transport = nodemailer.createTransport({ + host, + port, + secureConnection: true, + secure: true, + auth: { + user, + pass, + }, + }); + + return new Promise((resolve, reject) => { + transport.sendMail(message, function(err, info) { + if (err) { + console.log('发送邮件失败', err); + reject(err); + } else { + resolve(info); + } + }); + }); +}; diff --git a/server/src/modules/smtp/smtp.controller.ts b/server/src/modules/smtp/smtp.controller.ts new file mode 100644 index 0000000..452aebb --- /dev/null +++ b/server/src/modules/smtp/smtp.controller.ts @@ -0,0 +1,45 @@ +import { Body, Controller, Delete, Get, Param, Post, Query, UseGuards } from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { SMTP } from './smtp.entity'; +import { SMTPService } from './smtp.service'; + +@ApiTags('Smtp') +@Controller('smtp') +@UseGuards(RolesGuard) +export class SMTPController { + constructor(private readonly smtpService: SMTPService) {} + + /** + * 发送邮件 + * @param data + */ + @ApiResponse({ status: 200, description: '发送邮件', type: [SMTP] }) + @Post() + @UseGuards(JwtAuthGuard) + create(@Body() data) { + return this.smtpService.create(data); + } + + /** + * 获取所有邮件记录 + */ + @Get() + @UseGuards(JwtAuthGuard) + findAll(@Query() queryParam) { + return this.smtpService.findAll(queryParam); + } + + /** + * 删除邮件记录 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.smtpService.deleteById(id); + } +} diff --git a/server/src/modules/smtp/smtp.entity.ts b/server/src/modules/smtp/smtp.entity.ts new file mode 100644 index 0000000..7192062 --- /dev/null +++ b/server/src/modules/smtp/smtp.entity.ts @@ -0,0 +1,37 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm'; + +@Entity() +export class SMTP { + @ApiProperty() + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column({ type: 'text', default: null }) + from: string; // 发件人 + + @ApiProperty() + @Column({ type: 'text', default: null }) + to: string; // 收件人 + + @ApiProperty() + @Column({ type: 'text', default: null }) + subject: string; // 主题 + + @ApiProperty() + @Column({ type: 'text', default: null }) + text: string; // 文本内容 + + @ApiProperty() + @Column({ type: 'text', default: null }) + html: string; // html 内容 + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; +} diff --git a/server/src/modules/smtp/smtp.module.ts b/server/src/modules/smtp/smtp.module.ts new file mode 100644 index 0000000..452a15d --- /dev/null +++ b/server/src/modules/smtp/smtp.module.ts @@ -0,0 +1,16 @@ +import { forwardRef, Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { SettingModule } from '../setting/setting.module'; +import { SMTPController } from './smtp.controller'; +import { SMTP } from './smtp.entity'; +import { SMTPService } from './smtp.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([SMTP]), forwardRef(() => SettingModule), forwardRef(() => AuthModule)], + exports: [SMTPService], + controllers: [SMTPController], + providers: [SMTPService], +}) +export class SMTPModule {} diff --git a/server/src/modules/smtp/smtp.service.ts b/server/src/modules/smtp/smtp.service.ts new file mode 100644 index 0000000..da53532 --- /dev/null +++ b/server/src/modules/smtp/smtp.service.ts @@ -0,0 +1,69 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { SettingService } from '../setting/setting.service'; +import { sendEmail } from './mail.util'; +import { SMTP } from './smtp.entity'; + +@Injectable() +export class SMTPService { + constructor( + @InjectRepository(SMTP) + private readonly smtpRepository: Repository, + private readonly settingService: SettingService + ) {} + + /** + * 添加邮件,发送邮件并保存 + * @param SMTP + */ + async create(data: Partial): Promise { + const setting = await this.settingService.findAll(true); + const { smtpHost, smtpPort, smtpUser, smtpPass, smtpFromUser } = setting; + Object.assign(data, { + from: smtpFromUser, + }); + await sendEmail(data, { + host: smtpHost, + port: smtpPort, + user: smtpUser, + pass: smtpPass, + }).catch(() => { + throw new HttpException('邮件发送失败', HttpStatus.BAD_REQUEST); + }); + const newSMTP = await this.smtpRepository.create(data); + await this.smtpRepository.save(newSMTP); + return newSMTP; + } + + /** + * 获取所有邮件 + */ + async findAll(queryParams): Promise<[SMTP[], number]> { + const query = this.smtpRepository.createQueryBuilder('smtp').orderBy('smtp.createAt', 'DESC'); + + if (typeof queryParams === 'object') { + const { page = 1, pageSize = 12, ...otherParams } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`smtp.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + } + + return query.getManyAndCount(); + } + + /** + * 删除邮件 + * @param id + */ + async deleteById(id) { + const SMTP = await this.smtpRepository.findOne(id); + return this.smtpRepository.remove(SMTP); + } +} diff --git a/server/src/modules/tag/tag.controller.ts b/server/src/modules/tag/tag.controller.ts new file mode 100644 index 0000000..5de932e --- /dev/null +++ b/server/src/modules/tag/tag.controller.ts @@ -0,0 +1,75 @@ +import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { Tag } from './tag.entity'; +import { TagService } from './tag.service'; + +@ApiTags('Tag') +@Controller('tag') +@UseGuards(RolesGuard) +export class TagController { + constructor(private readonly tagService: TagService) {} + + /** + * 添加标签 + * @param tag + */ + @ApiResponse({ status: 200, description: '创建标签', type: [Tag] }) + @Post() + @Roles('admin') + @UseGuards(JwtAuthGuard) + create(@Body() tag) { + return this.tagService.create(tag); + } + + /** + * 获取所有标签 + */ + @Get() + findAll(@Query() queryParams): Promise { + return this.tagService.findAll(queryParams); + } + + /** + * 获取指定标签 + * @param id + */ + @Get(':id') + findById(@Param('id') id) { + return this.tagService.findById(id); + } + + /** + * 获取指定标签,包含相关文章信息 + * @param id + */ + @Get(':id/article') + getArticleById(@Param('id') id, @Query('status') status) { + return this.tagService.getArticleById(id, status); + } + + /** + * 更新标签 + * @param id + * @param tag + */ + @Patch(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + updateById(@Param('id') id, @Body() tag) { + return this.tagService.updateById(id, tag); + } + + /** + * 删除标签 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.tagService.deleteById(id); + } +} diff --git a/server/src/modules/tag/tag.entity.ts b/server/src/modules/tag/tag.entity.ts new file mode 100644 index 0000000..2998419 --- /dev/null +++ b/server/src/modules/tag/tag.entity.ts @@ -0,0 +1,41 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, ManyToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +import { Article } from '../article/article.entity'; + +@Entity() +export class Tag { + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column() + label: string; + + @ApiProperty() + @Column() + value: string; + + @ApiProperty() + @ManyToMany( + () => Article, + (article) => article.tags + ) + articles: Array
; + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/tag/tag.module.ts b/server/src/modules/tag/tag.module.ts new file mode 100644 index 0000000..c1adcc7 --- /dev/null +++ b/server/src/modules/tag/tag.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { TagController } from './tag.controller'; +import { Tag } from './tag.entity'; +import { TagService } from './tag.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Tag]), AuthModule], + exports: [TagService], + providers: [TagService], + controllers: [TagController], +}) +export class TagModule {} diff --git a/server/src/modules/tag/tag.service.ts b/server/src/modules/tag/tag.service.ts new file mode 100644 index 0000000..35d347a --- /dev/null +++ b/server/src/modules/tag/tag.service.ts @@ -0,0 +1,122 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { Tag } from './tag.entity'; + +@Injectable() +export class TagService { + constructor( + @InjectRepository(Tag) + private readonly tagRepository: Repository + ) {} + + /** + * 添加标签 + * @param tag + */ + async create(tag: Partial): Promise { + const { label } = tag; + const existTag = await this.tagRepository.findOne({ where: { label } }); + + if (existTag) { + throw new HttpException('标签已存在', HttpStatus.BAD_REQUEST); + } + + const newTag = await this.tagRepository.create(tag); + await this.tagRepository.save(newTag); + return newTag; + } + + /** + * 获取所有标签 + */ + async findAll(queryParams): Promise { + const { articleStatus } = queryParams; + const qb = this.tagRepository.createQueryBuilder('tag').orderBy('tag.createAt', 'ASC'); + + if (articleStatus) { + qb.leftJoinAndSelect('tag.articles', 'articles', 'articles.status=:status', { + status: articleStatus, + }); + } else { + qb.leftJoinAndSelect('tag.articles', 'articles'); + } + + const data = await qb.getMany(); + + data.forEach((d) => { + Object.assign(d, { articleCount: d.articles.length }); + delete d.articles; + }); + + return data; + } + + /** + * 获取指定标签 + * @param id + */ + async findById(id): Promise { + const data = await this.tagRepository + .createQueryBuilder('tag') + .where('tag.id=:id') + .orWhere('tag.label=:id') + .orWhere('tag.value=:id') + .setParameter('id', id) + .getOne(); + + return data; + } + + /** + * 获取指定标签信息,包含相关文章 + * @param id + */ + async getArticleById(id, status = null): Promise { + const data = await this.tagRepository + .createQueryBuilder('tag') + .leftJoinAndSelect('tag.articles', 'articles') + .orderBy('articles.updateAt', 'DESC') + .where('tag.id=:id') + .orWhere('tag.label=:id') + .orWhere('tag.value=:id') + .setParameter('id', id) + .getOne(); + + if (status) { + data.articles = data.articles.filter((a) => a.status === status); + return data; + } + return data; + } + + async findByIds(ids): Promise> { + return this.tagRepository.findByIds(ids); + } + + /** + * 更新标签 + * @param id + * @param tag + */ + async updateById(id, tag: Partial): Promise { + const oldTag = await this.tagRepository.findOne(id); + const updatedTag = await this.tagRepository.merge(oldTag, tag); + return this.tagRepository.save(updatedTag); + } + + /** + * 删除标签 + * @param id + */ + async deleteById(id) { + try { + const tag = await this.tagRepository.findOne(id); + await this.tagRepository.remove(tag); + return true; + } catch (e) { + throw new HttpException('删除失败,可能存在关联文章', HttpStatus.BAD_REQUEST); + } + } +} diff --git a/server/src/modules/user/user.controller.ts b/server/src/modules/user/user.controller.ts new file mode 100644 index 0000000..e4344f6 --- /dev/null +++ b/server/src/modules/user/user.controller.ts @@ -0,0 +1,105 @@ +import { + Body, + ClassSerializerInterceptor, + Controller, + Get, + HttpCode, + HttpException, + HttpStatus, + Post, + Query, + Request, + UseGuards, + UseInterceptors, +} from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { User } from './user.entity'; +import { UserService } from './user.service'; + +@ApiTags('User') +@Controller('user') +@UseGuards(RolesGuard) +export class UserController { + constructor(private readonly userService: UserService, private readonly jwtService: JwtService) {} + + @ApiResponse({ status: 200, description: '获取用户列表', type: [User] }) + @ApiResponse({ status: 403, description: '无权获取用户列表' }) + @UseInterceptors(ClassSerializerInterceptor) + @Get() + @Roles('admin') + @UseGuards(JwtAuthGuard) + findAll(@Query() query) { + return this.userService.findAll(query); + } + + /** + * 用户注册 + * @param user + */ + @ApiResponse({ status: 201, description: '创建用户', type: [User] }) + @UseInterceptors(ClassSerializerInterceptor) + @Post('register') + @HttpCode(HttpStatus.CREATED) + async register(@Body() user: Partial): Promise { + const d = await this.userService.createUser(user); + return d; + } + + async checkPermission(req, user) { + let token = req.headers.authorization; + + if (!token) { + throw new HttpException('未认证', HttpStatus.UNAUTHORIZED); + } + + if (/Bearer/.test(token)) { + // 不需要 Bearer,否则验证失败 + token = token.split(' ').pop(); + } + const tokenUser = this.jwtService.decode(token) as User; + const id = tokenUser.id; + + if (!id) { + throw new HttpException('未认证', HttpStatus.UNAUTHORIZED); + } + + const exist = await this.userService.findById(id); + if (exist.id !== user.id && exist.role !== 'admin') { + throw new HttpException('无权处理', HttpStatus.FORBIDDEN); + } + + req.user = tokenUser; + } + + /** + * 用户更新 + * @param user + */ + @ApiResponse({ status: 200, description: '更新用户成功', type: [User] }) + @UseInterceptors(ClassSerializerInterceptor) + @Post('update') + @HttpCode(HttpStatus.CREATED) + async update(@Request() req, @Body() user: Partial): Promise { + await this.checkPermission(req, user); + const d = await this.userService.updateById(req.user, user.id, user); + return d; + } + + /** + * 更新用户密码 + * @param user + */ + @ApiResponse({ status: 201, description: '更新密码成功', type: [User] }) + @UseInterceptors(ClassSerializerInterceptor) + @Post('password') + @HttpCode(HttpStatus.CREATED) + async updatePassword(@Request() req, @Body() user: Partial): Promise { + await this.checkPermission(req, user); + const d = await this.userService.updatePassword(user.id, user); + return d; + } +} diff --git a/server/src/modules/user/user.entity.ts b/server/src/modules/user/user.entity.ts new file mode 100644 index 0000000..dc50dd5 --- /dev/null +++ b/server/src/modules/user/user.entity.ts @@ -0,0 +1,76 @@ +import { ApiProperty } from '@nestjs/swagger'; +import * as bcrypt from 'bcryptjs'; +import { Exclude } from 'class-transformer'; +import { BeforeInsert, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +@Entity() +export class User { + /** + * 检测密码是否一致 + * @param password0 加密前密码 + * @param password1 加密后密码 + */ + static comparePassword(password0, password1) { + return bcrypt.compareSync(password0, password1); + } + + static encryptPassword(password) { + return bcrypt.hashSync(password, 10); + } + + @PrimaryGeneratedColumn('uuid') + id: number; + + @ApiProperty() + @Column({ length: 500 }) + name: string; + + @ApiProperty() + @Exclude() + @Column({ length: 500 }) + password: string; + + @ApiProperty() + @Column({ length: 500, default: null }) + avatar: string; // 头像 + + @ApiProperty() + @Column({ length: 500, default: null }) + email: string; // 邮箱 + + @ApiProperty() + @Column('simple-enum', { enum: ['admin', 'visitor'], default: 'visitor' }) + role: string; // 用户角色 + + @ApiProperty() + @Column('simple-enum', { enum: ['locked', 'active'], default: 'active' }) + status: string; // 用户状态 + + @ApiProperty() + @Column({ default: 'normal' }) + type: string; // 用户类型 + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; + + /** + * 插入数据前,对密码进行加密 + */ + @BeforeInsert() + encrypt() { + this.password = bcrypt.hashSync(this.password, 10); + } +} diff --git a/server/src/modules/user/user.module.ts b/server/src/modules/user/user.module.ts new file mode 100644 index 0000000..b9220e2 --- /dev/null +++ b/server/src/modules/user/user.module.ts @@ -0,0 +1,16 @@ +import { forwardRef, Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { UserController } from './user.controller'; +import { User } from './user.entity'; +import { UserService } from './user.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([User]), ConfigModule, forwardRef(() => AuthModule)], + providers: [UserService], + exports: [UserService], + controllers: [UserController], +}) +export class UserModule {} diff --git a/server/src/modules/user/user.service.ts b/server/src/modules/user/user.service.ts new file mode 100644 index 0000000..28fa4e6 --- /dev/null +++ b/server/src/modules/user/user.service.ts @@ -0,0 +1,201 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { InjectRepository } from '@nestjs/typeorm'; +import { FindManyOptions, Repository } from 'typeorm'; +import { isValidUsername } from '../../utils/user.util'; + +import { User } from './user.entity'; + +@Injectable() +export class UserService { + constructor( + @InjectRepository(User) + private readonly userRepository: Repository, + private readonly configService: ConfigService + ) { + const name = this.configService.get('ADMIN_USER', 'admin'); + const password = this.configService.get('ADMIN_PASSWD', 'admin'); + + this.createUser({ name, password, role: 'admin' }, true) + .then(() => { + console.log(`[reactpress] 管理员账户创建成功,用户名:${name},密码:${password},请及时登录系统修改默认密码`); + }) + .catch(async (e) => { + const existAdminUser = await this.userRepository.findOne({ where: { name } }); + const isDefaultPasswd = User.comparePassword(password, existAdminUser.password); + if (isDefaultPasswd) { + console.log(`[reactpress] 管理员账户已经存在,用户名:${name},密码:${password},请及时登录系统修改默认密码`); + } + }); + } + + async findByConditions(conditions: Partial) { + return await this.userRepository.findOne(conditions); + } + + async findAll(queryParams): Promise<[User[], number]> { + const query = this.userRepository.createQueryBuilder('user').orderBy('user.createAt', 'DESC'); + + if (typeof queryParams === 'object') { + const { page = 1, pageSize = 12, status, ...otherParams } = queryParams; + + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (status) { + query.andWhere('user.status=:status').setParameter('status', status); + } + + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`user.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + } + + return query.getManyAndCount(); + } + + /** + * 创建用户 + * @param user 用户模型 + * @param ignoreValidator 是否忽略名称校验 + */ + async createUser(user: Partial, ignoreValidator?: boolean): Promise { + const { name, password } = user; + + // 如果忽略了名称校验,来自于系统内部默认的注入 + if (!ignoreValidator) { + if (!name || !password) { + throw new HttpException('请输入用户名和密码', HttpStatus.BAD_REQUEST); + } + + // 防止用户名称非法 + if (!isValidUsername(name)) { + throw new HttpException('用户名不能包含空格和非法字符', HttpStatus.BAD_REQUEST); + } + } + + const existUser = await this.userRepository.findOne({ where: { name } }); + + if (existUser) { + throw new HttpException('用户已存在', HttpStatus.BAD_REQUEST); + } + + const newUser = await this.userRepository.create(user); + await this.userRepository.save(newUser); + return newUser; + } + + /** + * 用户登录 + * @param user + */ + async login(user: Partial): Promise { + const { name, password } = user; + const existUser = await this.userRepository.findOne({ where: { name } }); + + if (!existUser || !(await User.comparePassword(password, existUser.password))) { + throw new HttpException( + '用户名或密码错误', + // tslint:disable-next-line: trailing-comma + HttpStatus.BAD_REQUEST + ); + } + + if (existUser.status === 'locked') { + throw new HttpException( + '用户已锁定,无法登录', + // tslint:disable-next-line: trailing-comma + HttpStatus.BAD_REQUEST + ); + } + + delete existUser.password; + + return existUser; + } + + /** + * 无密码登录 + * @param user + */ + async loginWithoutPasswd(user: Partial): Promise { + const { name } = user; + const existUser = await this.userRepository.findOne({ where: { name } }); + + if (existUser.status === 'locked') { + throw new HttpException( + '用户已锁定,无法登录', + // tslint:disable-next-line: trailing-comma + HttpStatus.BAD_REQUEST + ); + } + + delete existUser.password; + + return existUser; + } + + /** + * 获取指定用户 + * @param id + */ + async findById(id): Promise { + return this.userRepository.findOne(id); + } + + /** + * 更新指定用户 + * @param id + */ + async updateById(currentUser, id, user): Promise { + if (user.role === 'admin') { + if (!currentUser || currentUser.role !== 'admin') { + throw new HttpException( + '您无权操作', + // tslint:disable-next-line: trailing-comma + HttpStatus.FORBIDDEN + ); + } + } + + const oldUser = await this.userRepository.findOne(id); + delete user.password; + + if (user.name && user.name !== oldUser.name) { + const existUser = await this.userRepository.findOne({ where: { name: user.name } }); + + if (existUser) { + throw new HttpException('用户已存在', HttpStatus.BAD_REQUEST); + } + } + + const newUser = await this.userRepository.merge(oldUser, user); + return this.userRepository.save(newUser); + } + + /** + * 更新指定用户密码 + * @param id + */ + async updatePassword(id, user): Promise { + const existUser = await this.userRepository.findOne(id); + const { oldPassword, newPassword } = user; + + if (!existUser || !(await User.comparePassword(oldPassword, existUser.password))) { + throw new HttpException( + '用户名或密码错误', + // tslint:disable-next-line: trailing-comma + HttpStatus.BAD_REQUEST + ); + } + + const hashNewPassword = User.encryptPassword(newPassword); + const newUser = await this.userRepository.merge(existUser, { + password: hashNewPassword, + }); + const d = await this.userRepository.save(newUser); + return d; + } +} diff --git a/server/src/modules/view/view.controller.ts b/server/src/modules/view/view.controller.ts new file mode 100644 index 0000000..fffa3d9 --- /dev/null +++ b/server/src/modules/view/view.controller.ts @@ -0,0 +1,66 @@ +import { Body, Controller, Delete, Get, Param, Post, Query, Request, UseGuards } from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { getClientIP } from '../../utils/ip.util'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; +import { Roles, RolesGuard } from '../auth/roles.guard'; +import { View } from './view.entity'; +import { ViewService } from './view.service'; + +@ApiTags('View') +@Controller('view') +@UseGuards(RolesGuard) +export class ViewController { + constructor(private readonly viewService: ViewService) {} + + /** + * 添加访问 + * @param tag + */ + @ApiResponse({ status: 200, description: '访问记录添加成功', type: [View] }) + @Post() + create(@Request() req, @Body() data) { + const userAgent = req.headers['user-agent']; + const url = data.url; + return this.viewService.create(getClientIP(req), userAgent, url); + } + + /** + * 获取所有访问 + */ + @Get() + @UseGuards(JwtAuthGuard) + findAll(@Query() queryParam) { + return this.viewService.findAll(queryParam); + } + + /** + * 获取指定访问 + * @param id + */ + @Get('/url') + findByUrl(@Query('url') url) { + return this.viewService.findByUrl(url); + } + + /** + * 获取指定访问 + * @param id + */ + @Get(':id') + @UseGuards(JwtAuthGuard) + findById(@Param('id') id) { + return this.viewService.findById(id); + } + + /** + * 删除访问 + * @param id + */ + @Delete(':id') + @Roles('admin') + @UseGuards(JwtAuthGuard) + deleteById(@Param('id') id) { + return this.viewService.deleteById(id); + } +} diff --git a/server/src/modules/view/view.entity.ts b/server/src/modules/view/view.entity.ts new file mode 100644 index 0000000..acaceef --- /dev/null +++ b/server/src/modules/view/view.entity.ts @@ -0,0 +1,60 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; + +@Entity() +export class View { + @PrimaryGeneratedColumn('uuid') + id: string; + + @ApiProperty() + @Column() + ip: string; + + @ApiProperty() + @Column({ type: 'text', default: null }) + userAgent: string; + + @ApiProperty() + @Column({ type: 'text', default: null }) + url: string; + + @ApiProperty() + @Column({ default: 1 }) + count: number; // 同一 userAgent ,同一 url 的访问量 + + @ApiProperty() + @Column({ type: 'text', default: null }) + address: string; // 访问地址 + + @ApiProperty() + @Column({ type: 'text', default: null }) + browser: string; // 访问浏览器 + + @ApiProperty() + @Column({ type: 'text', default: null }) + engine: string; // 访问的浏览器内核 + + @ApiProperty() + @Column({ type: 'text', default: null }) + os: string; // 访问操作系统 + + @ApiProperty() + @Column({ type: 'text', default: null }) + device: string; // 访问设备 + + @ApiProperty() + @CreateDateColumn({ + type: 'datetime', + comment: '创建时间', + name: 'create_at', + }) + createAt: Date; + + @ApiProperty() + @UpdateDateColumn({ + type: 'datetime', + comment: '更新时间', + name: 'update_at', + }) + updateAt: Date; +} diff --git a/server/src/modules/view/view.module.ts b/server/src/modules/view/view.module.ts new file mode 100644 index 0000000..d749a10 --- /dev/null +++ b/server/src/modules/view/view.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from '../auth/auth.module'; +import { ViewController } from './view.controller'; +import { View } from './view.entity'; +import { ViewService } from './view.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([View]), AuthModule], + exports: [ViewService], + providers: [ViewService], + controllers: [ViewController], +}) +export class ViewModule {} diff --git a/server/src/modules/view/view.service.ts b/server/src/modules/view/view.service.ts new file mode 100644 index 0000000..7f06c8d --- /dev/null +++ b/server/src/modules/view/view.service.ts @@ -0,0 +1,86 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { parseIp } from '../../utils/ip.util'; +import { parseUserAgent } from '../../utils/ua.util'; +import { View } from './view.entity'; + +@Injectable() +export class ViewService { + constructor( + @InjectRepository(View) + private readonly viewRepository: Repository + ) {} + + /** + * 添加访问 + * @param tag + */ + async create(ip: string, userAgent: string, url: string): Promise { + const exist = await this.viewRepository.findOne({ + where: { ip, userAgent, url }, + }); + if (exist) { + const count = exist.count; + const newData = await this.viewRepository.merge(exist, { + count: count + 1, + }); + await this.viewRepository.save(newData); + return newData; + } + const { data: uaInfo } = parseUserAgent(userAgent); + const address = parseIp(ip); + const newData = await this.viewRepository.create({ ip, userAgent, url, address, ...uaInfo }); + await this.viewRepository.save(newData); + return newData; + } + + /** + * 获取所有访问 + */ + async findAll(queryParams): Promise<[View[], number]> { + const query = this.viewRepository.createQueryBuilder('view').orderBy('view.createAt', 'DESC'); + if (typeof queryParams === 'object') { + const { page = 1, pageSize = 12, ...otherParams } = queryParams; + query.skip((+page - 1) * +pageSize); + query.take(+pageSize); + + if (otherParams) { + Object.keys(otherParams).forEach((key) => { + query.andWhere(`view.${key} LIKE :${key}`).setParameter(`${key}`, `%${otherParams[key]}%`); + }); + } + } + + return query.getManyAndCount(); + } + + /** + * 查找指定路径访问统计 + * @param url + */ + async findByUrl(url): Promise { + return this.viewRepository.find({ + where: { url }, + order: { updateAt: 'ASC' }, + }); + } + + /** + * 获取指定访问 + * @param id + */ + async findById(id): Promise { + return this.viewRepository.findOne(id); + } + + /** + * 删除访问量 + * @param id + */ + async deleteById(id) { + const data = await this.viewRepository.findOne(id); + return this.viewRepository.remove(data); + } +} diff --git a/server/src/starter.ts b/server/src/starter.ts new file mode 100644 index 0000000..c3d02b0 --- /dev/null +++ b/server/src/starter.ts @@ -0,0 +1,103 @@ +import { NestFactory } from '@nestjs/core'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import * as bodyParser from 'body-parser'; +import * as compression from 'compression'; +import * as express from 'express'; +import * as rateLimit from 'express-rate-limit'; +import * as helmet from 'helmet'; +import { join } from 'path'; +import { SwaggerTheme, SwaggerThemeNameEnum } from 'swagger-themes'; + +import { AppModule } from './app.module'; +import { HttpExceptionFilter } from './filters/http-exception.filter'; +import { TransformInterceptor } from './interceptors/transform.interceptor'; + +export async function bootstrap() { + try { + const app = await NestFactory.create(AppModule); + const configService = app.get('ConfigService'); + + app.enableCors(); + app.setGlobalPrefix(configService.get('SERVER_API_PREFIX', '/api')); + + app.use( + rateLimit({ + windowMs: 60 * 1000, + max: 10000, + }) + ); + + const rootDir = join(__dirname, '../public'); + app.use('/public', express.static(rootDir)); + + app.use(compression()); + app.use(helmet()); + app.useGlobalInterceptors(new TransformInterceptor()); + app.useGlobalFilters(new HttpExceptionFilter()); + app.use(bodyParser.json({ limit: '10mb' })); + app.use(bodyParser.urlencoded({ limit: '10mb', extended: true })); + + // 增强版 Swagger 配置 + const swaggerConfig = new DocumentBuilder() + .setTitle('ReactPress API Documentation') + .setDescription('Comprehensive API documentation for ReactPress - A modern content management system built with NestJS') + .setVersion('2.0') + .setContact('ReactPress Team', 'https://github.com/fecommunity/reactpress', 'admin@gaoredu.com') + .setLicense('MIT', 'https://github.com/fecommunity/reactpress/blob/main/LICENSE') + .addServer(configService.get('SERVER_SITE_URL', 'http://localhost:3002'), 'API Server') + .build(); + + const document = SwaggerModule.createDocument(app, swaggerConfig); + + // 使用 swagger-themes 提供专业主题 + const theme = new SwaggerTheme(); + + // 自定义 Swagger 设置 + const options = { + customCss: theme.getBuffer(SwaggerThemeNameEnum.MATERIAL), // 应用主题 + customSiteTitle: 'ReactPress API Documentation', + customfavIcon: '/public/favicon.png', + swaggerOptions: { + docExpansion: 'list', + filter: true, + showRequestDuration: true, + persistAuthorization: true, // 保持授权数据 + displayOperationId: true, + operationsSorter: 'method', // 按方法排序 + tagsSorter: 'alpha', // 按字母顺序排序标签 + }, + customCssUrl: '/public/swagger/custom.css', // 额外的自定义CSS + }; + + // 设置 Swagger UI + SwaggerModule.setup('api', app, document, options); + + const configuredPort = configService.get('SERVER_PORT', 3002); + + await app.listen(configuredPort); + console.log(`[ReactPress] Application started on http://localhost:${configuredPort}`); + console.log(`[ReactPress] API Documentation available at http://localhost:${configuredPort}/api`); + + return app; + + } catch (error) { + console.error('[ReactPress] Failed to start application:', error); + + if (error.code === 'EADDRINUSE') { + console.error('[ReactPress] Port is already in use. Please check for other running instances.'); + console.error('[ReactPress] You can change the port in your .env file or terminate the conflicting process.'); + } + + throw error; + } +} + +process.on('SIGINT', () => { + console.log('\n[ReactPress] Application shutting down gracefully...'); + process.exit(0); +}); + +process.on('SIGTERM', () => { + console.log('\n[ReactPress] Application shutting down gracefully...'); + process.exit(0); +}); \ No newline at end of file diff --git a/server/src/utils/date.util.ts b/server/src/utils/date.util.ts new file mode 100644 index 0000000..e95825a --- /dev/null +++ b/server/src/utils/date.util.ts @@ -0,0 +1,11 @@ +import { format as dateFormatFn } from 'date-fns'; + +export const dateFormat = (date = null, format = 'yyyy-MM-dd HH:mm:ss') => { + if (date === null || date === undefined) { + date = new Date(); // eslint-disable-line no-param-reassign + } + + const t = date instanceof Date ? date : new Date(date); + + return dateFormatFn(t, format); +}; diff --git a/server/src/utils/ip.util.ts b/server/src/utils/ip.util.ts new file mode 100644 index 0000000..56ef98d --- /dev/null +++ b/server/src/utils/ip.util.ts @@ -0,0 +1,25 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const ipSearcher = require('node-ip2region').create(); + +export function getClientIP(req) { + const ip = + req.headers['x-real-ip'] || + req.headers['x-forwarded-for'] || // 判断是否有反向代理 IP + (req.connection && req.connection.remoteAddress) || // 判断 connection 的远程 IP + (req.socket && req.socket.remoteAddress) || // 判断后端的 socket 的 IP + (req.connection && req.connection.socket && req.connection.socket.remoteAddress); + + return ip ? ip.split(':').pop() : ''; +} + +export function parseIp(ip) { + try { + const { region } = ipSearcher.btreeSearchSync(ip); + return region + .split('|') + .filter((d) => +d !== 0) + .join(' '); + } catch (e) { + return ''; + } +} diff --git a/server/src/utils/markdown.util.ts b/server/src/utils/markdown.util.ts new file mode 100644 index 0000000..e9a9656 --- /dev/null +++ b/server/src/utils/markdown.util.ts @@ -0,0 +1,46 @@ +import * as hljs from 'highlight.js'; +import * as Marked from 'marked'; + +const renderer = new Marked.Renderer(); + +renderer.heading = (text, level) => { + const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); + + return ` + + + + + ${text} +`; +}; + +Marked.setOptions({ + highlight(code: string, lang: string) { + if (hljs.getLanguage(lang)) { + return hljs.highlight(lang, code).value; + } + return hljs.highlightAuto(code).value; + }, + renderer, +}); + +export const marked = (content: string): { html: string; toc: string } => { + const toc = []; + + renderer.heading = (text: string, level: number) => { + const anchor = 'heading-' + toc.length; + + toc.push([level, anchor, text]); + return `${text}`; + }; + + const marked = (text: string) => { + const tok = Marked.lexer(text); + text = Marked.parser(tok).replace(/
/gi, '
'); // eslint-disable-line no-param-reassign
+    return text;
+  };
+
+  const html = marked(content);
+  return { html, toc: JSON.stringify(toc, null, 2) };
+};
diff --git a/server/src/utils/oss.util.ts b/server/src/utils/oss.util.ts
new file mode 100644
index 0000000..6ed91f5
--- /dev/null
+++ b/server/src/utils/oss.util.ts
@@ -0,0 +1,59 @@
+import { HttpException, HttpStatus } from '@nestjs/common';
+
+import { SettingService } from '../modules/setting/setting.service';
+import { AliyunOssClient } from './oss/aliyun-oss-client';
+import { OssClient } from './oss/oss-client';
+
+export class Oss {
+  settingService: SettingService;
+  config: Record;
+  ossClient: OssClient;
+
+  constructor(settingService: SettingService) {
+    this.settingService = settingService;
+  }
+
+  /**
+   * 是否有OSS的配置
+   */
+  public async hasOssConfig() {
+    try {
+      const data = await this.settingService.findAll(true);
+      const config = JSON.parse(data.oss);
+      return !!config;
+    } catch (e) {
+      return false;
+    }
+  }
+
+  private async getConfig() {
+    const data = await this.settingService.findAll(true);
+    const config = JSON.parse(data.oss);
+    if (!config) {
+      throw new HttpException('OSS 配置不完善,无法进行操作', HttpStatus.BAD_REQUEST);
+    }
+    return config as Record;
+  }
+
+  private async getOssClient() {
+    const config = await this.getConfig();
+    const type = String(config.type).toLowerCase();
+
+    switch (type) {
+      case 'aliyun':
+      default:
+        return new AliyunOssClient(config);
+    }
+  }
+
+  async putFile(filepath: string, buffer: ReadableStream) {
+    const client = await this.getOssClient();
+    const url = await client.putFile(filepath, buffer);
+    return url;
+  }
+
+  async deleteFile(url: string) {
+    const client = await this.getOssClient();
+    await client.deleteFile(url);
+  }
+}
diff --git a/server/src/utils/oss/aliyun-oss-client.ts b/server/src/utils/oss/aliyun-oss-client.ts
new file mode 100644
index 0000000..116a7aa
--- /dev/null
+++ b/server/src/utils/oss/aliyun-oss-client.ts
@@ -0,0 +1,27 @@
+import * as AliyunOSS from 'ali-oss';
+
+import { OssClient } from './oss-client';
+
+export class AliyunOssClient extends OssClient {
+  private async buildClient() {
+    const config = this.config;
+    return new AliyunOSS({
+      region: config.region,
+      accessKeyId: config.accessKeyId,
+      accessKeySecret: config.accessKeySecret,
+      bucket: config.bucket,
+      secure: config.https,
+    });
+  }
+
+  async putFile(filepath: string, buffer: ReadableStream) {
+    const client = await this.buildClient();
+    const { url } = await client.put(filepath, buffer);
+    return url;
+  }
+
+  async deleteFile(url: string) {
+    const client = await this.buildClient();
+    await client.delete(url);
+  }
+}
diff --git a/server/src/utils/oss/oss-client.ts b/server/src/utils/oss/oss-client.ts
new file mode 100644
index 0000000..874b00b
--- /dev/null
+++ b/server/src/utils/oss/oss-client.ts
@@ -0,0 +1,10 @@
+export abstract class OssClient {
+  config: Record;
+
+  constructor(config) {
+    this.config = config;
+  }
+
+  abstract putFile(filepath: string, buffer: ReadableStream): Promise;
+  abstract deleteFile(url: string): Promise;
+}
diff --git a/server/src/utils/ua.util.ts b/server/src/utils/ua.util.ts
new file mode 100644
index 0000000..bd9c3de
--- /dev/null
+++ b/server/src/utils/ua.util.ts
@@ -0,0 +1,36 @@
+import * as get from 'lodash/get';
+import * as UAParser from 'ua-parser-js';
+
+const keys = [
+  'browser.name',
+  'browser.version',
+  'engine.name',
+  'engine.version',
+  'os.name',
+  'os.version',
+  'device.vendor',
+  'device.model',
+  'device.type',
+];
+
+const joinMsg = (ua, keys) =>
+  keys
+    .map((key) => get(ua, key))
+    .filter(Boolean)
+    .join(' ');
+
+export const parseUserAgent = (userAgent) => {
+  const uaparser = new UAParser();
+  uaparser.setUA(userAgent);
+  const ua = uaparser.getResult();
+
+  return {
+    data: {
+      browser: joinMsg(ua, keys.slice(0, 2)),
+      engine: joinMsg(ua, keys.slice(2, 4)),
+      os: joinMsg(ua, keys.slice(4, 6)),
+      device: joinMsg(ua, keys.slice(6)),
+    },
+    text: joinMsg(ua, keys),
+  };
+};
diff --git a/server/src/utils/uniqueid.util.ts b/server/src/utils/uniqueid.util.ts
new file mode 100644
index 0000000..f0e0823
--- /dev/null
+++ b/server/src/utils/uniqueid.util.ts
@@ -0,0 +1,5 @@
+import { next } from 'nuid';
+
+export function uniqueid() {
+  return next();
+}
diff --git a/server/src/utils/upload.util.ts b/server/src/utils/upload.util.ts
new file mode 100644
index 0000000..62eceab
--- /dev/null
+++ b/server/src/utils/upload.util.ts
@@ -0,0 +1,34 @@
+import * as fs from 'fs';
+import * as path from 'path';
+
+export class LocalUpload {
+  // 递归创建目录 同步方法
+  private mkdDirsSync(dirname) {
+    if (fs.existsSync(dirname)) {
+      return true;
+    } else {
+      if (this.mkdDirsSync(path.dirname(dirname))) {
+        fs.mkdirSync(dirname);
+        return true;
+      }
+    }
+  }
+
+  public putFile(filename, buffer: ReadableStream) {
+    const saveFile = path.join(__dirname, `../../public/uploads/${filename}`);
+    const dirName = path.dirname(saveFile);
+    // 递归创建目录
+    this.mkdDirsSync(dirName);
+    // 创建文件
+    fs.writeFileSync(saveFile, buffer);
+    return saveFile;
+  }
+
+  public deleteFile(filename) {
+    const saveFileFolder = path.join(__dirname, '../../public/uploads');
+    const filePath = `${saveFileFolder}/${filename}`;
+    if (fs.existsSync(filePath)) {
+      fs.unlinkSync(filePath);
+    }
+  }
+}
diff --git a/server/src/utils/user.util.ts b/server/src/utils/user.util.ts
new file mode 100644
index 0000000..5976f55
--- /dev/null
+++ b/server/src/utils/user.util.ts
@@ -0,0 +1,16 @@
+export function isValidUsername(username) {
+  // 字符限制,只允许字母、数字、下划线
+  var reg = /^[a-zA-Z0-9_]+$/;
+  if (!reg.test(username)) {
+    return false;
+  }
+  // 空格限制
+  if (/\s/.test(username)) {
+    return false;
+  }
+  // 敏感词限制,这里假设不允许包含 admin、root 等词汇
+  if (username.indexOf('admin') >= 0 || username.indexOf('root') >= 0) {
+    return false;
+  }
+  return true;
+}
diff --git a/server/tsconfig.build.json b/server/tsconfig.build.json
new file mode 100644
index 0000000..64f86c6
--- /dev/null
+++ b/server/tsconfig.build.json
@@ -0,0 +1,4 @@
+{
+  "extends": "./tsconfig.json",
+  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
+}
diff --git a/server/tsconfig.json b/server/tsconfig.json
new file mode 100644
index 0000000..27e5a48
--- /dev/null
+++ b/server/tsconfig.json
@@ -0,0 +1,21 @@
+{
+  "compilerOptions": {
+    "module": "commonjs",
+    "declaration": true,
+    "removeComments": true,
+    "emitDecoratorMetadata": true,
+    "experimentalDecorators": true,
+    "skipLibCheck": true,
+    "target": "es2017",
+    "sourceMap": true,
+    "outDir": "./dist",
+    "baseUrl": "./",
+    "incremental": true,
+    "typeRoots": ["./node_modules/@types"],
+    "paths": {
+      "@fecommunity/reactpress-toolkit": ["../toolkit/dist"],
+      "@fecommunity/reactpress-toolkit/*": ["../toolkit/dist/*"]
+    }
+  },
+  "exclude": ["node_modules", "dist"]
+}
\ No newline at end of file
diff --git a/server/tslint.json b/server/tslint.json
new file mode 100644
index 0000000..5651b2f
--- /dev/null
+++ b/server/tslint.json
@@ -0,0 +1,18 @@
+{
+  "defaultSeverity": "error",
+  "extends": ["tslint:recommended"],
+  "jsRules": {
+    "no-unused-expression": true
+  },
+  "rules": {
+    "quotemark": [true, "single"],
+    "member-access": [false],
+    "ordered-imports": [false],
+    "max-line-length": [true, 150],
+    "member-ordering": [false],
+    "interface-name": [false],
+    "arrow-parens": false,
+    "object-literal-sort-keys": false
+  },
+  "rulesDirectory": []
+}
diff --git a/toolkit/scripts/generate-swagger.js b/toolkit/scripts/generate-swagger.js
index b2e7cf3..fec4cc3 100755
--- a/toolkit/scripts/generate-swagger.js
+++ b/toolkit/scripts/generate-swagger.js
@@ -9,7 +9,7 @@ const bundledServerDir = getBundledServerPathForGenerate();
 const swaggerPath = getSwaggerInputPath();
 
 try {
-  console.log('1️⃣ Generating Swagger JSON via @fecommunity/reactpress-cli bundled server...');
+  console.log('1️⃣ Generating Swagger JSON from monorepo server/ …');
   try {
     execSync('npm run generate:swagger', { cwd: bundledServerDir, stdio: 'inherit' });
     console.log('✅ Swagger JSON generated successfully!\n');
@@ -19,7 +19,7 @@ try {
 
   if (!existsSync(swaggerPath)) {
     console.error(`❌ No swagger.json at ${swaggerPath}`);
-    console.error('   Ensure @fecommunity/reactpress-cli is installed (pnpm install).');
+    console.error('   Run: pnpm run generate:swagger (requires server/ and .env).');
     process.exit(1);
   }
   console.log(`✅ Using swagger.json from ${swaggerPath}\n`);

From 96ff92cad3d514f8d8a02445f46521da0c0fcb59 Mon Sep 17 00:00:00 2001
From: m0_37981569 
Date: Tue, 5 May 2026 23:00:00 +0800
Subject: [PATCH 05/20] chore: enhance project initialization and development
 scripts, add environment checks, and update documentation for improved user
 experience

---
 .reactpress/server.pid              |   1 -
 README-zh_CN.md                     |   6 +-
 README.md                           |   7 +-
 package.json                        |  53 +++++++++-
 scripts/reactpress-api-dev.js       |  85 ++++++++-------
 scripts/reactpress-api-lifecycle.js |  20 ++--
 scripts/reactpress-bootstrap.js     | 158 ++++++++++++++++++++++++++++
 scripts/reactpress-cli.js           |   2 +-
 scripts/reactpress-dev.js           |  42 +++++---
 9 files changed, 296 insertions(+), 78 deletions(-)
 delete mode 100644 .reactpress/server.pid
 create mode 100644 scripts/reactpress-bootstrap.js

diff --git a/.reactpress/server.pid b/.reactpress/server.pid
deleted file mode 100644
index d728acc..0000000
--- a/.reactpress/server.pid
+++ /dev/null
@@ -1 +0,0 @@
-79734
\ No newline at end of file
diff --git a/README-zh_CN.md b/README-zh_CN.md
index c2b3eda..4029c7a 100644
--- a/README-zh_CN.md
+++ b/README-zh_CN.md
@@ -78,11 +78,11 @@
 
 ```bash
 pnpm install
-pnpm run init          # 首次:.reactpress/config.json + .env(可用 Docker MySQL)
-pnpm run docker:dev    # 可选:仅起 MySQL + nginx 代理
-pnpm run dev           # 构建 toolkit → API 热更新 (3002) → 前端 (3001)
+pnpm run dev           # 零配置:自动 init + Docker MySQL + toolkit + API (3002) + 前端 (3001)
 ```
 
+可选:`pnpm run init` 仅准备环境不启动服务;`pnpm run docker:dev` 使用独立 compose 起 MySQL + nginx。
+
 | 命令 | 说明 |
 |------|------|
 | `pnpm dev` | 一键本地全栈(推荐) |
diff --git a/README.md b/README.md
index 7bca9ed..78407f9 100644
--- a/README.md
+++ b/README.md
@@ -108,13 +108,12 @@ git clone https://github.com/fecommunity/reactpress.git
 cd reactpress
 pnpm install
 
-# Initialize .reactpress/config.json + .env (first time)
-pnpm run init
-
-# API from server/ (3002) + Web (3001)
+# Zero-config: auto-creates .reactpress + .env + Docker MySQL, then API + Web
 pnpm run dev
 ```
 
+Requires **Node.js ≥ 18** and **Docker** (for embedded MySQL). Optional: `pnpm run init` to prepare env without starting dev servers.
+
 See [README-zh_CN.md](./README-zh_CN.md) for the full dev/deploy workflow (Chinese).
 
 ### 🏁 End‑User Project (CLI Only)
diff --git a/package.json b/package.json
index aaf0974..8cbc578 100644
--- a/package.json
+++ b/package.json
@@ -3,8 +3,57 @@
   "private": true,
   "version": "1.0.0",
   "description": "ReactPress CMS & Blog site",
+  "bin": {
+    "reactpress": "./scripts/reactpress-cli.js"
+  },
   "scripts": {
-    "start": "reactpress-cli start",
-    "stop": "reactpress-cli stop"
+    "init": "node ./scripts/reactpress-bootstrap.js",
+    "init:force": "node ./scripts/reactpress-bootstrap.js --force",
+    "dev": "node ./scripts/reactpress-dev.js",
+    "dev:api": "node ./scripts/reactpress-api-dev.js",
+    "dev:client": "pnpm run --dir ./client dev",
+    "dev:server": "pnpm run --dir ./server dev",
+    "dev:docs": "pnpm run --dir ./docs dev",
+    "docker:dev": "node ./scripts/docker-dev.js",
+    "docker:dev:start": "node ./scripts/docker-dev.js start",
+    "docker:dev:stop": "node ./scripts/docker-dev.js stop",
+    "docker:dev:restart": "node ./scripts/docker-dev.js restart",
+    "docker:dev:status": "node ./scripts/docker-dev.js status",
+    "docker:dev:logs": "node ./scripts/docker-dev.js logs",
+    "build": "pnpm build:toolkit && pnpm build:server && pnpm build:client",
+    "build:toolkit": "pnpm run --dir ./toolkit build",
+    "build:server": "pnpm run --dir ./server build",
+    "build:client": "pnpm run --dir ./client build",
+    "build:docs": "pnpm run --dir ./docs build",
+    "start": "node ./scripts/reactpress-api-lifecycle.js start",
+    "start:bg": "node ./scripts/reactpress-api-lifecycle.js start:bg",
+    "start:client": "pnpm run --dir ./client start",
+    "start:all": "concurrently -n api,web -c blue,green \"pnpm run start\" \"pnpm run start:client\"",
+    "stop": "node ./scripts/reactpress-api-lifecycle.js stop",
+    "restart": "node ./scripts/reactpress-api-lifecycle.js restart",
+    "status": "node ./scripts/reactpress-api-lifecycle.js status",
+    "prepare": "husky",
+    "precommit": "lint-staged"
+  },
+  "dependencies": {
+    "chalk": "^4.1.2",
+    "commander": "^9.4.1",
+    "concurrently": "^7.0.0",
+    "conventional-changelog-cli": "^3.0.0",
+    "cross-env": "^7.0.3",
+    "dotenv": "^17.2.3",
+    "express": "^5.1.0",
+    "fs-extra": "^10.0.0",
+    "inquirer": "^8.2.4",
+    "mysql2": "^3.12.0",
+    "open": "^8.2.1",
+    "rimraf": "^3.0.2"
+  },
+  "devDependencies": {
+    "@fecommunity/reactpress-cli": "^0.1.0",
+    "husky": "^7.0.4",
+    "lint-staged": "^12.4.1",
+    "prettier": "^2.3.2",
+    "typescript": "~4.1.6"
   }
 }
diff --git a/scripts/reactpress-api-dev.js b/scripts/reactpress-api-dev.js
index 766df6f..c43080c 100644
--- a/scripts/reactpress-api-dev.js
+++ b/scripts/reactpress-api-dev.js
@@ -5,29 +5,16 @@
  */
 
 const { spawn, spawnSync } = require('child_process');
-const path = require('path');
-const fs = require('fs');
 const {
   getMonorepoRoot,
   isUsingMonorepoServer,
 } = require('./bundled-server-path');
+const { ensureProjectEnvironment } = require('./reactpress-bootstrap');
 
 const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
-const configPath = path.join(projectRoot, '.reactpress', 'config.json');
 
 process.env.REACTPRESS_ORIGINAL_CWD = projectRoot;
 
-if (!fs.existsSync(configPath)) {
-  console.warn('[reactpress] 未找到 .reactpress/config.json,正在执行 reactpress-cli init …');
-  const init = spawnSync('pnpm', ['exec', 'reactpress-cli', 'init', '.'], {
-    cwd: projectRoot,
-    stdio: 'inherit',
-  });
-  if (init.status !== 0) {
-    process.exit(init.status ?? 1);
-  }
-}
-
 let apiChild;
 
 function stopApi() {
@@ -42,34 +29,49 @@ function stopApi() {
   }
 }
 
-if (isUsingMonorepoServer()) {
-  console.log('[reactpress] 开发模式: server/ (nest start --watch)');
-  apiChild = spawn('pnpm', ['run', '--dir', './server', 'dev'], {
-    cwd: projectRoot,
-    stdio: 'inherit',
-    shell: true,
-    env: {
-      ...process.env,
-      REACTPRESS_ORIGINAL_CWD: projectRoot,
-    },
-  });
-} else {
-  console.log('[reactpress] 开发模式: reactpress-cli(未找到 server/src)');
-  const start = spawnSync('pnpm', ['exec', 'reactpress-cli', 'start'], {
-    cwd: projectRoot,
-    stdio: 'inherit',
-  });
-  if (start.status !== 0) {
-    process.exit(start.status ?? 1);
+function startApiProcess() {
+  if (isUsingMonorepoServer()) {
+    console.log('[reactpress] 开发模式: server/ (nest start --watch)');
+    apiChild = spawn('pnpm', ['run', '--dir', './server', 'dev'], {
+      cwd: projectRoot,
+      stdio: 'inherit',
+      shell: true,
+      env: {
+        ...process.env,
+        REACTPRESS_ORIGINAL_CWD: projectRoot,
+      },
+    });
+  } else {
+    console.log('[reactpress] 开发模式: reactpress-cli(未找到 server/src)');
+    const start = spawnSync('pnpm', ['exec', 'reactpress-cli', 'start'], {
+      cwd: projectRoot,
+      stdio: 'inherit',
+    });
+    if (start.status !== 0) {
+      process.exit(start.status ?? 1);
+    }
+    console.log('[reactpress] API 已由 reactpress-cli 启动。');
+    process.stdin.resume();
+    return;
+  }
+
+  if (apiChild) {
+    apiChild.on('close', (code) => {
+      process.exit(code ?? 0);
+    });
+    console.log('[reactpress] 按 Ctrl+C 停止 API 与前端。');
+    console.log('[reactpress] 单独停止 API: pnpm run stop');
   }
-  console.log('[reactpress] API 已由 reactpress-cli 启动。');
-  process.stdin.resume();
 }
 
-if (apiChild) {
-  apiChild.on('close', (code) => {
-    process.exit(code ?? 0);
-  });
+async function prepareAndStart() {
+  try {
+    await ensureProjectEnvironment(projectRoot);
+  } catch (err) {
+    console.error('[reactpress] 环境准备失败:', err.message || err);
+    process.exit(1);
+  }
+  startApiProcess();
 }
 
 process.on('SIGINT', () => {
@@ -82,7 +84,4 @@ process.on('SIGTERM', () => {
   process.exit(0);
 });
 
-if (apiChild) {
-  console.log('[reactpress] 按 Ctrl+C 停止 API 与前端。');
-  console.log('[reactpress] 单独停止 API: pnpm run stop');
-}
+prepareAndStart();
diff --git a/scripts/reactpress-api-lifecycle.js b/scripts/reactpress-api-lifecycle.js
index 9efc43b..800fe24 100644
--- a/scripts/reactpress-api-lifecycle.js
+++ b/scripts/reactpress-api-lifecycle.js
@@ -15,10 +15,10 @@ const {
   getServerDir,
   isUsingMonorepoServer,
 } = require('./bundled-server-path');
+const { ensureProjectEnvironment } = require('./reactpress-bootstrap');
 
 const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
 const pidFile = path.join(projectRoot, '.reactpress', 'server.pid');
-const configPath = path.join(projectRoot, '.reactpress', 'config.json');
 
 process.env.REACTPRESS_ORIGINAL_CWD = projectRoot;
 
@@ -36,16 +36,14 @@ function loadServerSiteUrl() {
   return 'http://localhost:3002';
 }
 
-function ensureConfig() {
-  if (fs.existsSync(configPath)) {
+async function ensureConfig() {
+  try {
+    await ensureProjectEnvironment(projectRoot);
     return true;
+  } catch (err) {
+    console.error('[reactpress] 环境准备失败:', err.message || err);
+    return false;
   }
-  console.warn('[reactpress] 未找到 .reactpress/config.json,正在执行 reactpress-cli init …');
-  const init = spawnSync('pnpm', ['exec', 'reactpress-cli', 'init', '.'], {
-    cwd: projectRoot,
-    stdio: 'inherit',
-  });
-  return init.status === 0;
 }
 
 function readPid() {
@@ -132,8 +130,8 @@ async function waitForApi(url, timeoutMs = 120_000) {
   return false;
 }
 
-function startApi({ wait = true } = {}) {
-  if (!ensureConfig()) {
+async function startApi({ wait = true } = {}) {
+  if (!(await ensureConfig())) {
     process.exit(1);
   }
 
diff --git a/scripts/reactpress-bootstrap.js b/scripts/reactpress-bootstrap.js
new file mode 100644
index 0000000..cdc31c8
--- /dev/null
+++ b/scripts/reactpress-bootstrap.js
@@ -0,0 +1,158 @@
+#!/usr/bin/env node
+
+/**
+ * Pre-start environment: init .reactpress + .env, ensure embedded Docker MySQL.
+ * Reuses @fecommunity/reactpress-cli services (same as reactpress-cli init/start).
+ * Monorepo: does not overwrite root package.json.
+ */
+
+const fs = require('fs');
+const path = require('path');
+const { pathToFileURL } = require('url');
+const { getMonorepoRoot } = require('./bundled-server-path');
+
+async function importCliModule(relativePath) {
+  const cliRoot = path.dirname(require.resolve('@fecommunity/reactpress-cli/package.json'));
+  const modulePath = path.join(cliRoot, 'dist', relativePath);
+  return import(pathToFileURL(modulePath).href);
+}
+
+function isMonorepoRoot(projectRoot) {
+  return (
+    fs.existsSync(path.join(projectRoot, 'pnpm-workspace.yaml')) ||
+    fs.existsSync(path.join(projectRoot, 'server', 'src', 'main.ts'))
+  );
+}
+
+async function copyTemplateFile(src, dest) {
+  await fs.promises.mkdir(path.dirname(dest), { recursive: true });
+  await fs.promises.copyFile(src, dest);
+}
+
+/**
+ * Monorepo init: config + docker-compose + .env only (no package.json template).
+ */
+async function initMonorepoProject(projectRoot, { force = false } = {}) {
+  const { getProjectPaths, getTemplatesDir } = await importCliModule('utils/paths.js');
+  const { saveConfig, syncEnvFromConfig } = await importCliModule('services/config.js');
+  const { ensureDatabase, ensureDatabaseHostPort } = await importCliModule('services/database.js');
+
+  const paths = getProjectPaths(projectRoot);
+  const templatesDir = getTemplatesDir();
+
+  if (fs.existsSync(paths.configPath) && !force) {
+    const config = await (await importCliModule('services/config.js')).loadConfig(projectRoot);
+    await ensureDatabaseHostPort(projectRoot, undefined, config);
+    const dbResult = await ensureDatabase(projectRoot, config);
+    if (!dbResult.ok) {
+      return { ok: false, projectRoot, message: dbResult.message };
+    }
+    return { ok: true, projectRoot, message: '配置已存在,数据库已就绪。' };
+  }
+
+  await fs.promises.mkdir(paths.reactpressDir, { recursive: true });
+  await copyTemplateFile(
+    path.join(templatesDir, 'docker-compose.yml'),
+    paths.dockerComposePath
+  );
+
+  const config = JSON.parse(
+    await fs.promises.readFile(path.join(templatesDir, 'config.default.json'), 'utf8')
+  );
+  await saveConfig(projectRoot, config);
+  await syncEnvFromConfig(projectRoot, config);
+
+  if (!fs.existsSync(paths.envPath) || force) {
+    await copyTemplateFile(path.join(templatesDir, 'env.default'), paths.envPath);
+    await syncEnvFromConfig(projectRoot, config);
+  }
+
+  await ensureDatabaseHostPort(projectRoot, undefined, config);
+  const dbResult = await ensureDatabase(projectRoot, config);
+
+  if (!dbResult.ok) {
+    return {
+      ok: true,
+      projectRoot,
+      message: `项目已创建,但数据库未就绪: ${dbResult.message}。请确认 Docker 已启动后重试 pnpm dev。`,
+    };
+  }
+
+  return {
+    ok: true,
+    projectRoot,
+    message: 'ReactPress 开发环境已就绪(配置 + 数据库)。',
+  };
+}
+
+/**
+ * Ensure config and database before API / dev stack starts.
+ */
+async function ensureProjectEnvironment(projectRoot = getMonorepoRoot()) {
+  const root = path.resolve(projectRoot);
+  const { setProjectCwd } = await importCliModule('utils/cli-context.js');
+  setProjectCwd(root);
+
+  const { isReactPressProject, loadConfig } = await importCliModule('services/config.js');
+  const { ensureDatabase, ensureDatabaseHostPort } = await importCliModule('services/database.js');
+
+  if (!(await isReactPressProject(root))) {
+    console.log('[reactpress] 首次运行,正在初始化配置与数据库…');
+    if (isMonorepoRoot(root)) {
+      const result = await initMonorepoProject(root);
+      if (!result.ok) {
+        throw new Error(result.message || '初始化失败');
+      }
+      console.log(`[reactpress] ${result.message}`);
+      return result;
+    }
+
+    const { initProject } = await importCliModule('services/init.js');
+    const result = await initProject({ directory: root, force: false });
+    if (!result.ok) {
+      throw new Error(result.message || 'reactpress-cli init 失败');
+    }
+    console.log(`[reactpress] ${result.message || '初始化完成'}`);
+    return result;
+  }
+
+  const config = await loadConfig(root);
+  await ensureDatabaseHostPort(root, undefined, config);
+  const dbResult = await ensureDatabase(root, config);
+  if (!dbResult.ok) {
+    throw new Error(dbResult.message || '数据库未就绪,请检查 Docker 与 .env 中的 DB_* 配置');
+  }
+
+  return { ok: true, projectRoot: root, message: '数据库已就绪' };
+}
+
+async function main() {
+  const force = process.argv.includes('--force');
+  const root = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
+  process.env.REACTPRESS_ORIGINAL_CWD = root;
+
+  try {
+    if (force && isMonorepoRoot(root)) {
+      const result = await initMonorepoProject(root, { force: true });
+      console.log(`[reactpress] ${result.message}`);
+      process.exit(result.ok ? 0 : 1);
+      return;
+    }
+    await ensureProjectEnvironment(root);
+    console.log('[reactpress] 环境检查完成');
+    process.exit(0);
+  } catch (err) {
+    console.error('[reactpress] 环境准备失败:', err.message || err);
+    process.exit(1);
+  }
+}
+
+module.exports = {
+  ensureProjectEnvironment,
+  initMonorepoProject,
+  isMonorepoRoot,
+};
+
+if (require.main === module) {
+  main();
+}
diff --git a/scripts/reactpress-cli.js b/scripts/reactpress-cli.js
index 04479ff..ee5ad10 100755
--- a/scripts/reactpress-cli.js
+++ b/scripts/reactpress-cli.js
@@ -112,7 +112,7 @@ program.on('--help', () => {
   console.log('  $ reactpress server start        # Local Nest API (server/)');
   console.log('  $ reactpress server start --pm2  # PM2 production API');
   console.log('  $ reactpress client start        # Next.js client');
-  console.log('  $ pnpm dev                       # toolkit + API + client');
+  console.log('  $ pnpm dev                       # 零配置: env + DB + toolkit + API + client');
   console.log('');
   console.log('API backend: monorepo server/ (NestJS). Init/DB: @fecommunity/reactpress-cli.');
 });
diff --git a/scripts/reactpress-dev.js b/scripts/reactpress-dev.js
index 5f53ffc..3731ff7 100644
--- a/scripts/reactpress-dev.js
+++ b/scripts/reactpress-dev.js
@@ -2,6 +2,7 @@ const { spawn } = require('child_process');
 const fs = require('fs');
 const http = require('http');
 const path = require('path');
+const { ensureProjectEnvironment } = require('./reactpress-bootstrap');
 
 const currentWorkingDir = process.cwd();
 process.env.REACTPRESS_ORIGINAL_CWD = currentWorkingDir;
@@ -132,20 +133,35 @@ async function startDev() {
   });
 }
 
-const build = spawn('pnpm', ['build:toolkit'], {
-  stdio: 'inherit',
-  shell: true,
-});
-
-build.on('close', (code) => {
-  if (code !== 0) {
-    console.error(`构建失败,退出码: ${code}`);
-    process.exit(code);
+async function runDev() {
+  try {
+    await ensureProjectEnvironment(currentWorkingDir);
+  } catch (err) {
+    console.error('[reactpress] 环境准备失败:', err.message || err);
+    process.exit(1);
   }
 
-  startDev().catch((err) => {
-    console.error('[reactpress] 启动失败:', err);
-    shutdown('SIGINT');
-    process.exit(1);
+  await new Promise((resolve, reject) => {
+    const build = spawn('pnpm', ['build:toolkit'], {
+      stdio: 'inherit',
+      shell: true,
+      cwd: currentWorkingDir,
+    });
+
+    build.on('close', (code) => {
+      if (code !== 0) {
+        reject(new Error(`toolkit 构建失败,退出码: ${code}`));
+        return;
+      }
+      resolve();
+    });
   });
+
+  await startDev();
+}
+
+runDev().catch((err) => {
+  console.error('[reactpress] 启动失败:', err.message || err);
+  shutdown('SIGINT');
+  process.exit(1);
 });

From 965b00a52d07ee989c97a97acd1bd206a988881c Mon Sep 17 00:00:00 2001
From: m0_37981569 
Date: Sat, 9 May 2026 22:00:00 +0800
Subject: [PATCH 06/20] chore: migrate to reactpress-cli for project commands,
 restructure scripts, and enhance CLI functionality for improved development
 experience

---
 cli/bin/reactpress.js               |  246 ++++
 cli/package.json                    |   18 +
 cli/ui/banner.js                    |   16 +
 cli/ui/interactive.js               |  158 +++
 cli/ui/theme.js                     |   25 +
 client/package.json                 |    1 +
 package.json                        |   54 +-
 pnpm-lock.yaml                      | 1950 ++++-----------------------
 pnpm-workspace.yaml                 |    2 +
 scripts/bundled-server-path.js      |   72 +-
 scripts/docker-dev.js               |  223 +--
 scripts/reactpress-api-dev.js       |   89 +-
 scripts/reactpress-api-lifecycle.js |  260 +---
 scripts/reactpress-api-pm2.js       |   34 +-
 scripts/reactpress-bootstrap.js     |  161 +--
 scripts/reactpress-cli.js           |  125 +-
 scripts/reactpress-dev.js           |  171 +--
 scripts/reactpress-publish.js       |  947 +------------
 18 files changed, 791 insertions(+), 3761 deletions(-)
 create mode 100755 cli/bin/reactpress.js
 create mode 100644 cli/package.json
 create mode 100644 cli/ui/banner.js
 create mode 100644 cli/ui/interactive.js
 create mode 100644 cli/ui/theme.js

diff --git a/cli/bin/reactpress.js b/cli/bin/reactpress.js
new file mode 100755
index 0000000..186ccf9
--- /dev/null
+++ b/cli/bin/reactpress.js
@@ -0,0 +1,246 @@
+#!/usr/bin/env node
+
+/**
+ * ReactPress unified CLI — init, dev, build, server, docker, publish.
+ * Run without arguments for an interactive menu (Claude Code–style).
+ */
+
+const { Command } = require('commander');
+const path = require('path');
+const chalk = require('chalk');
+const { ensureOriginalCwd, getMonorepoRoot } = require('../lib/root');
+const { ensureProjectEnvironment, initMonorepoProject } = require('../lib/bootstrap');
+const { runDev } = require('../lib/dev');
+const { runApiDev } = require('../lib/api-dev');
+const { runLifecycleCommand } = require('../lib/lifecycle');
+const { runDockerCommand } = require('../lib/docker');
+const { printUnifiedStatus } = require('../lib/status');
+const { runBuild } = require('../lib/build');
+const { startApiWithPm2 } = require('../lib/pm2');
+const { runNodeScript, runReactpressCli } = require('../lib/spawn');
+const { getClientBin } = require('../lib/paths');
+const { runInteractiveLoop } = require('../ui/interactive');
+
+const rootPkg = require(path.join(getMonorepoRoot(), 'package.json'));
+
+const program = new Command();
+
+program
+  .name('reactpress')
+  .description('ReactPress 全栈 CLI — 初始化、开发、构建、部署、发布')
+  .version(rootPkg.version);
+
+program
+  .command('init')
+  .description('初始化项目 (.reactpress/config.json + .env + Docker MySQL)')
+  .argument('[directory]', '项目目录', '.')
+  .option('-f, --force', '覆盖已有配置')
+  .action(async (directory, options) => {
+    const projectRoot = path.resolve(directory);
+    process.env.REACTPRESS_ORIGINAL_CWD = projectRoot;
+    const { isMonorepoCheckout } = require('../lib/bootstrap');
+    if (isMonorepoCheckout(projectRoot)) {
+      const result = await initMonorepoProject(projectRoot, { force: !!options.force });
+      console.log(`[reactpress] ${result.message}`);
+      process.exit(result.ok ? 0 : 1);
+      return;
+    }
+    const args = ['init', directory];
+    if (options.force) args.push('--force');
+    runReactpressCli(args, { cwd: projectRoot });
+  });
+
+program
+  .command('dev')
+  .description('零配置开发: 环境检查 + toolkit 构建 + API + 前端')
+  .option('--api-only', '仅启动 API (watch)')
+  .option('--client-only', '仅启动前端')
+  .action(async (options) => {
+    const projectRoot = ensureOriginalCwd();
+    try {
+      if (options.clientOnly) {
+        await runNodeScript(getClientBin(), [], { cwd: projectRoot });
+        return;
+      }
+      if (options.apiOnly) {
+        await runApiDev(projectRoot);
+        return;
+      }
+      await runDev(projectRoot);
+    } catch (err) {
+      console.error(chalk.red('[reactpress]'), err.message || err);
+      process.exit(err.exitCode ?? 1);
+    }
+  });
+
+const serverCmd = program.command('server').description('管理 API 服务');
+
+serverCmd
+  .command('start')
+  .description('启动 API(等待 HTTP 就绪)')
+  .option('--pm2', '使用 PM2 启动(生产)')
+  .option('--bg', '后台启动,不等待 HTTP')
+  .action(async (options) => {
+    const projectRoot = ensureOriginalCwd();
+    try {
+      if (options.pm2) {
+        await startApiWithPm2(projectRoot);
+        return;
+      }
+      const cmd = options.bg ? 'start:bg' : 'start';
+      const code = await runLifecycleCommand(cmd, projectRoot);
+      process.exit(code ?? 0);
+    } catch (err) {
+      console.error(chalk.red('[reactpress]'), err.message || err);
+      process.exit(1);
+    }
+  });
+
+serverCmd.command('stop').description('停止 API').action(async () => {
+  const code = await runLifecycleCommand('stop', ensureOriginalCwd());
+  process.exit(code ?? 0);
+});
+
+serverCmd.command('restart').description('重启 API').action(async () => {
+  const code = await runLifecycleCommand('restart', ensureOriginalCwd());
+  process.exit(code ?? 0);
+});
+
+serverCmd.command('status').description('查看 API 状态').action(async () => {
+  await runLifecycleCommand('status', ensureOriginalCwd());
+});
+
+const clientCmd = program.command('client').description('管理前端');
+
+clientCmd
+  .command('start')
+  .description('启动 Next.js 客户端')
+  .option('--pm2', '使用 PM2 启动')
+  .action(async (options) => {
+    const args = options.pm2 ? ['--pm2'] : [];
+    await runNodeScript(getClientBin(), args, { cwd: ensureOriginalCwd() });
+  });
+
+program
+  .command('build')
+  .description('构建生产产物')
+  .option('-t, --target ', 'toolkit | server | client | docs | all', 'all')
+  .action(async (options) => {
+    try {
+      await runBuild(options.target, ensureOriginalCwd());
+    } catch (err) {
+      console.error(chalk.red('[reactpress]'), err.message || err);
+      process.exit(1);
+    }
+  });
+
+const dockerCmd = program.command('docker').description('Docker 开发环境 (MySQL + nginx)');
+
+dockerCmd
+  .command('up')
+  .description('仅启动 Docker 服务并等待 MySQL')
+  .action(async () => {
+    await runDockerCommand('up', ensureOriginalCwd());
+  });
+
+dockerCmd
+  .command('down')
+  .alias('stop')
+  .description('停止 Docker 服务')
+  .action(async () => {
+    await runDockerCommand('down', ensureOriginalCwd());
+  });
+
+dockerCmd
+  .command('start')
+  .description('启动 Docker + 全栈开发 (API + 前端)')
+  .action(async () => {
+    await runDockerCommand('start', ensureOriginalCwd());
+  });
+
+dockerCmd.command('restart').description('重启 Docker 服务').action(async () => {
+  await runDockerCommand('restart', ensureOriginalCwd());
+});
+
+dockerCmd.command('status').description('查看 Docker 容器状态').action(async () => {
+  await runDockerCommand('status', ensureOriginalCwd());
+});
+
+dockerCmd
+  .command('logs [service]')
+  .description('查看 Docker 日志 (db | nginx)')
+  .action(async (service) => {
+    await runDockerCommand('logs', ensureOriginalCwd(), service ? [service] : []);
+  });
+
+program
+  .command('status')
+  .description('查看项目、API、前端、Docker 综合状态')
+  .action(async () => {
+    await printUnifiedStatus(ensureOriginalCwd());
+  });
+
+program
+  .command('publish')
+  .description('构建并发布 npm 包 (交互式)')
+  .option('--build', '仅构建所有包')
+  .option('--publish', '交互式发布')
+  .action(async (options) => {
+    const prev = process.argv.slice();
+    const args = [process.argv[0], process.argv[1]];
+    if (options.build) args.push('--build');
+    else if (options.publish) args.push('--publish');
+    else args.push('--publish');
+    process.argv = args;
+    try {
+      await require('../lib/publish').main();
+    } catch (err) {
+      console.error(chalk.red('[reactpress]'), err.message || err);
+      process.exit(1);
+    } finally {
+      process.argv = prev;
+    }
+  });
+
+program
+  .command('start')
+  .description('生产模式: 启动 API + 前端')
+  .action(async () => {
+    const projectRoot = ensureOriginalCwd();
+    const { spawn } = require('child_process');
+    const code = await runLifecycleCommand('start', projectRoot);
+    if (code !== 0) process.exit(code);
+    const child = spawn('pnpm', ['run', '--dir', './client', 'start'], {
+      stdio: 'inherit',
+      shell: true,
+      cwd: projectRoot,
+    });
+    child.on('close', (c) => process.exit(c ?? 0));
+  });
+
+program.on('--help', () => {
+  console.log('');
+  console.log(chalk.gray('示例:'));
+  console.log('  reactpress                  交互式菜单');
+  console.log('  reactpress dev              零配置全栈开发');
+  console.log('  reactpress init --force     重新初始化配置');
+  console.log('  reactpress server start     启动 API');
+  console.log('  reactpress status           综合状态');
+  console.log('  reactpress docker start     Docker + 全栈');
+  console.log('  reactpress publish          发布 npm 包');
+  console.log('');
+});
+
+async function main() {
+  const argv = process.argv.slice(2);
+  if (argv.length === 0) {
+    await runInteractiveLoop();
+    return;
+  }
+  program.parse(process.argv);
+}
+
+main().catch((err) => {
+  console.error(chalk.red('[reactpress]'), err.message || err);
+  process.exit(1);
+});
diff --git a/cli/package.json b/cli/package.json
new file mode 100644
index 0000000..b6cee42
--- /dev/null
+++ b/cli/package.json
@@ -0,0 +1,18 @@
+{
+  "name": "@fecommunity/reactpress-toolchain",
+  "version": "1.0.0",
+  "private": true,
+  "description": "ReactPress monorepo CLI — init, dev, build, deploy, publish",
+  "bin": {
+    "reactpress": "./bin/reactpress.js"
+  },
+  "main": "./bin/reactpress.js",
+  "dependencies": {
+    "@fecommunity/reactpress-cli": "^0.1.0",
+    "chalk": "^4.1.2",
+    "commander": "^9.4.1",
+    "concurrently": "^7.0.0",
+    "inquirer": "^8.2.4",
+    "open": "^8.2.1"
+  }
+}
diff --git a/cli/ui/banner.js b/cli/ui/banner.js
new file mode 100644
index 0000000..f9e8b45
--- /dev/null
+++ b/cli/ui/banner.js
@@ -0,0 +1,16 @@
+const chalk = require('chalk');
+const { brand } = require('./theme');
+const { getMonorepoRoot } = require('../lib/root');
+const path = require('path');
+
+function printBanner() {
+  const version = require(path.join(getMonorepoRoot(), 'package.json')).version;
+  console.log('');
+  console.log(brand.primary('  ╭─────────────────────────────────────────╮'));
+  console.log(brand.primary('  │') + chalk.bold.white('   ReactPress') + brand.muted('  ·  全栈发布平台 CLI        ') + brand.primary('│'));
+  console.log(brand.primary('  ╰─────────────────────────────────────────╯'));
+  console.log(brand.muted(`  v${version}  ·  init · dev · build · deploy · publish`));
+  console.log('');
+}
+
+module.exports = { printBanner };
diff --git a/cli/ui/interactive.js b/cli/ui/interactive.js
new file mode 100644
index 0000000..4808e18
--- /dev/null
+++ b/cli/ui/interactive.js
@@ -0,0 +1,158 @@
+const inquirer = require('inquirer');
+const open = require('open');
+const { printBanner } = require('./banner');
+const { brand, label } = require('./theme');
+const { ensureOriginalCwd } = require('../lib/root');
+const { ensureProjectEnvironment } = require('../lib/bootstrap');
+const { runDev } = require('../lib/dev');
+const { runApiDev } = require('../lib/api-dev');
+const { runLifecycleCommand } = require('../lib/lifecycle');
+const { runDockerCommand } = require('../lib/docker');
+const { printUnifiedStatus } = require('../lib/status');
+const { runBuild } = require('../lib/build');
+const { runNodeScript } = require('../lib/spawn');
+const { getClientBin } = require('../lib/paths');
+const { loadClientSiteUrl } = require('../lib/http');
+
+const MENU_ACTIONS = [
+  { name: '零配置开发 (env + DB + API + 前端)', value: 'dev' },
+  { name: '初始化项目 (.reactpress + .env + 数据库)', value: 'init' },
+  { name: '查看项目状态', value: 'status' },
+  new inquirer.Separator(),
+  { name: '仅启动 API (开发 watch)', value: 'dev:api' },
+  { name: '仅启动前端', value: 'dev:client' },
+  { name: '启动 API (后台生产)', value: 'server:start' },
+  { name: '停止 API', value: 'server:stop' },
+  { name: '重启 API', value: 'server:restart' },
+  new inquirer.Separator(),
+  { name: '构建 (toolkit → server → client)', value: 'build' },
+  { name: 'Docker 开发环境 (DB + nginx + 全栈)', value: 'docker:start' },
+  { name: 'Docker 仅启动数据库', value: 'docker:up' },
+  { name: '停止 Docker 服务', value: 'docker:stop' },
+  new inquirer.Separator(),
+  { name: '在浏览器打开管理后台', value: 'open:admin' },
+  { name: '发布 npm 包 (交互式)', value: 'publish' },
+  { name: '退出', value: 'exit' },
+];
+
+async function runMenuAction(action, projectRoot) {
+  switch (action) {
+    case 'dev':
+      console.log(label('启动全栈开发…'));
+      await runDev(projectRoot);
+      return false;
+    case 'init': {
+      console.log(label('初始化项目…'));
+      const result = await ensureProjectEnvironment(projectRoot);
+      console.log(brand.success(result.message || '完成'));
+      return true;
+    }
+    case 'status':
+      await printUnifiedStatus(projectRoot);
+      return true;
+    case 'dev:api':
+      await runApiDev(projectRoot);
+      return false;
+    case 'dev:client':
+      await runNodeScript(getClientBin(), [], { cwd: projectRoot });
+      return false;
+    case 'server:start': {
+      const code = await runLifecycleCommand('start', projectRoot);
+      if (code !== 0) process.exit(code);
+      return true;
+    }
+    case 'server:stop':
+      await runLifecycleCommand('stop', projectRoot);
+      return true;
+    case 'server:restart': {
+      const code = await runLifecycleCommand('restart', projectRoot);
+      if (code !== 0) process.exit(code);
+      return true;
+    }
+    case 'build':
+      await runBuild('all', projectRoot);
+      return true;
+    case 'docker:start':
+      await runDockerCommand('start', projectRoot);
+      return false;
+    case 'docker:up':
+      await runDockerCommand('up', projectRoot);
+      return true;
+    case 'docker:stop':
+      await runDockerCommand('down', projectRoot);
+      return true;
+    case 'open:admin': {
+      const url = loadClientSiteUrl(projectRoot);
+      console.log(label(`打开 ${url}`));
+      await open(url);
+      return true;
+    }
+    case 'publish': {
+      const prev = process.argv.slice();
+      process.argv = [process.argv[0], process.argv[1], '--publish'];
+      await require('../lib/publish').main();
+      process.argv = prev;
+      return true;
+    }
+    case 'exit':
+      console.log(brand.muted('  再见。'));
+      return false;
+    default:
+      return true;
+  }
+}
+
+async function runInteractiveLoop() {
+  const projectRoot = ensureOriginalCwd();
+  printBanner();
+
+  let loop = true;
+  while (loop) {
+    const { action } = await inquirer.prompt([
+      {
+        type: 'list',
+        name: 'action',
+        message: '选择操作',
+        pageSize: 14,
+        choices: MENU_ACTIONS,
+      },
+    ]);
+
+    if (action === 'exit') {
+      console.log(brand.muted('  再见。'));
+      break;
+    }
+
+    try {
+      const stay = await runMenuAction(action, projectRoot);
+      if (!stay) {
+        break;
+      }
+
+      if (action !== 'status') {
+        const { again } = await inquirer.prompt([
+          {
+            type: 'confirm',
+            name: 'again',
+            message: '返回主菜单?',
+            default: true,
+          },
+        ]);
+        loop = again;
+      }
+    } catch (err) {
+      console.error(brand.error(`  ${err.message || err}`));
+      const { retry } = await inquirer.prompt([
+        {
+          type: 'confirm',
+          name: 'retry',
+          message: '返回主菜单重试?',
+          default: true,
+        },
+      ]);
+      loop = retry;
+    }
+  }
+}
+
+module.exports = { runInteractiveLoop, runMenuAction };
diff --git a/cli/ui/theme.js b/cli/ui/theme.js
new file mode 100644
index 0000000..d752db2
--- /dev/null
+++ b/cli/ui/theme.js
@@ -0,0 +1,25 @@
+const chalk = require('chalk');
+
+const brand = {
+  primary: chalk.hex('#6366f1'),
+  accent: chalk.hex('#22d3ee'),
+  success: chalk.green,
+  warn: chalk.yellow,
+  error: chalk.red,
+  muted: chalk.gray,
+  bold: chalk.bold,
+};
+
+function label(text) {
+  return brand.primary(`› ${text}`);
+}
+
+function ok(text) {
+  return brand.success(`✓ ${text}`);
+}
+
+function fail(text) {
+  return brand.error(`✗ ${text}`);
+}
+
+module.exports = { brand, label, ok, fail };
diff --git a/client/package.json b/client/package.json
index 9734a99..f04849e 100644
--- a/client/package.json
+++ b/client/package.json
@@ -50,6 +50,7 @@
     "next-sitemap": "^1.6.102",
     "next-with-less": "^2.0.5",
     "nprogress": "^0.2.0",
+    "open": "^8.4.2",
     "preact": "^10.5.14",
     "qrcode-svg": "^1.1.0",
     "react": "17.0.2",
diff --git a/package.json b/package.json
index 8cbc578..3908664 100644
--- a/package.json
+++ b/package.json
@@ -4,53 +4,43 @@
   "version": "1.0.0",
   "description": "ReactPress CMS & Blog site",
   "bin": {
-    "reactpress": "./scripts/reactpress-cli.js"
+    "reactpress": "./cli/bin/reactpress.js"
   },
   "scripts": {
-    "init": "node ./scripts/reactpress-bootstrap.js",
-    "init:force": "node ./scripts/reactpress-bootstrap.js --force",
-    "dev": "node ./scripts/reactpress-dev.js",
-    "dev:api": "node ./scripts/reactpress-api-dev.js",
-    "dev:client": "pnpm run --dir ./client dev",
+    "init": "node ./cli/bin/reactpress.js init",
+    "init:force": "node ./cli/bin/reactpress.js init --force",
+    "dev": "node ./cli/bin/reactpress.js dev",
+    "dev:api": "node ./cli/bin/reactpress.js dev --api-only",
+    "dev:client": "node ./cli/bin/reactpress.js dev --client-only",
     "dev:server": "pnpm run --dir ./server dev",
     "dev:docs": "pnpm run --dir ./docs dev",
-    "docker:dev": "node ./scripts/docker-dev.js",
-    "docker:dev:start": "node ./scripts/docker-dev.js start",
-    "docker:dev:stop": "node ./scripts/docker-dev.js stop",
-    "docker:dev:restart": "node ./scripts/docker-dev.js restart",
-    "docker:dev:status": "node ./scripts/docker-dev.js status",
-    "docker:dev:logs": "node ./scripts/docker-dev.js logs",
-    "build": "pnpm build:toolkit && pnpm build:server && pnpm build:client",
+    "docker:dev": "node ./cli/bin/reactpress.js docker start",
+    "docker:dev:start": "node ./cli/bin/reactpress.js docker start",
+    "docker:dev:stop": "node ./cli/bin/reactpress.js docker down",
+    "docker:dev:restart": "node ./cli/bin/reactpress.js docker restart",
+    "docker:dev:status": "node ./cli/bin/reactpress.js docker status",
+    "docker:dev:logs": "node ./cli/bin/reactpress.js docker logs",
+    "build": "node ./cli/bin/reactpress.js build",
     "build:toolkit": "pnpm run --dir ./toolkit build",
     "build:server": "pnpm run --dir ./server build",
     "build:client": "pnpm run --dir ./client build",
     "build:docs": "pnpm run --dir ./docs build",
-    "start": "node ./scripts/reactpress-api-lifecycle.js start",
-    "start:bg": "node ./scripts/reactpress-api-lifecycle.js start:bg",
+    "start": "node ./cli/bin/reactpress.js server start",
+    "start:bg": "node ./cli/bin/reactpress.js server start --bg",
     "start:client": "pnpm run --dir ./client start",
-    "start:all": "concurrently -n api,web -c blue,green \"pnpm run start\" \"pnpm run start:client\"",
-    "stop": "node ./scripts/reactpress-api-lifecycle.js stop",
-    "restart": "node ./scripts/reactpress-api-lifecycle.js restart",
-    "status": "node ./scripts/reactpress-api-lifecycle.js status",
+    "start:all": "node ./cli/bin/reactpress.js start",
+    "stop": "node ./cli/bin/reactpress.js server stop",
+    "restart": "node ./cli/bin/reactpress.js server restart",
+    "status": "node ./cli/bin/reactpress.js status",
+    "publish:packages": "node ./cli/bin/reactpress.js publish --publish",
+    "publish:build": "node ./cli/bin/reactpress.js publish --build",
     "prepare": "husky",
     "precommit": "lint-staged"
   },
   "dependencies": {
-    "chalk": "^4.1.2",
-    "commander": "^9.4.1",
-    "concurrently": "^7.0.0",
-    "conventional-changelog-cli": "^3.0.0",
-    "cross-env": "^7.0.3",
-    "dotenv": "^17.2.3",
-    "express": "^5.1.0",
-    "fs-extra": "^10.0.0",
-    "inquirer": "^8.2.4",
-    "mysql2": "^3.12.0",
-    "open": "^8.2.1",
-    "rimraf": "^3.0.2"
+    "@fecommunity/reactpress-toolchain": "workspace:*"
   },
   "devDependencies": {
-    "@fecommunity/reactpress-cli": "^0.1.0",
     "husky": "^7.0.4",
     "lint-staged": "^12.4.1",
     "prettier": "^2.3.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7fc36ca..e8b7d51 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,6 +8,28 @@ importers:
 
   .:
     dependencies:
+      '@fecommunity/reactpress-toolchain':
+        specifier: workspace:*
+        version: link:cli
+    devDependencies:
+      husky:
+        specifier: ^7.0.4
+        version: 7.0.4
+      lint-staged:
+        specifier: ^12.4.1
+        version: 12.5.0(enquirer@2.3.6)
+      prettier:
+        specifier: ^2.3.2
+        version: 2.8.8
+      typescript:
+        specifier: ~4.1.6
+        version: 4.1.6
+
+  cli:
+    dependencies:
+      '@fecommunity/reactpress-cli':
+        specifier: ^0.1.0
+        version: 0.1.0(@types/node@24.5.2)
       chalk:
         specifier: ^4.1.2
         version: 4.1.2
@@ -17,49 +39,12 @@ importers:
       concurrently:
         specifier: ^7.0.0
         version: 7.6.0
-      conventional-changelog-cli:
-        specifier: ^3.0.0
-        version: 3.0.0
-      cross-env:
-        specifier: ^7.0.3
-        version: 7.0.3
-      dotenv:
-        specifier: ^17.2.3
-        version: 17.2.3
-      express:
-        specifier: ^5.1.0
-        version: 5.1.0
-      fs-extra:
-        specifier: ^10.0.0
-        version: 10.1.0
       inquirer:
         specifier: ^8.2.4
         version: 8.2.7(@types/node@24.5.2)
-      mysql2:
-        specifier: ^3.12.0
-        version: 3.12.0
       open:
         specifier: ^8.2.1
         version: 8.4.2
-      rimraf:
-        specifier: ^3.0.2
-        version: 3.0.2
-    devDependencies:
-      '@fecommunity/reactpress-cli':
-        specifier: ^0.1.0
-        version: 0.1.0(@types/node@24.5.2)
-      husky:
-        specifier: ^7.0.4
-        version: 7.0.4
-      lint-staged:
-        specifier: ^12.4.1
-        version: 12.5.0(enquirer@2.3.6)
-      prettier:
-        specifier: ^2.3.2
-        version: 2.8.8
-      typescript:
-        specifier: ~4.1.6
-        version: 4.1.6
 
   client:
     dependencies:
@@ -131,7 +116,7 @@ importers:
         version: 2.1.35
       next:
         specifier: ^12.3.4
-        version: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
+        version: 12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
       next-compose-plugins:
         specifier: ^2.2.1
         version: 2.2.1
@@ -143,22 +128,25 @@ importers:
         version: 1.8.5(webpack@5.98.0)
       next-intl:
         specifier: ^1.5.1
-        version: 1.5.1(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(react@17.0.2)
+        version: 1.5.1(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(react@17.0.2)
       next-page-transitions:
         specifier: ^1.0.0-beta.2
         version: 1.0.0-beta.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
       next-pwa:
         specifier: ^5.5.2
-        version: 5.6.0(@babel/core@7.25.2)(@types/babel__core@7.20.5)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(webpack@5.98.0)
+        version: 5.6.0(@babel/core@7.26.9)(@types/babel__core@7.20.5)(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(webpack@5.98.0)
       next-sitemap:
         specifier: ^1.6.102
-        version: 1.9.12(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))
+        version: 1.9.12(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))
       next-with-less:
         specifier: ^2.0.5
-        version: 2.0.5(less-loader@10.2.0(less@4.2.0)(webpack@5.98.0))(less@4.2.0)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))
+        version: 2.0.5(less-loader@10.2.0(less@4.2.0)(webpack@5.98.0))(less@4.2.0)(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))
       nprogress:
         specifier: ^0.2.0
         version: 0.2.0
+      open:
+        specifier: ^8.4.2
+        version: 8.4.2
       preact:
         specifier: ^10.5.14
         version: 10.24.0
@@ -182,7 +170,7 @@ importers:
         version: 2.0.0(prop-types@15.8.1)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
       react-spring:
         specifier: ^9.1.2
-        version: 9.7.4(@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0))(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react-konva@18.2.10(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react-zdog@1.2.2)(react@17.0.2)(three@0.168.0)(zdog@1.1.3)
+        version: 9.7.4(@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0))(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react-konva@18.2.10(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react-zdog@1.2.2)(react@17.0.2)(three@0.168.0)(zdog@1.1.3)
       react-text-loop:
         specifier: 2.3.0
         version: 2.3.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
@@ -222,7 +210,7 @@ importers:
         version: 8.11.0
       eslint-config-next:
         specifier: 12.1.0
-        version: 12.1.0(eslint@8.11.0)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(typescript@4.6.2)
+        version: 12.1.0(eslint@8.11.0)(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(typescript@4.6.2)
       eslint-config-prettier:
         specifier: ^8.5.0
         version: 8.10.0(eslint@8.11.0)
@@ -261,10 +249,10 @@ importers:
     dependencies:
       '@docusaurus/core':
         specifier: 3.7.0
-        version: 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+        version: 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
       '@docusaurus/preset-classic':
         specifier: 3.7.0
-        version: 3.7.0(@algolia/client-search@5.20.3)(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(@types/react@17.0.42)(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)(typescript@5.6.3)
+        version: 3.7.0(@algolia/client-search@5.20.3)(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(@types/react@17.0.42)(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)(typescript@5.6.3)
       '@mdx-js/react':
         specifier: ^3.0.0
         version: 3.1.0(@types/react@17.0.42)(react@19.0.0)
@@ -273,7 +261,7 @@ importers:
         version: 2.1.1
       docusaurus-plugin-sass:
         specifier: ^0.2.5
-        version: 0.2.6(@docusaurus/core@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(sass@1.79.3)(webpack@5.98.0)
+        version: 0.2.6(@docusaurus/core@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(sass@1.79.3)(webpack@5.98.0)
       prism-react-renderer:
         specifier: ^2.3.0
         version: 2.4.1(react@19.0.0)
@@ -289,13 +277,13 @@ importers:
     devDependencies:
       '@docusaurus/module-type-aliases':
         specifier: 3.7.0
-        version: 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+        version: 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@docusaurus/tsconfig':
         specifier: 3.7.0
         version: 3.7.0
       '@docusaurus/types':
         specifier: 3.7.0
-        version: 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+        version: 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       typescript:
         specifier: ~5.6.2
         version: 5.6.3
@@ -2577,10 +2565,6 @@ packages:
     resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
     engines: {node: '>=18.18'}
 
-  '@hutson/parse-repository-url@3.0.2':
-    resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==}
-    engines: {node: '>=6.9.0'}
-
   '@inquirer/external-editor@1.0.2':
     resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==}
     engines: {node: '>=18'}
@@ -3474,9 +3458,6 @@ packages:
   '@types/minimatch@5.1.2':
     resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
 
-  '@types/minimist@1.2.5':
-    resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
-
   '@types/ms@2.1.0':
     resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
 
@@ -3492,9 +3473,6 @@ packages:
   '@types/node@24.5.2':
     resolution: {integrity: sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==}
 
-  '@types/normalize-package-data@2.4.4':
-    resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
-
   '@types/parse-json@4.0.2':
     resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
 
@@ -3793,10 +3771,6 @@ packages:
   '@xtuc/long@4.2.2':
     resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
 
-  JSONStream@1.3.5:
-    resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
-    hasBin: true
-
   abab@2.0.6:
     resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
     deprecated: Use your platform's native atob() and btoa() methods instead
@@ -3809,10 +3783,6 @@ packages:
     resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
     engines: {node: '>= 0.6'}
 
-  accepts@2.0.0:
-    resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
-    engines: {node: '>= 0.6'}
-
   acorn-globals@4.3.4:
     resolution: {integrity: sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==}
 
@@ -3857,9 +3827,6 @@ packages:
   add-dom-event-listener@1.1.0:
     resolution: {integrity: sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==}
 
-  add-stream@1.0.0:
-    resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==}
-
   address@1.2.2:
     resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==}
     engines: {node: '>= 10.0.0'}
@@ -4062,9 +4029,6 @@ packages:
   array-flatten@1.1.1:
     resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
 
-  array-ify@1.0.0:
-    resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
-
   array-includes@3.1.8:
     resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
     engines: {node: '>= 0.4'}
@@ -4117,10 +4081,6 @@ packages:
     resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
     engines: {node: '>= 0.4'}
 
-  arrify@1.0.1:
-    resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
-    engines: {node: '>=0.10.0'}
-
   asap@2.0.6:
     resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
 
@@ -4369,10 +4329,6 @@ packages:
     resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
     engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
 
-  body-parser@2.2.0:
-    resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==}
-    engines: {node: '>=18'}
-
   bonjour-service@1.3.0:
     resolution: {integrity: sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==}
 
@@ -4551,10 +4507,6 @@ packages:
   camel-case@4.1.2:
     resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
 
-  camelcase-keys@6.2.2:
-    resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
-    engines: {node: '>=8'}
-
   camelcase@4.1.0:
     resolution: {integrity: sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==}
     engines: {node: '>=4'}
@@ -4887,9 +4839,6 @@ packages:
   commondir@1.0.1:
     resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
 
-  compare-func@2.0.0:
-    resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==}
-
   component-classes@1.2.6:
     resolution: {integrity: sha512-hPFGULxdwugu1QWW3SvVOCUHLzO34+a2J6Wqy0c5ASQkfi9/8nZcBB0ZohaEbXOQlCflMAEMmEWk7u7BVs4koA==}
 
@@ -4962,10 +4911,6 @@ packages:
     resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
     engines: {node: '>= 0.6'}
 
-  content-disposition@1.0.0:
-    resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
-    engines: {node: '>= 0.6'}
-
   content-security-policy-builder@2.1.0:
     resolution: {integrity: sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==}
     engines: {node: '>=4.0.0'}
@@ -4974,73 +4919,6 @@ packages:
     resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
     engines: {node: '>= 0.6'}
 
-  conventional-changelog-angular@6.0.0:
-    resolution: {integrity: sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-atom@3.0.0:
-    resolution: {integrity: sha512-pnN5bWpH+iTUWU3FaYdw5lJmfWeqSyrUkG+wyHBI9tC1dLNnHkbAOg1SzTQ7zBqiFrfo55h40VsGXWMdopwc5g==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-cli@3.0.0:
-    resolution: {integrity: sha512-3zMYi0IrfNd6AAHdPMrcgCg5DbcffiqNaEBf8cYrlntXPbBIXaELTbnRmUy5TQAe0Hkgi0J6+/VmRCkkJQflcQ==}
-    engines: {node: '>=14'}
-    hasBin: true
-
-  conventional-changelog-codemirror@3.0.0:
-    resolution: {integrity: sha512-wzchZt9HEaAZrenZAUUHMCFcuYzGoZ1wG/kTRMICxsnW5AXohYMRxnyecP9ob42Gvn5TilhC0q66AtTPRSNMfw==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-conventionalcommits@6.1.0:
-    resolution: {integrity: sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-core@5.0.2:
-    resolution: {integrity: sha512-RhQOcDweXNWvlRwUDCpaqXzbZemKPKncCWZG50Alth72WITVd6nhVk9MJ6w1k9PFNBcZ3YwkdkChE+8+ZwtUug==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-ember@3.0.0:
-    resolution: {integrity: sha512-7PYthCoSxIS98vWhVcSphMYM322OxptpKAuHYdVspryI0ooLDehRXWeRWgN+zWSBXKl/pwdgAg8IpLNSM1/61A==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-eslint@4.0.0:
-    resolution: {integrity: sha512-nEZ9byP89hIU0dMx37JXQkE1IpMmqKtsaR24X7aM3L6Yy/uAtbb+ogqthuNYJkeO1HyvK7JsX84z8649hvp43Q==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-express@3.0.0:
-    resolution: {integrity: sha512-HqxihpUMfIuxvlPvC6HltA4ZktQEUan/v3XQ77+/zbu8No/fqK3rxSZaYeHYant7zRxQNIIli7S+qLS9tX9zQA==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-jquery@4.0.0:
-    resolution: {integrity: sha512-TTIN5CyzRMf8PUwyy4IOLmLV2DFmPtasKN+x7EQKzwSX8086XYwo+NeaeA3VUT8bvKaIy5z/JoWUvi7huUOgaw==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-jshint@3.0.0:
-    resolution: {integrity: sha512-bQof4byF4q+n+dwFRkJ/jGf9dCNUv4/kCDcjeCizBvfF81TeimPZBB6fT4HYbXgxxfxWXNl/i+J6T0nI4by6DA==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-preset-loader@3.0.0:
-    resolution: {integrity: sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==}
-    engines: {node: '>=14'}
-
-  conventional-changelog-writer@6.0.1:
-    resolution: {integrity: sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==}
-    engines: {node: '>=14'}
-    hasBin: true
-
-  conventional-changelog@4.0.0:
-    resolution: {integrity: sha512-JbZjwE1PzxQCvm+HUTIr+pbSekS8qdOZzMakdFyPtdkEWwFvwEJYONzjgMm0txCb2yBcIcfKDmg8xtCKTdecNQ==}
-    engines: {node: '>=14'}
-
-  conventional-commits-filter@3.0.0:
-    resolution: {integrity: sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==}
-    engines: {node: '>=14'}
-
-  conventional-commits-parser@4.0.0:
-    resolution: {integrity: sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==}
-    engines: {node: '>=14'}
-    hasBin: true
-
   convert-source-map@1.9.0:
     resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
 
@@ -5050,10 +4928,6 @@ packages:
   cookie-signature@1.0.6:
     resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
 
-  cookie-signature@1.2.2:
-    resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
-    engines: {node: '>=6.6.0'}
-
   cookie@0.4.0:
     resolution: {integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==}
     engines: {node: '>= 0.6'}
@@ -5346,10 +5220,6 @@ packages:
   damerau-levenshtein@1.0.8:
     resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
 
-  dargs@7.0.0:
-    resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
-    engines: {node: '>=8'}
-
   dashdash@1.14.1:
     resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
     engines: {node: '>=0.10'}
@@ -5391,9 +5261,6 @@ packages:
   dateformat@2.2.0:
     resolution: {integrity: sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==}
 
-  dateformat@3.0.3:
-    resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==}
-
   dayjs@1.11.13:
     resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
 
@@ -5445,10 +5312,6 @@ packages:
       supports-color:
         optional: true
 
-  decamelize-keys@1.1.1:
-    resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
-    engines: {node: '>=0.10.0'}
-
   decamelize@1.2.0:
     resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
     engines: {node: '>=0.10.0'}
@@ -5680,10 +5543,6 @@ packages:
   dot-case@3.0.4:
     resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
 
-  dot-prop@5.3.0:
-    resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
-    engines: {node: '>=8'}
-
   dot-prop@6.0.1:
     resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==}
     engines: {node: '>=10'}
@@ -6238,10 +6097,6 @@ packages:
     resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
     engines: {node: '>= 0.10.0'}
 
-  express@5.1.0:
-    resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
-    engines: {node: '>= 18'}
-
   ext@1.7.0:
     resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
 
@@ -6389,10 +6244,6 @@ packages:
     resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
     engines: {node: '>= 0.8'}
 
-  finalhandler@2.1.0:
-    resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
-    engines: {node: '>= 0.8'}
-
   find-cache-dir@2.1.0:
     resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==}
     engines: {node: '>=6'}
@@ -6405,10 +6256,6 @@ packages:
     resolution: {integrity: sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==}
     engines: {node: '>=14.16'}
 
-  find-up@2.1.0:
-    resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==}
-    engines: {node: '>=4'}
-
   find-up@3.0.0:
     resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
     engines: {node: '>=6'}
@@ -6547,10 +6394,6 @@ packages:
     resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
     engines: {node: '>= 0.6'}
 
-  fresh@2.0.0:
-    resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
-    engines: {node: '>= 0.8'}
-
   from2@2.3.0:
     resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==}
 
@@ -6630,11 +6473,6 @@ packages:
   get-own-enumerable-property-symbols@3.0.2:
     resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
 
-  get-pkg-repo@4.2.1:
-    resolution: {integrity: sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==}
-    engines: {node: '>=6.9.0'}
-    hasBin: true
-
   get-proto@1.0.1:
     resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
     engines: {node: '>= 0.4'}
@@ -6673,26 +6511,9 @@ packages:
       js-git:
         optional: true
 
-  git-raw-commits@3.0.0:
-    resolution: {integrity: sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==}
-    engines: {node: '>=14'}
-    hasBin: true
-
-  git-remote-origin-url@2.0.0:
-    resolution: {integrity: sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==}
-    engines: {node: '>=4'}
-
-  git-semver-tags@5.0.1:
-    resolution: {integrity: sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==}
-    engines: {node: '>=14'}
-    hasBin: true
-
   git-sha1@0.1.2:
     resolution: {integrity: sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg==}
 
-  gitconfiglocal@1.0.0:
-    resolution: {integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==}
-
   github-buttons@2.29.1:
     resolution: {integrity: sha512-TV3YgAKda5hPz75n7QXmGCsSzgVya1vvmBieebg3EB5ScmashTZ0FldViG1aU2d4V5rcAGrtQ7k5uAaCo0A4PA==}
 
@@ -6795,11 +6616,6 @@ packages:
   handle-thing@2.0.1:
     resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==}
 
-  handlebars@4.7.8:
-    resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==}
-    engines: {node: '>=0.4.7'}
-    hasBin: true
-
   har-schema@2.0.0:
     resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==}
     engines: {node: '>=4'}
@@ -6809,10 +6625,6 @@ packages:
     engines: {node: '>=6'}
     deprecated: this library is no longer supported
 
-  hard-rejection@2.1.0:
-    resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
-    engines: {node: '>=6'}
-
   has-ansi@2.0.0:
     resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==}
     engines: {node: '>=0.10.0'}
@@ -6957,10 +6769,6 @@ packages:
   hosted-git-info@2.8.9:
     resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
 
-  hosted-git-info@4.1.0:
-    resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
-    engines: {node: '>=10'}
-
   hpack.js@2.1.6:
     resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==}
 
@@ -7095,10 +6903,6 @@ packages:
     resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
     engines: {node: '>=0.10.0'}
 
-  iconv-lite@0.7.0:
-    resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==}
-    engines: {node: '>=0.10.0'}
-
   iconv-lite@0.7.2:
     resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
     engines: {node: '>=0.10.0'}
@@ -7435,10 +7239,6 @@ packages:
     resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
     engines: {node: '>=8'}
 
-  is-plain-obj@1.1.0:
-    resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
-    engines: {node: '>=0.10.0'}
-
   is-plain-obj@3.0.0:
     resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==}
     engines: {node: '>=10'}
@@ -7454,9 +7254,6 @@ packages:
   is-promise@2.2.2:
     resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
 
-  is-promise@4.0.0:
-    resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
-
   is-property@1.0.2:
     resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==}
 
@@ -7496,10 +7293,6 @@ packages:
     resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
     engines: {node: '>= 0.4'}
 
-  is-text-path@1.0.1:
-    resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==}
-    engines: {node: '>=0.10.0'}
-
   is-type-of@1.4.0:
     resolution: {integrity: sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==}
 
@@ -7881,10 +7674,6 @@ packages:
   jsonfile@6.1.0:
     resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
 
-  jsonparse@1.3.1:
-    resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
-    engines: {'0': node >= 0.2.0}
-
   jsonpointer@5.0.1:
     resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
     engines: {node: '>=0.10.0'}
@@ -8051,10 +7840,6 @@ packages:
     resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==}
     engines: {node: '>= 12.13.0'}
 
-  locate-path@2.0.0:
-    resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
-    engines: {node: '>=4'}
-
   locate-path@3.0.0:
     resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
     engines: {node: '>=6'}
@@ -8096,9 +7881,6 @@ packages:
   lodash.isinteger@4.0.4:
     resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
 
-  lodash.ismatch@4.4.0:
-    resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==}
-
   lodash.isnumber@3.0.3:
     resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
 
@@ -8162,9 +7944,6 @@ packages:
     resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==}
     hasBin: true
 
-  long@5.2.3:
-    resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==}
-
   long@5.3.2:
     resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
 
@@ -8196,10 +7975,6 @@ packages:
   lru-queue@0.1.0:
     resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==}
 
-  lru.min@1.1.1:
-    resolution: {integrity: sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==}
-    engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'}
-
   lru.min@1.1.4:
     resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==}
     engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'}
@@ -8236,14 +8011,6 @@ packages:
     resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
     engines: {node: '>=0.10.0'}
 
-  map-obj@1.0.1:
-    resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==}
-    engines: {node: '>=0.10.0'}
-
-  map-obj@4.3.0:
-    resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==}
-    engines: {node: '>=8'}
-
   map-visit@1.0.0:
     resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==}
     engines: {node: '>=0.10.0'}
@@ -8337,10 +8104,6 @@ packages:
     resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
     engines: {node: '>= 0.6'}
 
-  media-typer@1.1.0:
-    resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
-    engines: {node: '>= 0.8'}
-
   memfs@3.5.3:
     resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==}
     engines: {node: '>= 4.0.0'}
@@ -8359,20 +8122,12 @@ packages:
     resolution: {integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==}
     engines: {node: '>=4.3.0 <5.0.0 || >=5.10'}
 
-  meow@8.1.2:
-    resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==}
-    engines: {node: '>=10'}
-
   merge-descriptors@1.0.1:
     resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
 
   merge-descriptors@1.0.3:
     resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
 
-  merge-descriptors@2.0.0:
-    resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
-    engines: {node: '>=18'}
-
   merge-stream@2.0.0:
     resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
 
@@ -8600,10 +8355,6 @@ packages:
     resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
     engines: {node: '>= 0.6'}
 
-  mime-types@3.0.1:
-    resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==}
-    engines: {node: '>= 0.6'}
-
   mime@1.6.0:
     resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
     engines: {node: '>=4'}
@@ -8657,10 +8408,6 @@ packages:
     resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
     engines: {node: '>=10'}
 
-  minimist-options@4.1.0:
-    resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
-    engines: {node: '>= 6'}
-
   minimist@1.2.0:
     resolution: {integrity: sha512-7Wl+Jz+IGWuSdgsQEJ4JunV0si/iMhg42MnQQG6h1R6TNeVenp4U9x5CC5v/gYqz/fENLQITAWXidNtVL0NNbw==}
 
@@ -8684,10 +8431,6 @@ packages:
     engines: {node: '>=10'}
     hasBin: true
 
-  modify-values@1.0.1:
-    resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==}
-    engines: {node: '>=0.10.0'}
-
   module-details-from-path@1.0.4:
     resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==}
 
@@ -8726,10 +8469,6 @@ packages:
   mute-stream@0.0.8:
     resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
 
-  mysql2@3.12.0:
-    resolution: {integrity: sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==}
-    engines: {node: '>= 8.0'}
-
   mysql2@3.22.3:
     resolution: {integrity: sha512-uWWxvZSRvRhtBdh2CdcuK83YcOfPdmEeEYB069bAmPnV93QApDGVPuvCQOLjlh7tYHEWdgQPrn6kosDxHBVLkA==}
     engines: {node: '>= 8.0'}
@@ -8739,10 +8478,6 @@ packages:
   mz@2.7.0:
     resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
 
-  named-placeholders@1.1.3:
-    resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==}
-    engines: {node: '>=12.0.0'}
-
   named-placeholders@1.1.6:
     resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==}
     engines: {node: '>=8.0.0'}
@@ -8784,10 +8519,6 @@ packages:
     resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
     engines: {node: '>= 0.6'}
 
-  negotiator@1.0.0:
-    resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
-    engines: {node: '>= 0.6'}
-
   neo-async@2.6.2:
     resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
 
@@ -8964,10 +8695,6 @@ packages:
   normalize-package-data@2.5.0:
     resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
 
-  normalize-package-data@3.0.3:
-    resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==}
-    engines: {node: '>=10'}
-
   normalize-path@2.1.1:
     resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==}
     engines: {node: '>=0.10.0'}
@@ -9210,10 +8937,6 @@ packages:
     resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
     engines: {node: '>=4'}
 
-  p-limit@1.3.0:
-    resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==}
-    engines: {node: '>=4'}
-
   p-limit@2.3.0:
     resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
     engines: {node: '>=6'}
@@ -9226,10 +8949,6 @@ packages:
     resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
 
-  p-locate@2.0.0:
-    resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==}
-    engines: {node: '>=4'}
-
   p-locate@3.0.0:
     resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
     engines: {node: '>=6'}
@@ -9262,10 +8981,6 @@ packages:
     resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==}
     engines: {node: '>=8'}
 
-  p-try@1.0.0:
-    resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==}
-    engines: {node: '>=4'}
-
   p-try@2.2.0:
     resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
     engines: {node: '>=6'}
@@ -9414,9 +9129,6 @@ packages:
   path-to-regexp@3.3.0:
     resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==}
 
-  path-to-regexp@8.3.0:
-    resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==}
-
   path-type@3.0.0:
     resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==}
     engines: {node: '>=4'}
@@ -10109,10 +9821,6 @@ packages:
   queue@6.0.2:
     resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
 
-  quick-lru@4.0.1:
-    resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
-    engines: {node: '>=8'}
-
   quick-lru@5.1.1:
     resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
     engines: {node: '>=10'}
@@ -10142,10 +9850,6 @@ packages:
     resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
     engines: {node: '>= 0.8'}
 
-  raw-body@3.0.1:
-    resolution: {integrity: sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==}
-    engines: {node: '>= 0.10'}
-
   rc-animate@2.11.1:
     resolution: {integrity: sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ==}
     peerDependencies:
@@ -10595,26 +10299,14 @@ packages:
     resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
     engines: {node: '>=0.10.0'}
 
-  read-pkg-up@3.0.0:
-    resolution: {integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==}
-    engines: {node: '>=4'}
-
   read-pkg-up@4.0.0:
     resolution: {integrity: sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==}
     engines: {node: '>=6'}
 
-  read-pkg-up@7.0.1:
-    resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
-    engines: {node: '>=8'}
-
   read-pkg@3.0.0:
     resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==}
     engines: {node: '>=4'}
 
-  read-pkg@5.2.0:
-    resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
-    engines: {node: '>=8'}
-
   read@1.0.7:
     resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==}
     engines: {node: '>=0.8'}
@@ -10944,10 +10636,6 @@ packages:
     engines: {node: '>=10.0.0'}
     hasBin: true
 
-  router@2.2.0:
-    resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
-    engines: {node: '>= 18'}
-
   rsvp@4.8.5:
     resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==}
     engines: {node: 6.* || >= 7.*}
@@ -11129,13 +10817,6 @@ packages:
     resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
     engines: {node: '>= 0.8.0'}
 
-  send@1.2.0:
-    resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==}
-    engines: {node: '>= 18'}
-
-  seq-queue@0.0.5:
-    resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==}
-
   serialize-error@2.1.0:
     resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==}
     engines: {node: '>=0.10.0'}
@@ -11161,10 +10842,6 @@ packages:
     resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
     engines: {node: '>= 0.8.0'}
 
-  serve-static@2.2.0:
-    resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
-    engines: {node: '>= 18'}
-
   set-blocking@2.0.0:
     resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
 
@@ -11436,12 +11113,6 @@ packages:
     resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
     engines: {node: '>=0.10.0'}
 
-  split2@3.2.2:
-    resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==}
-
-  split@1.0.1:
-    resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==}
-
   sprintf-js@1.0.3:
     resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
 
@@ -11452,10 +11123,6 @@ packages:
     resolution: {integrity: sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==}
     engines: {bun: '>=1.0.0', deno: '>=2.0.0', node: '>=12.0.0'}
 
-  sqlstring@2.3.3:
-    resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==}
-    engines: {node: '>= 0.6'}
-
   srcset@4.0.0:
     resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==}
     engines: {node: '>=12'}
@@ -11807,10 +11474,6 @@ packages:
     resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==}
     engines: {node: '>=6.0.0'}
 
-  tempfile@3.0.0:
-    resolution: {integrity: sha512-uNFCg478XovRi85iD42egu+eSFUmmka750Jy7L5tfHI5hQKKtbPnxaSaXAbBqCDYrw3wx4tXjKwci4/QmsZJxw==}
-    engines: {node: '>=8'}
-
   tempy@0.6.0:
     resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==}
     engines: {node: '>=10'}
@@ -11867,10 +11530,6 @@ packages:
     resolution: {integrity: sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==}
     engines: {node: '>=6'}
 
-  text-extensions@1.9.0:
-    resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==}
-    engines: {node: '>=0.10'}
-
   text-table@0.2.0:
     resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
 
@@ -11979,10 +11638,6 @@ packages:
   trim-lines@3.0.1:
     resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
 
-  trim-newlines@3.0.1:
-    resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
-    engines: {node: '>=8'}
-
   trough@2.2.0:
     resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
 
@@ -12083,10 +11738,6 @@ packages:
     resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==}
     engines: {node: '>=10'}
 
-  type-fest@0.18.1:
-    resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
-    engines: {node: '>=10'}
-
   type-fest@0.20.2:
     resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
     engines: {node: '>=10'}
@@ -12095,18 +11746,10 @@ packages:
     resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
     engines: {node: '>=10'}
 
-  type-fest@0.6.0:
-    resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
-    engines: {node: '>=8'}
-
   type-fest@0.7.1:
     resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==}
     engines: {node: '>=8'}
 
-  type-fest@0.8.1:
-    resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
-    engines: {node: '>=8'}
-
   type-fest@1.4.0:
     resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==}
     engines: {node: '>=10'}
@@ -12119,10 +11762,6 @@ packages:
     resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
     engines: {node: '>= 0.6'}
 
-  type-is@2.0.1:
-    resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
-    engines: {node: '>= 0.6'}
-
   type@2.7.3:
     resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
 
@@ -12232,11 +11871,6 @@ packages:
     resolution: {integrity: sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==}
     hasBin: true
 
-  uglify-js@3.19.3:
-    resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
-    engines: {node: '>=0.8.0'}
-    hasBin: true
-
   unbox-primitive@1.0.2:
     resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
 
@@ -12668,9 +12302,6 @@ packages:
     resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
     engines: {node: '>=0.10.0'}
 
-  wordwrap@1.0.0:
-    resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
-
   workbox-background-sync@6.6.0:
     resolution: {integrity: sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==}
 
@@ -13353,19 +12984,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/helper-create-class-features-plugin@7.26.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-annotate-as-pure': 7.25.9
-      '@babel/helper-member-expression-to-functions': 7.25.9
-      '@babel/helper-optimise-call-expression': 7.25.9
-      '@babel/helper-replace-supers': 7.26.5(@babel/core@7.25.2)
-      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
-      '@babel/traverse': 7.26.9
-      semver: 6.3.1
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/helper-create-class-features-plugin@7.26.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13393,13 +13011,6 @@ snapshots:
       regexpu-core: 5.3.2
       semver: 6.3.1
 
-  '@babel/helper-create-regexp-features-plugin@7.26.3(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-annotate-as-pure': 7.25.9
-      regexpu-core: 6.2.0
-      semver: 6.3.1
-
   '@babel/helper-create-regexp-features-plugin@7.26.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13429,17 +13040,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-compilation-targets': 7.26.5
-      '@babel/helper-plugin-utils': 7.26.5
-      debug: 4.4.3
-      lodash.debounce: 4.0.8
-      resolve: 1.22.8
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13489,25 +13089,16 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/helper-module-transforms@7.26.0(@babel/core@7.25.2)':
+  '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.9)':
     dependencies:
-      '@babel/core': 7.25.2
+      '@babel/core': 7.26.9
       '@babel/helper-module-imports': 7.25.9
       '@babel/helper-validator-identifier': 7.27.1
       '@babel/traverse': 7.26.9
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.9)':
-    dependencies:
-      '@babel/core': 7.26.9
-      '@babel/helper-module-imports': 7.25.9
-      '@babel/helper-validator-identifier': 7.27.1
-      '@babel/traverse': 7.26.9
-    transitivePeerDependencies:
-      - supports-color
-
-  '@babel/helper-optimise-call-expression@7.24.7':
+  '@babel/helper-optimise-call-expression@7.24.7':
     dependencies:
       '@babel/types': 7.28.4
 
@@ -13528,15 +13119,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-annotate-as-pure': 7.25.9
-      '@babel/helper-wrap-function': 7.25.9
-      '@babel/traverse': 7.26.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13555,15 +13137,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/helper-replace-supers@7.26.5(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-member-expression-to-functions': 7.25.9
-      '@babel/helper-optimise-call-expression': 7.25.9
-      '@babel/traverse': 7.26.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13644,14 +13217,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/traverse': 7.26.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13665,11 +13230,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13680,11 +13240,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13699,15 +13254,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
-      '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.25.2)
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13725,14 +13271,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/traverse': 7.26.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13749,11 +13287,11 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-proposal-export-default-from@7.24.7(@babel/core@7.25.2)':
+  '@babel/plugin-proposal-export-default-from@7.24.7(@babel/core@7.26.9)':
     dependencies:
-      '@babel/core': 7.25.2
+      '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
-      '@babel/plugin-syntax-export-default-from': 7.24.7(@babel/core@7.25.2)
+      '@babel/plugin-syntax-export-default-from': 7.24.7(@babel/core@7.26.9)
 
   '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.26.9)':
     dependencies:
@@ -13803,9 +13341,9 @@ snapshots:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-syntax-export-default-from@7.24.7(@babel/core@7.25.2)':
+  '@babel/plugin-syntax-export-default-from@7.24.7(@babel/core@7.26.9)':
     dependencies:
-      '@babel/core': 7.25.2
+      '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
 
   '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)':
@@ -13813,11 +13351,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13828,11 +13361,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13843,11 +13371,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13938,11 +13461,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13965,11 +13483,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -13985,15 +13498,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-async-generator-functions@7.26.8(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.25.2)
-      '@babel/traverse': 7.26.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-async-generator-functions@7.26.8(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14012,15 +13516,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-module-imports': 7.25.9
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.25.2)
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14035,11 +13530,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-block-scoped-functions@7.26.5(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-block-scoped-functions@7.26.5(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14050,11 +13540,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14068,14 +13553,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14093,14 +13570,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14121,18 +13590,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-classes@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-annotate-as-pure': 7.25.9
-      '@babel/helper-compilation-targets': 7.26.5
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-replace-supers': 7.26.5(@babel/core@7.25.2)
-      '@babel/traverse': 7.26.9
-      globals: 11.12.0
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14151,12 +13608,6 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       '@babel/template': 7.25.0
 
-  '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/template': 7.26.9
-
   '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14168,11 +13619,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14184,12 +13630,6 @@ snapshots:
       '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14201,11 +13641,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14217,12 +13652,6 @@ snapshots:
       '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14235,11 +13664,6 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2)
 
-  '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14253,11 +13677,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-exponentiation-operator@7.26.3(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-exponentiation-operator@7.26.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14269,22 +13688,11 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2)
 
-  '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
 
-  '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.25.2)
-
   '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14299,14 +13707,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-for-of@7.26.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-for-of@7.26.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14324,15 +13724,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-compilation-targets': 7.26.5
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/traverse': 7.26.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14348,11 +13739,6 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2)
 
-  '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14363,11 +13749,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-literals@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14379,11 +13760,6 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2)
 
-  '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14394,11 +13770,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14412,14 +13783,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-module-transforms': 7.26.0(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14437,14 +13800,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-module-transforms': 7.26.0(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14463,16 +13818,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-module-transforms': 7.26.0(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-validator-identifier': 7.27.1
-      '@babel/traverse': 7.26.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14491,14 +13836,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-module-transforms': 7.26.0(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14513,12 +13850,6 @@ snapshots:
       '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14530,11 +13861,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14546,11 +13872,6 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2)
 
-  '@babel/plugin-transform-nullish-coalescing-operator@7.26.6(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-nullish-coalescing-operator@7.26.6(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14562,11 +13883,6 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2)
 
-  '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14580,13 +13896,6 @@ snapshots:
       '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2)
       '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.25.2)
 
-  '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-compilation-targets': 7.26.5
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.25.2)
-
   '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14602,14 +13911,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-replace-supers': 7.26.5(@babel/core@7.25.2)
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14624,11 +13925,6 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2)
 
-  '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14643,14 +13939,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14664,11 +13952,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14682,14 +13965,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14708,15 +13983,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-annotate-as-pure': 7.25.9
-      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14731,11 +13997,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14770,14 +14031,14 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.25.2)':
+  '@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.26.9)':
     dependencies:
-      '@babel/core': 7.25.2
+      '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
 
-  '@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.25.2)':
+  '@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.26.9)':
     dependencies:
-      '@babel/core': 7.25.2
+      '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
 
   '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.25.2)':
@@ -14820,24 +14081,12 @@ snapshots:
       '@babel/helper-plugin-utils': 7.24.8
       regenerator-transform: 0.15.2
 
-  '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      regenerator-transform: 0.15.2
-
   '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
       regenerator-transform: 0.15.2
 
-  '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14849,28 +14098,11 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
 
-  '@babel/plugin-transform-runtime@7.26.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-module-imports': 7.25.9
-      '@babel/helper-plugin-utils': 7.26.5
-      babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2)
-      babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2)
-      babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2)
-      semver: 6.3.1
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-runtime@7.26.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14888,11 +14120,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14906,14 +14133,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-spread@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14927,11 +14146,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14942,11 +14156,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-template-literals@7.26.8(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-template-literals@7.26.8(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14957,11 +14166,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-typeof-symbol@7.26.7(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-typeof-symbol@7.26.7(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -14978,17 +14182,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/plugin-transform-typescript@7.26.8(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-annotate-as-pure': 7.25.9
-      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
-      '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.25.2)
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/plugin-transform-typescript@7.26.8(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -15005,11 +14198,6 @@ snapshots:
       '@babel/core': 7.25.2
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -15021,12 +14209,6 @@ snapshots:
       '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -15039,12 +14221,6 @@ snapshots:
       '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -15057,12 +14233,6 @@ snapshots:
       '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
       '@babel/helper-plugin-utils': 7.24.8
 
-  '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.25.2)
-      '@babel/helper-plugin-utils': 7.26.5
-
   '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
@@ -15158,81 +14328,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/preset-env@7.26.9(@babel/core@7.25.2)':
-    dependencies:
-      '@babel/compat-data': 7.26.8
-      '@babel/core': 7.25.2
-      '@babel/helper-compilation-targets': 7.26.5
-      '@babel/helper-plugin-utils': 7.26.5
-      '@babel/helper-validator-option': 7.25.9
-      '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)
-      '@babel/plugin-syntax-import-assertions': 7.26.0(@babel/core@7.25.2)
-      '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.25.2)
-      '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.25.2)
-      '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-async-generator-functions': 7.26.8(@babel/core@7.25.2)
-      '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-block-scoped-functions': 7.26.5(@babel/core@7.25.2)
-      '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-class-static-block': 7.26.0(@babel/core@7.25.2)
-      '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-exponentiation-operator': 7.26.3(@babel/core@7.25.2)
-      '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-for-of': 7.26.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.25.2)
-      '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.25.2)
-      '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-regexp-modifiers': 7.26.0(@babel/core@7.25.2)
-      '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-template-literals': 7.26.8(@babel/core@7.25.2)
-      '@babel/plugin-transform-typeof-symbol': 7.26.7(@babel/core@7.25.2)
-      '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.25.2)
-      babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2)
-      babel-plugin-polyfill-corejs3: 0.11.1(@babel/core@7.25.2)
-      babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2)
-      core-js-compat: 3.41.0
-      semver: 6.3.1
-    transitivePeerDependencies:
-      - supports-color
-
   '@babel/preset-env@7.26.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/compat-data': 7.26.8
@@ -15722,7 +14817,7 @@ snapshots:
     transitivePeerDependencies:
       - '@algolia/client-search'
 
-  '@docusaurus/babel@3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+  '@docusaurus/babel@3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/generator': 7.26.9
@@ -15735,7 +14830,7 @@ snapshots:
       '@babel/runtime-corejs3': 7.26.9
       '@babel/traverse': 7.26.9
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       babel-plugin-dynamic-import-node: 2.3.3
       fs-extra: 11.3.0
       tslib: 2.7.0
@@ -15749,14 +14844,14 @@ snapshots:
       - uglify-js
       - webpack-cli
 
-  '@docusaurus/bundler@3.7.0(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/bundler@3.7.0(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
       '@babel/core': 7.26.9
-      '@docusaurus/babel': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/babel': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@docusaurus/cssnano-preset': 3.7.0
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       babel-loader: 9.2.1(@babel/core@7.26.9)(webpack@5.98.0)
       clean-css: 5.3.3
       copy-webpack-plugin: 11.0.0(webpack@5.98.0)
@@ -15794,15 +14889,15 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/core@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/core@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/babel': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/bundler': 3.7.0(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/babel': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/bundler': 3.7.0(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/mdx-loader': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-common': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/mdx-loader': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-common': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@mdx-js/react': 3.1.0(@types/react@17.0.42)(react@19.0.0)
       boxen: 6.2.1
       chalk: 4.1.2
@@ -15873,12 +14968,12 @@ snapshots:
       chalk: 4.1.2
       tslib: 2.7.0
 
-  '@docusaurus/mdx-loader@3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+  '@docusaurus/mdx-loader@3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
     dependencies:
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@mdx-js/mdx': 3.1.0(acorn@8.14.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@mdx-js/mdx': 3.1.0(acorn@8.15.0)
       '@slorber/remark-comment': 1.0.0
       escape-html: 1.0.3
       estree-util-value-to-estree: 3.3.2
@@ -15909,9 +15004,9 @@ snapshots:
       - uglify-js
       - webpack-cli
 
-  '@docusaurus/module-type-aliases@3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+  '@docusaurus/module-type-aliases@3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
     dependencies:
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@types/history': 4.7.11
       '@types/react': 17.0.42
       '@types/react-router-config': 5.0.11
@@ -15928,17 +15023,17 @@ snapshots:
       - uglify-js
       - webpack-cli
 
-  '@docusaurus/plugin-content-blog@3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-content-blog@3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/mdx-loader': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-common': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/mdx-loader': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-common': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       cheerio: 1.0.0-rc.12
       feed: 4.2.2
       fs-extra: 11.3.0
@@ -15972,17 +15067,17 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/mdx-loader': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/module-type-aliases': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-common': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/mdx-loader': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/module-type-aliases': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-common': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@types/react-router-config': 5.0.11
       combine-promises: 1.2.0
       fs-extra: 11.3.0
@@ -16014,13 +15109,13 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/plugin-content-pages@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-content-pages@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/mdx-loader': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/mdx-loader': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       fs-extra: 11.3.0
       react: 19.0.0
       react-dom: 19.0.0(react@19.0.0)
@@ -16047,11 +15142,11 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/plugin-debug@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-debug@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       fs-extra: 11.3.0
       react: 19.0.0
       react-dom: 19.0.0(react@19.0.0)
@@ -16078,11 +15173,11 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/plugin-google-analytics@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-google-analytics@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       react: 19.0.0
       react-dom: 19.0.0(react@19.0.0)
       tslib: 2.7.0
@@ -16107,11 +15202,11 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/plugin-google-gtag@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-google-gtag@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@types/gtag.js': 0.0.12
       react: 19.0.0
       react-dom: 19.0.0(react@19.0.0)
@@ -16137,11 +15232,11 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/plugin-google-tag-manager@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-google-tag-manager@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       react: 19.0.0
       react-dom: 19.0.0(react@19.0.0)
       tslib: 2.7.0
@@ -16166,14 +15261,14 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/plugin-sitemap@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-sitemap@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-common': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-common': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       fs-extra: 11.3.0
       react: 19.0.0
       react-dom: 19.0.0(react@19.0.0)
@@ -16200,12 +15295,12 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/plugin-svgr@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/plugin-svgr@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@svgr/core': 8.1.0(typescript@5.6.3)
       '@svgr/webpack': 8.1.0(typescript@5.6.3)
       react: 19.0.0
@@ -16233,22 +15328,22 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/preset-classic@3.7.0(@algolia/client-search@5.20.3)(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(@types/react@17.0.42)(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)(typescript@5.6.3)':
-    dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-content-blog': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-content-pages': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-debug': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-google-analytics': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-google-gtag': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-google-tag-manager': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-sitemap': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-svgr': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/theme-classic': 3.7.0(@types/react@17.0.42)(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/theme-search-algolia': 3.7.0(@algolia/client-search@5.20.3)(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(@types/react@17.0.42)(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)(typescript@5.6.3)
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+  '@docusaurus/preset-classic@3.7.0(@algolia/client-search@5.20.3)(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(@types/react@17.0.42)(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)(typescript@5.6.3)':
+    dependencies:
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-content-blog': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-content-pages': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-debug': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-google-analytics': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-google-gtag': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-google-tag-manager': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-sitemap': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-svgr': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/theme-classic': 3.7.0(@types/react@17.0.42)(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/theme-search-algolia': 3.7.0(@algolia/client-search@5.20.3)(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(@types/react@17.0.42)(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)(typescript@5.6.3)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       react: 19.0.0
       react-dom: 19.0.0(react@19.0.0)
     transitivePeerDependencies:
@@ -16280,21 +15375,21 @@ snapshots:
       '@types/react': 17.0.42
       react: 19.0.0
 
-  '@docusaurus/theme-classic@3.7.0(@types/react@17.0.42)(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
+  '@docusaurus/theme-classic@3.7.0(@types/react@17.0.42)(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)':
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/mdx-loader': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/module-type-aliases': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/plugin-content-blog': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/plugin-content-pages': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/mdx-loader': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/module-type-aliases': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/plugin-content-blog': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/plugin-content-pages': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@docusaurus/theme-translations': 3.7.0
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-common': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-common': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@mdx-js/react': 3.1.0(@types/react@17.0.42)(react@19.0.0)
       clsx: 2.1.1
       copy-text-to-clipboard: 3.2.0
@@ -16331,13 +15426,13 @@ snapshots:
       - vue-template-compiler
       - webpack-cli
 
-  '@docusaurus/theme-common@3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+  '@docusaurus/theme-common@3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
     dependencies:
-      '@docusaurus/mdx-loader': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/module-type-aliases': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-common': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/mdx-loader': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/module-type-aliases': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-common': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@types/history': 4.7.11
       '@types/react': 17.0.42
       '@types/react-router-config': 5.0.11
@@ -16356,16 +15451,16 @@ snapshots:
       - uglify-js
       - webpack-cli
 
-  '@docusaurus/theme-search-algolia@3.7.0(@algolia/client-search@5.20.3)(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(@types/react@17.0.42)(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)(typescript@5.6.3)':
+  '@docusaurus/theme-search-algolia@3.7.0(@algolia/client-search@5.20.3)(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(@types/react@17.0.42)(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)(typescript@5.6.3)':
     dependencies:
       '@docsearch/react': 3.9.0(@algolia/client-search@5.20.3)(@types/react@17.0.42)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
-      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/plugin-content-docs': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/theme-common': 3.7.0(@docusaurus/plugin-content-docs@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       '@docusaurus/theme-translations': 3.7.0
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-validation': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-validation': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       algoliasearch: 5.20.3
       algoliasearch-helper: 3.24.1(algoliasearch@5.20.3)
       clsx: 2.1.1
@@ -16407,9 +15502,9 @@ snapshots:
 
   '@docusaurus/tsconfig@3.7.0': {}
 
-  '@docusaurus/types@3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+  '@docusaurus/types@3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
     dependencies:
-      '@mdx-js/mdx': 3.1.0(acorn@8.14.0)
+      '@mdx-js/mdx': 3.1.0(acorn@8.15.0)
       '@types/history': 4.7.11
       '@types/react': 17.0.42
       commander: 5.1.0
@@ -16428,9 +15523,9 @@ snapshots:
       - uglify-js
       - webpack-cli
 
-  '@docusaurus/utils-common@3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+  '@docusaurus/utils-common@3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
     dependencies:
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       tslib: 2.7.0
     transitivePeerDependencies:
       - '@swc/core'
@@ -16442,11 +15537,11 @@ snapshots:
       - uglify-js
       - webpack-cli
 
-  '@docusaurus/utils-validation@3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+  '@docusaurus/utils-validation@3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
     dependencies:
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/utils': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-common': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-common': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       fs-extra: 11.3.0
       joi: 17.13.3
       js-yaml: 4.1.0
@@ -16462,11 +15557,11 @@ snapshots:
       - uglify-js
       - webpack-cli
 
-  '@docusaurus/utils@3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+  '@docusaurus/utils@3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
     dependencies:
       '@docusaurus/logger': 3.7.0
-      '@docusaurus/types': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-      '@docusaurus/utils-common': 3.7.0(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/types': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+      '@docusaurus/utils-common': 3.7.0(acorn@8.15.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
       escape-string-regexp: 4.0.0
       file-loader: 6.2.0(webpack@5.98.0)
       fs-extra: 11.3.0
@@ -16664,8 +15759,6 @@ snapshots:
 
   '@humanwhocodes/retry@0.4.3': {}
 
-  '@hutson/parse-repository-url@3.0.2': {}
-
   '@inquirer/external-editor@1.0.2(@types/node@12.20.55)':
     dependencies:
       chardet: 2.1.0
@@ -16883,7 +15976,7 @@ snapshots:
 
   '@leichtgewicht/ip-codec@2.0.5': {}
 
-  '@mdx-js/mdx@3.1.0(acorn@8.14.0)':
+  '@mdx-js/mdx@3.1.0(acorn@8.15.0)':
     dependencies:
       '@types/estree': 1.0.6
       '@types/estree-jsx': 1.0.5
@@ -16897,7 +15990,7 @@ snapshots:
       hast-util-to-jsx-runtime: 2.3.5
       markdown-extensions: 2.0.0
       recma-build-jsx: 1.0.0
-      recma-jsx: 1.0.0(acorn@8.14.0)
+      recma-jsx: 1.0.0(acorn@8.15.0)
       recma-stringify: 1.0.0
       rehype-recma: 1.0.0
       remark-mdx: 3.1.0
@@ -17402,84 +16495,84 @@ snapshots:
 
   '@react-native/assets-registry@0.75.3': {}
 
-  '@react-native/babel-plugin-codegen@0.75.3(@babel/preset-env@7.26.9(@babel/core@7.25.2))':
+  '@react-native/babel-plugin-codegen@0.75.3(@babel/preset-env@7.26.9(@babel/core@7.26.9))':
     dependencies:
-      '@react-native/codegen': 0.75.3(@babel/preset-env@7.26.9(@babel/core@7.25.2))
+      '@react-native/codegen': 0.75.3(@babel/preset-env@7.26.9(@babel/core@7.26.9))
     transitivePeerDependencies:
       - '@babel/preset-env'
       - supports-color
 
-  '@react-native/babel-preset@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))':
+  '@react-native/babel-preset@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))':
     dependencies:
-      '@babel/core': 7.25.2
-      '@babel/plugin-proposal-export-default-from': 7.24.7(@babel/core@7.25.2)
-      '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2)
-      '@babel/plugin-syntax-export-default-from': 7.24.7(@babel/core@7.25.2)
-      '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.25.2)
-      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2)
-      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2)
-      '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-async-generator-functions': 7.26.8(@babel/core@7.25.2)
-      '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-flow-strip-types': 7.25.2(@babel/core@7.25.2)
-      '@babel/plugin-transform-for-of': 7.26.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.25.2)
-      '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.25.2)
-      '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2)
-      '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2)
-      '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-runtime': 7.26.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.25.2)
-      '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.25.2)
-      '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.25.2)
+      '@babel/core': 7.26.9
+      '@babel/plugin-proposal-export-default-from': 7.24.7(@babel/core@7.26.9)
+      '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.9)
+      '@babel/plugin-syntax-export-default-from': 7.24.7(@babel/core@7.26.9)
+      '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.26.9)
+      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.9)
+      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.9)
+      '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-async-generator-functions': 7.26.8(@babel/core@7.26.9)
+      '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-flow-strip-types': 7.25.2(@babel/core@7.26.9)
+      '@babel/plugin-transform-for-of': 7.26.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.9)
+      '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.26.9)
+      '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.26.9)
+      '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.26.9)
+      '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-runtime': 7.26.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.9)
+      '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.9)
+      '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.9)
       '@babel/template': 7.26.9
-      '@react-native/babel-plugin-codegen': 0.75.3(@babel/preset-env@7.26.9(@babel/core@7.25.2))
-      babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.25.2)
+      '@react-native/babel-plugin-codegen': 0.75.3(@babel/preset-env@7.26.9(@babel/core@7.26.9))
+      babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.9)
       react-refresh: 0.14.2
     transitivePeerDependencies:
       - '@babel/preset-env'
       - supports-color
 
-  '@react-native/codegen@0.75.3(@babel/preset-env@7.26.9(@babel/core@7.25.2))':
+  '@react-native/codegen@0.75.3(@babel/preset-env@7.26.9(@babel/core@7.26.9))':
     dependencies:
       '@babel/parser': 7.26.9
-      '@babel/preset-env': 7.26.9(@babel/core@7.25.2)
+      '@babel/preset-env': 7.26.9(@babel/core@7.26.9)
       glob: 7.2.3
       hermes-parser: 0.22.0
       invariant: 2.2.4
-      jscodeshift: 0.14.0(@babel/preset-env@7.26.9(@babel/core@7.25.2))
+      jscodeshift: 0.14.0(@babel/preset-env@7.26.9(@babel/core@7.26.9))
       mkdirp: 0.5.6
       nullthrows: 1.1.1
       yargs: 17.7.2
     transitivePeerDependencies:
       - supports-color
 
-  '@react-native/community-cli-plugin@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(encoding@0.1.13)':
+  '@react-native/community-cli-plugin@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(encoding@0.1.13)':
     dependencies:
       '@react-native-community/cli-server-api': 14.1.0
       '@react-native-community/cli-tools': 14.1.0
       '@react-native/dev-middleware': 0.75.3(encoding@0.1.13)
-      '@react-native/metro-babel-transformer': 0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))
+      '@react-native/metro-babel-transformer': 0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))
       chalk: 4.1.2
       execa: 5.1.1
       metro: 0.80.12
@@ -17521,10 +16614,10 @@ snapshots:
 
   '@react-native/js-polyfills@0.75.3': {}
 
-  '@react-native/metro-babel-transformer@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))':
+  '@react-native/metro-babel-transformer@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))':
     dependencies:
-      '@babel/core': 7.25.2
-      '@react-native/babel-preset': 0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))
+      '@babel/core': 7.26.9
+      '@react-native/babel-preset': 0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))
       hermes-parser: 0.22.0
       nullthrows: 1.1.1
     transitivePeerDependencies:
@@ -17533,12 +16626,12 @@ snapshots:
 
   '@react-native/normalize-colors@0.75.3': {}
 
-  '@react-native/virtualized-lists@0.75.3(@types/react@17.0.42)(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)':
+  '@react-native/virtualized-lists@0.75.3(@types/react@17.0.42)(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)':
     dependencies:
       invariant: 2.2.4
       nullthrows: 1.1.1
       react: 17.0.2
-      react-native: 0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2)
+      react-native: 0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2)
     optionalDependencies:
       '@types/react': 17.0.42
 
@@ -17565,14 +16658,14 @@ snapshots:
       react: 17.0.2
       react-konva: 18.2.10(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
 
-  '@react-spring/native@9.7.4(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)':
+  '@react-spring/native@9.7.4(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)':
     dependencies:
       '@react-spring/animated': 9.7.4(react@17.0.2)
       '@react-spring/core': 9.7.4(react@17.0.2)
       '@react-spring/shared': 9.7.4(react@17.0.2)
       '@react-spring/types': 9.7.4
       react: 17.0.2
-      react-native: 0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2)
+      react-native: 0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2)
 
   '@react-spring/rafz@9.7.4': {}
 
@@ -17582,13 +16675,13 @@ snapshots:
       '@react-spring/types': 9.7.4
       react: 17.0.2
 
-  '@react-spring/three@9.7.4(@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0))(react@17.0.2)(three@0.168.0)':
+  '@react-spring/three@9.7.4(@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0))(react@17.0.2)(three@0.168.0)':
     dependencies:
       '@react-spring/animated': 9.7.4(react@17.0.2)
       '@react-spring/core': 9.7.4(react@17.0.2)
       '@react-spring/shared': 9.7.4(react@17.0.2)
       '@react-spring/types': 9.7.4
-      '@react-three/fiber': 8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0)
+      '@react-three/fiber': 8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0)
       react: 17.0.2
       three: 0.168.0
 
@@ -17614,7 +16707,7 @@ snapshots:
       react-zdog: 1.2.2
       zdog: 1.1.3
 
-  '@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0)':
+  '@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0)':
     dependencies:
       '@babel/runtime': 7.26.0
       '@types/debounce': 1.2.4
@@ -17632,7 +16725,7 @@ snapshots:
       zustand: 3.7.2(react@17.0.2)
     optionalDependencies:
       react-dom: 17.0.2(react@17.0.2)
-      react-native: 0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2)
+      react-native: 0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2)
 
   '@rollup/plugin-babel@5.3.1(@babel/core@7.25.2)(@types/babel__core@7.20.5)(rollup@2.79.1)':
     dependencies:
@@ -18017,8 +17110,6 @@ snapshots:
 
   '@types/minimatch@5.1.2': {}
 
-  '@types/minimist@1.2.5': {}
-
   '@types/ms@2.1.0': {}
 
   '@types/node-forge@1.3.11':
@@ -18033,8 +17124,6 @@ snapshots:
     dependencies:
       undici-types: 7.12.0
 
-  '@types/normalize-package-data@2.4.4': {}
-
   '@types/parse-json@4.0.2': {}
 
   '@types/prismjs@1.26.5': {}
@@ -18519,11 +17608,6 @@ snapshots:
 
   '@xtuc/long@4.2.2': {}
 
-  JSONStream@1.3.5:
-    dependencies:
-      jsonparse: 1.3.1
-      through: 2.3.8
-
   abab@2.0.6: {}
 
   abort-controller@3.0.0:
@@ -18535,11 +17619,6 @@ snapshots:
       mime-types: 2.1.35
       negotiator: 0.6.3
 
-  accepts@2.0.0:
-    dependencies:
-      mime-types: 3.0.1
-      negotiator: 1.0.0
-
   acorn-globals@4.3.4:
     dependencies:
       acorn: 6.4.2
@@ -18577,8 +17656,6 @@ snapshots:
     dependencies:
       object-assign: 4.1.1
 
-  add-stream@1.0.0: {}
-
   address@1.2.2: {}
 
   agent-base@7.1.4: {}
@@ -18847,8 +17924,6 @@ snapshots:
 
   array-flatten@1.1.1: {}
 
-  array-ify@1.0.0: {}
-
   array-includes@3.1.8:
     dependencies:
       call-bind: 1.0.7
@@ -18931,8 +18006,6 @@ snapshots:
       is-array-buffer: 3.0.4
       is-shared-array-buffer: 1.0.3
 
-  arrify@1.0.1: {}
-
   asap@2.0.6: {}
 
   asn1.js@4.10.1:
@@ -19055,9 +18128,9 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  babel-loader@8.4.1(@babel/core@7.25.2)(webpack@5.98.0):
+  babel-loader@8.4.1(@babel/core@7.26.9)(webpack@5.98.0):
     dependencies:
-      '@babel/core': 7.25.2
+      '@babel/core': 7.26.9
       find-cache-dir: 3.3.2
       loader-utils: 2.0.4
       make-dir: 3.1.0
@@ -19122,14 +18195,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  babel-plugin-polyfill-corejs3@0.11.1(@babel/core@7.25.2):
-    dependencies:
-      '@babel/core': 7.25.2
-      '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.25.2)
-      core-js-compat: 3.41.0
-    transitivePeerDependencies:
-      - supports-color
-
   babel-plugin-polyfill-corejs3@0.11.1(@babel/core@7.26.9):
     dependencies:
       '@babel/core': 7.26.9
@@ -19152,9 +18217,9 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.25.2):
+  babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.26.9):
     dependencies:
-      '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.25.2)
+      '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.26.9)
     transitivePeerDependencies:
       - '@babel/core'
 
@@ -19254,20 +18319,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  body-parser@2.2.0:
-    dependencies:
-      bytes: 3.1.2
-      content-type: 1.0.5
-      debug: 4.4.3
-      http-errors: 2.0.0
-      iconv-lite: 0.6.3
-      on-finished: 2.4.1
-      qs: 6.14.0
-      raw-body: 3.0.1
-      type-is: 2.0.1
-    transitivePeerDependencies:
-      - supports-color
-
   bonjour-service@1.3.0:
     dependencies:
       fast-deep-equal: 3.1.3
@@ -19528,12 +18579,6 @@ snapshots:
       pascal-case: 3.1.2
       tslib: 2.7.0
 
-  camelcase-keys@6.2.2:
-    dependencies:
-      camelcase: 5.3.1
-      map-obj: 4.3.0
-      quick-lru: 4.0.1
-
   camelcase@4.1.0: {}
 
   camelcase@5.3.1: {}
@@ -19902,11 +18947,6 @@ snapshots:
 
   commondir@1.0.1: {}
 
-  compare-func@2.0.0:
-    dependencies:
-      array-ify: 1.0.0
-      dot-prop: 5.3.0
-
   component-classes@1.2.6:
     dependencies:
       component-indexof: 0.0.3
@@ -19986,106 +19026,19 @@ snapshots:
 
   constants-browserify@1.0.0: {}
 
-  content-disposition@0.5.2: {}
-
-  content-disposition@0.5.3:
-    dependencies:
-      safe-buffer: 5.1.2
-
-  content-disposition@0.5.4:
-    dependencies:
-      safe-buffer: 5.2.1
-
-  content-disposition@1.0.0:
-    dependencies:
-      safe-buffer: 5.2.1
-
-  content-security-policy-builder@2.1.0: {}
-
-  content-type@1.0.5: {}
-
-  conventional-changelog-angular@6.0.0:
-    dependencies:
-      compare-func: 2.0.0
-
-  conventional-changelog-atom@3.0.0: {}
-
-  conventional-changelog-cli@3.0.0:
-    dependencies:
-      add-stream: 1.0.0
-      conventional-changelog: 4.0.0
-      meow: 8.1.2
-      tempfile: 3.0.0
-
-  conventional-changelog-codemirror@3.0.0: {}
-
-  conventional-changelog-conventionalcommits@6.1.0:
-    dependencies:
-      compare-func: 2.0.0
-
-  conventional-changelog-core@5.0.2:
-    dependencies:
-      add-stream: 1.0.0
-      conventional-changelog-writer: 6.0.1
-      conventional-commits-parser: 4.0.0
-      dateformat: 3.0.3
-      get-pkg-repo: 4.2.1
-      git-raw-commits: 3.0.0
-      git-remote-origin-url: 2.0.0
-      git-semver-tags: 5.0.1
-      normalize-package-data: 3.0.3
-      read-pkg: 3.0.0
-      read-pkg-up: 3.0.0
-
-  conventional-changelog-ember@3.0.0: {}
-
-  conventional-changelog-eslint@4.0.0: {}
-
-  conventional-changelog-express@3.0.0: {}
-
-  conventional-changelog-jquery@4.0.0: {}
-
-  conventional-changelog-jshint@3.0.0:
-    dependencies:
-      compare-func: 2.0.0
-
-  conventional-changelog-preset-loader@3.0.0: {}
+  content-disposition@0.5.2: {}
 
-  conventional-changelog-writer@6.0.1:
+  content-disposition@0.5.3:
     dependencies:
-      conventional-commits-filter: 3.0.0
-      dateformat: 3.0.3
-      handlebars: 4.7.8
-      json-stringify-safe: 5.0.1
-      meow: 8.1.2
-      semver: 7.6.3
-      split: 1.0.1
+      safe-buffer: 5.1.2
 
-  conventional-changelog@4.0.0:
+  content-disposition@0.5.4:
     dependencies:
-      conventional-changelog-angular: 6.0.0
-      conventional-changelog-atom: 3.0.0
-      conventional-changelog-codemirror: 3.0.0
-      conventional-changelog-conventionalcommits: 6.1.0
-      conventional-changelog-core: 5.0.2
-      conventional-changelog-ember: 3.0.0
-      conventional-changelog-eslint: 4.0.0
-      conventional-changelog-express: 3.0.0
-      conventional-changelog-jquery: 4.0.0
-      conventional-changelog-jshint: 3.0.0
-      conventional-changelog-preset-loader: 3.0.0
+      safe-buffer: 5.2.1
 
-  conventional-commits-filter@3.0.0:
-    dependencies:
-      lodash.ismatch: 4.4.0
-      modify-values: 1.0.1
+  content-security-policy-builder@2.1.0: {}
 
-  conventional-commits-parser@4.0.0:
-    dependencies:
-      JSONStream: 1.3.5
-      is-text-path: 1.0.1
-      meow: 8.1.2
-      split2: 3.2.2
+  content-type@1.0.5: {}
 
   convert-source-map@1.9.0: {}
 
@@ -20093,8 +19046,6 @@ snapshots:
 
   cookie-signature@1.0.6: {}
 
-  cookie-signature@1.2.2: {}
-
   cookie@0.4.0: {}
 
   cookie@0.7.1: {}
@@ -20447,8 +19398,6 @@ snapshots:
 
   damerau-levenshtein@1.0.8: {}
 
-  dargs@7.0.0: {}
-
   dashdash@1.14.1:
     dependencies:
       assert-plus: 1.0.0
@@ -20491,8 +19440,6 @@ snapshots:
 
   dateformat@2.2.0: {}
 
-  dateformat@3.0.3: {}
-
   dayjs@1.11.13: {}
 
   dayjs@1.8.36: {}
@@ -20521,11 +19468,6 @@ snapshots:
     dependencies:
       ms: 2.1.3
 
-  decamelize-keys@1.1.1:
-    dependencies:
-      decamelize: 1.2.0
-      map-obj: 1.0.1
-
   decamelize@1.2.0: {}
 
   decode-named-character-reference@1.0.2:
@@ -20711,9 +19653,9 @@ snapshots:
     dependencies:
       esutils: 2.0.3
 
-  docusaurus-plugin-sass@0.2.6(@docusaurus/core@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(sass@1.79.3)(webpack@5.98.0):
+  docusaurus-plugin-sass@0.2.6(@docusaurus/core@3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3))(sass@1.79.3)(webpack@5.98.0):
     dependencies:
-      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.14.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
+      '@docusaurus/core': 3.7.0(@mdx-js/react@3.1.0(@types/react@17.0.42)(react@19.0.0))(acorn@8.15.0)(eslint@9.36.0(jiti@1.21.7))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.6.3)
       sass: 1.79.3
       sass-loader: 16.0.5(sass@1.79.3)(webpack@5.98.0)
     transitivePeerDependencies:
@@ -20783,10 +19725,6 @@ snapshots:
       no-case: 3.0.4
       tslib: 2.7.0
 
-  dot-prop@5.3.0:
-    dependencies:
-      is-obj: 2.0.0
-
   dot-prop@6.0.1:
     dependencies:
       is-obj: 2.0.0
@@ -21128,7 +20066,7 @@ snapshots:
     optionalDependencies:
       source-map: 0.6.1
 
-  eslint-config-next@12.1.0(eslint@8.11.0)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(typescript@4.6.2):
+  eslint-config-next@12.1.0(eslint@8.11.0)(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(typescript@4.6.2):
     dependencies:
       '@next/eslint-plugin-next': 12.1.0
       '@rushstack/eslint-patch': 1.10.4
@@ -21140,7 +20078,7 @@ snapshots:
       eslint-plugin-jsx-a11y: 6.10.0(eslint@8.11.0)
       eslint-plugin-react: 7.36.1(eslint@8.11.0)
       eslint-plugin-react-hooks: 4.6.2(eslint@8.11.0)
-      next: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
+      next: 12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
     optionalDependencies:
       typescript: 4.6.2
     transitivePeerDependencies:
@@ -21167,7 +20105,7 @@ snapshots:
     dependencies:
       debug: 4.4.3
       eslint: 8.11.0
-      eslint-plugin-import: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint@8.11.0)
+      eslint-plugin-import: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint-import-resolver-typescript@2.7.1)(eslint@8.11.0)
       glob: 7.2.3
       is-glob: 4.0.3
       resolve: 1.22.8
@@ -21224,34 +20162,6 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
-  eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint@8.11.0):
-    dependencies:
-      '@rtsao/scc': 1.1.0
-      array-includes: 3.1.8
-      array.prototype.findlastindex: 1.2.5
-      array.prototype.flat: 1.3.2
-      array.prototype.flatmap: 1.3.2
-      debug: 3.2.7
-      doctrine: 2.1.0
-      eslint: 8.11.0
-      eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.11.0(@typescript-eslint/parser@5.62.0(eslint@8.11.0)(typescript@4.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@2.7.1)(eslint@8.11.0)
-      hasown: 2.0.2
-      is-core-module: 2.15.1
-      is-glob: 4.0.3
-      minimatch: 3.1.2
-      object.fromentries: 2.0.8
-      object.groupby: 1.0.3
-      object.values: 1.2.0
-      semver: 6.3.1
-      tsconfig-paths: 3.15.0
-    optionalDependencies:
-      '@typescript-eslint/parser': 5.62.0(eslint@8.11.0)(typescript@4.6.2)
-    transitivePeerDependencies:
-      - eslint-import-resolver-typescript
-      - eslint-import-resolver-webpack
-      - supports-color
-
   eslint-plugin-import@2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.1.6))(eslint@8.57.1):
     dependencies:
       '@rtsao/scc': 1.1.0
@@ -21735,38 +20645,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  express@5.1.0:
-    dependencies:
-      accepts: 2.0.0
-      body-parser: 2.2.0
-      content-disposition: 1.0.0
-      content-type: 1.0.5
-      cookie: 0.7.1
-      cookie-signature: 1.2.2
-      debug: 4.4.3
-      encodeurl: 2.0.0
-      escape-html: 1.0.3
-      etag: 1.8.1
-      finalhandler: 2.1.0
-      fresh: 2.0.0
-      http-errors: 2.0.0
-      merge-descriptors: 2.0.0
-      mime-types: 3.0.1
-      on-finished: 2.4.1
-      once: 1.4.0
-      parseurl: 1.3.3
-      proxy-addr: 2.0.7
-      qs: 6.14.0
-      range-parser: 1.2.1
-      router: 2.2.0
-      send: 1.2.0
-      serve-static: 2.2.0
-      statuses: 2.0.1
-      type-is: 2.0.1
-      vary: 1.1.2
-    transitivePeerDependencies:
-      - supports-color
-
   ext@1.7.0:
     dependencies:
       type: 2.7.3
@@ -21946,17 +20824,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  finalhandler@2.1.0:
-    dependencies:
-      debug: 4.4.3
-      encodeurl: 2.0.0
-      escape-html: 1.0.3
-      on-finished: 2.4.1
-      parseurl: 1.3.3
-      statuses: 2.0.1
-    transitivePeerDependencies:
-      - supports-color
-
   find-cache-dir@2.1.0:
     dependencies:
       commondir: 1.0.1
@@ -21974,10 +20841,6 @@ snapshots:
       common-path-prefix: 3.0.0
       pkg-dir: 7.0.0
 
-  find-up@2.1.0:
-    dependencies:
-      locate-path: 2.0.0
-
   find-up@3.0.0:
     dependencies:
       locate-path: 3.0.0
@@ -22120,8 +20983,6 @@ snapshots:
 
   fresh@0.5.2: {}
 
-  fresh@2.0.0: {}
-
   from2@2.3.0:
     dependencies:
       inherits: 2.0.4
@@ -22218,13 +21079,6 @@ snapshots:
 
   get-own-enumerable-property-symbols@3.0.2: {}
 
-  get-pkg-repo@4.2.1:
-    dependencies:
-      '@hutson/parse-repository-url': 3.0.2
-      hosted-git-info: 4.1.0
-      through2: 2.0.5
-      yargs: 16.2.0
-
   get-proto@1.0.1:
     dependencies:
       dunder-proto: 1.0.1
@@ -22262,28 +21116,8 @@ snapshots:
     optionalDependencies:
       js-git: 0.7.8
 
-  git-raw-commits@3.0.0:
-    dependencies:
-      dargs: 7.0.0
-      meow: 8.1.2
-      split2: 3.2.2
-
-  git-remote-origin-url@2.0.0:
-    dependencies:
-      gitconfiglocal: 1.0.0
-      pify: 2.3.0
-
-  git-semver-tags@5.0.1:
-    dependencies:
-      meow: 8.1.2
-      semver: 7.6.3
-
   git-sha1@0.1.2: {}
 
-  gitconfiglocal@1.0.0:
-    dependencies:
-      ini: 1.3.8
-
   github-buttons@2.29.1: {}
 
   github-slugger@1.5.0: {}
@@ -22414,15 +21248,6 @@ snapshots:
 
   handle-thing@2.0.1: {}
 
-  handlebars@4.7.8:
-    dependencies:
-      minimist: 1.2.8
-      neo-async: 2.6.2
-      source-map: 0.6.1
-      wordwrap: 1.0.0
-    optionalDependencies:
-      uglify-js: 3.19.3
-
   har-schema@2.0.0: {}
 
   har-validator@5.1.5:
@@ -22430,8 +21255,6 @@ snapshots:
       ajv: 6.12.6
       har-schema: 2.0.0
 
-  hard-rejection@2.1.0: {}
-
   has-ansi@2.0.0:
     dependencies:
       ansi-regex: 2.1.1
@@ -22656,10 +21479,6 @@ snapshots:
 
   hosted-git-info@2.8.9: {}
 
-  hosted-git-info@4.1.0:
-    dependencies:
-      lru-cache: 6.0.0
-
   hpack.js@2.1.6:
     dependencies:
       inherits: 2.0.4
@@ -22831,10 +21650,6 @@ snapshots:
     dependencies:
       safer-buffer: 2.1.2
 
-  iconv-lite@0.7.0:
-    dependencies:
-      safer-buffer: 2.1.2
-
   iconv-lite@0.7.2:
     dependencies:
       safer-buffer: 2.1.2
@@ -23168,8 +21983,6 @@ snapshots:
 
   is-path-inside@3.0.3: {}
 
-  is-plain-obj@1.1.0: {}
-
   is-plain-obj@3.0.0: {}
 
   is-plain-obj@4.1.0: {}
@@ -23180,8 +21993,6 @@ snapshots:
 
   is-promise@2.2.2: {}
 
-  is-promise@4.0.0: {}
-
   is-property@1.0.2: {}
 
   is-regex@1.1.4:
@@ -23211,10 +22022,6 @@ snapshots:
     dependencies:
       has-symbols: 1.0.3
 
-  is-text-path@1.0.1:
-    dependencies:
-      text-extensions: 1.9.0
-
   is-type-of@1.4.0:
     dependencies:
       core-util-is: 1.0.3
@@ -23757,7 +22564,7 @@ snapshots:
 
   jsc-safe-url@0.2.4: {}
 
-  jscodeshift@0.14.0(@babel/preset-env@7.26.9(@babel/core@7.25.2)):
+  jscodeshift@0.14.0(@babel/preset-env@7.26.9(@babel/core@7.26.9)):
     dependencies:
       '@babel/core': 7.26.9
       '@babel/parser': 7.26.9
@@ -23765,7 +22572,7 @@ snapshots:
       '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.9)
       '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.9)
       '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.9)
-      '@babel/preset-env': 7.26.9(@babel/core@7.25.2)
+      '@babel/preset-env': 7.26.9(@babel/core@7.26.9)
       '@babel/preset-flow': 7.24.7(@babel/core@7.26.9)
       '@babel/preset-typescript': 7.26.0(@babel/core@7.26.9)
       '@babel/register': 7.24.6(@babel/core@7.26.9)
@@ -23858,8 +22665,6 @@ snapshots:
     optionalDependencies:
       graceful-fs: 4.2.11
 
-  jsonparse@1.3.1: {}
-
   jsonpointer@5.0.1: {}
 
   jsonwebtoken@8.5.1:
@@ -24073,11 +22878,6 @@ snapshots:
 
   loader-utils@3.3.1: {}
 
-  locate-path@2.0.0:
-    dependencies:
-      p-locate: 2.0.0
-      path-exists: 3.0.0
-
   locate-path@3.0.0:
     dependencies:
       p-locate: 3.0.0
@@ -24111,8 +22911,6 @@ snapshots:
 
   lodash.isinteger@4.0.4: {}
 
-  lodash.ismatch@4.4.0: {}
-
   lodash.isnumber@3.0.3: {}
 
   lodash.isplainobject@4.0.6: {}
@@ -24176,8 +22974,6 @@ snapshots:
       dayjs: 1.11.13
       yargs: 15.4.1
 
-  long@5.2.3: {}
-
   long@5.3.2: {}
 
   longest-streak@3.1.0: {}
@@ -24206,8 +23002,6 @@ snapshots:
     dependencies:
       es5-ext: 0.10.64
 
-  lru.min@1.1.1: {}
-
   lru.min@1.1.4: {}
 
   lz-string@1.5.0: {}
@@ -24237,10 +23031,6 @@ snapshots:
 
   map-cache@0.2.2: {}
 
-  map-obj@1.0.1: {}
-
-  map-obj@4.3.0: {}
-
   map-visit@1.0.0:
     dependencies:
       object-visit: 1.0.1
@@ -24459,8 +23249,6 @@ snapshots:
 
   media-typer@0.3.0: {}
 
-  media-typer@1.1.0: {}
-
   memfs@3.5.3:
     dependencies:
       fs-monkey: 1.0.6
@@ -24488,26 +23276,10 @@ snapshots:
       errno: 0.1.8
       readable-stream: 2.3.8
 
-  meow@8.1.2:
-    dependencies:
-      '@types/minimist': 1.2.5
-      camelcase-keys: 6.2.2
-      decamelize-keys: 1.1.1
-      hard-rejection: 2.1.0
-      minimist-options: 4.1.0
-      normalize-package-data: 3.0.3
-      read-pkg-up: 7.0.1
-      redent: 3.0.0
-      trim-newlines: 3.0.1
-      type-fest: 0.18.1
-      yargs-parser: 20.2.9
-
   merge-descriptors@1.0.1: {}
 
   merge-descriptors@1.0.3: {}
 
-  merge-descriptors@2.0.0: {}
-
   merge-stream@2.0.0: {}
 
   merge2@1.4.1: {}
@@ -25033,10 +23805,6 @@ snapshots:
     dependencies:
       mime-db: 1.52.0
 
-  mime-types@3.0.1:
-    dependencies:
-      mime-db: 1.54.0
-
   mime@1.6.0: {}
 
   mime@2.6.0: {}
@@ -25071,12 +23839,6 @@ snapshots:
     dependencies:
       brace-expansion: 2.0.1
 
-  minimist-options@4.1.0:
-    dependencies:
-      arrify: 1.0.1
-      is-plain-obj: 1.1.0
-      kind-of: 6.0.3
-
   minimist@1.2.0: {}
 
   minimist@1.2.8: {}
@@ -25105,8 +23867,6 @@ snapshots:
 
   mkdirp@1.0.4: {}
 
-  modify-values@1.0.1: {}
-
   module-details-from-path@1.0.4: {}
 
   monaco-editor@0.52.0: {}
@@ -25148,18 +23908,6 @@ snapshots:
 
   mute-stream@0.0.8: {}
 
-  mysql2@3.12.0:
-    dependencies:
-      aws-ssl-profiles: 1.1.2
-      denque: 2.1.0
-      generate-function: 2.3.1
-      iconv-lite: 0.6.3
-      long: 5.2.3
-      lru.min: 1.1.1
-      named-placeholders: 1.1.3
-      seq-queue: 0.0.5
-      sqlstring: 2.3.3
-
   mysql2@3.22.3(@types/node@12.20.55):
     dependencies:
       '@types/node': 12.20.55
@@ -25190,10 +23938,6 @@ snapshots:
       object-assign: 4.1.1
       thenify-all: 1.6.0
 
-  named-placeholders@1.1.3:
-    dependencies:
-      lru-cache: 7.18.3
-
   named-placeholders@1.1.6:
     dependencies:
       lru.min: 1.1.4
@@ -25241,8 +23985,6 @@ snapshots:
 
   negotiator@0.6.3: {}
 
-  negotiator@1.0.0: {}
-
   neo-async@2.6.2: {}
 
   netmask@2.1.1: {}
@@ -25261,9 +24003,9 @@ snapshots:
       url-loader: 4.1.1(file-loader@6.2.0(webpack@5.98.0))(webpack@5.98.0)
       webpack: 5.98.0
 
-  next-intl@1.5.1(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(react@17.0.2):
+  next-intl@1.5.1(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(react@17.0.2):
     dependencies:
-      next: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
+      next: 12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
       react: 17.0.2
       use-intl: 1.5.1(react@17.0.2)
 
@@ -25274,12 +24016,12 @@ snapshots:
       react-dom: 17.0.2(react@17.0.2)
       react-transition-group: 2.9.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
 
-  next-pwa@5.6.0(@babel/core@7.25.2)(@types/babel__core@7.20.5)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(webpack@5.98.0):
+  next-pwa@5.6.0(@babel/core@7.26.9)(@types/babel__core@7.20.5)(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3))(webpack@5.98.0):
     dependencies:
-      babel-loader: 8.4.1(@babel/core@7.25.2)(webpack@5.98.0)
+      babel-loader: 8.4.1(@babel/core@7.26.9)(webpack@5.98.0)
       clean-webpack-plugin: 4.0.0(webpack@5.98.0)
       globby: 11.1.0
-      next: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
+      next: 12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
       terser-webpack-plugin: 5.3.10(webpack@5.98.0)
       workbox-webpack-plugin: 6.6.0(@types/babel__core@7.20.5)(webpack@5.98.0)
       workbox-window: 6.6.0
@@ -25292,11 +24034,11 @@ snapshots:
       - uglify-js
       - webpack
 
-  next-sitemap@1.9.12(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)):
+  next-sitemap@1.9.12(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)):
     dependencies:
       '@corex/deepmerge': 2.6.148
       minimist: 1.2.8
-      next: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
+      next: 12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
 
   next-tick@1.1.0: {}
 
@@ -25305,41 +24047,12 @@ snapshots:
       enhanced-resolve: 5.17.1
       escalade: 3.2.0
 
-  next-with-less@2.0.5(less-loader@10.2.0(less@4.2.0)(webpack@5.98.0))(less@4.2.0)(next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)):
+  next-with-less@2.0.5(less-loader@10.2.0(less@4.2.0)(webpack@5.98.0))(less@4.2.0)(next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)):
     dependencies:
       clone-deep: 4.0.1
       less: 4.2.0
       less-loader: 10.2.0(less@4.2.0)(webpack@5.98.0)
-      next: 12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
-
-  next@12.3.4(@babel/core@7.25.2)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3):
-    dependencies:
-      '@next/env': 12.3.4
-      '@swc/helpers': 0.4.11
-      caniuse-lite: 1.0.30001701
-      postcss: 8.4.14
-      react: 17.0.2
-      react-dom: 17.0.2(react@17.0.2)
-      styled-jsx: 5.0.7(@babel/core@7.25.2)(react@17.0.2)
-      use-sync-external-store: 1.2.0(react@17.0.2)
-    optionalDependencies:
-      '@next/swc-android-arm-eabi': 12.3.4
-      '@next/swc-android-arm64': 12.3.4
-      '@next/swc-darwin-arm64': 12.3.4
-      '@next/swc-darwin-x64': 12.3.4
-      '@next/swc-freebsd-x64': 12.3.4
-      '@next/swc-linux-arm-gnueabihf': 12.3.4
-      '@next/swc-linux-arm64-gnu': 12.3.4
-      '@next/swc-linux-arm64-musl': 12.3.4
-      '@next/swc-linux-x64-gnu': 12.3.4
-      '@next/swc-linux-x64-musl': 12.3.4
-      '@next/swc-win32-arm64-msvc': 12.3.4
-      '@next/swc-win32-ia32-msvc': 12.3.4
-      '@next/swc-win32-x64-msvc': 12.3.4
-      sass: 1.79.3
-    transitivePeerDependencies:
-      - '@babel/core'
-      - babel-plugin-macros
+      next: 12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3)
 
   next@12.3.4(@babel/core@7.26.9)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(sass@1.79.3):
     dependencies:
@@ -25491,13 +24204,6 @@ snapshots:
       semver: 5.7.2
       validate-npm-package-license: 3.0.4
 
-  normalize-package-data@3.0.3:
-    dependencies:
-      hosted-git-info: 4.1.0
-      is-core-module: 2.15.1
-      semver: 7.6.3
-      validate-npm-package-license: 3.0.4
-
   normalize-path@2.1.1:
     dependencies:
       remove-trailing-separator: 1.1.0
@@ -25779,10 +24485,6 @@ snapshots:
 
   p-finally@1.0.0: {}
 
-  p-limit@1.3.0:
-    dependencies:
-      p-try: 1.0.0
-
   p-limit@2.3.0:
     dependencies:
       p-try: 2.2.0
@@ -25795,10 +24497,6 @@ snapshots:
     dependencies:
       yocto-queue: 1.1.1
 
-  p-locate@2.0.0:
-    dependencies:
-      p-limit: 1.3.0
-
   p-locate@3.0.0:
     dependencies:
       p-limit: 2.3.0
@@ -25828,8 +24526,6 @@ snapshots:
       '@types/retry': 0.12.0
       retry: 0.13.1
 
-  p-try@1.0.0: {}
-
   p-try@2.2.0: {}
 
   pac-proxy-agent@7.2.0:
@@ -25984,8 +24680,6 @@ snapshots:
 
   path-to-regexp@3.3.0: {}
 
-  path-to-regexp@8.3.0: {}
-
   path-type@3.0.0:
     dependencies:
       pify: 3.0.0
@@ -26751,8 +25445,6 @@ snapshots:
     dependencies:
       inherits: 2.0.4
 
-  quick-lru@4.0.1: {}
-
   quick-lru@5.1.1: {}
 
   raf@3.4.1:
@@ -26786,13 +25478,6 @@ snapshots:
       iconv-lite: 0.4.24
       unpipe: 1.0.0
 
-  raw-body@3.0.1:
-    dependencies:
-      bytes: 3.1.2
-      http-errors: 2.0.0
-      iconv-lite: 0.7.0
-      unpipe: 1.0.0
-
   rc-animate@2.11.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2):
     dependencies:
       babel-runtime: 6.26.0
@@ -27310,19 +25995,19 @@ snapshots:
       raf: 3.4.1
       react: 17.0.2
 
-  react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2):
+  react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2):
     dependencies:
       '@jest/create-cache-key-function': 29.7.0
       '@react-native-community/cli': 14.1.0(typescript@4.6.2)
       '@react-native-community/cli-platform-android': 14.1.0
       '@react-native-community/cli-platform-ios': 14.1.0
       '@react-native/assets-registry': 0.75.3
-      '@react-native/codegen': 0.75.3(@babel/preset-env@7.26.9(@babel/core@7.25.2))
-      '@react-native/community-cli-plugin': 0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(encoding@0.1.13)
+      '@react-native/codegen': 0.75.3(@babel/preset-env@7.26.9(@babel/core@7.26.9))
+      '@react-native/community-cli-plugin': 0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(encoding@0.1.13)
       '@react-native/gradle-plugin': 0.75.3
       '@react-native/js-polyfills': 0.75.3
       '@react-native/normalize-colors': 0.75.3
-      '@react-native/virtualized-lists': 0.75.3(@types/react@17.0.42)(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)
+      '@react-native/virtualized-lists': 0.75.3(@types/react@17.0.42)(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)
       abort-controller: 3.0.0
       anser: 1.4.10
       ansi-regex: 5.0.1
@@ -27415,12 +26100,12 @@ snapshots:
       react: 17.0.2
       react-dom: 17.0.2(react@17.0.2)
 
-  react-spring@9.7.4(@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0))(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react-konva@18.2.10(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react-zdog@1.2.2)(react@17.0.2)(three@0.168.0)(zdog@1.1.3):
+  react-spring@9.7.4(@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0))(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react-konva@18.2.10(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react-zdog@1.2.2)(react@17.0.2)(three@0.168.0)(zdog@1.1.3):
     dependencies:
       '@react-spring/core': 9.7.4(react@17.0.2)
       '@react-spring/konva': 9.7.4(konva@9.3.15)(react-konva@18.2.10(konva@9.3.15)(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react@17.0.2)
-      '@react-spring/native': 9.7.4(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)
-      '@react-spring/three': 9.7.4(@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.26.9(@babel/core@7.25.2))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0))(react@17.0.2)(three@0.168.0)
+      '@react-spring/native': 9.7.4(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)
+      '@react-spring/three': 9.7.4(@react-three/fiber@8.17.7(react-dom@17.0.2(react@17.0.2))(react-native@0.75.3(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@17.0.42)(encoding@0.1.13)(react@17.0.2)(typescript@4.6.2))(react@17.0.2)(three@0.168.0))(react@17.0.2)(three@0.168.0)
       '@react-spring/web': 9.7.4(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
       '@react-spring/zdog': 9.7.4(react-dom@17.0.2(react@17.0.2))(react-zdog@1.2.2)(react@17.0.2)(zdog@1.1.3)
       react: 17.0.2
@@ -27474,35 +26159,17 @@ snapshots:
 
   react@19.0.0: {}
 
-  read-pkg-up@3.0.0:
-    dependencies:
-      find-up: 2.1.0
-      read-pkg: 3.0.0
-
   read-pkg-up@4.0.0:
     dependencies:
       find-up: 3.0.0
       read-pkg: 3.0.0
 
-  read-pkg-up@7.0.1:
-    dependencies:
-      find-up: 4.1.0
-      read-pkg: 5.2.0
-      type-fest: 0.8.1
-
   read-pkg@3.0.0:
     dependencies:
       load-json-file: 4.0.0
       normalize-package-data: 2.5.0
       path-type: 3.0.0
 
-  read-pkg@5.2.0:
-    dependencies:
-      '@types/normalize-package-data': 2.4.4
-      normalize-package-data: 2.5.0
-      parse-json: 5.2.0
-      type-fest: 0.6.0
-
   read@1.0.7:
     dependencies:
       mute-stream: 0.0.8
@@ -27576,9 +26243,9 @@ snapshots:
       estree-util-build-jsx: 3.0.1
       vfile: 6.0.3
 
-  recma-jsx@1.0.0(acorn@8.14.0):
+  recma-jsx@1.0.0(acorn@8.15.0):
     dependencies:
-      acorn-jsx: 5.3.2(acorn@8.14.0)
+      acorn-jsx: 5.3.2(acorn@8.15.0)
       estree-util-to-js: 2.0.0
       recma-parse: 1.0.0
       recma-stringify: 1.0.0
@@ -27931,16 +26598,6 @@ snapshots:
     optionalDependencies:
       fsevents: 2.3.3
 
-  router@2.2.0:
-    dependencies:
-      debug: 4.4.3
-      depd: 2.0.0
-      is-promise: 4.0.0
-      parseurl: 1.3.3
-      path-to-regexp: 8.3.0
-    transitivePeerDependencies:
-      - supports-color
-
   rsvp@4.8.5: {}
 
   rtlcss@4.3.0:
@@ -28152,24 +26809,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  send@1.2.0:
-    dependencies:
-      debug: 4.4.3
-      encodeurl: 2.0.0
-      escape-html: 1.0.3
-      etag: 1.8.1
-      fresh: 2.0.0
-      http-errors: 2.0.0
-      mime-types: 3.0.1
-      ms: 2.1.3
-      on-finished: 2.4.1
-      range-parser: 1.2.1
-      statuses: 2.0.1
-    transitivePeerDependencies:
-      - supports-color
-
-  seq-queue@0.0.5: {}
-
   serialize-error@2.1.0: {}
 
   serialize-javascript@4.0.0:
@@ -28220,15 +26859,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  serve-static@2.2.0:
-    dependencies:
-      encodeurl: 2.0.0
-      escape-html: 1.0.3
-      parseurl: 1.3.3
-      send: 1.2.0
-    transitivePeerDependencies:
-      - supports-color
-
   set-blocking@2.0.0: {}
 
   set-function-length@1.2.2:
@@ -28544,22 +27174,12 @@ snapshots:
     dependencies:
       extend-shallow: 3.0.2
 
-  split2@3.2.2:
-    dependencies:
-      readable-stream: 3.6.2
-
-  split@1.0.1:
-    dependencies:
-      through: 2.3.8
-
   sprintf-js@1.0.3: {}
 
   sprintf-js@1.1.2: {}
 
   sql-escaper@1.3.3: {}
 
-  sqlstring@2.3.3: {}
-
   srcset@4.0.0: {}
 
   sshpk@1.18.0:
@@ -28804,12 +27424,6 @@ snapshots:
     dependencies:
       inline-style-parser: 0.2.4
 
-  styled-jsx@5.0.7(@babel/core@7.25.2)(react@17.0.2):
-    dependencies:
-      react: 17.0.2
-    optionalDependencies:
-      '@babel/core': 7.25.2
-
   styled-jsx@5.0.7(@babel/core@7.26.9)(react@17.0.2):
     dependencies:
       react: 17.0.2
@@ -28959,11 +27573,6 @@ snapshots:
     dependencies:
       rimraf: 2.6.3
 
-  tempfile@3.0.0:
-    dependencies:
-      temp-dir: 2.0.0
-      uuid: 3.4.0
-
   tempy@0.6.0:
     dependencies:
       is-stream: 2.0.1
@@ -29023,8 +27632,6 @@ snapshots:
       read-pkg-up: 4.0.0
       require-main-filename: 2.0.0
 
-  text-extensions@1.9.0: {}
-
   text-table@0.2.0: {}
 
   thenify-all@1.6.0:
@@ -29122,8 +27729,6 @@ snapshots:
 
   trim-lines@3.0.1: {}
 
-  trim-newlines@3.0.1: {}
-
   trough@2.2.0: {}
 
   ts-jest@24.3.0(jest@24.9.0):
@@ -29253,18 +27858,12 @@ snapshots:
 
   type-fest@0.16.0: {}
 
-  type-fest@0.18.1: {}
-
   type-fest@0.20.2: {}
 
   type-fest@0.21.3: {}
 
-  type-fest@0.6.0: {}
-
   type-fest@0.7.1: {}
 
-  type-fest@0.8.1: {}
-
   type-fest@1.4.0: {}
 
   type-fest@2.19.0: {}
@@ -29274,12 +27873,6 @@ snapshots:
       media-typer: 0.3.0
       mime-types: 2.1.35
 
-  type-is@2.0.1:
-    dependencies:
-      content-type: 1.0.5
-      media-typer: 1.1.0
-      mime-types: 3.0.1
-
   type@2.7.3: {}
 
   typed-array-buffer@1.0.2:
@@ -29362,9 +27955,6 @@ snapshots:
 
   ua-parser-js@0.7.39: {}
 
-  uglify-js@3.19.3:
-    optional: true
-
   unbox-primitive@1.0.2:
     dependencies:
       call-bind: 1.0.7
@@ -29947,8 +28537,6 @@ snapshots:
 
   word-wrap@1.2.5: {}
 
-  wordwrap@1.0.0: {}
-
   workbox-background-sync@6.6.0:
     dependencies:
       idb: 7.1.1
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 7725ede..7b048f6 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,4 +1,6 @@
 packages:
+  # CLI 工具链
+  - 'cli'
   # 后端 API
   - 'server'
   # 客户端
diff --git a/scripts/bundled-server-path.js b/scripts/bundled-server-path.js
index d2bdf6e..55a5fd4 100644
--- a/scripts/bundled-server-path.js
+++ b/scripts/bundled-server-path.js
@@ -1,70 +1,2 @@
-/**
- * Resolve ReactPress API server paths.
- * Monorepo: prefer ./server when Nest source exists; otherwise fall back to CLI bundle.
- */
-const fs = require('fs');
-const path = require('path');
-
-function getMonorepoRoot() {
-  return path.resolve(__dirname, '..');
-}
-
-function getMonorepoServerDir() {
-  return path.join(getMonorepoRoot(), 'server');
-}
-
-function hasMonorepoServerSource() {
-  return fs.existsSync(path.join(getMonorepoServerDir(), 'src', 'main.ts'));
-}
-
-function getCliPackageRoot() {
-  return path.dirname(require.resolve('@fecommunity/reactpress-cli/package.json'));
-}
-
-function getBundledServerDir() {
-  return path.join(getCliPackageRoot(), 'server');
-}
-
-function getServerDir() {
-  if (hasMonorepoServerSource()) {
-    return getMonorepoServerDir();
-  }
-  return getBundledServerDir();
-}
-
-function getServerBin() {
-  return path.join(getServerDir(), 'bin', 'reactpress-server.js');
-}
-
-function getSwaggerPath() {
-  return path.join(getServerDir(), 'public', 'swagger.json');
-}
-
-function getServerMain() {
-  return path.join(getServerDir(), 'dist', 'main.js');
-}
-
-function isUsingMonorepoServer() {
-  return hasMonorepoServerSource();
-}
-
-// Legacy export names
-const getBundledServerBin = getServerBin;
-const getBundledSwaggerPath = getSwaggerPath;
-const getBundledServerMain = getServerMain;
-
-module.exports = {
-  getMonorepoRoot,
-  getMonorepoServerDir,
-  hasMonorepoServerSource,
-  isUsingMonorepoServer,
-  getCliPackageRoot,
-  getBundledServerDir,
-  getServerDir,
-  getServerBin,
-  getSwaggerPath,
-  getServerMain,
-  getBundledServerBin,
-  getBundledSwaggerPath,
-  getBundledServerMain,
-};
+/** @deprecated Import from `cli/lib/paths` */
+module.exports = require('../cli/lib/paths');
diff --git a/scripts/docker-dev.js b/scripts/docker-dev.js
index 6a846db..e027040 100755
--- a/scripts/docker-dev.js
+++ b/scripts/docker-dev.js
@@ -1,219 +1,6 @@
 #!/usr/bin/env node
-
-// Enhanced Docker Development Script
-const { spawn, execSync } = require('child_process');
-const path = require('path');
-const fs = require('fs');
-
-// 获取当前工作目录
-const currentWorkingDir = process.cwd();
-
-// 设置环境变量
-process.env.REACTPRESS_ORIGINAL_CWD = currentWorkingDir;
-
-console.log(`[ReactPress] Setting REACTPRESS_ORIGINAL_CWD: ${currentWorkingDir}`);
-
-// Helper function to check if Docker is running
-function isDockerRunning() {
-  try {
-    execSync('docker info', { stdio: 'ignore' });
-    return true;
-  } catch (error) {
-    return false;
-  }
-}
-
-// Helper function to check if containers are running
-function areContainersRunning() {
-  try {
-    const output = execSync('docker-compose -f docker-compose.dev.yml ps --services --filter "status=running"', { 
-      encoding: 'utf-8' 
-    });
-    const services = output.trim().split('\n').filter(line => line.length > 0);
-    return services.length >= 2; // db and nginx
-  } catch (error) {
-    return false;
-  }
-}
-
-// Helper function to stop Docker services
-function stopDockerServices() {
-  console.log('[ReactPress] Stopping Docker services...');
-  try {
-    execSync('docker-compose -f docker-compose.dev.yml down', { 
-      stdio: 'inherit' 
-    });
-    console.log('[ReactPress] Docker services stopped successfully.');
-  } catch (error) {
-    console.error('[ReactPress] Error stopping Docker services:', error.message);
-  }
-}
-
-// Helper function to start Docker services
-function startDockerServices() {
-  console.log('[ReactPress] Starting Docker services...');
-  
-  if (!isDockerRunning()) {
-    console.error('[ReactPress] Docker is not running. Please start Docker first.');
-    process.exit(1);
-  }
-  
-  try {
-    execSync('docker-compose -f docker-compose.dev.yml up -d', { 
-      stdio: 'inherit' 
-    });
-    console.log('[ReactPress] Docker services started successfully.');
-    return true;
-  } catch (error) {
-    console.error('[ReactPress] Error starting Docker services:', error.message);
-    return false;
-  }
-}
-
-// Helper function to wait for services to be ready
-async function waitForServices() {
-  console.log('[ReactPress] Waiting for services to be ready...');
-  
-  // Check MySQL connection
-  let attempts = 0;
-  const maxAttempts = 30; // 30 seconds max wait
-  
-  while (attempts < maxAttempts) {
-    try {
-      execSync('docker exec reactpress_db mysql -u reactpress -preactpress -e "SELECT 1"', { 
-        stdio: 'ignore' 
-      });
-      console.log('[ReactPress] MySQL database is ready!');
-      return true;
-    } catch (error) {
-      attempts++;
-      if (attempts % 5 === 0) {
-        console.log(`[ReactPress] Waiting for MySQL... (${attempts}/${maxAttempts})`);
-      }
-      await new Promise(resolve => setTimeout(resolve, 1000));
-    }
-  }
-  
-  console.error('[ReactPress] MySQL database failed to start within timeout period.');
-  return false;
-}
-
-// Parse command line arguments
-const args = process.argv.slice(2);
-const command = args[0] || 'start';
-
-switch (command) {
-  case 'start':
-    // Start Docker services and development server
-    console.log('[ReactPress] Starting development environment...');
-    
-    if (!startDockerServices()) {
-      process.exit(1);
-    }
-    
-    waitForServices().then((ready) => {
-      if (ready) {
-        console.log('[ReactPress] Starting development server...');
-        
-        // 执行构建命令
-        const build = spawn('pnpm', ['build:toolkit'], {
-          stdio: 'inherit',
-          shell: true
-        });
-        
-        build.on('close', (code) => {
-          if (code !== 0) {
-            console.error(`[ReactPress] Build failed with exit code: ${code}`);
-            process.exit(code);
-          }
-          
-          console.log('[ReactPress] Toolkit built successfully.');
-          console.log('[ReactPress] Starting client and API (monorepo server/) in development mode...');
-          console.log('[ReactPress] Access your application at: http://localhost:8080');
-          
-          // 执行并发命令
-          const concurrently = spawn('npx', [
-            'concurrently',
-            '-n', 'api,web',
-            '-c', 'blue,green',
-            'pnpm:dev:api',
-            'pnpm:dev:client'
-          ], {
-            stdio: 'inherit',
-            shell: true,
-            cwd: currentWorkingDir
-          });
-          
-          concurrently.on('close', (code) => {
-            process.exit(code);
-          });
-        });
-      } else {
-        console.error('[ReactPress] Failed to start services.');
-        process.exit(1);
-      }
-    });
-    break;
-    
-  case 'stop':
-    // Stop Docker services
-    stopDockerServices();
-    break;
-    
-  case 'restart':
-    // Restart Docker services
-    console.log('[ReactPress] Restarting development environment...');
-    stopDockerServices();
-    
-    setTimeout(() => {
-      if (!startDockerServices()) {
-        process.exit(1);
-      }
-    }, 2000);
-    break;
-    
-  case 'status':
-    // Show status of Docker services
-    console.log('[ReactPress] Checking Docker services status...');
-    try {
-      execSync('docker-compose -f docker-compose.dev.yml ps', { 
-        stdio: 'inherit' 
-      });
-    } catch (error) {
-      console.error('[ReactPress] Error checking Docker services status:', error.message);
-    }
-    break;
-    
-  case 'logs':
-    // Show Docker logs
-    console.log('[ReactPress] Showing Docker services logs...');
-    try {
-      const logService = args[1] || '';
-      execSync(`docker-compose -f docker-compose.dev.yml logs -f ${logService}`, { 
-        stdio: 'inherit' 
-      });
-    } catch (error) {
-      console.error('[ReactPress] Error showing Docker services logs:', error.message);
-    }
-    break;
-    
-  default:
-    console.log(`
-ReactPress Docker Development Environment
-
-Usage: node scripts/docker-dev.js [command]
-
-Commands:
-  start   Start Docker services and development server (default)
-  stop    Stop Docker services
-  restart Restart Docker services
-  status  Show status of Docker services
-  logs    Show Docker services logs (optionally specify service: db, nginx)
-
-Examples:
-  node scripts/docker-dev.js
-  node scripts/docker-dev.js stop
-  node scripts/docker-dev.js logs db
-    `);
-    break;
-}
\ No newline at end of file
+/** @deprecated Use `reactpress docker ` */
+const cmd = process.argv[2] || 'start';
+const map = { stop: 'down' };
+process.argv = [process.argv[0], process.argv[1], 'docker', map[cmd] || cmd, ...process.argv.slice(3)];
+require('../cli/bin/reactpress');
diff --git a/scripts/reactpress-api-dev.js b/scripts/reactpress-api-dev.js
index c43080c..d0213e0 100644
--- a/scripts/reactpress-api-dev.js
+++ b/scripts/reactpress-api-dev.js
@@ -1,87 +1,4 @@
 #!/usr/bin/env node
-
-/**
- * Development API: Nest watch (monorepo server) or reactpress-cli fallback.
- */
-
-const { spawn, spawnSync } = require('child_process');
-const {
-  getMonorepoRoot,
-  isUsingMonorepoServer,
-} = require('./bundled-server-path');
-const { ensureProjectEnvironment } = require('./reactpress-bootstrap');
-
-const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
-
-process.env.REACTPRESS_ORIGINAL_CWD = projectRoot;
-
-let apiChild;
-
-function stopApi() {
-  if (apiChild && !apiChild.killed) {
-    apiChild.kill('SIGTERM');
-  }
-  if (!isUsingMonorepoServer()) {
-    spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], {
-      cwd: projectRoot,
-      stdio: 'inherit',
-    });
-  }
-}
-
-function startApiProcess() {
-  if (isUsingMonorepoServer()) {
-    console.log('[reactpress] 开发模式: server/ (nest start --watch)');
-    apiChild = spawn('pnpm', ['run', '--dir', './server', 'dev'], {
-      cwd: projectRoot,
-      stdio: 'inherit',
-      shell: true,
-      env: {
-        ...process.env,
-        REACTPRESS_ORIGINAL_CWD: projectRoot,
-      },
-    });
-  } else {
-    console.log('[reactpress] 开发模式: reactpress-cli(未找到 server/src)');
-    const start = spawnSync('pnpm', ['exec', 'reactpress-cli', 'start'], {
-      cwd: projectRoot,
-      stdio: 'inherit',
-    });
-    if (start.status !== 0) {
-      process.exit(start.status ?? 1);
-    }
-    console.log('[reactpress] API 已由 reactpress-cli 启动。');
-    process.stdin.resume();
-    return;
-  }
-
-  if (apiChild) {
-    apiChild.on('close', (code) => {
-      process.exit(code ?? 0);
-    });
-    console.log('[reactpress] 按 Ctrl+C 停止 API 与前端。');
-    console.log('[reactpress] 单独停止 API: pnpm run stop');
-  }
-}
-
-async function prepareAndStart() {
-  try {
-    await ensureProjectEnvironment(projectRoot);
-  } catch (err) {
-    console.error('[reactpress] 环境准备失败:', err.message || err);
-    process.exit(1);
-  }
-  startApiProcess();
-}
-
-process.on('SIGINT', () => {
-  stopApi();
-  process.exit(0);
-});
-
-process.on('SIGTERM', () => {
-  stopApi();
-  process.exit(0);
-});
-
-prepareAndStart();
+/** @deprecated Use `reactpress dev --api-only` */
+process.argv = [process.argv[0], process.argv[1], 'dev', '--api-only'];
+require('../cli/bin/reactpress');
diff --git a/scripts/reactpress-api-lifecycle.js b/scripts/reactpress-api-lifecycle.js
index 800fe24..1417fc4 100644
--- a/scripts/reactpress-api-lifecycle.js
+++ b/scripts/reactpress-api-lifecycle.js
@@ -1,255 +1,7 @@
 #!/usr/bin/env node
-
-/**
- * API lifecycle for monorepo: start / stop / restart / status (local server package).
- * Init and Docker DB still use reactpress-cli when needed.
- */
-
-const { spawn, spawnSync } = require('child_process');
-const fs = require('fs');
-const http = require('http');
-const path = require('path');
-const {
-  getMonorepoRoot,
-  getServerBin,
-  getServerDir,
-  isUsingMonorepoServer,
-} = require('./bundled-server-path');
-const { ensureProjectEnvironment } = require('./reactpress-bootstrap');
-
-const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
-const pidFile = path.join(projectRoot, '.reactpress', 'server.pid');
-
-process.env.REACTPRESS_ORIGINAL_CWD = projectRoot;
-
-function loadServerSiteUrl() {
-  const envPath = path.join(projectRoot, '.env');
-  try {
-    const content = fs.readFileSync(envPath, 'utf8');
-    const match = content.match(/^SERVER_SITE_URL=(.+)$/m);
-    if (match) {
-      return match[1].trim().replace(/^['"]|['"]$/g, '');
-    }
-  } catch {
-    // ignore
-  }
-  return 'http://localhost:3002';
-}
-
-async function ensureConfig() {
-  try {
-    await ensureProjectEnvironment(projectRoot);
-    return true;
-  } catch (err) {
-    console.error('[reactpress] 环境准备失败:', err.message || err);
-    return false;
-  }
-}
-
-function readPid() {
-  try {
-    const raw = fs.readFileSync(pidFile, 'utf8').trim();
-    const pid = Number.parseInt(raw, 10);
-    return Number.isFinite(pid) ? pid : null;
-  } catch {
-    return null;
-  }
-}
-
-function isProcessRunning(pid) {
-  if (!pid) return false;
-  try {
-    process.kill(pid, 0);
-    return true;
-  } catch {
-    return false;
-  }
-}
-
-function clearPidFile() {
-  if (fs.existsSync(pidFile)) {
-    fs.unlinkSync(pidFile);
-  }
-}
-
-function writePid(pid) {
-  fs.mkdirSync(path.dirname(pidFile), { recursive: true });
-  fs.writeFileSync(pidFile, String(pid));
-}
-
-function stopApi() {
-  const pid = readPid();
-  if (pid && isProcessRunning(pid)) {
-    try {
-      process.kill(pid, 'SIGTERM');
-      console.log(`[reactpress] 已停止 API 进程 (pid ${pid})`);
-    } catch (err) {
-      console.warn(`[reactpress] 停止 pid ${pid} 失败:`, err.message);
-    }
-  }
-  clearPidFile();
-}
-
-function isApiResponding(url, timeoutMs = 2000) {
-  return new Promise((resolve) => {
-    let parsed;
-    try {
-      parsed = new URL(url);
-    } catch {
-      resolve(false);
-      return;
-    }
-    const port = parsed.port || (parsed.protocol === 'https:' ? 443 : 80);
-    const req = http.request(
-      {
-        hostname: parsed.hostname,
-        port,
-        path: parsed.pathname || '/',
-        method: 'GET',
-        timeout: timeoutMs,
-      },
-      (res) => resolve(res.statusCode > 0)
-    );
-    req.on('timeout', () => {
-      req.destroy();
-      resolve(false);
-    });
-    req.on('error', () => resolve(false));
-    req.end();
-  });
-}
-
-async function waitForApi(url, timeoutMs = 120_000) {
-  const deadline = Date.now() + timeoutMs;
-  while (Date.now() < deadline) {
-    if (await isApiResponding(url)) {
-      return true;
-    }
-    await new Promise((r) => setTimeout(r, 500));
-  }
-  return false;
-}
-
-async function startApi({ wait = true } = {}) {
-  if (!(await ensureConfig())) {
-    process.exit(1);
-  }
-
-  const existing = readPid();
-  if (existing && isProcessRunning(existing)) {
-    console.log(`[reactpress] API 已在运行 (pid ${existing})`);
-    return 0;
-  }
-  clearPidFile();
-
-  if (!isUsingMonorepoServer()) {
-    console.warn('[reactpress] 未检测到 server/src,回退到 reactpress-cli start');
-    const start = spawnSync('pnpm', ['exec', 'reactpress-cli', 'start'], {
-      cwd: projectRoot,
-      stdio: 'inherit',
-    });
-    return start.status ?? 1;
-  }
-
-  console.log('[reactpress] 正在启动本地 API (server/)…');
-  const child = spawn(process.execPath, [getServerBin()], {
-    cwd: getServerDir(),
-    detached: true,
-    stdio: 'ignore',
-    env: {
-      ...process.env,
-      REACTPRESS_ORIGINAL_CWD: projectRoot,
-    },
-  });
-
-  child.unref();
-  writePid(child.pid);
-  console.log(`[reactpress] API 已后台启动 (pid ${child.pid})`);
-
-  if (!wait) {
-    return 0;
-  }
-
-  const serverUrl = loadServerSiteUrl();
-  return waitForApi(serverUrl).then((ready) => {
-    if (!ready) {
-      console.error(`[reactpress] API 在 120s 内未就绪: ${serverUrl}`);
-      return 1;
-    }
-    console.log(`[reactpress] API 已就绪: ${serverUrl}`);
-    return 0;
-  });
-}
-
-async function statusApi() {
-  const pid = readPid();
-  const serverUrl = loadServerSiteUrl();
-  const httpOk = await isApiResponding(serverUrl);
-
-  console.log('[reactpress] API 状态');
-  console.log(`  来源: ${isUsingMonorepoServer() ? 'monorepo server/' : 'reactpress-cli bundle'}`);
-  console.log(`  PID 文件: ${pidFile}`);
-  console.log(`  记录 PID: ${pid ?? '(无)'}`);
-  console.log(`  进程存活: ${pid ? (isProcessRunning(pid) ? '是' : '否') : '—'}`);
-  console.log(`  HTTP (${serverUrl}): ${httpOk ? '可访问' : '不可访问'}`);
-}
-
-const command = process.argv[2] || 'start';
-
-async function main() {
-  switch (command) {
-    case 'start': {
-      const code = await startApi({ wait: true });
-      process.exit(typeof code === 'number' ? code : 0);
-      break;
-    }
-    case 'start:bg': {
-      const code = await startApi({ wait: false });
-      process.exit(typeof code === 'number' ? code : 0);
-      break;
-    }
-    case 'stop':
-      stopApi();
-      if (!isUsingMonorepoServer()) {
-        spawnSync('pnpm', ['exec', 'reactpress-cli', 'stop'], {
-          cwd: projectRoot,
-          stdio: 'inherit',
-        });
-      }
-      break;
-    case 'restart':
-      stopApi();
-      if (!isUsingMonorepoServer()) {
-        spawnSync('pnpm', ['exec', 'reactpress-cli', 'restart'], {
-          cwd: projectRoot,
-          stdio: 'inherit',
-        });
-        break;
-      }
-      {
-        const code = await startApi({ wait: true });
-        process.exit(code ?? 0);
-      }
-      break;
-    case 'status':
-      await statusApi();
-      break;
-    default:
-      console.log(`
-用法: node scripts/reactpress-api-lifecycle.js 
-
-命令:
-  start      启动 API 并等待就绪(默认)
-  start:bg   后台启动,不等待 HTTP
-  stop       停止 API
-  restart    重启 API
-  status     查看 API 状态
-`);
-      process.exit(1);
-  }
-}
-
-main().catch((err) => {
-  console.error('[reactpress]', err);
-  process.exit(1);
-});
+/** @deprecated Use `reactpress server ` */
+const cmd = process.argv[2] || 'start';
+const map = { 'start:bg': ['server', 'start', '--bg'] };
+const extra = map[cmd] || ['server', cmd];
+process.argv = [process.argv[0], process.argv[1], ...extra];
+require('../cli/bin/reactpress');
diff --git a/scripts/reactpress-api-pm2.js b/scripts/reactpress-api-pm2.js
index a54f445..2dd49d4 100644
--- a/scripts/reactpress-api-pm2.js
+++ b/scripts/reactpress-api-pm2.js
@@ -1,32 +1,4 @@
 #!/usr/bin/env node
-
-/**
- * Start API with PM2 (monorepo server or CLI bundle).
- */
-
-const { spawn } = require('child_process');
-const {
-  getServerBin,
-  getServerDir,
-  getMonorepoRoot,
-} = require('./bundled-server-path');
-
-const projectRoot = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
-
-const child = spawn(process.execPath, [getServerBin(), '--pm2'], {
-  stdio: 'inherit',
-  cwd: getServerDir(),
-  env: {
-    ...process.env,
-    REACTPRESS_ORIGINAL_CWD: projectRoot,
-  },
-});
-
-child.on('error', (error) => {
-  console.error('[reactpress] PM2 启动 API 失败:', error);
-  process.exit(1);
-});
-
-child.on('close', (code) => {
-  process.exit(code ?? 0);
-});
+/** @deprecated Use `reactpress server start --pm2` */
+process.argv = [process.argv[0], process.argv[1], 'server', 'start', '--pm2'];
+require('../cli/bin/reactpress');
diff --git a/scripts/reactpress-bootstrap.js b/scripts/reactpress-bootstrap.js
index cdc31c8..0305718 100644
--- a/scripts/reactpress-bootstrap.js
+++ b/scripts/reactpress-bootstrap.js
@@ -1,158 +1,5 @@
 #!/usr/bin/env node
-
-/**
- * Pre-start environment: init .reactpress + .env, ensure embedded Docker MySQL.
- * Reuses @fecommunity/reactpress-cli services (same as reactpress-cli init/start).
- * Monorepo: does not overwrite root package.json.
- */
-
-const fs = require('fs');
-const path = require('path');
-const { pathToFileURL } = require('url');
-const { getMonorepoRoot } = require('./bundled-server-path');
-
-async function importCliModule(relativePath) {
-  const cliRoot = path.dirname(require.resolve('@fecommunity/reactpress-cli/package.json'));
-  const modulePath = path.join(cliRoot, 'dist', relativePath);
-  return import(pathToFileURL(modulePath).href);
-}
-
-function isMonorepoRoot(projectRoot) {
-  return (
-    fs.existsSync(path.join(projectRoot, 'pnpm-workspace.yaml')) ||
-    fs.existsSync(path.join(projectRoot, 'server', 'src', 'main.ts'))
-  );
-}
-
-async function copyTemplateFile(src, dest) {
-  await fs.promises.mkdir(path.dirname(dest), { recursive: true });
-  await fs.promises.copyFile(src, dest);
-}
-
-/**
- * Monorepo init: config + docker-compose + .env only (no package.json template).
- */
-async function initMonorepoProject(projectRoot, { force = false } = {}) {
-  const { getProjectPaths, getTemplatesDir } = await importCliModule('utils/paths.js');
-  const { saveConfig, syncEnvFromConfig } = await importCliModule('services/config.js');
-  const { ensureDatabase, ensureDatabaseHostPort } = await importCliModule('services/database.js');
-
-  const paths = getProjectPaths(projectRoot);
-  const templatesDir = getTemplatesDir();
-
-  if (fs.existsSync(paths.configPath) && !force) {
-    const config = await (await importCliModule('services/config.js')).loadConfig(projectRoot);
-    await ensureDatabaseHostPort(projectRoot, undefined, config);
-    const dbResult = await ensureDatabase(projectRoot, config);
-    if (!dbResult.ok) {
-      return { ok: false, projectRoot, message: dbResult.message };
-    }
-    return { ok: true, projectRoot, message: '配置已存在,数据库已就绪。' };
-  }
-
-  await fs.promises.mkdir(paths.reactpressDir, { recursive: true });
-  await copyTemplateFile(
-    path.join(templatesDir, 'docker-compose.yml'),
-    paths.dockerComposePath
-  );
-
-  const config = JSON.parse(
-    await fs.promises.readFile(path.join(templatesDir, 'config.default.json'), 'utf8')
-  );
-  await saveConfig(projectRoot, config);
-  await syncEnvFromConfig(projectRoot, config);
-
-  if (!fs.existsSync(paths.envPath) || force) {
-    await copyTemplateFile(path.join(templatesDir, 'env.default'), paths.envPath);
-    await syncEnvFromConfig(projectRoot, config);
-  }
-
-  await ensureDatabaseHostPort(projectRoot, undefined, config);
-  const dbResult = await ensureDatabase(projectRoot, config);
-
-  if (!dbResult.ok) {
-    return {
-      ok: true,
-      projectRoot,
-      message: `项目已创建,但数据库未就绪: ${dbResult.message}。请确认 Docker 已启动后重试 pnpm dev。`,
-    };
-  }
-
-  return {
-    ok: true,
-    projectRoot,
-    message: 'ReactPress 开发环境已就绪(配置 + 数据库)。',
-  };
-}
-
-/**
- * Ensure config and database before API / dev stack starts.
- */
-async function ensureProjectEnvironment(projectRoot = getMonorepoRoot()) {
-  const root = path.resolve(projectRoot);
-  const { setProjectCwd } = await importCliModule('utils/cli-context.js');
-  setProjectCwd(root);
-
-  const { isReactPressProject, loadConfig } = await importCliModule('services/config.js');
-  const { ensureDatabase, ensureDatabaseHostPort } = await importCliModule('services/database.js');
-
-  if (!(await isReactPressProject(root))) {
-    console.log('[reactpress] 首次运行,正在初始化配置与数据库…');
-    if (isMonorepoRoot(root)) {
-      const result = await initMonorepoProject(root);
-      if (!result.ok) {
-        throw new Error(result.message || '初始化失败');
-      }
-      console.log(`[reactpress] ${result.message}`);
-      return result;
-    }
-
-    const { initProject } = await importCliModule('services/init.js');
-    const result = await initProject({ directory: root, force: false });
-    if (!result.ok) {
-      throw new Error(result.message || 'reactpress-cli init 失败');
-    }
-    console.log(`[reactpress] ${result.message || '初始化完成'}`);
-    return result;
-  }
-
-  const config = await loadConfig(root);
-  await ensureDatabaseHostPort(root, undefined, config);
-  const dbResult = await ensureDatabase(root, config);
-  if (!dbResult.ok) {
-    throw new Error(dbResult.message || '数据库未就绪,请检查 Docker 与 .env 中的 DB_* 配置');
-  }
-
-  return { ok: true, projectRoot: root, message: '数据库已就绪' };
-}
-
-async function main() {
-  const force = process.argv.includes('--force');
-  const root = process.env.REACTPRESS_ORIGINAL_CWD || getMonorepoRoot();
-  process.env.REACTPRESS_ORIGINAL_CWD = root;
-
-  try {
-    if (force && isMonorepoRoot(root)) {
-      const result = await initMonorepoProject(root, { force: true });
-      console.log(`[reactpress] ${result.message}`);
-      process.exit(result.ok ? 0 : 1);
-      return;
-    }
-    await ensureProjectEnvironment(root);
-    console.log('[reactpress] 环境检查完成');
-    process.exit(0);
-  } catch (err) {
-    console.error('[reactpress] 环境准备失败:', err.message || err);
-    process.exit(1);
-  }
-}
-
-module.exports = {
-  ensureProjectEnvironment,
-  initMonorepoProject,
-  isMonorepoRoot,
-};
-
-if (require.main === module) {
-  main();
-}
+/** @deprecated Use `reactpress init` */
+const force = process.argv.includes('--force');
+process.argv = [process.argv[0], process.argv[1], 'init', '.', ...(force ? ['--force'] : [])];
+require('../cli/bin/reactpress');
diff --git a/scripts/reactpress-cli.js b/scripts/reactpress-cli.js
index ee5ad10..5b5b902 100755
--- a/scripts/reactpress-cli.js
+++ b/scripts/reactpress-cli.js
@@ -1,124 +1,3 @@
 #!/usr/bin/env node
-
-/**
- * ReactPress CLI — unified entry for monorepo development.
- * API: local server/ package; init / Docker DB: reactpress-cli.
- */
-
-const { Command } = require('commander');
-const { spawn, spawnSync } = require('child_process');
-const path = require('path');
-const chalk = require('chalk');
-
-const binDir = __dirname;
-const rootDir = path.join(binDir, '..');
-
-const program = new Command();
-
-function runReactpressCli(args, options = {}) {
-  const result = spawnSync('pnpm', ['exec', 'reactpress-cli', ...args], {
-    cwd: options.cwd || rootDir,
-    stdio: 'inherit',
-    env: {
-      ...process.env,
-      REACTPRESS_ORIGINAL_CWD: process.env.REACTPRESS_ORIGINAL_CWD || process.cwd(),
-    },
-  });
-  if (result.status !== 0) {
-    process.exit(result.status ?? 1);
-  }
-}
-
-function runLifecycle(command, extraArgs = []) {
-  spawnNodeScript(path.join(rootDir, 'scripts', 'reactpress-api-lifecycle.js'), [command, ...extraArgs]);
-}
-
-function spawnNodeScript(scriptPath, args = [], options = {}) {
-  const child = spawn(process.execPath, [scriptPath, ...args], {
-    stdio: 'inherit',
-    cwd: options.cwd || rootDir,
-    env: {
-      ...process.env,
-      REACTPRESS_ORIGINAL_CWD: process.env.REACTPRESS_ORIGINAL_CWD || process.cwd(),
-      ...options.env,
-    },
-  });
-  child.on('error', (error) => {
-    console.error(chalk.red('[ReactPress CLI]'), error);
-    process.exit(1);
-  });
-  child.on('close', (code) => process.exit(code ?? 0));
-}
-
-const serverCmd = program.command('server').description('Manage the ReactPress API (monorepo server/)');
-
-serverCmd
-  .command('start')
-  .description('Start the API server (local server/ or --pm2 for production)')
-  .option('--pm2', 'Start API with PM2 process manager')
-  .action((options) => {
-    if (options.pm2) {
-      spawnNodeScript(path.join(rootDir, 'scripts', 'reactpress-api-pm2.js'));
-      return;
-    }
-    runLifecycle('start');
-  });
-
-serverCmd
-  .command('stop')
-  .description('Stop the API server')
-  .action(() => runLifecycle('stop'));
-
-serverCmd
-  .command('restart')
-  .description('Restart the API server')
-  .action(() => runLifecycle('restart'));
-
-serverCmd
-  .command('status')
-  .description('Show API status')
-  .action(() => runLifecycle('status'));
-
-const clientCmd = program.command('client').description('Manage the ReactPress client');
-
-clientCmd
-  .command('start')
-  .description('Start the ReactPress client')
-  .option('--pm2', 'Start client with PM2 process manager')
-  .action((options) => {
-    const clientScript = path.join(rootDir, 'client', 'bin', 'reactpress-client.js');
-    const args = options.pm2 ? ['--pm2'] : [];
-    spawnNodeScript(clientScript, args);
-  });
-
-program
-  .command('init')
-  .description('Initialize ReactPress (.reactpress/config.json + .env via reactpress-cli)')
-  .argument('[directory]', 'Project directory', '.')
-  .option('-f, --force', 'Overwrite existing configuration')
-  .action((directory, options) => {
-    const args = ['init', directory];
-    if (options.force) args.push('--force');
-    runReactpressCli(args);
-  });
-
-const packageJson = require(path.join(rootDir, 'package.json'));
-program.version(packageJson.version);
-
-program.on('--help', () => {
-  console.log('');
-  console.log('Examples:');
-  console.log('  $ reactpress init .              # .reactpress/config.json + .env');
-  console.log('  $ reactpress server start        # Local Nest API (server/)');
-  console.log('  $ reactpress server start --pm2  # PM2 production API');
-  console.log('  $ reactpress client start        # Next.js client');
-  console.log('  $ pnpm dev                       # 零配置: env + DB + toolkit + API + client');
-  console.log('');
-  console.log('API backend: monorepo server/ (NestJS). Init/DB: @fecommunity/reactpress-cli.');
-});
-
-program.parse(process.argv);
-
-if (!process.argv.slice(2).length) {
-  program.outputHelp();
-}
+/** @deprecated Use `reactpress` or `node ./cli/bin/reactpress.js` */
+require('../cli/bin/reactpress');
diff --git a/scripts/reactpress-dev.js b/scripts/reactpress-dev.js
index 3731ff7..354c002 100644
--- a/scripts/reactpress-dev.js
+++ b/scripts/reactpress-dev.js
@@ -1,167 +1,4 @@
-const { spawn } = require('child_process');
-const fs = require('fs');
-const http = require('http');
-const path = require('path');
-const { ensureProjectEnvironment } = require('./reactpress-bootstrap');
-
-const currentWorkingDir = process.cwd();
-process.env.REACTPRESS_ORIGINAL_CWD = currentWorkingDir;
-
-const API_READY_TIMEOUT_MS = 180_000;
-const API_POLL_INTERVAL_MS = 500;
-
-console.log(`设置 REACTPRESS_ORIGINAL_CWD: ${currentWorkingDir}`);
-
-function loadServerSiteUrl() {
-  const envPath = path.join(currentWorkingDir, '.env');
-  try {
-    const content = fs.readFileSync(envPath, 'utf8');
-    const match = content.match(/^SERVER_SITE_URL=(.+)$/m);
-    if (match) {
-      return match[1].trim().replace(/^['"]|['"]$/g, '');
-    }
-  } catch {
-    // ignore
-  }
-  return 'http://localhost:3002';
-}
-
-function isApiResponding(url, timeoutMs = 2000) {
-  return new Promise((resolve) => {
-    let parsed;
-    try {
-      parsed = new URL(url);
-    } catch {
-      resolve(false);
-      return;
-    }
-
-    const port = parsed.port || (parsed.protocol === 'https:' ? 443 : 80);
-    const req = http.request(
-      {
-        hostname: parsed.hostname,
-        port,
-        path: parsed.pathname || '/',
-        method: 'GET',
-        timeout: timeoutMs,
-      },
-      (res) => {
-        resolve(res.statusCode > 0);
-      }
-    );
-
-    req.on('timeout', () => {
-      req.destroy();
-      resolve(false);
-    });
-    req.on('error', () => resolve(false));
-    req.end();
-  });
-}
-
-async function waitForApi(url, timeoutMs = API_READY_TIMEOUT_MS) {
-  const deadline = Date.now() + timeoutMs;
-  while (Date.now() < deadline) {
-    if (await isApiResponding(url)) {
-      return true;
-    }
-    await new Promise((r) => setTimeout(r, API_POLL_INTERVAL_MS));
-  }
-  return false;
-}
-
-let apiChild;
-let webChild;
-let shuttingDown = false;
-
-function shutdown(signal = 'SIGINT') {
-  if (shuttingDown) return;
-  shuttingDown = true;
-  if (webChild && !webChild.killed) {
-    webChild.kill(signal);
-  }
-  if (apiChild && !apiChild.killed) {
-    apiChild.kill(signal);
-  }
-}
-
-process.on('SIGINT', () => shutdown('SIGINT'));
-process.on('SIGTERM', () => shutdown('SIGTERM'));
-
-async function startDev() {
-  const serverUrl = loadServerSiteUrl();
-
-  console.log('[reactpress] 正在启动 API(首次可能需安装内置服务端依赖,请稍候)…');
-  apiChild = spawn(process.execPath, [path.join(__dirname, 'reactpress-api-dev.js')], {
-    stdio: 'inherit',
-    cwd: currentWorkingDir,
-  });
-
-  apiChild.on('close', (code) => {
-    if (shuttingDown) {
-      process.exit(code ?? 0);
-      return;
-    }
-    if (webChild && !webChild.killed) {
-      webChild.kill('SIGINT');
-    }
-    process.exit(code ?? 1);
-  });
-
-  console.log(`[reactpress] 等待 API 就绪: ${serverUrl}`);
-  const ready = await waitForApi(serverUrl);
-  if (!ready) {
-    console.error(
-      `[reactpress] API 在 ${API_READY_TIMEOUT_MS / 1000}s 内未就绪。请检查 Docker/MySQL 与 .env 中的 DB_* 配置。`
-    );
-    shutdown('SIGINT');
-    process.exit(1);
-  }
-
-  console.log('[reactpress] API 已就绪,正在启动前端…');
-  webChild = spawn('pnpm', ['dev:client'], {
-    stdio: 'inherit',
-    shell: true,
-    cwd: currentWorkingDir,
-  });
-
-  webChild.on('close', (code) => {
-    if (!shuttingDown) {
-      shutdown('SIGINT');
-    }
-    process.exit(code ?? 0);
-  });
-}
-
-async function runDev() {
-  try {
-    await ensureProjectEnvironment(currentWorkingDir);
-  } catch (err) {
-    console.error('[reactpress] 环境准备失败:', err.message || err);
-    process.exit(1);
-  }
-
-  await new Promise((resolve, reject) => {
-    const build = spawn('pnpm', ['build:toolkit'], {
-      stdio: 'inherit',
-      shell: true,
-      cwd: currentWorkingDir,
-    });
-
-    build.on('close', (code) => {
-      if (code !== 0) {
-        reject(new Error(`toolkit 构建失败,退出码: ${code}`));
-        return;
-      }
-      resolve();
-    });
-  });
-
-  await startDev();
-}
-
-runDev().catch((err) => {
-  console.error('[reactpress] 启动失败:', err.message || err);
-  shutdown('SIGINT');
-  process.exit(1);
-});
+#!/usr/bin/env node
+/** @deprecated Use `reactpress dev` */
+process.argv = [process.argv[0], process.argv[1], 'dev'];
+require('../cli/bin/reactpress');
diff --git a/scripts/reactpress-publish.js b/scripts/reactpress-publish.js
index 5d5c1ae..95e2349 100644
--- a/scripts/reactpress-publish.js
+++ b/scripts/reactpress-publish.js
@@ -1,943 +1,6 @@
 #!/usr/bin/env node
-
-const { execSync } = require('child_process');
-const fs = require('fs');
-const path = require('path');
-const chalk = require('chalk');
-const inquirer = require('inquirer');
-const crypto = require('crypto');
-
-// Package build order (dependencies first)
-const packages = [
-  {
-    name: '@fecommunity/reactpress',
-    path: '.',
-    description: 'Main ReactPress package'
-  },
-  {
-    name: '@fecommunity/reactpress-server',
-    path: 'server',
-    description: 'NestJS backend API'
-  },
-  {
-    name: '@fecommunity/reactpress-client',
-    path: 'client',
-    description: 'Frontend application package'
-  },
-  {
-    name: '@fecommunity/reactpress-toolkit',
-    path: 'toolkit',
-    description: 'API client and utilities toolkit'
-  },
-  {
-    name: '@fecommunity/reactpress-template-hello-world',
-    path: 'templates/hello-world',
-    description: 'Hello World template for ReactPress'
-  },
-  {
-    name: '@fecommunity/reactpress-template-twentytwentyfive',
-    path: 'templates/twentytwentyfive',
-    description: 'Twenty Twenty Five blog template for ReactPress'
-  }
-];
-
-// Generate a hash for a file or directory
-function generateHash(filePath) {
-  try {
-    if (fs.statSync(filePath).isDirectory()) {
-      const files = fs.readdirSync(filePath);
-      const hashes = files
-        .filter(file => !file.startsWith('.') && file !== 'node_modules' && file !== 'dist' && file !== '.next') // Ignore hidden files and build directories
-        .map(file => generateHash(path.join(filePath, file)))
-        .sort();
-      return crypto.createHash('md5').update(hashes.join('')).digest('hex');
-    } else {
-      const content = fs.readFileSync(filePath);
-      return crypto.createHash('md5').update(content).digest('hex');
-    }
-  } catch (error) {
-    return '';
-  }
-}
-
-// Get package content hash
-function getPackageHash(packagePath) {
-  const fullPath = path.join(process.cwd(), packagePath);
-  return generateHash(fullPath);
-}
-
-// Check if package has meaningful changes (for build)
-function hasMeaningfulChangesForBuild(packagePath, packageName) {
-  try {
-    // Create a hash file path to store previous hash in node_modules
-    const hashFilePath = path.join(process.cwd(), 'node_modules', '.build-cache', `${packageName.replace('/', '_')}.hash`);
-    
-    // Generate current hash
-    const currentHash = getPackageHash(packagePath);
-    
-    // Check if we have a previous hash
-    if (fs.existsSync(hashFilePath)) {
-      const previousHash = fs.readFileSync(hashFilePath, 'utf8').trim();
-      return currentHash !== previousHash;
-    }
-    
-    // If no previous hash, consider it as having changes
-    return true;
-  } catch (error) {
-    console.log(chalk.yellow(`⚠️  Could not check changes for ${packageName}, assuming changes exist`));
-    return true;
-  }
-}
-
-// Check if package has meaningful changes (for publish)
-function hasMeaningfulChangesForPublish(packagePath, packageName) {
-  try {
-    // Create a hash file path to store previous hash in node_modules
-    const hashFilePath = path.join(process.cwd(), 'node_modules', '.publish-cache', `${packageName.replace('/', '_')}.hash`);
-    
-    // Generate current hash
-    const currentHash = getPackageHash(packagePath);
-    
-    // Check if we have a previous hash
-    if (fs.existsSync(hashFilePath)) {
-      const previousHash = fs.readFileSync(hashFilePath, 'utf8').trim();
-      return currentHash !== previousHash;
-    }
-    
-    // If no previous hash, consider it as having changes
-    return true;
-  } catch (error) {
-    console.log(chalk.yellow(`⚠️  Could not check changes for ${packageName}, assuming changes exist`));
-    return true;
-  }
-}
-
-// Save package hash (for build)
-function savePackageHashForBuild(packagePath, packageName) {
-  try {
-    const hashFilePath = path.join(process.cwd(), 'node_modules', '.build-cache', `${packageName.replace('/', '_')}.hash`);
-    
-    // Ensure cache directory exists
-    const cacheDir = path.dirname(hashFilePath);
-    if (!fs.existsSync(cacheDir)) {
-      fs.mkdirSync(cacheDir, { recursive: true });
-    }
-    
-    // Generate and save current hash
-    const currentHash = getPackageHash(packagePath);
-    fs.writeFileSync(hashFilePath, currentHash);
-  } catch (error) {
-    console.log(chalk.yellow(`⚠️  Could not save hash for ${packageName}`));
-  }
-}
-
-// Save package hash (for publish)
-function savePackageHashForPublish(packagePath, packageName) {
-  try {
-    const hashFilePath = path.join(process.cwd(), 'node_modules', '.publish-cache', `${packageName.replace('/', '_')}.hash`);
-    
-    // Ensure cache directory exists
-    const cacheDir = path.dirname(hashFilePath);
-    if (!fs.existsSync(cacheDir)) {
-      fs.mkdirSync(cacheDir, { recursive: true });
-    }
-    
-    // Generate and save current hash
-    const currentHash = getPackageHash(packagePath);
-    fs.writeFileSync(hashFilePath, currentHash);
-  } catch (error) {
-    console.log(chalk.yellow(`⚠️  Could not save hash for ${packageName}`));
-  }
-}
-
-// Get current versions
-function getCurrentVersion(packagePath) {
-  try {
-    const pkgPath = path.join(process.cwd(), packagePath, 'package.json');
-    const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
-    return pkg.version;
-  } catch (error) {
-    return 'unknown';
-  }
-}
-
-// Increment version based on type
-function incrementVersion(version, type) {
-  const parts = version.split('-')[0].split('.');
-  const major = parseInt(parts[0]);
-  const minor = parseInt(parts[1]);
-  const patch = parseInt(parts[2]);
-  
-  switch (type) {
-    case 'major':
-      return `${major + 1}.0.0`;
-    case 'minor':
-      return `${major}.${minor + 1}.0`;
-    case 'patch':
-      return `${major}.${minor}.${patch + 1}`;
-    case 'beta':
-      // For beta, we increment the beta number or add beta.1 if not present
-      const match = version.match(/^(.*)-beta\.(\d+)$/);
-      if (match) {
-        const baseVersion = match[1];
-        const betaNumber = parseInt(match[2]);
-        return `${baseVersion}-beta.${betaNumber + 1}`;
-      } else {
-        // If no beta version exists, add beta.1
-        return `${version}-beta.1`;
-      }
-    case 'alpha':
-      // For alpha, we increment the alpha number or add alpha.1 if not present
-      const alphaMatch = version.match(/^(.*)-alpha\.(\d+)$/);
-      if (alphaMatch) {
-        const baseVersion = alphaMatch[1];
-        const alphaNumber = parseInt(alphaMatch[2]);
-        return `${baseVersion}-alpha.${alphaNumber + 1}`;
-      } else {
-        // If no alpha version exists, add alpha.1
-        return `${version}-alpha.1`;
-      }
-    default:
-      return version;
-  }
-}
-
-// Get next available version from npm registry
-function getNextAvailableVersion(packageName, currentVersion, versionType) {
-  try {
-    // First, increment the version locally
-    let nextVersion = incrementVersion(currentVersion, versionType);
-    
-    // Check if this version already exists on npm
-    let versionExists = true;
-    let attempts = 0;
-    const maxAttempts = 100; // Prevent infinite loop
-    
-    while (versionExists && attempts < maxAttempts) {
-      try {
-        execSync(`npm view ${packageName}@${nextVersion} version`, { stdio: 'ignore' });
-        // If we get here, the version exists, so we need to increment again
-        nextVersion = incrementVersion(nextVersion, versionType);
-        attempts++;
-      } catch (error) {
-        // If we get an error, the version doesn't exist, which is what we want
-        versionExists = false;
-      }
-    }
-    
-    if (attempts >= maxAttempts) {
-      throw new Error('Too many attempts to find available version');
-    }
-    
-    return nextVersion;
-  } catch (error) {
-    // Fallback to simple increment if npm view fails
-    console.log(chalk.yellow(`⚠️  Could not check npm registry, using local increment for ${packageName}`));
-    return incrementVersion(currentVersion, versionType);
-  }
-}
-
-// Update package version
-function updateVersion(packagePath, newVersion) {
-  console.log(chalk.blue(`\n✏️  Updating version to ${newVersion}...`));
-  
-  const pkgPath = path.join(process.cwd(), packagePath, 'package.json');
-  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
-  
-  const oldVersion = pkg.version;
-  pkg.version = newVersion;
-  
-  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
-  console.log(chalk.green(`✅ Version updated from ${oldVersion} to ${newVersion}`));
-}
-
-// Fix workspace dependencies for build
-function fixWorkspaceDependenciesForBuild(packagePath) {
-  console.log(chalk.blue(`🔧 Fixing workspace dependencies for build: ${packagePath}...`));
-  
-  const pkgPath = path.join(process.cwd(), packagePath, 'package.json');
-  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
-  
-  // Fix dependencies
-  const depTypes = ['dependencies', 'devDependencies', 'peerDependencies'];
-  
-  depTypes.forEach(depType => {
-    if (pkg[depType]) {
-      Object.keys(pkg[depType]).forEach(depName => {
-        // Check if it's a workspace dependency
-        if (pkg[depType][depName] === 'workspace:*' || pkg[depType][depName].startsWith('workspace:')) {
-          // For build purposes, we'll use the file: protocol to reference local packages
-          const depPackage = packages.find(p => p.name === depName);
-          if (depPackage) {
-            console.log(chalk.gray(`  Replacing ${depName} workspace dependency with file reference`));
-            pkg[depType][depName] = `file:../${depPackage.path}`;
-          }
-        }
-      });
-    }
-  });
-  
-  // Write the updated package.json
-  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
-  console.log(chalk.green(`✅ Workspace dependencies fixed for build: ${packagePath}`));
-}
-
-// Restore workspace dependencies after build
-function restoreWorkspaceDependenciesAfterBuild(packagePath) {
-  console.log(chalk.blue(`🔄 Restoring workspace dependencies after build: ${packagePath}...`));
-  
-  const pkgPath = path.join(process.cwd(), packagePath, 'package.json');
-  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
-  
-  // Restore dependencies
-  const depTypes = ['dependencies', 'devDependencies', 'peerDependencies'];
-  
-  depTypes.forEach(depType => {
-    if (pkg[depType]) {
-      Object.keys(pkg[depType]).forEach(depName => {
-        // Check if this is one of our internal packages referenced with file:
-        const depPackage = packages.find(p => p.name === depName);
-        if (depPackage && pkg[depType][depName].startsWith('file:')) {
-          console.log(chalk.gray(`  Restoring ${depName} to workspace dependency`));
-          pkg[depType][depName] = 'workspace:*';
-        }
-      });
-    }
-  });
-  
-  // Write the updated package.json
-  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
-  console.log(chalk.green(`✅ Workspace dependencies restored after build: ${packagePath}`));
-}
-
-// Fix workspace dependencies for publish
-function fixWorkspaceDependenciesForPublish(packagePath, packageVersions) {
-  console.log(chalk.blue(`🔧 Fixing workspace dependencies for publish: ${packagePath}...`));
-  
-  const pkgPath = path.join(process.cwd(), packagePath, 'package.json');
-  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
-  
-  // Fix dependencies
-  const depTypes = ['dependencies', 'devDependencies', 'peerDependencies'];
-  
-  depTypes.forEach(depType => {
-    if (pkg[depType]) {
-      Object.keys(pkg[depType]).forEach(depName => {
-        // Check if it's a workspace dependency
-        if (pkg[depType][depName] === 'workspace:*' || pkg[depType][depName].startsWith('workspace:')) {
-          // Replace with actual version
-          const depPackage = packages.find(p => p.name === depName);
-          if (depPackage && packageVersions[depName]) {
-            console.log(chalk.gray(`  Replacing ${depName} workspace dependency with version ${packageVersions[depName]}`));
-            pkg[depType][depName] = packageVersions[depName];
-          }
-        }
-      });
-    }
-  });
-  
-  // Write the updated package.json
-  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
-  console.log(chalk.green(`✅ Workspace dependencies fixed for publish: ${packagePath}`));
-}
-
-// Restore workspace dependencies after publish
-function restoreWorkspaceDependenciesAfterPublish(packagePath) {
-  console.log(chalk.blue(`🔄 Restoring workspace dependencies for ${packagePath}...`));
-  
-  const pkgPath = path.join(process.cwd(), packagePath, 'package.json');
-  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
-  
-  // Restore dependencies
-  const depTypes = ['dependencies', 'devDependencies', 'peerDependencies'];
-  
-  depTypes.forEach(depType => {
-    if (pkg[depType]) {
-      Object.keys(pkg[depType]).forEach(depName => {
-        // Check if this is one of our internal packages
-        const depPackage = packages.find(p => p.name === depName);
-        if (depPackage) {
-          console.log(chalk.gray(`  Restoring ${depName} to workspace dependency`));
-          pkg[depType][depName] = 'workspace:*';
-        }
-      });
-    }
-  });
-  
-  // Write the updated package.json
-  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
-  console.log(chalk.green(`✅ Workspace dependencies restored for ${packagePath}`));
-}
-
-// Build package
-function buildPackage(pkg) {
-  console.log(chalk.blue(`\n🔨 Building ${pkg.name} (${pkg.description})...`));
-  
-  try {
-    // Fix workspace dependencies for build
-    fixWorkspaceDependenciesForBuild(pkg.path);
-    
-    try {
-      if (pkg.path === 'config') {
-        execSync('pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' });
-      } else if (pkg.path === 'client') {
-        execSync('pnpm run prebuild && pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' });
-      } else if (pkg.path === 'toolkit') {
-        execSync('pnpm run build', { cwd: path.join(process.cwd(), pkg.path), stdio: 'inherit' });
-      } else if (pkg.path === 'templates/hello-world' || pkg.path === 'templates/twentytwentyfive') {
-        // Templates don't need to be built, just validate package.json
-        console.log(chalk.gray('  Templates do not require building, skipping...'));
-      }
-      console.log(chalk.green(`✅ ${pkg.name} built successfully`));
-    } finally {
-      // Always restore workspace dependencies
-      restoreWorkspaceDependenciesAfterBuild(pkg.path);
-    }
-  } catch (error) {
-    console.log(chalk.red(`❌ Failed to build ${pkg.name}`));
-    throw error;
-  }
-}
-
-// Publish package
-function publishPackage(packagePath, packageName, tag = 'latest') {
-  console.log(chalk.blue(`\n🚀 Publishing ${packageName} with tag ${tag}...`));
-  
-  try {
-    const command = `pnpm publish --access public --tag ${tag} --registry https://registry.npmjs.org --no-git-checks`;
-    execSync(command, { cwd: path.join(process.cwd(), packagePath), stdio: 'inherit' });
-    console.log(chalk.green(`✅ ${packageName} published successfully!`));
-  } catch (error) {
-    console.log(chalk.red(`❌ Failed to publish ${packageName}`));
-    throw error;
-  }
-}
-
-// Create GitHub release
-function createGitHubRelease(tagName, releaseNotes) {
-  console.log(chalk.blue(`\n📝 Creating GitHub release ${tagName}...`));
-  
-  try {
-    // Create release using GitHub CLI if available
-    const command = `gh release create ${tagName} --title "${tagName}" --notes "${releaseNotes}"`;
-    execSync(command, { stdio: 'inherit' });
-    console.log(chalk.green(`✅ GitHub release ${tagName} created successfully!`));
-  } catch (error) {
-    console.log(chalk.yellow(`⚠️  Failed to create GitHub release (GitHub CLI may not be installed or configured)`));
-    console.log(chalk.gray('You can manually create the release at: https://github.com/fecommunity/reactpress/releases/new'));
-  }
-}
-
-// Check environment
-function checkEnvironment() {
-  // Check if pnpm is installed
-  try {
-    execSync('pnpm --version', { stdio: 'ignore' });
-  } catch (error) {
-    console.log(chalk.red('❌ pnpm is not installed. Please install pnpm first.'));
-    return false;
-  }
-  
-  // Check if logged in to npm
-  try {
-    execSync('pnpm whoami --registry https://registry.npmjs.org', { stdio: 'ignore' });
-  } catch (error) {
-    console.log(chalk.red('❌ Not logged in to npm. Please run "pnpm login --registry https://registry.npmjs.org" first.'));
-    return false;
-  }
-  
-  return true;
-}
-
-// Build packages function
-async function buildPackages() {
-  console.log(chalk.blue('🏗️  ReactPress Package Builder\n'));
-  
-  // Show current versions
-  console.log(chalk.cyan('📋 Current package versions:'));
-  packages.forEach(pkg => {
-    const version = getCurrentVersion(pkg.path);
-    console.log(chalk.gray(`  ${pkg.name}: ${version}`));
-  });
-  console.log();
-  
-  try {
-    // Track which packages actually need to be built
-    const packagesToBuild = [];
-    
-    // Check for meaningful changes in each package
-    for (const pkg of packages) {
-      if (fs.existsSync(path.join(process.cwd(), pkg.path))) {
-        if (hasMeaningfulChangesForBuild(pkg.path, pkg.name)) {
-          packagesToBuild.push(pkg);
-          console.log(chalk.blue(`\n📦 ${pkg.name} has changes, will be built`));
-        } else {
-          console.log(chalk.gray(`\n⏭️  ${pkg.name} has no meaningful changes, skipping...`));
-        }
-      } else {
-        console.log(chalk.yellow(`⚠️  Package ${pkg.name} directory not found, skipping...`));
-      }
-    }
-    
-    if (packagesToBuild.length === 0) {
-      console.log(chalk.green('\n✅ No packages have meaningful changes. Nothing to build!'));
-      return;
-    }
-    
-    // Build packages that have changes
-    for (const pkg of packagesToBuild) {
-      await buildPackage(pkg);
-      // Save the hash after successful build
-      savePackageHashForBuild(pkg.path, pkg.name);
-    }
-    
-    console.log(chalk.green(`\n🎉 ${packagesToBuild.length} package(s) built successfully!`));
-  } catch (error) {
-    console.error(chalk.red('❌ Build failed:'), error);
-    process.exit(1);
-  }
-}
-
-// Publish packages function
-async function publishPackages() {
-  // Check if called with --no-build flag
-  const noBuild = process.argv.includes('--no-build');
-  
-  console.log(chalk.blue('📦 ReactPress Package Publisher\n'));
-  
-  // Run environment checks
-  if (!checkEnvironment()) {
-    process.exit(1);
-  }
-  
-  // Show current versions
-  console.log(chalk.cyan('📋 Current package versions:'));
-  packages.forEach(pkg => {
-    const version = getCurrentVersion(pkg.path);
-    console.log(chalk.gray(`  ${pkg.name}: ${version}`));
-  });
-  console.log();
-  
-  // Ask for publishing options
-  const { action } = await inquirer.prompt([
-    {
-      type: 'list',
-      name: 'action',
-      message: 'What would you like to do?',
-      choices: [
-        { name: '🚀 Publish all packages with version bump', value: 'publish-all' },
-        { name: '📦 Publish specific package', value: 'publish-one' },
-        { name: '🔨 Build all packages only', value: 'build-all' },
-        { name: '🏷️  Publish as beta/alpha', value: 'publish-prerelease' },
-        { name: '❌ Cancel', value: 'cancel' }
-      ]
-    }
-  ]);
-  
-  if (action === 'cancel') {
-    console.log(chalk.yellow('Operation cancelled.'));
-    return;
-  }
-  
-  if (action === 'build-all') {
-    console.log(chalk.blue('🔨 Building all packages...\n'));
-    
-    // Track which packages actually need to be built
-    const packagesToBuild = [];
-    
-    // Check for meaningful changes in each package
-    for (const pkg of packages) {
-      if (fs.existsSync(path.join(process.cwd(), pkg.path))) {
-        if (hasMeaningfulChangesForPublish(pkg.path, pkg.name)) {
-          packagesToBuild.push(pkg);
-          console.log(chalk.blue(`\n📦 ${pkg.name} has changes, will be built`));
-        } else {
-          console.log(chalk.gray(`\n⏭️  ${pkg.name} has no meaningful changes, skipping...`));
-        }
-      } else {
-        console.log(chalk.yellow(`⚠️  Package ${pkg.name} directory not found, skipping...`));
-      }
-    }
-    
-    if (packagesToBuild.length === 0) {
-      console.log(chalk.green('\n✅ No packages have meaningful changes. Nothing to build!'));
-      return;
-    }
-    
-    // Build packages that have changes
-    for (const pkg of packagesToBuild) {
-      buildPackage(pkg);
-      // Save the hash after successful build
-      savePackageHashForPublish(pkg.path, pkg.name);
-    }
-    
-    console.log(chalk.green(`\n🎉 ${packagesToBuild.length} package(s) built successfully!`));
-    return;
-  }
-  
-  if (action === 'publish-one') {
-    const { selectedPackage } = await inquirer.prompt([
-      {
-        type: 'list',
-        name: 'selectedPackage',
-        message: 'Which package would you like to publish?',
-        choices: packages.map(pkg => ({
-          name: `${pkg.name} (${pkg.description})`,
-          value: pkg
-        }))
-      }
-    ]);
-    
-    // Check if the selected package has meaningful changes
-    if (!hasMeaningfulChangesForPublish(selectedPackage.path, selectedPackage.name)) {
-      console.log(chalk.gray(`\n⏭️  ${selectedPackage.name} has no meaningful changes, skipping...`));
-      console.log(chalk.green('✅ Nothing to publish!'));
-      return;
-    }
-    
-    const { versionType } = await inquirer.prompt([
-      {
-        type: 'list',
-        name: 'versionType',
-        message: 'Version bump type:',
-        choices: [
-          { name: 'Beta (1.0.0-beta.1 -> 1.0.0-beta.2)', value: 'beta' },
-          { name: 'Patch (1.0.0 -> 1.0.1)', value: 'patch' },
-          { name: 'Minor (1.0.0 -> 1.1.0)', value: 'minor' },
-          { name: 'Major (1.0.0 -> 2.0.0)', value: 'major' },
-          { name: 'Custom version', value: 'custom' }
-        ]
-      }
-    ]);
-    
-    let newVersion;
-    const currentVersion = getCurrentVersion(selectedPackage.path);
-    
-    if (versionType === 'custom') {
-      const { customVersion } = await inquirer.prompt([
-        {
-          type: 'input',
-          name: 'customVersion',
-          message: `Enter new version for ${selectedPackage.name} (current: ${currentVersion}):`,
-          validate: (input) => {
-            const semverRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/;
-            return semverRegex.test(input) || 'Please enter a valid semver version (e.g., 1.0.0)';
-          }
-        }
-      ]);
-      newVersion = customVersion;
-    } else {
-      newVersion = getNextAvailableVersion(selectedPackage.name, currentVersion, versionType);
-    }
-    
-    // Get all package versions for dependency resolution
-    const packageVersions = {};
-    packages.forEach(pkg => {
-      packageVersions[pkg.name] = getCurrentVersion(pkg.path);
-    });
-    // Update the selected package version
-    packageVersions[selectedPackage.name] = newVersion;
-    
-    // Fix workspace dependencies before publishing
-    fixWorkspaceDependenciesForPublish(selectedPackage.path, packageVersions);
-    
-    try {
-      updateVersion(selectedPackage.path, newVersion);
-      // Only build if not disabled
-      if (!noBuild) {
-        buildPackage(selectedPackage);
-      }
-      
-      // Determine tag based on version type
-      const tag = versionType === 'beta' ? 'beta' : 'latest';
-      publishPackage(selectedPackage.path, selectedPackage.name, tag);
-      
-      // Save the hash after successful publish
-      savePackageHashForPublish(selectedPackage.path, selectedPackage.name);
-      
-      console.log(chalk.green(`\n🎉 ${selectedPackage.name} v${newVersion} published successfully!`));
-    } finally {
-      // Always restore workspace dependencies
-      restoreWorkspaceDependenciesAfterPublish(selectedPackage.path);
-    }
-    
-    return;
-  }
-  
-  if (action === 'publish-prerelease') {
-    const { tag } = await inquirer.prompt([
-      {
-        type: 'list',
-        name: 'tag',
-        message: 'Select prerelease tag:',
-        choices: ['beta', 'alpha', 'rc', 'next']
-      }
-    ]);
-    
-    const { versionType } = await inquirer.prompt([
-      {
-        type: 'list',
-        name: 'versionType',
-        message: 'Version bump type:',
-        choices: [
-          { name: `Prerelease (${tag})`, value: tag },
-          { name: 'Patch (1.0.0 -> 1.0.1)', value: 'patch' },
-          { name: 'Minor (1.0.0 -> 1.1.0)', value: 'minor' },
-          { name: 'Major (1.0.0 -> 2.0.0)', value: 'major' },
-          { name: 'Custom version', value: 'custom' }
-        ]
-      }
-    ]);
-    
-    // Get all package versions for dependency resolution
-    const packageVersions = {};
-    packages.forEach(pkg => {
-      const currentVersion = getCurrentVersion(pkg.path);
-      packageVersions[pkg.name] = currentVersion;
-    });
-    
-    // Track which packages actually need to be published
-    const packagesToPublish = [];
-    
-    // Check for meaningful changes in each package
-    for (const pkg of packages) {
-      if (!fs.existsSync(path.join(process.cwd(), pkg.path))) {
-        console.log(chalk.yellow(`⚠️  Package ${pkg.name} directory not found, skipping...`));
-        continue;
-      }
-      
-      if (hasMeaningfulChangesForPublish(pkg.path, pkg.name)) {
-        packagesToPublish.push(pkg);
-        console.log(chalk.blue(`\n📦 ${pkg.name} has changes, will be published`));
-      } else {
-        console.log(chalk.gray(`\n⏭️  ${pkg.name} has no meaningful changes, skipping...`));
-      }
-    }
-    
-    if (packagesToPublish.length === 0) {
-      console.log(chalk.green('\n✅ No packages have meaningful changes. Nothing to publish!'));
-      return;
-    }
-    
-    // Process each package that has changes
-    for (const pkg of packagesToPublish) {
-      let newVersion;
-      const currentVersion = getCurrentVersion(pkg.path);
-      
-      if (versionType === 'custom') {
-        const { customVersion } = await inquirer.prompt([
-          {
-            type: 'input',
-            name: 'customVersion',
-            message: `Enter version for ${pkg.name} (current: ${currentVersion}):`,
-            default: currentVersion
-          }
-        ]);
-        newVersion = customVersion;
-      } else {
-        newVersion = getNextAvailableVersion(pkg.name, currentVersion, versionType);
-      }
-      
-      // Update package version in our tracking
-      packageVersions[pkg.name] = newVersion;
-      
-      // Fix workspace dependencies before publishing
-      fixWorkspaceDependenciesForPublish(pkg.path, packageVersions);
-      
-      try {
-        updateVersion(pkg.path, newVersion);
-        // Only build if not disabled
-        if (!noBuild) {
-          buildPackage(pkg);
-        }
-        publishPackage(pkg.path, pkg.name, tag);
-        
-        // Save the hash after successful publish
-        savePackageHashForPublish(pkg.path, pkg.name);
-      } finally {
-        // Always restore workspace dependencies
-        restoreWorkspaceDependenciesAfterPublish(pkg.path);
-      }
-    }
-    
-    console.log(chalk.green(`\n🎉 ${packagesToPublish.length} package(s) published with ${tag} tag!`));
-    return;
-  }
-  
-  if (action === 'publish-all') {
-    // Check if we're on master branch for final release
-    let isMasterBranch = false;
-    try {
-      const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();
-      isMasterBranch = branch === 'master' || branch === 'main';
-    } catch (error) {
-      console.log(chalk.yellow('⚠️  Unable to determine current branch'));
-    }
-    
-    const { versionType } = await inquirer.prompt([
-      {
-        type: 'list',
-        name: 'versionType',
-        message: 'Version bump type:',
-        choices: [
-          { name: `Beta ${isMasterBranch ? '(will publish as final)' : '(will publish as beta)'}`, value: 'beta' },
-          { name: 'Patch (1.0.0 -> 1.0.1)', value: 'patch' },
-          { name: 'Minor (1.0.0 -> 1.1.0)', value: 'minor' },
-          { name: 'Major (1.0.0 -> 2.0.0)', value: 'major' },
-          { name: 'Custom version', value: 'custom' }
-        ]
-      }
-    ]);
-    
-    // Get all package versions for dependency resolution
-    const packageVersions = {};
-    const originalVersions = {};
-    
-    packages.forEach(pkg => {
-      const currentVersion = getCurrentVersion(pkg.path);
-      originalVersions[pkg.name] = currentVersion;
-      packageVersions[pkg.name] = currentVersion;
-    });
-    
-    let baseVersion;
-    if (versionType === 'custom') {
-      const { customVersion } = await inquirer.prompt([
-        {
-          type: 'input',
-          name: 'customVersion',
-          message: 'Enter new version for all packages:',
-          validate: (input) => {
-            const semverRegex = /^\d+\.\d+\.\d+$/;
-            return semverRegex.test(input) || 'Please enter a valid semver version (e.g., 1.0.0)';
-          }
-        }
-      ]);
-      baseVersion = customVersion;
-    } else {
-      // Use the highest current version as base and increment
-      const nextVersion = getNextAvailableVersion(packages[0].name, originalVersions[packages[0].name], versionType);
-      baseVersion = nextVersion;
-    }
-    
-    console.log(chalk.cyan(`\n📋 Will publish all packages with version: ${baseVersion}\n`));
-    
-    const { confirm } = await inquirer.prompt([
-      {
-        type: 'confirm',
-        name: 'confirm',
-        message: 'Are you sure you want to proceed?',
-        default: false
-      }
-    ]);
-    
-    if (!confirm) {
-      console.log(chalk.yellow('Operation cancelled.'));
-      return;
-    }
-    
-    // Track which packages actually need to be published
-    const packagesToPublish = [];
-    
-    // Check for meaningful changes in each package
-    for (const pkg of packages) {
-      if (!fs.existsSync(path.join(process.cwd(), pkg.path))) {
-        console.log(chalk.yellow(`⚠️  Package ${pkg.name} directory not found, skipping...`));
-        continue;
-      }
-      
-      if (hasMeaningfulChangesForPublish(pkg.path, pkg.name)) {
-        packagesToPublish.push(pkg);
-        console.log(chalk.blue(`\n📦 ${pkg.name} has changes, will be published`));
-      } else {
-        console.log(chalk.gray(`\n⏭️  ${pkg.name} has no meaningful changes, skipping...`));
-      }
-    }
-    
-    if (packagesToPublish.length === 0) {
-      console.log(chalk.green('\n✅ No packages have meaningful changes. Nothing to publish!'));
-      return;
-    }
-    
-    // Update versions, build and publish only packages with changes
-    for (const pkg of packagesToPublish) {
-      console.log(chalk.blue(`\n📦 Processing ${pkg.name}...`));
-      
-      // For publish-all, we use the same version for all packages
-      const pkgVersion = baseVersion;
-      packageVersions[pkg.name] = pkgVersion;
-      
-      // Fix workspace dependencies before publishing
-      fixWorkspaceDependenciesForPublish(pkg.path, packageVersions);
-      
-      try {
-        updateVersion(pkg.path, pkgVersion);
-        // Only build if not disabled
-        if (!noBuild) {
-          buildPackage(pkg);
-        }
-        
-        // Determine tag based on version type and branch
-        const tag = (versionType === 'beta' && !isMasterBranch) ? 'beta' : 'latest';
-        publishPackage(pkg.path, pkg.name, tag);
-        
-        // Save the hash after successful publish
-        savePackageHashForPublish(pkg.path, pkg.name);
-      } finally {
-        // Always restore workspace dependencies
-        restoreWorkspaceDependenciesAfterPublish(pkg.path);
-      }
-    }
-    
-    // Create GitHub release if on master and we actually published something
-    if (isMasterBranch && packagesToPublish.length > 0) {
-      const tagName = `v${baseVersion}`;
-      const releaseNotes = `Release ${baseVersion}
-
-Packages released:
-${Object.entries(packageVersions).map(([name, version]) => `- ${name}@${version}`).join('\n')}`;
-      createGitHubRelease(tagName, releaseNotes);
-    }
-    
-    console.log(chalk.green(`\n🎉 ${packagesToPublish.length} package(s) published successfully with version ${baseVersion}!`));
-    console.log(chalk.cyan('\n📋 Next steps:'));
-    console.log(chalk.gray('1. Create a git tag: git tag v' + baseVersion));
-    console.log(chalk.gray('2. Push changes: git push && git push --tags'));
-  }
-}
-
-// Main function
-async function main() {
-  // Check command line arguments
-  const args = process.argv.slice(2);
-  
-  if (args.includes('--publish')) {
-    // When called with --publish, start the publish process
-    console.log(chalk.blue('🏗️  ReactPress Package Builder\n'));
-    
-    // Show current versions
-    console.log(chalk.cyan('📋 Current package versions:'));
-    packages.forEach(pkg => {
-      const version = getCurrentVersion(pkg.path);
-      console.log(chalk.gray(`  ${pkg.name}: ${version}`));
-    });
-    console.log();
-    
-    // Start the publish process
-    await publishPackages();
-  } else if (args.includes('--build')) {
-    // When called with --build, just build packages
-    await buildPackages();
-  } else {
-    // Default behavior - show help
-    console.log(chalk.blue('🏗️  ReactPress CLI\n'));
-    console.log('Usage:');
-    console.log('  node scripts/reactpress-publish.js --build    Build all packages');
-    console.log('  node scripts/reactpress-publish.js --publish  Publish packages (interactive)');
-    console.log('');
-  }
-}
-
-main().catch(error => {
-  console.error(chalk.red('❌ Operation failed:'), error);
-  process.exit(1);
-});
\ No newline at end of file
+/** @deprecated Use `reactpress publish` */
+const args = process.argv.slice(2);
+const flag = args.includes('--build') ? '--build' : '--publish';
+process.argv = [process.argv[0], process.argv[1], 'publish', flag];
+require('../cli/bin/reactpress');

From 428a57f85bc9ae1f69682714a1ed1c64b765fb50 Mon Sep 17 00:00:00 2001
From: m0_37981569 
Date: Sat, 9 May 2026 22:25:00 +0800
Subject: [PATCH 07/20] chore: rename reactpress-toolchain to reactpress-cli,
 add server and client configurations, and enhance CLI functionality with new
 scripts and templates

---
 cli/LICENSE                             |  21 ++
 cli/README.md                           |  47 +++
 cli/package.json                        |  49 ++-
 cli/scripts/install-bundled-runtime.mjs |  46 +++
 cli/scripts/sync-bundled-core.mjs       |  63 ++++
 cli/server/bin/reactpress-server.js     | 203 +++++++++++
 cli/server/ecosystem.config.js          |  18 +
 cli/server/package.json                 | 146 ++++++++
 cli/server/public/favicon.png           | Bin 0 -> 33057 bytes
 cli/server/public/index.html            | 439 ++++++++++++++++++++++++
 cli/server/public/swagger/custom.css    |  11 +
 cli/templates/config.default.json       |  12 +
 cli/templates/docker-compose.yml        |  27 ++
 cli/templates/env.default               |  11 +
 cli/templates/package.json              |  10 +
 package.json                            |   2 +-
 pnpm-lock.yaml                          |   9 +-
 17 files changed, 1103 insertions(+), 11 deletions(-)
 create mode 100644 cli/LICENSE
 create mode 100644 cli/README.md
 create mode 100644 cli/scripts/install-bundled-runtime.mjs
 create mode 100644 cli/scripts/sync-bundled-core.mjs
 create mode 100644 cli/server/bin/reactpress-server.js
 create mode 100644 cli/server/ecosystem.config.js
 create mode 100644 cli/server/package.json
 create mode 100644 cli/server/public/favicon.png
 create mode 100644 cli/server/public/index.html
 create mode 100644 cli/server/public/swagger/custom.css
 create mode 100644 cli/templates/config.default.json
 create mode 100644 cli/templates/docker-compose.yml
 create mode 100644 cli/templates/env.default
 create mode 100644 cli/templates/package.json

diff --git a/cli/LICENSE b/cli/LICENSE
new file mode 100644
index 0000000..269cb6b
--- /dev/null
+++ b/cli/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 FECommunity
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/cli/README.md b/cli/README.md
new file mode 100644
index 0000000..fdaf2ac
--- /dev/null
+++ b/cli/README.md
@@ -0,0 +1,47 @@
+# @fecommunity/reactpress-cli
+
+零配置一键初始化与管理 ReactPress CMS & 博客服务器。内置 NestJS 服务端,无需单独克隆 [fecommunity/reactpress](https://github.com/fecommunity/reactpress)。
+
+完整文档与贡献指南见:[github.com/fecommunity/reactpress-cli](https://github.com/fecommunity/reactpress-cli)
+
+## 安装
+
+```bash
+npm install -g @fecommunity/reactpress-cli
+```
+
+全局命令为 `reactpress-cli`(与 npm 包名无关)。
+
+> npm 上的无作用域包名 `reactpress-cli` 已被占用,本包发布为 `@fecommunity/reactpress-cli`。
+
+## 快速开始
+
+```bash
+mkdir my-blog && cd my-blog
+reactpress-cli init
+reactpress-cli start
+```
+
+浏览器访问 `http://localhost:3002`(API 文档:`/api`)。
+
+## 常用命令
+
+| 命令 | 说明 |
+|------|------|
+| `reactpress-cli init [dir]` | 初始化项目 |
+| `reactpress-cli start` | 启动服务(自动准备数据库) |
+| `reactpress-cli stop` | 停止服务 |
+| `reactpress-cli restart` | 重启服务 |
+| `reactpress-cli status` | 查看状态 |
+| `reactpress-cli config [key] [value]` | 查看/修改配置 |
+| `reactpress-cli config server.port 3003 --apply` | 改端口并重启 |
+
+## 要求
+
+- Node.js 18+
+- macOS / Linux / Windows
+- 默认使用 Docker 运行嵌入式 MySQL;也可在 `.reactpress/config.json` 中配置外部数据库
+
+## 许可证
+
+MIT © FECommunity
diff --git a/cli/package.json b/cli/package.json
index b6cee42..b29d71c 100644
--- a/cli/package.json
+++ b/cli/package.json
@@ -1,18 +1,55 @@
 {
-  "name": "@fecommunity/reactpress-toolchain",
-  "version": "1.0.0",
-  "private": true,
-  "description": "ReactPress monorepo CLI — init, dev, build, deploy, publish",
+  "name": "@fecommunity/reactpress-cli",
+  "version": "0.2.0",
+  "description": "ReactPress CLI — init, dev, build, deploy, publish",
+  "author": "fecommunity",
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/fecommunity/reactpress.git",
+    "directory": "cli"
+  },
+  "keywords": [
+    "reactpress",
+    "cms",
+    "blog",
+    "cli"
+  ],
+  "engines": {
+    "node": ">=18"
+  },
   "bin": {
-    "reactpress": "./bin/reactpress.js"
+    "reactpress": "./bin/reactpress.js",
+    "reactpress-cli": "./dist/index.js"
   },
   "main": "./bin/reactpress.js",
+  "files": [
+    "bin",
+    "lib",
+    "ui",
+    "dist",
+    "server",
+    "templates",
+    "scripts/install-bundled-runtime.mjs",
+    "README.md",
+    "LICENSE"
+  ],
+  "scripts": {
+    "prepare": "node scripts/sync-bundled-core.mjs",
+    "prepack": "node scripts/sync-bundled-core.mjs"
+  },
+  "publishConfig": {
+    "access": "public",
+    "registry": "https://registry.npmjs.org/"
+  },
   "dependencies": {
-    "@fecommunity/reactpress-cli": "^0.1.0",
     "chalk": "^4.1.2",
     "commander": "^9.4.1",
     "concurrently": "^7.0.0",
     "inquirer": "^8.2.4",
     "open": "^8.2.1"
+  },
+  "devDependencies": {
+    "@fecommunity/reactpress-cli-core": "npm:@fecommunity/reactpress-cli@0.1.0"
   }
 }
diff --git a/cli/scripts/install-bundled-runtime.mjs b/cli/scripts/install-bundled-runtime.mjs
new file mode 100644
index 0000000..89e63b5
--- /dev/null
+++ b/cli/scripts/install-bundled-runtime.mjs
@@ -0,0 +1,46 @@
+import { existsSync } from 'node:fs';
+import { spawnSync } from 'node:child_process';
+import { dirname, join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const cliRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
+const serverDir = join(cliRoot, 'server');
+
+function npmInstall() {
+  console.log('[reactpress-cli] installing bundled server runtime dependencies…');
+  const result = spawnSync(
+    'npm',
+    ['install', '--omit=dev', '--legacy-peer-deps', '--no-bin-links'],
+    {
+      cwd: serverDir,
+      stdio: 'inherit',
+      shell: process.platform === 'win32',
+    }
+  );
+  if (result.status !== 0) {
+    process.exit(result.status ?? 1);
+  }
+}
+
+if (!existsSync(join(serverDir, 'package.json'))) {
+  console.warn('[reactpress-cli] bundled server missing, skip runtime install');
+  process.exit(0);
+}
+
+const serverRuntimeModules = [
+  ['node_modules', '@nestjs', 'core'],
+  ['node_modules', '@nestjs', 'typeorm'],
+  ['node_modules', 'typeorm'],
+  ['node_modules', 'express'],
+  ['node_modules', '@fecommunity', 'reactpress-toolkit'],
+];
+
+const serverReady =
+  existsSync(join(serverDir, 'dist', 'main.js')) &&
+  serverRuntimeModules.every((parts) => existsSync(join(serverDir, ...parts)));
+
+if (serverReady) {
+  process.exit(0);
+}
+
+npmInstall();
diff --git a/cli/scripts/sync-bundled-core.mjs b/cli/scripts/sync-bundled-core.mjs
new file mode 100644
index 0000000..f7004c4
--- /dev/null
+++ b/cli/scripts/sync-bundled-core.mjs
@@ -0,0 +1,63 @@
+#!/usr/bin/env node
+/**
+ * Copy core CLI runtime (dist, server, templates) from the legacy npm package
+ * so @fecommunity/reactpress-cli can be published as a self-contained package.
+ */
+import fs from 'fs';
+import path from 'path';
+import { fileURLToPath } from 'url';
+import { createRequire } from 'module';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const cliRoot = path.join(__dirname, '..');
+const require = createRequire(import.meta.url);
+
+const LEGACY_PKG = '@fecommunity/reactpress-cli-core';
+
+const SKIP_DIRS = new Set(['node_modules', '.git', 'logs']);
+const SKIP_FILES = new Set(['package-lock.json']);
+
+function copyDir(src, dest) {
+  fs.mkdirSync(dest, { recursive: true });
+  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
+    if (entry.isDirectory() && SKIP_DIRS.has(entry.name)) continue;
+    if (!entry.isDirectory() && SKIP_FILES.has(entry.name)) continue;
+    const from = path.join(src, entry.name);
+    const to = path.join(dest, entry.name);
+    if (entry.isDirectory()) {
+      copyDir(from, to);
+    } else {
+      fs.copyFileSync(from, to);
+    }
+  }
+}
+
+function main() {
+  let legacyRoot;
+  try {
+    legacyRoot = path.dirname(require.resolve(`${LEGACY_PKG}/package.json`));
+  } catch {
+    console.warn(
+      `[sync-bundled-core] Skip: install devDependency ${LEGACY_PKG} (npm:@fecommunity/reactpress-cli@0.1.0) first`
+    );
+    process.exit(0);
+  }
+
+  const entries = ['dist', 'server', 'templates', 'scripts'];
+  for (const name of entries) {
+    const src = path.join(legacyRoot, name);
+    if (!fs.existsSync(src)) continue;
+    const dest = path.join(cliRoot, name);
+    copyDir(src, dest);
+    console.log(`[sync-bundled-core] ${name}/ -> cli/${name}/`);
+  }
+
+  for (const file of ['LICENSE', 'README.md']) {
+    const src = path.join(legacyRoot, file);
+    if (fs.existsSync(src)) {
+      fs.copyFileSync(src, path.join(cliRoot, file));
+    }
+  }
+}
+
+main();
diff --git a/cli/server/bin/reactpress-server.js b/cli/server/bin/reactpress-server.js
new file mode 100644
index 0000000..c6121a1
--- /dev/null
+++ b/cli/server/bin/reactpress-server.js
@@ -0,0 +1,203 @@
+#!/usr/bin/env node
+
+/**
+ * ReactPress Server CLI Entry Point
+ * This script allows starting the ReactPress server via npx
+ * Supports both regular and PM2 startup modes
+ */
+
+const path = require('path');
+const fs = require('fs');
+const { spawn, spawnSync } = require('child_process');
+
+// Capture the original working directory where npx was executed
+// BUT prioritize the REACTPRESS_ORIGINAL_CWD environment variable if it exists
+// This ensures consistency when running via pnpm dev from root directory
+const originalCwd = process.env.REACTPRESS_ORIGINAL_CWD || process.cwd();
+
+// Get command line arguments
+const args = process.argv.slice(2);
+const usePM2 = args.includes('--pm2');
+const showHelp = args.includes('--help') || args.includes('-h');
+
+// Show help if requested
+if (showHelp) {
+  console.log(`
+ReactPress Server - NestJS-based backend API for ReactPress CMS
+
+Usage:
+  reactpress-server [options]
+  (通常由 reactpress-cli start 调用)
+
+Options:
+  --pm2        Start server with PM2 process manager
+  --help, -h   Show this help message
+
+Examples:
+  node bin/reactpress-server.js          # Start server normally
+  node bin/reactpress-server.js --pm2    # Start server with PM2
+  `);
+  process.exit(0);
+}
+
+// Get the directory where this script is located
+const binDir = __dirname;
+const serverDir = path.join(binDir, '..');
+const distPath = path.join(serverDir, 'dist', 'main.js');
+const ecosystemPath = path.join(serverDir, 'ecosystem.config.js');
+
+// Function to check if PM2 is installed
+function isPM2Installed() {
+  try {
+    require.resolve('pm2');
+    return true;
+  } catch (e) {
+    // Check if PM2 is installed globally
+    try {
+      spawnSync('pm2', ['--version'], { stdio: 'ignore' });
+      return true;
+    } catch (e) {
+      return false;
+    }
+  }
+}
+
+// Function to install PM2
+function installPM2() {
+  console.log('[ReactPress Server] Installing PM2...');
+  const installResult = spawnSync('npm', ['install', 'pm2', '--no-save'], {
+    stdio: 'inherit',
+    cwd: serverDir
+  });
+  
+  if (installResult.status !== 0) {
+    console.error('[ReactPress Server] Failed to install PM2');
+    return false;
+  }
+  
+  return true;
+}
+
+// Function to start with PM2
+function startWithPM2() {
+  // Check if PM2 is installed
+  if (!isPM2Installed()) {
+    // Try to install PM2
+    if (!installPM2()) {
+      console.error('[ReactPress Server] Cannot start with PM2');
+      process.exit(1);
+    }
+  }
+  
+  // Check if the server is built
+  if (!fs.existsSync(distPath)) {
+    console.log('[ReactPress Server] Server not built yet. Building...');
+    
+    // Try to build the server
+    const buildResult = spawnSync('npm', ['run', 'build'], {
+      stdio: 'inherit',
+      cwd: serverDir
+    });
+    
+    if (buildResult.status !== 0) {
+      console.error('[ReactPress Server] Failed to build server');
+      process.exit(1);
+    }
+  }
+  
+  console.log('[ReactPress Server] Starting with PM2...');
+  
+  // Use ecosystem.config.js if it exists, otherwise use direct command
+  let pm2Command = 'pm2';
+  try {
+    // Try to resolve PM2 path
+    pm2Command = path.join(serverDir, 'node_modules', '.bin', 'pm2');
+    if (!fs.existsSync(pm2Command)) {
+      pm2Command = 'pm2';
+    }
+  } catch (e) {
+    pm2Command = 'pm2';
+  }
+  
+  // Check if ecosystem.config.js exists
+  if (fs.existsSync(ecosystemPath)) {
+    const pm2 = spawn(pm2Command, ['start', ecosystemPath], {
+      stdio: 'inherit',
+      cwd: serverDir
+    });
+    
+    pm2.on('close', (code) => {
+      console.log(`[ReactPress Server] PM2 process exited with code ${code}`);
+      process.exit(code);
+    });
+    
+    pm2.on('error', (error) => {
+      console.error('[ReactPress Server] Failed to start with PM2:', error);
+      process.exit(1);
+    });
+  } else {
+    // Fallback to direct start
+    const pm2 = spawn(pm2Command, ['start', distPath, '--name', 'reactpress-server'], {
+      stdio: 'inherit',
+      cwd: serverDir
+    });
+    
+    pm2.on('close', (code) => {
+      console.log(`[ReactPress Server] PM2 process exited with code ${code}`);
+      process.exit(code);
+    });
+    
+    pm2.on('error', (error) => {
+      console.error('[ReactPress Server] Failed to start with PM2:', error);
+      process.exit(1);
+    });
+  }
+}
+
+// Function to start with regular Node.js
+function startWithNode() {
+  // Check if the server is built
+  if (!fs.existsSync(distPath)) {
+    console.log('[ReactPress Server] Server not built yet. Building...');
+    
+    // Try to build the server
+    const buildResult = spawnSync('npm', ['run', 'build'], {
+      stdio: 'inherit',
+      cwd: serverDir
+    });
+    
+    if (buildResult.status !== 0) {
+      console.error('[ReactPress Server] Failed to build server');
+      process.exit(1);
+    }
+  }
+
+  // ONLY set the environment variable if it's not already set
+  // This preserves the value set by set-env.js when running pnpm dev from root
+  if (!process.env.REACTPRESS_ORIGINAL_CWD) {
+    process.env.REACTPRESS_ORIGINAL_CWD = originalCwd;
+  } else {
+    console.log(`[ReactPress Server] Using existing REACTPRESS_ORIGINAL_CWD: ${process.env.REACTPRESS_ORIGINAL_CWD}`);
+  }
+
+  // Change to the server directory
+  process.chdir(serverDir);
+
+  // Set environment variables
+  process.env.NODE_ENV = process.env.NODE_ENV || 'production';
+
+  // Import and run the server
+  try {
+    require(distPath);
+  } catch (error) {
+    console.error('[ReactPress Server] Failed to start server:', error);
+    process.exit(1);
+  }
+}
+
+// Main execution
+if (usePM2) {
+  startWithPM2();
+} else {
+  startWithNode();
+}
diff --git a/cli/server/ecosystem.config.js b/cli/server/ecosystem.config.js
new file mode 100644
index 0000000..6a90515
--- /dev/null
+++ b/cli/server/ecosystem.config.js
@@ -0,0 +1,18 @@
+module.exports = {
+  apps: [
+    {
+      name: 'reactpress-server',
+      script: './dist/main.js',
+      instances: 1,
+      autorestart: true,
+      watch: false,
+      max_memory_restart: '1G',
+      env: {
+        NODE_ENV: 'production',
+      },
+      env_development: {
+        NODE_ENV: 'development',
+      },
+    },
+  ],
+};
\ No newline at end of file
diff --git a/cli/server/package.json b/cli/server/package.json
new file mode 100644
index 0000000..4f84e92
--- /dev/null
+++ b/cli/server/package.json
@@ -0,0 +1,146 @@
+{
+  "name": "reactpress-server",
+  "version": "1.0.0-beta.16",
+  "description": "ReactPress Server - NestJS-based backend API for ReactPress CMS",
+  "author": "fecommunity",
+  "license": "MIT",
+  "main": "dist/main.js",
+  "types": "dist/index.d.ts",
+  "files": [
+    "dist/**/*",
+    "public/**/*",
+    "bin/**/*",
+    "README.md",
+    "LICENSE"
+  ],
+  "keywords": [
+    "reactpress",
+    "server",
+    "nestjs",
+    "cms",
+    "blog",
+    "api",
+    "typescript"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/fecommunity/reactpress.git",
+    "directory": "server"
+  },
+  "engines": {
+    "node": ">=16.5.0"
+  },
+  "scripts": {
+    "prebuild": "rimraf dist",
+    "build": "nest build && npm run copy-assets",
+    "copy-assets": "cp -r public dist/ 2>/dev/null || true",
+    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
+    "dev": "nest start --watch",
+    "debug": "nest start --debug --watch",
+    "start": "cross-env NODE_ENV=production node dist/main",
+    "pm2": "pm2 start npm --name @fecommunity/reactpress-server -- start",
+    "lint": "tslint -p tsconfig.json -c tslint.json",
+    "test": "jest",
+    "test:watch": "jest --watch",
+    "test:cov": "jest --coverage",
+    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
+    "test:e2e": "jest --config ./test/jest-e2e.json",
+    "prepublishOnly": "npm run build",
+    "pm2:start": "pm2 start dist/main.js --name reactpress-server",
+    "pm2:stop": "pm2 stop reactpress-server",
+    "pm2:restart": "pm2 restart reactpress-server",
+    "pm2:delete": "pm2 delete reactpress-server",
+    "pm2:logs": "pm2 logs reactpress-server",
+    "pm2:status": "pm2 status reactpress-server",
+    "generate:swagger": "ts-node src/generate-swagger.ts"
+  },
+  "dependencies": {
+    "@fecommunity/reactpress-toolkit": "file:../toolkit",
+    "@nestjs/cli": "^6.9.0",
+    "@nestjs/common": "^6.7.2",
+    "@nestjs/config": "^0.6.3",
+    "@nestjs/core": "^6.7.2",
+    "@nestjs/jwt": "^6.1.1",
+    "@nestjs/passport": "^6.1.1",
+    "@nestjs/platform-express": "^6.11.5",
+    "@nestjs/swagger": "^4.8.2",
+    "@nestjs/typeorm": "^6.3.4",
+    "@types/express-serve-static-core": "^4.19.5",
+    "ali-oss": "^6.5.1",
+    "axios": "^0.23.0",
+    "bcryptjs": "^2.4.3",
+    "body-parser": "^1.19.0",
+    "chalk": "^4.1.2",
+    "class-transformer": "^0.2.3",
+    "commander": "^9.4.1",
+    "compression": "^1.7.4",
+    "cross-env": "^7.0.3",
+    "date-fns": "^2.17.0",
+    "deepmerge": "^4.2.2",
+    "dotenv": "^8.2.0",
+    "express": "^4.18.2",
+    "express-rate-limit": "^5.0.0",
+    "fs-extra": "^10.0.0",
+    "helmet": "^3.21.2",
+    "highlight.js": "^9.18.0",
+    "inquirer": "^8.2.4",
+    "lodash": "^4.17.21",
+    "log4js": "^6.1.0",
+    "marked": "^0.8.0",
+    "mysql2": "^3.12.0",
+    "node-ip2region": "^1.0.2",
+    "nodemailer": "^6.4.2",
+    "nuid": "^1.1.0",
+    "open": "^8.2.1",
+    "passport": "^0.4.1",
+    "passport-jwt": "^4.0.0",
+    "pm2": "^5.2.0",
+    "reflect-metadata": "^0.1.13",
+    "rimraf": "^3.0.0",
+    "rxjs": "^6.5.3",
+    "segment": "^0.1.3",
+    "swagger-themes": "^1.4.3",
+    "swagger-ui-express": "^4.1.6",
+    "typeorm": "^0.2.45",
+    "ua-parser-js": "^0.7.28"
+  },
+  "devDependencies": {
+    "@nestjs/schematics": "^6.7.0",
+    "@nestjs/testing": "^6.7.1",
+    "@types/express": "4.17.18",
+    "@types/jest": "^24.0.18",
+    "@types/node": "^12.7.5",
+    "@types/supertest": "^2.0.8",
+    "@typescript-eslint/eslint-plugin": "^5.21.0",
+    "@typescript-eslint/parser": "^5.21.0",
+    "eslint": "^8.15.0",
+    "eslint-config-prettier": "^8.5.0",
+    "eslint-plugin-import": "^2.26.0",
+    "eslint-plugin-prettier": "^4.0.0",
+    "eslint-plugin-simple-import-sort": "^7.0.0",
+    "jest": "^24.9.0",
+    "next-transpile-modules": "^6.3.0",
+    "prettier": "^1.18.2",
+    "supertest": "^4.0.2",
+    "ts-jest": "^24.1.0",
+    "ts-loader": "^6.1.1",
+    "ts-node": "^8.4.1",
+    "tsconfig-paths": "^3.9.0",
+    "tslint": "^5.20.0",
+    "typescript": "~4.1.6"
+  },
+  "jest": {
+    "moduleFileExtensions": [
+      "js",
+      "json",
+      "ts"
+    ],
+    "rootDir": "src",
+    "testRegex": ".spec.ts$",
+    "transform": {
+      "^.+\\.(t|j)s$": "ts-jest"
+    },
+    "coverageDirectory": "../coverage",
+    "testEnvironment": "node"
+  }
+}
diff --git a/cli/server/public/favicon.png b/cli/server/public/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..521edf80e7dfb357e0bb99f8659aad49b04430b8
GIT binary patch
literal 33057
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

oLluaFg!lf8R;7G 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 FV1m^A{DS}h literal 0 HcmV?d00001 diff --git a/cli/server/public/index.html b/cli/server/public/index.html new file mode 100644 index 0000000..4c285e3 --- /dev/null +++ b/cli/server/public/index.html @@ -0,0 +1,439 @@ + + + + + + ReactPress › Installation + + + +

+ + +
+
+
+ +
+ +
+

Database Connection Information

+ +
+ You should have this information available from your web hosting provider. If you don't have it, contact them before continuing. +
+ + + + + + + + + + + + + + + + + + + + + + +
+ +

Usually "localhost" or "127.0.0.1"

+
+ +

Default MySQL port is 3306

+
+ +

Your MySQL username

+
+ +

Your MySQL password

+
+ +

The name of the database you want to use with ReactPress

+
+ +
+ +

+ +

+
+ + +
+

Site Information

+ +
+ Please provide the following information. Don't worry, you can always change these settings later. +
+ + + + + + + + + + +
+ +

The URL where your ReactPress frontend will be accessible

+
+ +

The URL where your ReactPress API server will run

+
+ +
+ +

+ +

+
+ + +
+

🎉 Installation Complete!

+ +
+

ReactPress has been installed successfully!

+
+ +

Your ReactPress server configuration has been saved. You can:

+ +
    +
  • Close this browser window
  • +
  • Restart the server by running npx @fecommunity/reactpress-server in your terminal
  • +
  • Access your admin panel at http://localhost:3001/admin (when client is running)
  • +
+ + +
+

Waiting for server to start...

+
+ +
+ + +
+ +
+ Note: To start the server with your new configuration, run npx @fecommunity/reactpress-server in your terminal. +
+
+
+ + +
+ + + + \ No newline at end of file diff --git a/cli/server/public/swagger/custom.css b/cli/server/public/swagger/custom.css new file mode 100644 index 0000000..fee918b --- /dev/null +++ b/cli/server/public/swagger/custom.css @@ -0,0 +1,11 @@ +.swagger-ui div.topbar { + display: none !important; + padding: 0 !important; +} + + +.swagger-ui .scheme-container { + display: none !important; + margin: 0 !important; + padding: 0 !important; +} \ No newline at end of file diff --git a/cli/templates/config.default.json b/cli/templates/config.default.json new file mode 100644 index 0000000..7144102 --- /dev/null +++ b/cli/templates/config.default.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "database": { + "mode": "embedded-docker", + "containerName": "reactpress_cli_db" + }, + "server": { + "port": 3002, + "clientUrl": "http://localhost:3001", + "serverUrl": "http://localhost:3002" + } +} diff --git a/cli/templates/docker-compose.yml b/cli/templates/docker-compose.yml new file mode 100644 index 0000000..4755498 --- /dev/null +++ b/cli/templates/docker-compose.yml @@ -0,0 +1,27 @@ +services: + db: + image: mysql:8.0 + container_name: reactpress_cli_db + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-reactpress_root} + MYSQL_DATABASE: ${DB_DATABASE:-reactpress} + MYSQL_USER: ${DB_USER:-reactpress} + MYSQL_PASSWORD: ${DB_PASSWD:-reactpress} + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --default-authentication-plugin=mysql_native_password + volumes: + - reactpress_cli_db_data:/var/lib/mysql + ports: + - "${DB_PORT:-3306}:3306" + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-reactpress_root}"] + interval: 5s + timeout: 5s + retries: 12 + start_period: 20s + +volumes: + reactpress_cli_db_data: diff --git a/cli/templates/env.default b/cli/templates/env.default new file mode 100644 index 0000000..c38aa03 --- /dev/null +++ b/cli/templates/env.default @@ -0,0 +1,11 @@ +# ReactPress — auto-generated by reactpress-cli (do not edit DB_* unless you know what you are doing) +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_USER=reactpress +DB_PASSWD=reactpress +DB_DATABASE=reactpress + +CLIENT_SITE_URL=http://localhost:3001 +SERVER_SITE_URL=http://localhost:3002 +SERVER_PORT=3002 +SERVER_API_PREFIX=/api diff --git a/cli/templates/package.json b/cli/templates/package.json new file mode 100644 index 0000000..aaf0974 --- /dev/null +++ b/cli/templates/package.json @@ -0,0 +1,10 @@ +{ + "name": "reactpress-site", + "private": true, + "version": "1.0.0", + "description": "ReactPress CMS & Blog site", + "scripts": { + "start": "reactpress-cli start", + "stop": "reactpress-cli stop" + } +} diff --git a/package.json b/package.json index 3908664..6eb79b0 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "precommit": "lint-staged" }, "dependencies": { - "@fecommunity/reactpress-toolchain": "workspace:*" + "@fecommunity/reactpress-cli": "workspace:*" }, "devDependencies": { "husky": "^7.0.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e8b7d51..11b2f77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,7 +8,7 @@ importers: .: dependencies: - '@fecommunity/reactpress-toolchain': + '@fecommunity/reactpress-cli': specifier: workspace:* version: link:cli devDependencies: @@ -27,9 +27,6 @@ importers: cli: dependencies: - '@fecommunity/reactpress-cli': - specifier: ^0.1.0 - version: 0.1.0(@types/node@24.5.2) chalk: specifier: ^4.1.2 version: 4.1.2 @@ -45,6 +42,10 @@ importers: open: specifier: ^8.2.1 version: 8.4.2 + devDependencies: + '@fecommunity/reactpress-cli-core': + specifier: npm:@fecommunity/reactpress-cli@0.1.0 + version: '@fecommunity/reactpress-cli@0.1.0(@types/node@24.5.2)' client: dependencies: From b4d10ce8dedf6559a4799457b7c773a068878d15 Mon Sep 17 00:00:00 2001 From: m0_37981569 Date: Sun, 10 May 2026 22:10:00 +0800 Subject: [PATCH 08/20] docs: expand README.md with detailed CLI usage instructions, command descriptions, and project setup guidelines for both Monorepo and standalone projects --- cli/README.md | 195 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 179 insertions(+), 16 deletions(-) diff --git a/cli/README.md b/cli/README.md index fdaf2ac..12641ed 100644 --- a/cli/README.md +++ b/cli/README.md @@ -1,46 +1,209 @@ # @fecommunity/reactpress-cli -零配置一键初始化与管理 ReactPress CMS & 博客服务器。内置 NestJS 服务端,无需单独克隆 [fecommunity/reactpress](https://github.com/fecommunity/reactpress)。 +ReactPress 命令行工具:零配置初始化、全栈开发、构建与发布。本包提供两种入口: -完整文档与贡献指南见:[github.com/fecommunity/reactpress-cli](https://github.com/fecommunity/reactpress-cli) +| 命令 | 场景 | 说明 | +|------|------|------| +| `reactpress` | Monorepo / 产品仓库 | 统一全栈 CLI(`cli/bin/reactpress.js`) | +| `reactpress-cli` | 独立 CMS 项目 | 内置 NestJS 服务端,无需克隆完整仓库(`cli/dist/`) | + +仓库根目录通过 `pnpm run dev` 等脚本调用 `reactpress`;发布到 npm 后全局安装使用 `reactpress-cli`。 + +## 要求 + +- Node.js **18+** +- **pnpm**(Monorepo 开发) +- **Docker**(嵌入式 MySQL,默认 `embedded-docker` 模式) +- macOS / Linux / Windows ## 安装 +### 独立项目(npm 全局) + ```bash npm install -g @fecommunity/reactpress-cli ``` -全局命令为 `reactpress-cli`(与 npm 包名无关)。 +全局命令为 **`reactpress-cli`**(与 scoped 包名 `@fecommunity/reactpress-cli` 不同)。 > npm 上的无作用域包名 `reactpress-cli` 已被占用,本包发布为 `@fecommunity/reactpress-cli`。 +### Monorepo 内 + +在仓库根目录执行 `pnpm install` 后,可通过根 `package.json` 的 `bin` 使用 `reactpress`,或直接: + +```bash +node ./cli/bin/reactpress.js --help +``` + ## 快速开始 +### Monorepo 开发 + +```bash +git clone https://github.com/fecommunity/reactpress.git +cd reactpress +pnpm install + +# 零配置:.reactpress + .env + Docker MySQL → API + 前端 +pnpm run dev +``` + +无子命令时进入交互式菜单: + +```bash +reactpress +``` + +默认端口(可在 `.reactpress/config.json` 修改): + +| 服务 | 地址 | +|------|------| +| 前端 | http://localhost:3001 | +| API | http://localhost:3002 | +| API 文档 | http://localhost:3002/api | + +### 独立 CMS 项目 + ```bash mkdir my-blog && cd my-blog reactpress-cli init reactpress-cli start ``` -浏览器访问 `http://localhost:3002`(API 文档:`/api`)。 +## `reactpress` 命令(Monorepo) -## 常用命令 +在项目根目录执行(或通过 `pnpm run