diff --git a/.env.example b/.env.example index f5d95656..12a7ba63 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ # =========================================== -# 课伴 (KeBan) MVP-2 Alpha 环境变量模板 +# 熵减 (Entropydecrease) 环境变量模板 # =========================================== # 复制此文件为 .env 并填入实际值 @@ -54,10 +54,10 @@ AI_GATEWAY_PORT=8000 # --- 生产部署配置 --- # CORS 允许的前端域名(多个用逗号分隔) -# CORS_ORIGINS=https://keban.app,https://www.keban.app +# CORS_ORIGINS=https://entropydecrease.com,https://www.entropydecrease.com # 前端 API 基础 URL(生产环境设置为后端服务域名) -# VITE_API_BASE_URL=https://api.keban.app +# VITE_API_BASE_URL=https://api.entropydecrease.com # 日志级别(DEBUG/INFO/WARNING/ERROR) # LOG_LEVEL=INFO diff --git a/.gitattributes b/.gitattributes index 24a8e879..e86aa3a4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -*.png filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/deploy-server.yml b/.github/workflows/deploy-server.yml index 24c98881..69bafed0 100644 --- a/.github/workflows/deploy-server.yml +++ b/.github/workflows/deploy-server.yml @@ -2,7 +2,7 @@ name: Deploy AI Gateway on: push: - branches: [master] + branches: [main] paths: ['server/**'] jobs: @@ -10,19 +10,48 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Build and push Docker image - run: | - cd server - docker build -t ai-gateway:${{ github.sha }} . - - name: Deploy to server + + # 上传 server/ 源码到服务器(服务器非 git 仓库,代码由 CI 同步) + # 注意:rm 必须为 false —— 服务器上的 .env.production 为真实生产密钥, + # 不在仓库内(被 gitignore),删除目标目录会导致密钥永久丢失。 + - name: Upload server sources + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.SERVER_HOST }} + username: ${{ secrets.SERVER_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + source: server/* + target: /opt/Entropydecrease + rm: false + + - name: Rebuild and restart services uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | - cd /opt/keban - docker-compose pull - docker-compose up -d --force-recreate - sleep 10 - curl -f http://localhost:8000/health || (docker-compose rollback && exit 1) + set -e + cd /opt/Entropydecrease/server + + # .env.production 含生产密钥,必须显式传入,否则 DB_PASSWORD 等会被解析为空串 + COMPOSE="docker compose -f docker-compose.prod.yml --env-file .env.production" + + # 拉取第三方镜像(postgres/redis/nginx),自建服务由 --build 重新构建 + $COMPOSE pull --ignore-buildable || true + $COMPOSE up -d --build --force-recreate + + # 健康检查:失败时输出日志便于定位(docker compose 无 rollback 子命令, + # 回滚由 revert 提交重新触发部署完成) + sleep 15 + if ! curl -fsS http://127.0.0.1:8000/health; then + echo "::error::ai-gateway 健康检查失败,最近日志:" + $COMPOSE logs --tail=60 ai-gateway + exit 1 + fi + if ! curl -fsS http://127.0.0.1:8080/health; then + echo "::error::sync-service 健康检查失败,最近日志:" + $COMPOSE logs --tail=60 sync-service + exit 1 + fi + echo "部署成功:ai-gateway 与 sync-service 健康检查通过" diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml index a5b89c93..b1c7438f 100644 --- a/.github/workflows/deploy-website.yml +++ b/.github/workflows/deploy-website.yml @@ -2,7 +2,7 @@ name: Deploy Website on: push: - branches: [master] + branches: [main] paths: ['website/**'] jobs: @@ -29,7 +29,7 @@ jobs: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} - script: mkdir -p /opt/keban/website + script: mkdir -p /opt/Entropydecrease/website - name: Upload static files to server uses: appleboy/scp-action@v0.1.7 @@ -38,7 +38,7 @@ jobs: username: ${{ secrets.SERVER_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} source: website/out/* - target: /opt/keban/website + target: /opt/Entropydecrease/website strip_components: 2 rm: true @@ -52,7 +52,7 @@ jobs: # scp 的 rm:true 会重建挂载目录导致 bind mount 失效,必须重启容器 docker restart entropy-decrease-nginx sleep 5 - curl -sf https://entropydecrease.com/ | grep -q "课伴" || exit 1 + curl -sf https://entropydecrease.com/ | grep -q "熵减" || exit 1 - name: Notify IndexNow run: | diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index 70a7be61..6c67ce45 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -2,7 +2,7 @@ name: PR Quality Check on: pull_request: - branches: [master] + branches: [main, dev] jobs: # =========================================================================== diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 23d7b86d..ab436568 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,55 +1,55 @@ -name: Release Electron App - -# 由 semantic-release 创建的 v* tag 触发:构建 Electron 安装包并附加到对应 Release -on: - push: - tags: ['v*'] - -# 上传构建产物到 GitHub Release 需要写权限 -permissions: - contents: write - -jobs: - lint-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: 'npm' - cache-dependency-path: client/package-lock.json - - run: cd client && npm ci - - run: cd client && npm run lint - - run: cd client && npm run test -- --run - - build: - needs: lint-test - strategy: - matrix: - os: [windows-latest, macos-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: 'npm' - cache-dependency-path: client/package-lock.json - - run: cd client && npm ci - - run: cd client && npm run electron:build - - uses: actions/upload-artifact@v4 - with: - name: release-${{ matrix.os }} - path: client/release/*.{exe,dmg,AppImage} - - release: - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/download-artifact@v4 - with: - pattern: release-* - - uses: softprops/action-gh-release@v2 - with: - files: release-*/* +name: Release Electron App + +# 由 semantic-release 创建的 v* tag 触发:构建 Electron 安装包并附加到对应 Release +on: + push: + tags: ['v*'] + +# 上传构建产物到 GitHub Release 需要写权限 +permissions: + contents: write + +jobs: + lint-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + cache-dependency-path: client/package-lock.json + - run: cd client && npm ci + - run: cd client && npm run lint + - run: cd client && npm run test -- --run + + build: + needs: lint-test + strategy: + matrix: + os: [windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + cache-dependency-path: client/package-lock.json + - run: cd client && npm ci + - run: cd client && npm run electron:build + - uses: actions/upload-artifact@v4 + with: + name: release-${{ matrix.os }} + path: client/release/*.{exe,dmg,AppImage} + + release: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4 + with: + pattern: release-* + - uses: softprops/action-gh-release@v2 + with: + files: release-*/* diff --git a/.github/workflows/version-release.yml b/.github/workflows/version-release.yml index f2f23b4a..03ab5ff9 100644 --- a/.github/workflows/version-release.yml +++ b/.github/workflows/version-release.yml @@ -6,7 +6,7 @@ name: Version & Release # 自动更新 package.json/package-lock.json、生成 CHANGELOG、创建 Git tag 与 GitHub Release。 on: push: - branches: [master] + branches: [main] # 同一分支串行执行,避免并发发布产生 tag/版本竞争 concurrency: diff --git a/.gitignore b/.gitignore index d1f613b0..553912a4 100644 --- a/.gitignore +++ b/.gitignore @@ -35,9 +35,9 @@ Thumbs.db .env.local .env.*.local .env.production +.env.test -# Documentation (local only, not version controlled) -docs/ +# Brainstorm scratch (personal notes) brainstorm*.md ui_brainstorm.md diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 00000000..da994831 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..2312dc58 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.releaserc.json b/.releaserc.json index 95b47479..88fde5d8 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,6 +1,6 @@ { "branches": [ - "master" + "main" ], "tagFormat": "v${version}", "plugins": [ diff --git a/AGENTS.md b/AGENTS.md index c26ad8b0..22a53e7f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,80 +1,91 @@ -# AGENTS.md — 课伴 (KeBan) 仓库代理上下文 - -## 项目概述 - -课伴是面向学生与终身学习者的 AI 智能学习桌面应用,践行费曼学习法与间隔重复。 -核心理念:本地优先 + AI 增强可选。 - -## 项目结构 - -``` -├── client/ # Electron + React 桌面客户端(主产品) -│ ├── electron/ # Electron 主进程(TypeScript) -│ └── src/ # React 渲染进程(Vite + Tailwind) -├── server/ # 后端服务 -│ ├── ai-gateway/ # AI 网关(Python / FastAPI / LangChain) -│ ├── sync-service/# 数据同步服务(Go / Gin) -│ └── nginx/ # 反向代理配置 -├── website/ # 官网(Next.js 静态站点) -├── scripts/ # 仓库级工具脚本(版本、音效生成、会话检测) -└── docs/ # 全生命周期开发工作流文档 -``` - -## 核心模块边界 - -| 模块 | 入口 | 职责 | -|------|------|------| -| Electron 主进程 | `client/electron/main.ts` | 窗口管理、IPC、系统托盘、自动更新 | -| AI 集成层 | `client/electron/ai/` | 本地 Ollama 推理 + 云端 AI 网关调度 | -| AI 网关配置 | `server/ai-gateway/config.py` | 多模型路由(Qwen/DeepSeek/GLM)、超时、降级 | -| AI 网关入口 | `server/ai-gateway/main.py` | FastAPI 应用、中间件、路由注册 | -| 前端渲染 | `client/src/App.tsx` | React 路由、全局布局、3D 场景 | -| 数据层 | `client/electron/db/` | better-sqlite3 本地持久化 | - -## 变更需额外审查的文件 - -以下文件变更影响面大,需要额外审查: - -- `client/electron/main.ts` — 应用生命周期,改动可能导致启动失败 -- `client/electron/preload.ts` — IPC 桥接安全边界 -- `client/electron/ai/` — AI 调度逻辑,涉及多 provider 降级链 -- `server/ai-gateway/config.py` — 模型路由与密钥配置,影响全部 AI 功能 -- `server/ai-gateway/middleware/auth.py` — JWT 认证,安全关键 -- `server/ai-gateway/middleware/rate_limit.py` — 频率限制,影响可用性 -- `server/docker-compose.prod.yml` — 生产编排,改动影响部署 -- `client/electron-builder.yml` — 打包配置,影响发布产物 -- `.github/workflows/` — CI/CD 流水线 - -## 本地验证命令 - -```bash -# 客户端(在 client/ 目录下执行) -npm run lint # Oxlint 代码检查 -npm run test # Vitest 单元测试 -npm run build # tsc -b && vite build(TypeScript 编译 + Vite 打包) - -# Electron 桌面端构建 -npm run electron:build - -# 服务端 AI 网关(在 server/ai-gateway/ 目录下) -pip install -r requirements.txt -python main.py # 启动 FastAPI 开发服务器 - -# 仓库级 -npm run release:dry # semantic-release 干跑验证 -``` - -## 技术栈速查 - -- **客户端**: React 18, TypeScript, Vite, Electron, Tailwind CSS, Zustand, TanStack Query, Dexie.js, TipTap, Framer Motion, Vitest, Oxlint -- **AI 网关**: Python, FastAPI, LangChain, 通义千问/DeepSeek/智谱 GLM -- **同步服务**: Go, Gin, PostgreSQL, Redis -- **官网**: Next.js (静态导出) -- **基础设施**: Docker, docker-compose, Nginx, electron-updater - -## 约定 - -- 提交信息遵循 Conventional Commits 规范 -- 版本号由 semantic-release 自动管理 -- AI 功能必须支持离线降级(本地优先原则) -- 多模态模型 `max_tokens` 限制:Qwen 最大 4096,GLM-4V-Flash 最大 1024 +# AGENTS.md — 熵减 (Entropydecrease) 仓库代理上下文 + +## 项目概述 + +熵减是面向学生与终身学习者的 AI 智能学习桌面应用,践行费曼学习法与间隔重复。 +核心理念:本地优先 + AI 增强可选。 + +## 项目结构 + +``` +├── client/ # Electron + React 桌面客户端(主产品) +│ ├── electron/ # Electron 主进程(TypeScript) +│ └── src/ # React 渲染进程(Vite + Tailwind) +├── server/ # 后端服务 +│ ├── ai-gateway/ # AI 网关(Python / FastAPI / LangChain) +│ ├── sync-service/# 数据同步服务(Go / Gin) +│ └── nginx/ # 反向代理配置 +├── website/ # 官网(Next.js 静态站点) +├── scripts/ # 仓库级工具脚本(版本、音效生成、会话检测) +└── docs/ # 全生命周期开发工作流文档 +``` + +## 核心模块边界 + +| 模块 | 入口 | 职责 | +|------|------|------| +| Electron 主进程 | `client/electron/main.ts` | 窗口管理、IPC、系统托盘、自动更新 | +| AI 集成层 | `client/electron/ai/` | 本地 Ollama 推理 + 云端 AI 网关调度 | +| AI 网关配置 | `server/ai-gateway/config/` | 多模型路由(Qwen/DeepSeek/GLM/Gemini)、超时、降级(包化:runtime/limits/providers/fallback/app) | +| AI 网关入口 | `server/ai-gateway/main.py` | FastAPI 应用装配、中间件、路由注册 | +| 前端渲染 | `client/src/App.tsx` | React 路由、全局布局、3D 场景 | +| 数据层 | `client/electron/db/` | better-sqlite3 本地持久化 | +| 同步服务入口 | `server/sync-service/main.go` | Gin 路由装配、健康探针、WebSocket 通道 | + +## 变更需额外审查的文件 + +以下文件变更影响面大,需要额外审查: + +- `client/electron/main.ts` — 应用生命周期,改动可能导致启动失败 +- `client/electron/preload.ts` — IPC 桥接安全边界 +- `client/electron/ai/` — AI 调度逻辑,涉及多 provider 降级链 +- `server/ai-gateway/config/` — 模型路由与密钥配置,影响全部 AI 功能 +- `server/ai-gateway/middleware/auth.py` — JWT 认证,安全关键 +- `server/ai-gateway/middleware/rate_limit.py` — 频率限制,影响可用性 +- `server/sync-service/middleware/auth.go` — 同步服务 JWT 认证,安全关键 +- `server/docker-compose.prod.yml` — 生产编排,改动影响部署 +- `client/electron-builder.yml` — 打包配置,影响发布产物 +- `.github/workflows/` — CI/CD 流水线 + +## 本地验证命令 + +```bash +# 客户端(在 client/ 目录下执行) +npm run lint # Oxlint 代码检查 +npm run test # Vitest 单元测试 +npm run build # tsc -b && vite build(TypeScript 编译 + Vite 打包) + +# Electron 桌面端构建 +npm run electron:build + +# 服务端 AI 网关(在 server/ai-gateway/ 目录下) +pip install -r requirements.txt +python -m pytest tests/ -q # 单元测试(133 基线) +python main.py # 启动 FastAPI 开发服务器 + +# 同步服务(在 server/sync-service/ 目录下) +go build ./... && go vet ./... && go test ./... + +# 官网(在 website/ 目录下) +npm run build # next build(静态导出) + +# 仓库级 +npm run release:dry # semantic-release 干跑验证(需 git 仓库) +``` + +## 技术栈速查 + +- **客户端**: React 18, TypeScript, Vite, Electron, Tailwind CSS, Zustand, TanStack Query, Dexie.js, TipTap, Framer Motion, Vitest, Oxlint +- **AI 网关**: Python, FastAPI, LangChain, 通义千问/DeepSeek/智谱 GLM/Gemini +- **同步服务**: Go, Gin, PostgreSQL, Redis +- **官网**: Next.js (静态导出) +- **基础设施**: Docker, docker-compose, Nginx, electron-updater + +## 约定 + +- 提交信息遵循 Conventional Commits 规范 +- 版本号由 semantic-release 自动管理 +- AI 功能必须支持离线降级(本地优先原则) +- 多模态模型 `max_tokens` 限制:Qwen 最大 4096,GLM-4V-Flash 最大 1024 +- 单文件 ≤300 行(AI 编程规范 §1);全部源码文件需含 `@ai-context` 中英双语注释(§3) +- 用户数据标识(keban 库名 / keban_device_id / keban_crypto_salt 等)永久豁免品牌重命名,保证跨版本数据兼容 diff --git a/CHANGELOG.md b/CHANGELOG.md index ee1e37be..963513de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,70 +1,64 @@ -# 更新日志 - -本项目所有值得关注的变更都会记录在此文件中。 -版本号遵循 [语义化版本 SemVer](https://semver.org/lang/zh-CN/),提交信息遵循 [Conventional Commits](https://www.conventionalcommits.org/zh-hans/)。 - -## [0.24.0](https://github.com/Aparencia/KeBan/compare/v0.23.0...v0.24.0) (2026-07-29) - -### ✨ 新功能 - -* v0.22.0 — 音效系统重构、UI 组件增强与 AI 余额查询 ([b8c20e2](https://github.com/Aparencia/KeBan/commit/b8c20e2497cfed8c0e690998bf27a078746ab401)) - -## [0.23.0](https://github.com/Aparencia/KeBan/compare/v0.22.0...v0.23.0) (2026-07-28) - -### ✨ 新功能 - -* v0.21.0 — 许可证变更为 BUSL 1.1 与快捷方式设置优化 ([601d2a8](https://github.com/Aparencia/KeBan/commit/601d2a80fe62078d66b068f82139aad8302a71de)) - -## [0.22.0](https://github.com/Aparencia/KeBan/compare/v0.21.0...v0.22.0) (2026-07-28) - -### ✨ 新功能 - -* v0.20.1 — 课堂笔记插入、3D 安全合成器与捕获系统优化 ([0267a27](https://github.com/Aparencia/KeBan/commit/0267a2799fcbb15fc3aaf93e1e33aa45f42ba1ec)) - -## [0.21.0](https://github.com/Aparencia/KeBan/compare/v0.20.1...v0.21.0) (2026-07-28) - -### ✨ 新功能 - -* **website:** add Baidu site verification meta tag ([858666f](https://github.com/Aparencia/KeBan/commit/858666f1a4afb5221e4b73883d8ffa48b467e899)) - -## [0.20.1](https://github.com/Aparencia/KeBan/compare/v0.20.0...v0.20.1) (2026-07-27) - -### 🐛 缺陷修复 - -* **ci:** 部署后重启Nginx容器修复bind mount失效导致的403 ([babb5e8](https://github.com/Aparencia/KeBan/commit/babb5e8b6b7a2934bf2da8f79564ea1cbd3499b6)) - -## [0.20.0](https://github.com/Aparencia/KeBan/compare/v0.19.0...v0.20.0) (2026-07-27) - -### ✨ 新功能 - -* v0.18.0 — 官网 SEO 优化、支持页面与赞助二维码 ([0a332f1](https://github.com/Aparencia/KeBan/commit/0a332f1e5a51a2a721849209d18bb642c509a59a)) - -## [0.19.0](https://github.com/Aparencia/KeBan/compare/v0.18.0...v0.19.0) (2026-07-27) - -### ✨ 新功能 - -* v0.17.1 — CRDT 协同引擎、FSRS 调度器、AI 流式传输与全模块增强 ([231ab19](https://github.com/Aparencia/KeBan/commit/231ab19c27c46cfd597c2febdc627b4ea425cf8e)) - -## [0.18.0](https://github.com/Aparencia/KeBan/compare/v0.17.1...v0.18.0) (2026-07-27) - -### ✨ 新功能 - -* v0.17.0 — 课堂模块组件化、课程智能检测与多模态分析增强 ([9f2cf56](https://github.com/Aparencia/KeBan/commit/9f2cf5678da78185335edfed629cf6b06967ea25)) - -## [0.17.1](https://github.com/Aparencia/KeBan/compare/v0.17.0...v0.17.1) (2026-07-26) - -### 🐛 缺陷修复 - -* **classroom:** 智能采集语音识别流式化+merge降级+去重复传输 ([cd26df0](https://github.com/Aparencia/KeBan/commit/cd26df0b6cce555908108fb9faa5204396aa2ec1)) - -## [0.17.0](https://github.com/Aparencia/KeBan/compare/v0.16.0...v0.17.0) (2026-07-25) - -### ✨ 新功能 - -* **classroom:** 课堂助手模式UI优化、窗口智能识别与笔记生成加速 ([aad3c6c](https://github.com/Aparencia/KeBan/commit/aad3c6c9680501c52384f6fc3d656d5f0d39645d)) - -## [0.16.0](https://github.com/Aparencia/KeBan/compare/v0.15.0...v0.16.0) (2026-07-25) - -### ✨ 新功能 - -* v0.15.1 — Ollama 本地模型接入、AI 处理器重构与认证体系增强 ([8bcad71](https://github.com/Aparencia/KeBan/commit/8bcad7141c270f5ec585f3ea3587d18aa4f01b57)) +# 更新日志 + +本项目所有值得关注的变更都会记录在此文件中。 +版本号遵循 [语义化版本 SemVer](https://semver.org/lang/zh-CN/),提交信息遵循 [Conventional Commits](https://www.conventionalcommits.org/zh-hans/)。 + +## [0.23.0](https://github.com/Aparencia/KeBan/compare/v0.22.0...v0.23.0) (2026-07-28) + +### ✨ 新功能 + +* v0.21.0 — 许可证变更为 BUSL 1.1 与快捷方式设置优化 ([601d2a8](https://github.com/Aparencia/KeBan/commit/601d2a80fe62078d66b068f82139aad8302a71de)) + +## [0.22.0](https://github.com/Aparencia/KeBan/compare/v0.21.0...v0.22.0) (2026-07-28) + +### ✨ 新功能 + +* v0.20.1 — 课堂笔记插入、3D 安全合成器与捕获系统优化 ([0267a27](https://github.com/Aparencia/KeBan/commit/0267a2799fcbb15fc3aaf93e1e33aa45f42ba1ec)) + +## [0.21.0](https://github.com/Aparencia/KeBan/compare/v0.20.1...v0.21.0) (2026-07-28) + +### ✨ 新功能 + +* **website:** add Baidu site verification meta tag ([858666f](https://github.com/Aparencia/KeBan/commit/858666f1a4afb5221e4b73883d8ffa48b467e899)) + +## [0.20.1](https://github.com/Aparencia/KeBan/compare/v0.20.0...v0.20.1) (2026-07-27) + +### 🐛 缺陷修复 + +* **ci:** 部署后重启Nginx容器修复bind mount失效导致的403 ([babb5e8](https://github.com/Aparencia/KeBan/commit/babb5e8b6b7a2934bf2da8f79564ea1cbd3499b6)) + +## [0.20.0](https://github.com/Aparencia/KeBan/compare/v0.19.0...v0.20.0) (2026-07-27) + +### ✨ 新功能 + +* v0.18.0 — 官网 SEO 优化、支持页面与赞助二维码 ([0a332f1](https://github.com/Aparencia/KeBan/commit/0a332f1e5a51a2a721849209d18bb642c509a59a)) + +## [0.19.0](https://github.com/Aparencia/KeBan/compare/v0.18.0...v0.19.0) (2026-07-27) + +### ✨ 新功能 + +* v0.17.1 — CRDT 协同引擎、FSRS 调度器、AI 流式传输与全模块增强 ([231ab19](https://github.com/Aparencia/KeBan/commit/231ab19c27c46cfd597c2febdc627b4ea425cf8e)) + +## [0.18.0](https://github.com/Aparencia/KeBan/compare/v0.17.1...v0.18.0) (2026-07-27) + +### ✨ 新功能 + +* v0.17.0 — 课堂模块组件化、课程智能检测与多模态分析增强 ([9f2cf56](https://github.com/Aparencia/KeBan/commit/9f2cf5678da78185335edfed629cf6b06967ea25)) + +## [0.17.1](https://github.com/Aparencia/KeBan/compare/v0.17.0...v0.17.1) (2026-07-26) + +### 🐛 缺陷修复 + +* **classroom:** 智能采集语音识别流式化+merge降级+去重复传输 ([cd26df0](https://github.com/Aparencia/KeBan/commit/cd26df0b6cce555908108fb9faa5204396aa2ec1)) + +## [0.17.0](https://github.com/Aparencia/KeBan/compare/v0.16.0...v0.17.0) (2026-07-25) + +### ✨ 新功能 + +* **classroom:** 课堂助手模式UI优化、窗口智能识别与笔记生成加速 ([aad3c6c](https://github.com/Aparencia/KeBan/commit/aad3c6c9680501c52384f6fc3d656d5f0d39645d)) + +## [0.16.0](https://github.com/Aparencia/KeBan/compare/v0.15.0...v0.16.0) (2026-07-25) + +### ✨ 新功能 + +* v0.15.1 — Ollama 本地模型接入、AI 处理器重构与认证体系增强 ([8bcad71](https://github.com/Aparencia/KeBan/commit/8bcad7141c270f5ec585f3ea3587d18aa4f01b57)) diff --git a/LICENSE b/LICENSE index 7cd150aa..f248ca0f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,100 +1,100 @@ -Business Source License 1.1 - -Parameters - -Licensor: KeBan (课伴) Copyright Holder -Licensed Work: KeBan (课伴) - AI-Powered Learning Companion - The Licensed Work is (c) 2025-2026 KeBan Contributors. -Additional Use Grant: You may make use of the Licensed Work, provided that - you do not use the Licensed Work for a Production - Purpose that competes with the Licensed Work. - "Production Purpose" means any use that is intended - for or directed to commercial advantage or monetary - compensation. Non-commercial personal use, educational - use by students, and internal evaluation are permitted. -Change Date: Four years from the date the Licensed Work is - published. -Change License: Apache License, Version 2.0 - -For information about alternative licensing arrangements for the Software, -please contact the Licensor. - -Notice - -The Business Source License (this document, or the "License") is not an Open -Source license. However, the Licensed Work will eventually be made available -under an Open Source License, as stated in this License. - -License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. -"Business Source License" is a trademark of MariaDB Corporation Ab. - ------------------------------------------------------------------------------ - -Business Source License 1.1 - -Terms - -The Licensor hereby grants you the right to copy, modify, create derivative -works, redistribute, and make non-production use of the Licensed Work. The -Licensor may make an Additional Use Grant, above, permitting limited -production use. - -Effective on the Change Date, or the fourth anniversary of the first publicly -available distribution of a specific version of the Licensed Work under this -License, whichever comes first, the Licensor hereby grants you rights under -the terms of the Change License, and the rights granted in the paragraph -above terminate. - -If your use of the Licensed Work does not comply with the requirements -currently in effect as described in this License, you must purchase a -commercial license from the Licensor, its affiliated entities, or authorized -resellers, or you must refrain from using the Licensed Work. - -All copies of the original and modified Licensed Work, and derivative works -of the Licensed Work, are subject to this License. This License applies -separately for each version of the Licensed Work and the Change Date may -vary for each version of the Licensed Work released by Licensor. - -You must conspicuously display this License on each original or modified copy -of the Licensed Work. If you receive the Licensed Work in original or -modified form from a third party, the terms and conditions set forth in this -License apply to your use of that work. - -Any use of the Licensed Work in violation of this License will automatically -terminate your rights under this License for the current and all other -versions of the Licensed Work. - -This License does not grant you any right in any trademark or logo of -Licensor or its affiliates (provided that you may use a trademark or logo of -Licensor as expressly required by this License). - -TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON -AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, -EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -TITLE. - -MariaDB hereby grants you permission to use this License's text to license -your works, and to refer to it using the trademark "Business Source License", -as long as you comply with the Covenants of Licensor below. - -Covenants of Licensor - -In consideration of the right to use this License's text and the "Business -Source License" name and trademark, Licensor covenants to MariaDB, and to all -other recipients of the licensed work to be provided by Licensor: - -1. To specify as the Change License the GPL Version 2.0 or any later version, - or a license that is compatible with GPL Version 2.0 or a later version, - where "compatible" means that software provided under the Change License - can be included in a program with software provided under GPL Version 2.0 - or a later version. Licensor may specify additional Change Licenses without - limitation. - -2. To either: (a) specify an additional grant of rights to use that does not - impose any additional restriction on the right granted in this License, as - the Additional Use Grant; or (b) insert the text "None". - -3. To specify a Change Date. - -4. Not to modify this License in any other way. +Business Source License 1.1 + +Parameters + +Licensor: KeBan (课伴) Copyright Holder +Licensed Work: KeBan (课伴) - AI-Powered Learning Companion + The Licensed Work is (c) 2025-2026 KeBan Contributors. +Additional Use Grant: You may make use of the Licensed Work, provided that + you do not use the Licensed Work for a Production + Purpose that competes with the Licensed Work. + "Production Purpose" means any use that is intended + for or directed to commercial advantage or monetary + compensation. Non-commercial personal use, educational + use by students, and internal evaluation are permitted. +Change Date: Four years from the date the Licensed Work is + published. +Change License: Apache License, Version 2.0 + +For information about alternative licensing arrangements for the Software, +please contact the Licensor. + +Notice + +The Business Source License (this document, or the "License") is not an Open +Source license. However, the Licensed Work will eventually be made available +under an Open Source License, as stated in this License. + +License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. +"Business Source License" is a trademark of MariaDB Corporation Ab. + +----------------------------------------------------------------------------- + +Business Source License 1.1 + +Terms + +The Licensor hereby grants you the right to copy, modify, create derivative +works, redistribute, and make non-production use of the Licensed Work. The +Licensor may make an Additional Use Grant, above, permitting limited +production use. + +Effective on the Change Date, or the fourth anniversary of the first publicly +available distribution of a specific version of the Licensed Work under this +License, whichever comes first, the Licensor hereby grants you rights under +the terms of the Change License, and the rights granted in the paragraph +above terminate. + +If your use of the Licensed Work does not comply with the requirements +currently in effect as described in this License, you must purchase a +commercial license from the Licensor, its affiliated entities, or authorized +resellers, or you must refrain from using the Licensed Work. + +All copies of the original and modified Licensed Work, and derivative works +of the Licensed Work, are subject to this License. This License applies +separately for each version of the Licensed Work and the Change Date may +vary for each version of the Licensed Work released by Licensor. + +You must conspicuously display this License on each original or modified copy +of the Licensed Work. If you receive the Licensed Work in original or +modified form from a third party, the terms and conditions set forth in this +License apply to your use of that work. + +Any use of the Licensed Work in violation of this License will automatically +terminate your rights under this License for the current and all other +versions of the Licensed Work. + +This License does not grant you any right in any trademark or logo of +Licensor or its affiliates (provided that you may use a trademark or logo of +Licensor as expressly required by this License). + +TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +TITLE. + +MariaDB hereby grants you permission to use this License's text to license +your works, and to refer to it using the trademark "Business Source License", +as long as you comply with the Covenants of Licensor below. + +Covenants of Licensor + +In consideration of the right to use this License's text and the "Business +Source License" name and trademark, Licensor covenants to MariaDB, and to all +other recipients of the licensed work to be provided by Licensor: + +1. To specify as the Change License the GPL Version 2.0 or any later version, + or a license that is compatible with GPL Version 2.0 or a later version, + where "compatible" means that software provided under the Change License + can be included in a program with software provided under GPL Version 2.0 + or a later version. Licensor may specify additional Change Licenses without + limitation. + +2. To either: (a) specify an additional grant of rights to use that does not + impose any additional restriction on the right granted in this License, as + the Additional Use Grant; or (b) insert the text "None". + +3. To specify a Change Date. + +4. Not to modify this License in any other way. diff --git a/README.md b/README.md index e87b663f..4e89e076 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

-

📚 课伴 KeBan

+

📚 熵减 Entropydecrease

你的 AI 智能学习伙伴 — 让每一分钟学习都高效有价值

Status @@ -10,13 +10,13 @@ --- -## 📝 关于课伴 +## 📝 关于熵减 -**课伴(KeBan)** 是一款面向学生和终身学习者的高效学习桌面应用。它围绕全场景学习需求,基于费曼学习法、间隔重复等科学方法论,将时间管理、笔记记录、记忆巩固和深度理解整合在一个工具中,帮助你建立科学的学习闭环。 +**熵减(Entropydecrease)** 是一款面向学生和终身学习者的高效学习桌面应用。它围绕全场景学习需求,基于费曼学习法、间隔重复等科学方法论,将时间管理、笔记记录、记忆巩固和深度理解整合在一个工具中,帮助你建立科学的学习闭环。 **解决的核心痛点:** -| 痛点 | 课伴方案 | +| 痛点 | 熵减方案 | |------|----------| | 学习时容易走神、效率低 | 沉浸式番茄钟 + 滑动退出 + 后台不中断计时 | | 网课内容记不下来 | 网课笔记提取:自动截屏 + AI 视觉识别 + ASR 语音转写 | @@ -33,7 +33,7 @@ ## ✨ 核心功能 -课伴围绕 **"学 → 记 → 练 → 悟 → 思"** 学习闭环,提供六大模块: +熵减围绕 **"学 → 记 → 练 → 悟 → 思"** 学习闭环,提供六大模块: ### 🍅 番茄钟 — 时间管理 @@ -153,8 +153,8 @@ ```bash # 克隆仓库 -git clone https://github.com/Aparencia/KeBan.git -cd KeBan/client +git clone https://github.com/Aparencia/Entropydecrease.git +cd Entropydecrease/client # 安装依赖并启动开发服务器 npm install @@ -172,14 +172,14 @@ npm run electron:build 构建产物位于 `client/release/` 目录,格式为 Windows NSIS(`.exe`),支持当前用户安装,无需管理员权限。应用内置自动更新功能。 -也可以从 [GitHub Releases](https://github.com/Aparencia/KeBan/releases) 页面直接下载最新安装包。 +也可以从 [GitHub Releases](https://github.com/Aparencia/Entropydecrease/releases) 页面直接下载最新安装包。 --- ## 📁 项目结构 ``` -KeBan/ +Entropydecrease/ ├── client/ # 前端客户端(React + Electron 桌面应用) │ ├── src/features/ # 业务功能模块(番茄钟、笔记、闪卡、费曼、灵感、仪表盘) │ ├── src/lib/ # 核心库(AI、存储、同步、加密、网络、捕获、音效等) diff --git a/client/.env.example b/client/.env.example index c428dc0d..418cf68e 100644 --- a/client/.env.example +++ b/client/.env.example @@ -1,30 +1,30 @@ -# ============================================ -# 课伴 KeBan - 环境变量配置模板 -# 复制此文件为 .env 并填入实际值 -# ============================================ - -# ---- Supabase 配置 ---- -# Supabase 项目 URL(从 Supabase Dashboard 获取) -VITE_SUPABASE_URL= -# Supabase 匿名公钥(从 Supabase Dashboard 获取) -VITE_SUPABASE_ANON_KEY= - -# ---- API 服务地址 ---- -# 同步服务(sync-service)基础地址 -# 开发环境: http://127.0.0.1:8080 -# 生产环境: https://entropydecrease.com -VITE_API_BASE_URL=https://entropydecrease.com - -# 同步服务健康检查端点 -VITE_API_HEALTH_URL=https://entropydecrease.com/health - -# ---- AI 网关 ---- -# AI Gateway 服务地址 -# 开发环境: http://127.0.0.1:8000 -# 生产环境: https://entropydecrease.com -VITE_AI_GATEWAY_URL=https://entropydecrease.com - -# ---- Ollama 本地推理(可选) ---- -# Ollama 服务地址,默认自动检测 localhost:11434 -# 仅在自定义端口或远程 Ollama 时需要配置 -# VITE_OLLAMA_BASE_URL=http://localhost:11434 +# ============================================ +# 熵减 Entropydecrease - 环境变量配置模板 +# 复制此文件为 .env 并填入实际值 +# ============================================ + +# ---- Supabase 配置 ---- +# Supabase 项目 URL(从 Supabase Dashboard 获取) +VITE_SUPABASE_URL= +# Supabase 匿名公钥(从 Supabase Dashboard 获取) +VITE_SUPABASE_ANON_KEY= + +# ---- API 服务地址 ---- +# 同步服务(sync-service)基础地址 +# 开发环境: http://127.0.0.1:8080 +# 生产环境: https://entropydecrease.com +VITE_API_BASE_URL=https://entropydecrease.com + +# 同步服务健康检查端点 +VITE_API_HEALTH_URL=https://entropydecrease.com/health + +# ---- AI 网关 ---- +# AI Gateway 服务地址 +# 开发环境: http://127.0.0.1:8000 +# 生产环境: https://entropydecrease.com +VITE_AI_GATEWAY_URL=https://entropydecrease.com + +# ---- Ollama 本地推理(可选) ---- +# Ollama 服务地址,默认自动检测 localhost:11434 +# 仅在自定义端口或远程 Ollama 时需要配置 +# VITE_OLLAMA_BASE_URL=http://localhost:11434 diff --git a/client/.gitignore b/client/.gitignore index 6618bdad..aebfb8d2 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,30 +1,30 @@ -# Environment variables -.env -.env.local -.env.test -.env.*.local - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? +# Environment variables +.env +.env.local +.env.test +.env.*.local + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/client/.oxlintrc.json b/client/.oxlintrc.json index 6fa991da..d2ffbe25 100644 --- a/client/.oxlintrc.json +++ b/client/.oxlintrc.json @@ -1,8 +1,8 @@ -{ - "$schema": "./node_modules/oxlint/configuration_schema.json", - "plugins": ["react", "typescript", "oxc"], - "rules": { - "react/rules-of-hooks": "error", - "react/only-export-components": ["warn", { "allowConstantExport": true }] - } -} +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["react", "typescript", "oxc"], + "rules": { + "react/rules-of-hooks": "error", + "react/only-export-components": ["warn", { "allowConstantExport": true }] + } +} diff --git a/client/components.json b/client/components.json index 0eb78712..153487b6 100644 --- a/client/components.json +++ b/client/components.json @@ -1,19 +1,19 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "src/styles/tokens.css", - "baseColor": "neutral", - "cssVariables": true - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - } -} +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/styles/tokens.css", + "baseColor": "neutral", + "cssVariables": true + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} diff --git a/client/electron-builder.yml b/client/electron-builder.yml index b3023594..3d6b8365 100644 --- a/client/electron-builder.yml +++ b/client/electron-builder.yml @@ -3,8 +3,8 @@ appId: com.entropydecrease.app productName: "Entropy decrease" publish: provider: github - owner: YourGitHubUsername - repo: KeBan + owner: Aparencia + repo: Entropydecrease directories: output: release buildResources: build diff --git a/client/electron/ai/gatewayConfig.ts b/client/electron/ai/gatewayConfig.ts new file mode 100644 index 00000000..fcf4a3bf --- /dev/null +++ b/client/electron/ai/gatewayConfig.ts @@ -0,0 +1,117 @@ +/** + * AI 网关地址管理(主进程侧) + * + * @ai-context: 从 ai/utils.ts 拆出。地址解析优先级按模式分流: + * 开发=env > IPC运行时 > 默认;生产=IPC/持久化 > env > 默认。 + * 开发模式不写持久化文件(防调试数据污染生产配置)。 + * 持久化文件为 userData/ai-gateway-config.json。 + * @ai-context: DEFAULT_GATEWAY_URL 与 cspPolicy.ts、渲染进程 config.ts + * 三处需保持一致;修改默认域名需三处同步。 + */ +import { app } from 'electron'; +import * as path from 'path'; +import { readFile, writeFile } from 'fs/promises'; +import { logger } from '../logger.js'; + +const DEFAULT_GATEWAY_URL = 'https://entropydecrease.com'; +const GATEWAY_CONFIG_FILE = 'ai-gateway-config.json'; + +// ── 运行时网关地址(渲染进程通过 IPC 同步) ── +let _runtimeGatewayUrl: string | null = null; + +/** 记录 gatewayUrl() 是否已打印过首次解析日志,避免重复输出 */ +let _gatewayFirstResolveLogged = false; + +/** + * 判定当前是否为开发模式 + * 可靠依据:electron:dev 脚本设置 NODE_ENV=development,安装包运行时 app.isPackaged=true + */ +export function isDevMode(): boolean { + return process.env.NODE_ENV === 'development' || !app.isPackaged; +} + +/** + * 获取 AI 网关地址 + * + * 按模式分流优先级: + * - 开发模式:环境变量 > 运行时 IPC > 默认值 + * - 生产模式:运行时 IPC > 持久化文件(已存入_runtimeGatewayUrl) > 环境变量 > 默认值 + */ +export function gatewayUrl(): string { + const url = _resolveGatewayUrl(); + if (!_gatewayFirstResolveLogged) { + _gatewayFirstResolveLogged = true; + const dev = isDevMode(); + const source = dev + ? (process.env.VITE_AI_GATEWAY_URL + ? `env (VITE_AI_GATEWAY_URL=${process.env.VITE_AI_GATEWAY_URL})` + : _runtimeGatewayUrl + ? 'runtime (IPC)' + : 'DEFAULT (hardcoded fallback)') + : (_runtimeGatewayUrl + ? 'runtime (IPC/persisted)' + : process.env.VITE_AI_GATEWAY_URL + ? `env (VITE_AI_GATEWAY_URL=${process.env.VITE_AI_GATEWAY_URL})` + : 'DEFAULT (hardcoded fallback)'); + logger.info(`[AI] Gateway URL resolved: ${url} [source: ${source}, mode: ${dev ? 'dev' : 'prod'}]`); + if (!process.env.VITE_AI_GATEWAY_URL && !_runtimeGatewayUrl) { + logger.warn('[AI] Gateway URL fell back to DEFAULT. Set VITE_AI_GATEWAY_URL in .env or configure via AI settings.'); + } + } + return url; +} + +/** 内部解析逻辑,按模式分流优先级 */ +function _resolveGatewayUrl(): string { + if (isDevMode()) { + // 开发模式:环境变量优先,持久化不覆盖开发配置 + return process.env.VITE_AI_GATEWAY_URL || _runtimeGatewayUrl || DEFAULT_GATEWAY_URL; + } + // 生产模式:运行时/持久化 > 环境变量 > 默认值 + return _runtimeGatewayUrl || process.env.VITE_AI_GATEWAY_URL || DEFAULT_GATEWAY_URL; +} + +/** + * 设置运行时网关地址(由渲染进程通过 IPC 调用) + * 同时持久化到 userData 目录,确保主进程重启后仍可用 + */ +export async function setRuntimeGatewayUrl(url: string): Promise { + _runtimeGatewayUrl = url; + // 重置首次解析日志标记,使下次 gatewayUrl() 重新打印来源 + _gatewayFirstResolveLogged = false; + logger.info(`[AI] Runtime gateway URL set via IPC: ${url}`); + // 开发模式不写入持久化文件,防止调试数据污染生产配置 + if (isDevMode()) { + logger.info('[AI] Dev mode: skip persisting gateway URL to file'); + return; + } + // 持久化到文件 + try { + const configPath = path.join(app.getPath('userData'), GATEWAY_CONFIG_FILE); + await writeFile(configPath, JSON.stringify({ gatewayUrl: url }), 'utf-8'); + } catch (err) { + logger.error('[AI-Gateway] Failed to persist gateway URL', err); + } +} + +/** + * 应用启动时从持久化文件加载网关地址 + * 在 registerAIHandlers 之前调用 + */ +export async function loadPersistedGatewayUrl(): Promise { + if (isDevMode()) { + logger.info('[AI] Dev mode: skip loading persisted gateway URL (using .env config)'); + return; + } + try { + const configPath = path.join(app.getPath('userData'), GATEWAY_CONFIG_FILE); + const raw = await readFile(configPath, 'utf-8'); + const config = JSON.parse(raw); + if (config.gatewayUrl) { + _runtimeGatewayUrl = config.gatewayUrl; + logger.info(`[AI] Loaded persisted gateway URL from file: ${config.gatewayUrl}`); + } + } catch { + // 文件不存在或解析失败,静默忽略 + } +} diff --git a/client/electron/ai/gatewayHttp.ts b/client/electron/ai/gatewayHttp.ts new file mode 100644 index 00000000..ebc6bd56 --- /dev/null +++ b/client/electron/ai/gatewayHttp.ts @@ -0,0 +1,186 @@ +/** + * AI 网关 HTTP 请求层(postJson / postMultipart / 降级链) + * + * @ai-context: 从 ai/utils.ts 拆出。executePost 统一 JSON 与 multipart + * 两种请求的公共骨架(超时/日志/req-id/错误诊断/响应解析),消除原 + * 两函数 80 行重复;错误诊断按 ECONNREFUSED/ENOTFOUND/ETIMEDOUT 给出 + * 运维提示。X-Request-ID 贯穿网关日志链路。 + * @ai-context: callWithLocalFallback 是"本地优先、云端降级"的核心: + * Ollama 启用且运行 → localHandler,失败静默降级 postJson; + * source 字段('local'|'remote')供渲染层展示推理来源,勿删。 + */ +import { randomUUID } from 'crypto'; +import { logger } from '../logger.js'; +import { gatewayUrl } from './gatewayConfig.js'; +import { isLocalInferenceEnabled } from './ollama/config.js'; +import { isOllamaAvailable } from './ollama/OllamaService.js'; + +/** 构建公共请求头(JSON 模式含 Content-Type,multipart 由 fetch 自动生成) */ +function buildHeaders(clientRequestId: string, json: boolean, authToken?: string, userApiKey?: string): Record { + const headers: Record = { 'X-Request-ID': clientRequestId }; + if (json) headers['Content-Type'] = 'application/json'; + if (authToken) headers['Authorization'] = `Bearer ${authToken}`; + if (userApiKey) headers['X-User-API-Key'] = userApiKey; + return headers; +} + +/** 网络错误诊断日志(常见错误码给出运维提示) */ +function logNetworkHint(errDetail: string): void { + if (/ECONNREFUSED/i.test(errDetail)) { + logger.error('[AI] Hint: Connection refused — check if AI Gateway service is running and the URL is correct'); + } else if (/ENOTFOUND/i.test(errDetail)) { + logger.error('[AI] Hint: DNS resolution failed — check the gateway URL hostname'); + } else if (/ETIMEDOUT/i.test(errDetail)) { + logger.error('[AI] Hint: Connection timed out — check network connectivity and firewall rules'); + } +} + +/** + * POST 公共骨架:超时控制 + 日志 + req-id + 错误诊断 + JSON 响应解析 + */ +async function executePost( + apiPath: string, + requestBody: string | FormData, + isJson: boolean, + bodyDesc: string, + authToken?: string, + userApiKey?: string, + timeoutMs: number = 60000, +): Promise<{ data: TRes; requestId: string | undefined }> { + const base = gatewayUrl(); + if (!base) { + throw new Error('[AI] Gateway URL not configured. Set VITE_AI_GATEWAY_URL in .env or configure via AI settings'); + } + const url = `${base}${apiPath}`; + const startTime = Date.now(); + const clientRequestId = randomUUID(); + + // ── 请求前日志 ── + logger.info(`[AI] → POST ${url} [req-id: ${clientRequestId}]`); + logger.debug(`[AI] Request config: timeout=${timeoutMs}ms, hasAuth=${!!authToken}, hasUserKey=${!!userApiKey}, ${bodyDesc}`); + + const headers = buildHeaders(clientRequestId, isJson, authToken, userApiKey); + + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + + let resp: Response; + try { + resp = await fetch(url, { + method: 'POST', + headers, + body: requestBody, + signal: controller.signal, + }); + } catch (networkError: unknown) { + const elapsed = Date.now() - startTime; + const err = networkError as { name?: string; message?: string; cause?: unknown }; + if (err.name === 'AbortError') { + logger.error(`[AI] ✖ TIMEOUT ${url} after ${elapsed}ms`); + throw new Error(`Request timeout after ${timeoutMs}ms`); + } + // 详细网络错误诊断 + const cause = err.cause ? String(err.cause) : ''; + const errDetail = err.message || String(networkError); + logger.error(`[AI] ✖ NETWORK_ERROR ${url} after ${elapsed}ms: ${errDetail}${cause ? ` (cause: ${cause})` : ''}`); + logNetworkHint(errDetail); + throw new Error(`Network error: ${errDetail}`); + } finally { + clearTimeout(timeoutId); + } + + const elapsed = Date.now() - startTime; + const requestId = resp.headers.get('ai-gateway-request-id') ?? undefined; + + if (!resp.ok) { + const detail = await resp.text().catch(() => 'unknown error'); + // 截取响应体前 500 字符防止日志爆炸 + const detailPreview = detail.length > 500 ? `${detail.slice(0, 500)}...(+${detail.length - 500} chars)` : detail; + logger.error(`[AI] ✖ HTTP ${resp.status} ${url} (${elapsed}ms) [req-id: ${requestId ?? clientRequestId}]: ${detailPreview}`); + throw new Error(`HTTP ${resp.status}: ${detail}`); + } + + logger.info(`[AI] ← ${resp.status} ${url} (${elapsed}ms)${requestId ? ` [req-id: ${requestId}]` : ''}`); + + try { + const data = (await resp.json()) as TRes; + return { data, requestId }; + } catch (e) { + logger.error(`[AI] Response JSON parse error for ${url}: ${e}`); + throw new Error(`Response parse error: ${e}`); + } +} + +/** + * 通用 POST 请求辅助函数: + * 1. 将请求体序列化为 JSON + * 2. 如有 authToken,添加 Authorization header + * 3. HTTP 失败时抛出包含状态码和详情的错误字符串 + * 4. 返回解析后的 JSON 响应 + */ +export async function postJson( + apiPath: string, + body: TReq, + authToken?: string, + userApiKey?: string, + timeoutMs: number = 60000, +): Promise<{ data: TRes; requestId: string | undefined }> { + const bodyDesc = `bodyKeys=${Object.keys(body as Record).join(',')}`; + return executePost(apiPath, JSON.stringify(body), true, bodyDesc, authToken, userApiKey, timeoutMs); +} + +/** + * Multipart POST 请求辅助函数: + * 1. 不设置 Content-Type header(Node.js fetch 自动设置 multipart/form-data; boundary=...) + * 2. body 直接传 FormData(不做 JSON.stringify) + * 3. 默认超时 300000ms(5 分钟,视频文件较大) + */ +export async function postMultipart( + apiPath: string, + formData: FormData, + authToken?: string, + userApiKey?: string, + timeoutMs: number = 300000, +): Promise<{ data: TRes; requestId: string | undefined }> { + return executePost(apiPath, formData, false, 'body=FormData', authToken, userApiKey, timeoutMs); +} + +/** + * 带本地 Ollama 降级的调用函数 + * + * 逻辑: + * 1. 检查 OllamaConfig.enabled && OllamaService.isRunning() + * 2. 是 → 调用 localHandler(),成功则返回 { source: 'local' } + * 3. 本地失败/未启用 → 调用现有 postJson()(远程 AI Gateway) + */ +export async function callWithLocalFallback( + apiPath: string, + body: TReq, + localHandler: () => Promise, + authToken?: string, + userApiKey?: string, + timeoutMs: number = 60000, +): Promise<{ data: TRes; source: 'local' | 'remote'; requestId?: string }> { + // 检查本地 Ollama 是否可用 + if (isLocalInferenceEnabled() && isOllamaAvailable()) { + try { + const localResult = await localHandler(); + logger.info(`[AI] ← Local Ollama success for ${apiPath}`); + return { data: localResult, source: 'local' }; + } catch (localErr) { + const errMsg = localErr instanceof Error ? localErr.message : String(localErr); + logger.warn(`[AI] Local Ollama failed for ${apiPath}, falling back to remote: ${errMsg}`); + // 本地失败,降级到远程 + } + } + + // 远程 AI Gateway 调用 + const { data, requestId } = await postJson( + apiPath, + body, + authToken, + userApiKey, + timeoutMs, + ); + return { data, source: 'remote', requestId }; +} diff --git a/client/electron/ai/gatewayStream.ts b/client/electron/ai/gatewayStream.ts new file mode 100644 index 00000000..340b6c1c --- /dev/null +++ b/client/electron/ai/gatewayStream.ts @@ -0,0 +1,122 @@ +/** + * AI 网关流式请求层(SSE 解析) + * + * @ai-context: 从 ai/utils.ts 拆出。按 \n\n 分割 SSE 事件、data: 行 + * 逐 chunk yield;[DONE] 结束、parsed.error 抛错、JSON 解析失败时 + * 回退为纯文本 yield(网关某些端点直接输出文本片段)。 + * 消费方为 streamHandler.ts(转发到渲染进程 ai:stream:* 事件)。 + */ +import { randomUUID } from 'crypto'; +import { logger } from '../logger.js'; +import { gatewayUrl } from './gatewayConfig.js'; + +/** + * 流式 POST 请求:解析 SSE data: 行,逐 chunk yield 文本 + */ +export async function* postJsonStream( + apiPath: string, + body: TReq, + authToken?: string, + userApiKey?: string, + timeoutMs: number = 300000, +): AsyncGenerator { + const base = gatewayUrl(); + if (!base) { + throw new Error('[AI] Gateway URL not configured'); + } + const url = `${base}${apiPath}`; + const clientRequestId = randomUUID(); + + logger.info(`[AI] → POST (stream) ${url} [req-id: ${clientRequestId}]`); + + const headers: Record = { + 'Content-Type': 'application/json', + 'X-Request-ID': clientRequestId, + }; + if (authToken) { + headers['Authorization'] = `Bearer ${authToken}`; + } + if (userApiKey) { + headers['X-User-API-Key'] = userApiKey; + } + + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + + let resp: Response; + try { + resp = await fetch(url, { + method: 'POST', + headers, + body: JSON.stringify(body), + signal: controller.signal, + }); + } catch (networkError: unknown) { + const err = networkError as { name?: string; message?: string }; + if (err.name === 'AbortError') { + throw new Error(`Stream request timeout after ${timeoutMs}ms`); + } + throw new Error(`Stream network error: ${err.message || String(networkError)}`); + } finally { + clearTimeout(timeoutId); + } + + const requestId = resp.headers.get('ai-gateway-request-id') ?? undefined; + + if (!resp.ok) { + const detail = await resp.text().catch(() => 'unknown error'); + logger.error(`[AI] ✖ Stream HTTP ${resp.status} ${url} [req-id: ${requestId ?? clientRequestId}]: ${detail.slice(0, 200)}`); + throw new Error(`Stream HTTP ${resp.status}: ${detail}`); + } + + logger.info(`[AI] ← Stream started ${url}${requestId ? ` [req-id: ${requestId}]` : ''}`); + + if (!resp.body) { + throw new Error('Stream response body is null'); + } + + const reader = resp.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ''; + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, { stream: true }); + + // 按 \n\n 分割 SSE 事件 + const events = buffer.split('\n\n'); + buffer = events.pop() || ''; + + for (const event of events) { + const lines = event.split('\n'); + for (const line of lines) { + if (line.startsWith('data: ')) { + const data = line.slice(6).trim(); + if (data === '[DONE]') { + return; + } + try { + const parsed = JSON.parse(data); + if (parsed.error) { + throw new Error(`Stream error: ${parsed.error}`); + } + if (parsed.chunk) { + yield parsed.chunk; + } + } catch (e) { + // JSON 解析失败,尝试作为纯文本 + if (data && data !== '[DONE]') { + yield data; + } + } + } + } + } + } + } finally { + reader.releaseLock(); + } +} diff --git a/client/electron/ai/handlers/anchorPointHandler.ts b/client/electron/ai/handlers/anchorPointHandler.ts index 70b4f4db..dad35cbe 100644 --- a/client/electron/ai/handlers/anchorPointHandler.ts +++ b/client/electron/ai/handlers/anchorPointHandler.ts @@ -1,109 +1,111 @@ -/** - * AI 记忆锚点生成功能 Handler - * - * 处理 ai_anchor_point IPC 请求,调用 AI 网关从笔记内容生成记忆锚点。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_anchor_point — POST /api/v1/ai/anchor-point - */ -function register(): void { - safeHandle( - 'ai_anchor_point', - async ( - _event, - args: { - content: string; - title?: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [anchor-point] IPC received: content_length=${args.content.length}, title=${args.title ?? '(empty)'}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [anchor-point] Content preview: ${args.content.slice(0, 80)}...`); - - const reqBody = { - content: args.content, - title: args.title ?? '', - }; - - logger.info(`[AI] [anchor-point] Target: ${gatewayUrl()}/api/v1/ai/anchor-point`); - - interface AnchorPointResp { - concept: string; - association: string; - memory_technique: string; - importance: number; - } - interface AnchorPointGenResp { - anchor_points: AnchorPointResp[]; - status: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `从以下笔记中生成记忆锚点,返回JSON: {"anchor_points": [{"concept": "...", "association": "...", "memory_technique": "...", "importance": 0.8}], "status": "ok"}\n\n笔记:\n${args.content}`; - const result = await generateText(prompt, '你是一个记忆锚点生成助手。请仅返回JSON。', { temperature: 0.6, maxTokens: 1024 }); - const parsed = JSON.parse(result.content); - return { anchor_points: parsed.anchor_points ?? [], status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/anchor-point', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 60000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [anchor-point] ✔ Success (${source}): anchor_points=${resp.anchor_points.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - anchorPoints: resp.anchor_points.map((ap: { concept: string; association: string; memory_technique: string; importance: number }) => ({ - concept: ap.concept, - association: ap.association, - memoryTechnique: ap.memory_technique, - importance: ap.importance, - })), - status: resp.status, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [anchor-point] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [anchor-point] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_anchor_point', - name: 'AI 记忆锚点', - version: '1.0.0', - register, -}; +/** + * AI 记忆锚点生成功能 Handler + * + * 处理 ai_anchor_point IPC 请求,调用 AI 网关从笔记内容生成记忆锚点。 + * + * @ai-context: 记忆锚点生成 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_anchor_point — POST /api/v1/ai/anchor-point + */ +function register(): void { + safeHandle( + 'ai_anchor_point', + async ( + _event, + args: { + content: string; + title?: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [anchor-point] IPC received: content_length=${args.content.length}, title=${args.title ?? '(empty)'}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [anchor-point] Content preview: ${args.content.slice(0, 80)}...`); + + const reqBody = { + content: args.content, + title: args.title ?? '', + }; + + logger.info(`[AI] [anchor-point] Target: ${gatewayUrl()}/api/v1/ai/anchor-point`); + + interface AnchorPointResp { + concept: string; + association: string; + memory_technique: string; + importance: number; + } + interface AnchorPointGenResp { + anchor_points: AnchorPointResp[]; + status: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `从以下笔记中生成记忆锚点,返回JSON: {"anchor_points": [{"concept": "...", "association": "...", "memory_technique": "...", "importance": 0.8}], "status": "ok"}\n\n笔记:\n${args.content}`; + const result = await generateText(prompt, '你是一个记忆锚点生成助手。请仅返回JSON。', { temperature: 0.6, maxTokens: 1024 }); + const parsed = JSON.parse(result.content); + return { anchor_points: parsed.anchor_points ?? [], status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/anchor-point', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 60000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [anchor-point] ✔ Success (${source}): anchor_points=${resp.anchor_points.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + anchorPoints: resp.anchor_points.map((ap: { concept: string; association: string; memory_technique: string; importance: number }) => ({ + concept: ap.concept, + association: ap.association, + memoryTechnique: ap.memory_technique, + importance: ap.importance, + })), + status: resp.status, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [anchor-point] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [anchor-point] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_anchor_point', + name: 'AI 记忆锚点', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/evaluateHandler.ts b/client/electron/ai/handlers/evaluateHandler.ts index 47364a63..cd71312f 100644 --- a/client/electron/ai/handlers/evaluateHandler.ts +++ b/client/electron/ai/handlers/evaluateHandler.ts @@ -1,126 +1,128 @@ -/** - * AI 评估功能 Handler - * - * 处理 ai_evaluate IPC 请求,调用 AI 网关评估用户对概念的解释。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_evaluate — POST /api/v1/ai/evaluate-explanation - */ -function register(): void { - safeHandle( - 'ai_evaluate', - async ( - _event, - args: { - concept: string; - explanation: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [evaluate] IPC received: concept_length=${args.concept.length}, explanation_length=${args.explanation.length}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [evaluate] Concept: ${args.concept.slice(0, 60)}, Explanation preview: ${args.explanation.slice(0, 80)}...`); - - const reqBody = { - concept: args.concept, - explanation: args.explanation, - }; - - logger.info(`[AI] [evaluate] Target: ${gatewayUrl()}/api/v1/ai/evaluate-explanation`); - - interface DimensionResp { - dimension: string; - score: number; - feedback: string; - } - interface EvaluateResp { - overall_score: number; - dimensions: DimensionResp[]; - strengths: string[]; - improvements: string[]; - encouragement: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `请评估以下对概念“${args.concept}”的解释:\n\n${args.explanation}\n\n请以JSON格式返回评估结果,格式为: {"overall_score": 75, "strengths": ["..."], "improvements": ["..."], "encouragement": "..."}`; - const result = await generateText(prompt, '你是一个费曼学习法评估助手,擅长评估学生对概念的理解程度。请仅返回JSON。', { temperature: 0.4, maxTokens: 1024 }); - try { - const parsed = JSON.parse(result.content); - return { - overall_score: parsed.overall_score ?? 60, - dimensions: [], - strengths: parsed.strengths ?? [], - improvements: parsed.improvements ?? [], - encouragement: parsed.encouragement ?? '继续加油!', - model: result.model, - tokens_used: result.tokens_used, - latency_ms: result.latency_ms, - }; - } catch { - return { overall_score: 60, dimensions: [], strengths: [], improvements: [], encouragement: result.content.slice(0, 200), model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - } - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/evaluate-explanation', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 40000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [evaluate] ✔ Success (${source}): overall_score=${resp.overall_score}, dimensions=${resp.dimensions.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - overallScore: resp.overall_score, - dimensions: resp.dimensions.map((d) => ({ - name: d.dimension, - score: d.score, - feedback: d.feedback, - })), - strengths: resp.strengths, - improvements: resp.improvements, - encouragement: resp.encouragement, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [evaluate] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [evaluate] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_evaluate', - name: 'AI 解释评估', - version: '1.0.0', - register, -}; +/** + * AI 评估功能 Handler + * + * 处理 ai_evaluate IPC 请求,调用 AI 网关评估用户对概念的解释。 + * + * @ai-context: 费曼解释评估 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_evaluate — POST /api/v1/ai/evaluate-explanation + */ +function register(): void { + safeHandle( + 'ai_evaluate', + async ( + _event, + args: { + concept: string; + explanation: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [evaluate] IPC received: concept_length=${args.concept.length}, explanation_length=${args.explanation.length}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [evaluate] Concept: ${args.concept.slice(0, 60)}, Explanation preview: ${args.explanation.slice(0, 80)}...`); + + const reqBody = { + concept: args.concept, + explanation: args.explanation, + }; + + logger.info(`[AI] [evaluate] Target: ${gatewayUrl()}/api/v1/ai/evaluate-explanation`); + + interface DimensionResp { + dimension: string; + score: number; + feedback: string; + } + interface EvaluateResp { + overall_score: number; + dimensions: DimensionResp[]; + strengths: string[]; + improvements: string[]; + encouragement: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `请评估以下对概念“${args.concept}”的解释:\n\n${args.explanation}\n\n请以JSON格式返回评估结果,格式为: {"overall_score": 75, "strengths": ["..."], "improvements": ["..."], "encouragement": "..."}`; + const result = await generateText(prompt, '你是一个费曼学习法评估助手,擅长评估学生对概念的理解程度。请仅返回JSON。', { temperature: 0.4, maxTokens: 1024 }); + try { + const parsed = JSON.parse(result.content); + return { + overall_score: parsed.overall_score ?? 60, + dimensions: [], + strengths: parsed.strengths ?? [], + improvements: parsed.improvements ?? [], + encouragement: parsed.encouragement ?? '继续加油!', + model: result.model, + tokens_used: result.tokens_used, + latency_ms: result.latency_ms, + }; + } catch { + return { overall_score: 60, dimensions: [], strengths: [], improvements: [], encouragement: result.content.slice(0, 200), model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + } + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/evaluate-explanation', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 40000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [evaluate] ✔ Success (${source}): overall_score=${resp.overall_score}, dimensions=${resp.dimensions.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + overallScore: resp.overall_score, + dimensions: resp.dimensions.map((d) => ({ + name: d.dimension, + score: d.score, + feedback: d.feedback, + })), + strengths: resp.strengths, + improvements: resp.improvements, + encouragement: resp.encouragement, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [evaluate] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [evaluate] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_evaluate', + name: 'AI 解释评估', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/feynmanHandler.ts b/client/electron/ai/handlers/feynmanHandler.ts index f0eaaee6..b100e925 100644 --- a/client/electron/ai/handlers/feynmanHandler.ts +++ b/client/electron/ai/handlers/feynmanHandler.ts @@ -1,180 +1,182 @@ -/** - * 费曼学习法功能 Handler - * - * 处理 ai_feynman_question 和 ai_feynman_evaluate_answers IPC 请求, - * 调用 AI 网关生成追问并评估用户回答。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * 注册费曼学习法相关的所有 IPC handler - */ -function register(): void { - /** - * ai_feynman_question — POST /api/v1/ai/feynman-question - */ - safeHandle( - 'ai_feynman_question', - async ( - _event, - args: { - concept: string; - explanation: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [feynman-q] IPC received: concept_length=${args.concept.length}, explanation_length=${args.explanation.length}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [feynman-q] Concept: ${args.concept.slice(0, 60)}`); - - const reqBody = { - concept: args.concept, - explanation: args.explanation, - }; - - logger.info(`[AI] [feynman-q] Target: ${gatewayUrl()}/api/v1/ai/feynman-question`); - - interface FeynmanQuestionResp { - questions: Array<{ question: string; focus: string }>; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `针对概念“${args.concept}”和解释“${args.explanation}”,生成苏格拉底式追问,返回JSON: {"questions": [{"question": "...", "focus": "..."}]}`; - const result = await generateText(prompt, '你是一个费曼学习法追问助手。请仅返回JSON。', { temperature: 0.7, maxTokens: 1024 }); - const parsed = JSON.parse(result.content); - return { questions: parsed.questions ?? [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/feynman-question', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 40000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [feynman-q] ✔ Success (${source}): questions=${resp.questions.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - questions: resp.questions.map((q: { question: string; focus: string }) => ({ - question: q.question, - focus: q.focus, - })), - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [feynman-q] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [feynman-q] Error cause: ${error.cause}`); - throw error; - } - }, - ); - - /** - * ai_feynman_evaluate_answers — POST /api/v1/ai/feynman-evaluate-answers - */ - safeHandle( - 'ai_feynman_evaluate_answers', - async ( - _event, - args: { - concept: string; - questions: string[]; - answers: string[]; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [feynman-eval] IPC received: concept_length=${args.concept.length}, questions=${args.questions.length}, answers=${args.answers.length}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [feynman-eval] Concept: ${args.concept.slice(0, 60)}, Q count=${args.questions.length}`); - - const reqBody = { - concept: args.concept, - questions: args.questions, - answers: args.answers, - }; - - logger.info(`[AI] [feynman-eval] Target: ${gatewayUrl()}/api/v1/ai/feynman-evaluate-answers`); - - interface FeynmanAnswerEvalResp { - understanding_score: number; - feedback: string; - strong_points: string[]; - weak_points: string[]; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `评估用户对概念“${args.concept}”的回答,返回JSON: {"understanding_score": 70, "feedback": "...", "strong_points": ["..."], "weak_points": ["..."]}`; - const result = await generateText(prompt, '你是一个费曼学习法评估助手。请仅返回JSON。', { temperature: 0.4, maxTokens: 1024 }); - const parsed = JSON.parse(result.content); - return { understanding_score: parsed.understanding_score ?? 60, feedback: parsed.feedback ?? '', strong_points: parsed.strong_points ?? [], weak_points: parsed.weak_points ?? [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/feynman-evaluate-answers', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 40000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [feynman-eval] ✔ Success (${source}): score=${resp.understanding_score}, strong=${resp.strong_points.length}, weak=${resp.weak_points.length}, model=${resp.model}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - understandingScore: resp.understanding_score, - feedback: resp.feedback, - strongPoints: resp.strong_points, - weakPoints: resp.weak_points, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [feynman-eval] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [feynman-eval] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_feynman', - name: '浮出水面', - version: '1.0.0', - register, -}; +/** + * 费曼学习法功能 Handler + * + * 处理 ai_feynman_question 和 ai_feynman_evaluate_answers IPC 请求, + * 调用 AI 网关生成追问并评估用户回答。 + * + * @ai-context: 费曼提问与答案评估 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * 注册费曼学习法相关的所有 IPC handler + */ +function register(): void { + /** + * ai_feynman_question — POST /api/v1/ai/feynman-question + */ + safeHandle( + 'ai_feynman_question', + async ( + _event, + args: { + concept: string; + explanation: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [feynman-q] IPC received: concept_length=${args.concept.length}, explanation_length=${args.explanation.length}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [feynman-q] Concept: ${args.concept.slice(0, 60)}`); + + const reqBody = { + concept: args.concept, + explanation: args.explanation, + }; + + logger.info(`[AI] [feynman-q] Target: ${gatewayUrl()}/api/v1/ai/feynman-question`); + + interface FeynmanQuestionResp { + questions: Array<{ question: string; focus: string }>; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `针对概念“${args.concept}”和解释“${args.explanation}”,生成苏格拉底式追问,返回JSON: {"questions": [{"question": "...", "focus": "..."}]}`; + const result = await generateText(prompt, '你是一个费曼学习法追问助手。请仅返回JSON。', { temperature: 0.7, maxTokens: 1024 }); + const parsed = JSON.parse(result.content); + return { questions: parsed.questions ?? [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/feynman-question', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 40000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [feynman-q] ✔ Success (${source}): questions=${resp.questions.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + questions: resp.questions.map((q: { question: string; focus: string }) => ({ + question: q.question, + focus: q.focus, + })), + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [feynman-q] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [feynman-q] Error cause: ${error.cause}`); + throw error; + } + }, + ); + + /** + * ai_feynman_evaluate_answers — POST /api/v1/ai/feynman-evaluate-answers + */ + safeHandle( + 'ai_feynman_evaluate_answers', + async ( + _event, + args: { + concept: string; + questions: string[]; + answers: string[]; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [feynman-eval] IPC received: concept_length=${args.concept.length}, questions=${args.questions.length}, answers=${args.answers.length}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [feynman-eval] Concept: ${args.concept.slice(0, 60)}, Q count=${args.questions.length}`); + + const reqBody = { + concept: args.concept, + questions: args.questions, + answers: args.answers, + }; + + logger.info(`[AI] [feynman-eval] Target: ${gatewayUrl()}/api/v1/ai/feynman-evaluate-answers`); + + interface FeynmanAnswerEvalResp { + understanding_score: number; + feedback: string; + strong_points: string[]; + weak_points: string[]; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `评估用户对概念“${args.concept}”的回答,返回JSON: {"understanding_score": 70, "feedback": "...", "strong_points": ["..."], "weak_points": ["..."]}`; + const result = await generateText(prompt, '你是一个费曼学习法评估助手。请仅返回JSON。', { temperature: 0.4, maxTokens: 1024 }); + const parsed = JSON.parse(result.content); + return { understanding_score: parsed.understanding_score ?? 60, feedback: parsed.feedback ?? '', strong_points: parsed.strong_points ?? [], weak_points: parsed.weak_points ?? [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/feynman-evaluate-answers', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 40000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [feynman-eval] ✔ Success (${source}): score=${resp.understanding_score}, strong=${resp.strong_points.length}, weak=${resp.weak_points.length}, model=${resp.model}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + understandingScore: resp.understanding_score, + feedback: resp.feedback, + strongPoints: resp.strong_points, + weakPoints: resp.weak_points, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [feynman-eval] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [feynman-eval] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_feynman', + name: '浮出水面', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/flashcardHandler.ts b/client/electron/ai/handlers/flashcardHandler.ts index 82eeff27..70711c29 100644 --- a/client/electron/ai/handlers/flashcardHandler.ts +++ b/client/electron/ai/handlers/flashcardHandler.ts @@ -1,119 +1,121 @@ -/** - * AI 闪卡生成功能 Handler - * - * 处理 ai_generate_cards IPC 请求,调用 AI 网关从笔记生成闪卡。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_generate_cards — POST /api/v1/ai/generate-cards - */ -function register(): void { - safeHandle( - 'ai_generate_cards', - async ( - _event, - args: { - note: string; - maxCards?: number; - difficulty?: string; - cardType?: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [flashcard] IPC received: note_length=${args.note.length}, maxCards=${args.maxCards ?? 'default'}, difficulty=${args.difficulty ?? 'default'}, cardType=${args.cardType ?? 'default'}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [flashcard] Note preview: ${args.note.slice(0, 80)}...`); - - const reqBody = { - note: args.note, - options: { - ...(args.maxCards != null && { max_cards: args.maxCards }), - ...(args.difficulty != null && { difficulty: args.difficulty }), - ...(args.cardType != null && { card_type: args.cardType }), - }, - }; - - logger.info(`[AI] [flashcard] Target: ${gatewayUrl()}/api/v1/ai/generate-cards`); - - interface CardResp { - front: string; - back: string; - type: string; - confidence: number; - } - interface CardGenResp { - cards: CardResp[]; - total_extracted: number; - model: string; - tokens_used: number; - } - - try { - const localHandler = async (): Promise => { - const maxHint = args.maxCards ? `,最多生成${args.maxCards}张` : ''; - const diffHint = args.difficulty ? `,难度:${args.difficulty}` : ''; - const prompt = `请从以下笔记内容生成闪卡(问答对)${maxHint}${diffHint}。\n请以JSON格式返回,格式为: {"cards": [{"front": "问题", "back": "答案", "type": "basic", "confidence": 0.9}]}\n\n笔记内容:\n${args.note}`; - const result = await generateText(prompt, '你是一个专业的闪卡生成助手,擅长从笔记中提取核心知识点并生成问答对。请仅返回JSON。', { temperature: 0.5, maxTokens: 2048 }); - try { - const parsed = JSON.parse(result.content); - return { cards: parsed.cards || [], total_extracted: (parsed.cards || []).length, model: result.model, tokens_used: result.tokens_used }; - } catch { - return { cards: [], total_extracted: 0, model: result.model, tokens_used: result.tokens_used }; - } - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/generate-cards', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 90000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [flashcard] ✔ Success (${source}): cards=${resp.cards.length}, total_extracted=${resp.total_extracted}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - cards: resp.cards.map((c) => ({ - front: c.front, - back: c.back, - type: c.type, - confidence: c.confidence, - })), - totalExtracted: resp.total_extracted, - model: resp.model, - tokensUsed: resp.tokens_used, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [flashcard] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [flashcard] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_generate_cards', - name: 'AI 反衰减呼吸生成', - version: '1.0.0', - register, -}; +/** + * AI 闪卡生成功能 Handler + * + * 处理 ai_generate_cards IPC 请求,调用 AI 网关从笔记生成闪卡。 + * + * @ai-context: 闪卡生成 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_generate_cards — POST /api/v1/ai/generate-cards + */ +function register(): void { + safeHandle( + 'ai_generate_cards', + async ( + _event, + args: { + note: string; + maxCards?: number; + difficulty?: string; + cardType?: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [flashcard] IPC received: note_length=${args.note.length}, maxCards=${args.maxCards ?? 'default'}, difficulty=${args.difficulty ?? 'default'}, cardType=${args.cardType ?? 'default'}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [flashcard] Note preview: ${args.note.slice(0, 80)}...`); + + const reqBody = { + note: args.note, + options: { + ...(args.maxCards != null && { max_cards: args.maxCards }), + ...(args.difficulty != null && { difficulty: args.difficulty }), + ...(args.cardType != null && { card_type: args.cardType }), + }, + }; + + logger.info(`[AI] [flashcard] Target: ${gatewayUrl()}/api/v1/ai/generate-cards`); + + interface CardResp { + front: string; + back: string; + type: string; + confidence: number; + } + interface CardGenResp { + cards: CardResp[]; + total_extracted: number; + model: string; + tokens_used: number; + } + + try { + const localHandler = async (): Promise => { + const maxHint = args.maxCards ? `,最多生成${args.maxCards}张` : ''; + const diffHint = args.difficulty ? `,难度:${args.difficulty}` : ''; + const prompt = `请从以下笔记内容生成闪卡(问答对)${maxHint}${diffHint}。\n请以JSON格式返回,格式为: {"cards": [{"front": "问题", "back": "答案", "type": "basic", "confidence": 0.9}]}\n\n笔记内容:\n${args.note}`; + const result = await generateText(prompt, '你是一个专业的闪卡生成助手,擅长从笔记中提取核心知识点并生成问答对。请仅返回JSON。', { temperature: 0.5, maxTokens: 2048 }); + try { + const parsed = JSON.parse(result.content); + return { cards: parsed.cards || [], total_extracted: (parsed.cards || []).length, model: result.model, tokens_used: result.tokens_used }; + } catch { + return { cards: [], total_extracted: 0, model: result.model, tokens_used: result.tokens_used }; + } + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/generate-cards', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 90000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [flashcard] ✔ Success (${source}): cards=${resp.cards.length}, total_extracted=${resp.total_extracted}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + cards: resp.cards.map((c) => ({ + front: c.front, + back: c.back, + type: c.type, + confidence: c.confidence, + })), + totalExtracted: resp.total_extracted, + model: resp.model, + tokensUsed: resp.tokens_used, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [flashcard] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [flashcard] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_generate_cards', + name: 'AI 反衰减呼吸生成', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/mergeNotesHandler.ts b/client/electron/ai/handlers/mergeNotesHandler.ts index 2881b812..5abc4186 100644 --- a/client/electron/ai/handlers/mergeNotesHandler.ts +++ b/client/electron/ai/handlers/mergeNotesHandler.ts @@ -1,137 +1,139 @@ -/** - * AI 片段笔记合并 Handler - * - * 处理 ai_merge_notes IPC 请求,将增量分析产生的多个片段笔记 - * 合并为一份完整结构化笔记。纯文本操作,无需多模态模型。 - * 对应端点:POST /api/v1/multimodal/merge-notes - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_merge_notes — POST /api/v1/multimodal/merge-notes - */ -function register(): void { - safeHandle( - 'ai_merge_notes', - async ( - _event, - args: { - partials: string[]; - duration?: number; // 秒 - language?: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - const partialCount = args.partials?.length ?? 0; - logger.info(`[AI] [merge-notes] IPC received: partials=${partialCount}, duration=${args.duration ?? 0}s`); - - if (!args.partials || args.partials.length === 0) { - throw new Error('partials 不能为空'); - } - - // 只有一个片段时直接返回 - if (args.partials.length === 1) { - return { - content: args.partials[0].trim(), - modelUsed: 'none (single partial)', - source: 'local' as const, - }; - } - - const reqBody = { - partials: args.partials, - duration: args.duration ?? 0, - language: args.language ?? 'zh-CN', - }; - - logger.info(`[AI] [merge-notes] Target: ${gatewayUrl()}/api/v1/multimodal/merge-notes`); - - interface MergeNotesResp { - content: string; - model_used: string; - } - - try { - // 本地 Ollama 降级:纯文本合并 - const localHandler = async (): Promise => { - const partsContent = args.partials - .map((p, i) => `### 片段 ${i + 1}\n\n${p.trim()}`) - .join('\n\n---\n\n'); - - const prompt = [ - `以下是一门课程(总时长约 ${args.duration ?? 0} 秒)的 ${args.partials.length} 个片段笔记。`, - '请将它们合并为一份完整的结构化课堂笔记,要求:', - '1. 去除重复内容', - '2. 使用 Markdown 二级标题按知识模块组织', - '3. 补充片段间的衔接语句', - '4. 保留所有公式、定义、代码', - '5. 末尾添加「核心知识点摘要」', - '', - '---', - '', - partsContent, - '', - '---', - '', - '请直接输出合并后的 Markdown 笔记。', - ].join('\n'); - - const result = await generateText( - prompt, - '你是一个专业的课堂笔记整理助手,擅长将多个片段笔记合并为完整、连贯的结构化笔记。', - { temperature: 0.3, maxTokens: 4096 }, - ); - - return { - content: result.content, - model_used: result.model, - }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/multimodal/merge-notes', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 30000, // 纯文本合并,30s 超时足够 - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [merge-notes] ✔ Success (${source}): content_length=${resp.content?.length ?? 0}, model=${resp.model_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - content: resp.content, - modelUsed: resp.model_used, - source, - requestId, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [merge-notes] ✖ Failed after ${elapsed}ms: ${error.message}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_merge_notes', - name: 'AI 片段笔记合并', - version: '1.0.0', - register, -}; +/** + * AI 片段笔记合并 Handler + * + * 处理 ai_merge_notes IPC 请求,将增量分析产生的多个片段笔记 + * 合并为一份完整结构化笔记。纯文本操作,无需多模态模型。 + * 对应端点:POST /api/v1/multimodal/merge-notes + * + * @ai-context: 笔记合并 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_merge_notes — POST /api/v1/multimodal/merge-notes + */ +function register(): void { + safeHandle( + 'ai_merge_notes', + async ( + _event, + args: { + partials: string[]; + duration?: number; // 秒 + language?: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + const partialCount = args.partials?.length ?? 0; + logger.info(`[AI] [merge-notes] IPC received: partials=${partialCount}, duration=${args.duration ?? 0}s`); + + if (!args.partials || args.partials.length === 0) { + throw new Error('partials 不能为空'); + } + + // 只有一个片段时直接返回 + if (args.partials.length === 1) { + return { + content: args.partials[0].trim(), + modelUsed: 'none (single partial)', + source: 'local' as const, + }; + } + + const reqBody = { + partials: args.partials, + duration: args.duration ?? 0, + language: args.language ?? 'zh-CN', + }; + + logger.info(`[AI] [merge-notes] Target: ${gatewayUrl()}/api/v1/multimodal/merge-notes`); + + interface MergeNotesResp { + content: string; + model_used: string; + } + + try { + // 本地 Ollama 降级:纯文本合并 + const localHandler = async (): Promise => { + const partsContent = args.partials + .map((p, i) => `### 片段 ${i + 1}\n\n${p.trim()}`) + .join('\n\n---\n\n'); + + const prompt = [ + `以下是一门课程(总时长约 ${args.duration ?? 0} 秒)的 ${args.partials.length} 个片段笔记。`, + '请将它们合并为一份完整的结构化课堂笔记,要求:', + '1. 去除重复内容', + '2. 使用 Markdown 二级标题按知识模块组织', + '3. 补充片段间的衔接语句', + '4. 保留所有公式、定义、代码', + '5. 末尾添加「核心知识点摘要」', + '', + '---', + '', + partsContent, + '', + '---', + '', + '请直接输出合并后的 Markdown 笔记。', + ].join('\n'); + + const result = await generateText( + prompt, + '你是一个专业的课堂笔记整理助手,擅长将多个片段笔记合并为完整、连贯的结构化笔记。', + { temperature: 0.3, maxTokens: 4096 }, + ); + + return { + content: result.content, + model_used: result.model, + }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/multimodal/merge-notes', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 30000, // 纯文本合并,30s 超时足够 + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [merge-notes] ✔ Success (${source}): content_length=${resp.content?.length ?? 0}, model=${resp.model_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + content: resp.content, + modelUsed: resp.model_used, + source, + requestId, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [merge-notes] ✖ Failed after ${elapsed}ms: ${error.message}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_merge_notes', + name: 'AI 片段笔记合并', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/optimizeCardHandler.ts b/client/electron/ai/handlers/optimizeCardHandler.ts index 5bfd2add..9e79895a 100644 --- a/client/electron/ai/handlers/optimizeCardHandler.ts +++ b/client/electron/ai/handlers/optimizeCardHandler.ts @@ -1,102 +1,104 @@ -/** - * AI 闪卡优化功能 Handler - * - * 处理 ai_optimize_card IPC 请求,调用 AI 网关优化已有闪卡的正反面内容。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_optimize_card — POST /api/v1/ai/optimize-card - */ -function register(): void { - safeHandle( - 'ai_optimize_card', - async ( - _event, - args: { - front: string; - back: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [optimize-card] IPC received: front_length=${args.front.length}, back_length=${args.back.length}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [optimize-card] Front preview: ${args.front.slice(0, 60)}, Back preview: ${args.back.slice(0, 60)}`); - - const reqBody = { - front: args.front, - back: args.back, - }; - - logger.info(`[AI] [optimize-card] Target: ${gatewayUrl()}/api/v1/ai/optimize-card`); - - interface OptimizeCardResp { - suggested_front: string; - suggested_back: string; - improvements: string[]; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `请优化以下闪卡,返回JSON: {"suggested_front": "...", "suggested_back": "...", "improvements": ["..."]} -正面:${args.front} -反面:${args.back}`; - const result = await generateText(prompt, '你是一个闪卡优化助手,擅长改进问答对的表述。请仅返回JSON。', { temperature: 0.5, maxTokens: 1024 }); - const parsed = JSON.parse(result.content); - return { suggested_front: parsed.suggested_front ?? args.front, suggested_back: parsed.suggested_back ?? args.back, improvements: parsed.improvements ?? [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/optimize-card', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 60000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [optimize-card] ✔ Success (${source}): improvements=${resp.improvements.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - suggestedFront: resp.suggested_front, - suggestedBack: resp.suggested_back, - improvements: resp.improvements, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [optimize-card] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [optimize-card] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_optimize_card', - name: 'AI 闪卡优化', - version: '1.0.0', - register, -}; +/** + * AI 闪卡优化功能 Handler + * + * 处理 ai_optimize_card IPC 请求,调用 AI 网关优化已有闪卡的正反面内容。 + * + * @ai-context: 卡片优化 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_optimize_card — POST /api/v1/ai/optimize-card + */ +function register(): void { + safeHandle( + 'ai_optimize_card', + async ( + _event, + args: { + front: string; + back: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [optimize-card] IPC received: front_length=${args.front.length}, back_length=${args.back.length}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [optimize-card] Front preview: ${args.front.slice(0, 60)}, Back preview: ${args.back.slice(0, 60)}`); + + const reqBody = { + front: args.front, + back: args.back, + }; + + logger.info(`[AI] [optimize-card] Target: ${gatewayUrl()}/api/v1/ai/optimize-card`); + + interface OptimizeCardResp { + suggested_front: string; + suggested_back: string; + improvements: string[]; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `请优化以下闪卡,返回JSON: {"suggested_front": "...", "suggested_back": "...", "improvements": ["..."]} +正面:${args.front} +反面:${args.back}`; + const result = await generateText(prompt, '你是一个闪卡优化助手,擅长改进问答对的表述。请仅返回JSON。', { temperature: 0.5, maxTokens: 1024 }); + const parsed = JSON.parse(result.content); + return { suggested_front: parsed.suggested_front ?? args.front, suggested_back: parsed.suggested_back ?? args.back, improvements: parsed.improvements ?? [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/optimize-card', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 60000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [optimize-card] ✔ Success (${source}): improvements=${resp.improvements.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + suggestedFront: resp.suggested_front, + suggestedBack: resp.suggested_back, + improvements: resp.improvements, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [optimize-card] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [optimize-card] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_optimize_card', + name: 'AI 闪卡优化', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/predictHandler.ts b/client/electron/ai/handlers/predictHandler.ts index d1f2b9f8..5f245d53 100644 --- a/client/electron/ai/handlers/predictHandler.ts +++ b/client/electron/ai/handlers/predictHandler.ts @@ -1,105 +1,107 @@ -/** - * AI 学习预测功能 Handler - * - * 处理 ai_predict IPC 请求,调用 AI 网关基于笔记内容生成预测性问题。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_predict — POST /api/v1/ai/predict - */ -function register(): void { - safeHandle( - 'ai_predict', - async ( - _event, - args: { - content: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [predict] IPC received: content_length=${args.content.length}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [predict] Content preview: ${args.content.slice(0, 80)}...`); - - const reqBody = { content: args.content }; - - logger.info(`[AI] [predict] Target: ${gatewayUrl()}/api/v1/ai/predict`); - - interface PredictionResp { - question: string; - type: string; - reason: string; - curiosity_score: number; - } - interface PredictGenResp { - predictions: PredictionResp[]; - status: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `基于以下笔记内容,生成预测性问题,返回JSON: {"predictions": [{"question": "...", "type": "...", "reason": "...", "curiosity_score": 0.8}], "status": "ok"}\n\n笔记:\n${args.content}`; - const result = await generateText(prompt, '你是一个预测驱动学习助手,擅长从笔记中生成引导性问题。请仅返回JSON。', { temperature: 0.6, maxTokens: 1024 }); - const parsed = JSON.parse(result.content); - return { predictions: parsed.predictions ?? [], status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/predict', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 60000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [predict] ✔ Success (${source}): predictions=${resp.predictions.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - predictions: resp.predictions.map((p: { question: string; type: string; reason: string; curiosity_score: number }) => ({ - question: p.question, - type: p.type, - reason: p.reason, - curiosityScore: p.curiosity_score, - })), - status: resp.status, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [predict] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [predict] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_predict', - name: 'AI 学习预测', - version: '1.0.0', - register, -}; +/** + * AI 学习预测功能 Handler + * + * 处理 ai_predict IPC 请求,调用 AI 网关基于笔记内容生成预测性问题。 + * + * @ai-context: 预测提问 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_predict — POST /api/v1/ai/predict + */ +function register(): void { + safeHandle( + 'ai_predict', + async ( + _event, + args: { + content: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [predict] IPC received: content_length=${args.content.length}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [predict] Content preview: ${args.content.slice(0, 80)}...`); + + const reqBody = { content: args.content }; + + logger.info(`[AI] [predict] Target: ${gatewayUrl()}/api/v1/ai/predict`); + + interface PredictionResp { + question: string; + type: string; + reason: string; + curiosity_score: number; + } + interface PredictGenResp { + predictions: PredictionResp[]; + status: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `基于以下笔记内容,生成预测性问题,返回JSON: {"predictions": [{"question": "...", "type": "...", "reason": "...", "curiosity_score": 0.8}], "status": "ok"}\n\n笔记:\n${args.content}`; + const result = await generateText(prompt, '你是一个预测驱动学习助手,擅长从笔记中生成引导性问题。请仅返回JSON。', { temperature: 0.6, maxTokens: 1024 }); + const parsed = JSON.parse(result.content); + return { predictions: parsed.predictions ?? [], status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/predict', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 60000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [predict] ✔ Success (${source}): predictions=${resp.predictions.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + predictions: resp.predictions.map((p: { question: string; type: string; reason: string; curiosity_score: number }) => ({ + question: p.question, + type: p.type, + reason: p.reason, + curiosityScore: p.curiosity_score, + })), + status: resp.status, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [predict] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [predict] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_predict', + name: 'AI 学习预测', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/recommendHandler.ts b/client/electron/ai/handlers/recommendHandler.ts index e92b9e35..65e48353 100644 --- a/client/electron/ai/handlers/recommendHandler.ts +++ b/client/electron/ai/handlers/recommendHandler.ts @@ -1,112 +1,114 @@ -/** - * AI 推荐时长功能 Handler - * - * 处理 ai_recommend_duration IPC 请求, - * 调用 AI 网关根据学习历史推荐最佳学习时长。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_recommend_duration — POST /api/v1/ai/recommend-duration - */ -function register(): void { - safeHandle( - 'ai_recommend_duration', - async ( - _event, - args: { - history: Array<{ - durationMinutes: number; - completed: boolean; - subject: string; - timestamp: string; - }>; - authToken?: string; - userApiKey?: string; - }, - ) => { - // 前端 camelCase → 后端 snake_case - const startMs = Date.now(); - logger.info(`[AI] [recommend] IPC received: sessions_count=${args.history.length}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [recommend] History preview: ${args.history.length} sessions, first=${args.history[0]?.timestamp ?? 'N/A'}, last=${args.history[args.history.length - 1]?.timestamp ?? 'N/A'}`); - - const reqBody = { - history: args.history.map((h) => ({ - duration_minutes: h.durationMinutes, - completed: h.completed, - subject: h.subject, - timestamp: h.timestamp, - })), - }; - - logger.info(`[AI] [recommend] Target: ${gatewayUrl()}/api/v1/ai/recommend-duration`); - - interface RecommendResp { - recommended_minutes: number; - break_minutes: number; - reason: string; - source: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `根据学习历史推荐最佳学习时长,返回JSON: {"recommended_minutes": 25, "break_minutes": 5, "reason": "...", "source": "local_ollama"}\n学习历史:${JSON.stringify(reqBody)}`; - const result = await generateText(prompt, '你是一个学习时间管理助手。请仅返回JSON。', { temperature: 0.4, maxTokens: 512 }); - const parsed = JSON.parse(result.content); - return { recommended_minutes: parsed.recommended_minutes ?? 25, break_minutes: parsed.break_minutes ?? 5, reason: parsed.reason ?? '', source: 'local_ollama', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/recommend-duration', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 40000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [recommend] ✔ Success (${source}): recommended=${resp.recommended_minutes}min, break=${resp.break_minutes}min, source=${resp.source}, model=${resp.model}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - recommendedMinutes: resp.recommended_minutes, - breakMinutes: resp.break_minutes, - reason: resp.reason, - source: resp.source, - isLocalFallback: resp.source === 'local_rule' || source === 'local', - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [recommend] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [recommend] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_recommend_duration', - name: 'AI 推荐学习时长', - version: '1.0.0', - register, -}; +/** + * AI 推荐时长功能 Handler + * + * 处理 ai_recommend_duration IPC 请求, + * 调用 AI 网关根据学习历史推荐最佳学习时长。 + * + * @ai-context: 时长推荐 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_recommend_duration — POST /api/v1/ai/recommend-duration + */ +function register(): void { + safeHandle( + 'ai_recommend_duration', + async ( + _event, + args: { + history: Array<{ + durationMinutes: number; + completed: boolean; + subject: string; + timestamp: string; + }>; + authToken?: string; + userApiKey?: string; + }, + ) => { + // 前端 camelCase → 后端 snake_case + const startMs = Date.now(); + logger.info(`[AI] [recommend] IPC received: sessions_count=${args.history.length}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [recommend] History preview: ${args.history.length} sessions, first=${args.history[0]?.timestamp ?? 'N/A'}, last=${args.history[args.history.length - 1]?.timestamp ?? 'N/A'}`); + + const reqBody = { + history: args.history.map((h) => ({ + duration_minutes: h.durationMinutes, + completed: h.completed, + subject: h.subject, + timestamp: h.timestamp, + })), + }; + + logger.info(`[AI] [recommend] Target: ${gatewayUrl()}/api/v1/ai/recommend-duration`); + + interface RecommendResp { + recommended_minutes: number; + break_minutes: number; + reason: string; + source: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `根据学习历史推荐最佳学习时长,返回JSON: {"recommended_minutes": 25, "break_minutes": 5, "reason": "...", "source": "local_ollama"}\n学习历史:${JSON.stringify(reqBody)}`; + const result = await generateText(prompt, '你是一个学习时间管理助手。请仅返回JSON。', { temperature: 0.4, maxTokens: 512 }); + const parsed = JSON.parse(result.content); + return { recommended_minutes: parsed.recommended_minutes ?? 25, break_minutes: parsed.break_minutes ?? 5, reason: parsed.reason ?? '', source: 'local_ollama', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/recommend-duration', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 40000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [recommend] ✔ Success (${source}): recommended=${resp.recommended_minutes}min, break=${resp.break_minutes}min, source=${resp.source}, model=${resp.model}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + recommendedMinutes: resp.recommended_minutes, + breakMinutes: resp.break_minutes, + reason: resp.reason, + source: resp.source, + isLocalFallback: resp.source === 'local_rule' || source === 'local', + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [recommend] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [recommend] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_recommend_duration', + name: 'AI 推荐学习时长', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/rescueHandler.ts b/client/electron/ai/handlers/rescueHandler.ts index 01e237a6..eba86b90 100644 --- a/client/electron/ai/handlers/rescueHandler.ts +++ b/client/electron/ai/handlers/rescueHandler.ts @@ -1,114 +1,116 @@ -/** - * AI 学习救援功能 Handler - * - * 处理 ai_rescue IPC 请求,调用 AI 网关为卡住的学习者提供分层救援提示。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_rescue — POST /api/v1/ai/rescue - */ -function register(): void { - safeHandle( - 'ai_rescue', - async ( - _event, - args: { - content: string; - stuckDescription: string; - attemptedMethods?: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [rescue] IPC received: content_length=${args.content.length}, stuck_length=${args.stuckDescription.length}, methods=${args.attemptedMethods ?? 'none'}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [rescue] Stuck description: ${args.stuckDescription.slice(0, 80)}`); - - // 前端 camelCase → 后端 snake_case - const reqBody = { - content: args.content, - stuck_description: args.stuckDescription, - attempted_methods: args.attemptedMethods ?? '', - }; - - logger.info(`[AI] [rescue] Target: ${gatewayUrl()}/api/v1/ai/rescue`); - - interface RescueLevelResp { - level: number; - label: string; - suggestion: string; - hint_question: string; - } - interface RescueGenResp { - rescue_levels: RescueLevelResp[]; - encouragement: string; - status: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `学习者卡住了,请提供分层救援提示,返回JSON: {"rescue_levels": [{"level": 1, "label": "...", "suggestion": "...", "hint_question": "..."}], "encouragement": "...", "status": "ok"}\n\n卡住情境:${JSON.stringify(reqBody)}`; - const result = await generateText(prompt, '你是一个学习救援助手,擅长为卡住的学习者提供分层提示。请仅返回JSON。', { temperature: 0.6, maxTokens: 1024 }); - const parsed = JSON.parse(result.content); - return { rescue_levels: parsed.rescue_levels ?? [], encouragement: parsed.encouragement ?? '加油!', status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/rescue', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 60000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [rescue] ✔ Success (${source}): levels=${resp.rescue_levels.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - rescueLevels: resp.rescue_levels.map((lv: { level: number; label: string; suggestion: string; hint_question: string }) => ({ - level: lv.level, - label: lv.label, - suggestion: lv.suggestion, - hintQuestion: lv.hint_question, - })), - encouragement: resp.encouragement, - status: resp.status, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [rescue] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [rescue] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_rescue', - name: 'AI 学习救援', - version: '1.0.0', - register, -}; +/** + * AI 学习救援功能 Handler + * + * 处理 ai_rescue IPC 请求,调用 AI 网关为卡住的学习者提供分层救援提示。 + * + * @ai-context: 卡壳救援 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_rescue — POST /api/v1/ai/rescue + */ +function register(): void { + safeHandle( + 'ai_rescue', + async ( + _event, + args: { + content: string; + stuckDescription: string; + attemptedMethods?: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [rescue] IPC received: content_length=${args.content.length}, stuck_length=${args.stuckDescription.length}, methods=${args.attemptedMethods ?? 'none'}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [rescue] Stuck description: ${args.stuckDescription.slice(0, 80)}`); + + // 前端 camelCase → 后端 snake_case + const reqBody = { + content: args.content, + stuck_description: args.stuckDescription, + attempted_methods: args.attemptedMethods ?? '', + }; + + logger.info(`[AI] [rescue] Target: ${gatewayUrl()}/api/v1/ai/rescue`); + + interface RescueLevelResp { + level: number; + label: string; + suggestion: string; + hint_question: string; + } + interface RescueGenResp { + rescue_levels: RescueLevelResp[]; + encouragement: string; + status: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `学习者卡住了,请提供分层救援提示,返回JSON: {"rescue_levels": [{"level": 1, "label": "...", "suggestion": "...", "hint_question": "..."}], "encouragement": "...", "status": "ok"}\n\n卡住情境:${JSON.stringify(reqBody)}`; + const result = await generateText(prompt, '你是一个学习救援助手,擅长为卡住的学习者提供分层提示。请仅返回JSON。', { temperature: 0.6, maxTokens: 1024 }); + const parsed = JSON.parse(result.content); + return { rescue_levels: parsed.rescue_levels ?? [], encouragement: parsed.encouragement ?? '加油!', status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/rescue', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 60000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [rescue] ✔ Success (${source}): levels=${resp.rescue_levels.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + rescueLevels: resp.rescue_levels.map((lv: { level: number; label: string; suggestion: string; hint_question: string }) => ({ + level: lv.level, + label: lv.label, + suggestion: lv.suggestion, + hintQuestion: lv.hint_question, + })), + encouragement: resp.encouragement, + status: resp.status, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [rescue] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [rescue] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_rescue', + name: 'AI 学习救援', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/sessionAnalyzeHandler.ts b/client/electron/ai/handlers/sessionAnalyzeHandler.ts index 1f505712..21265d68 100644 --- a/client/electron/ai/handlers/sessionAnalyzeHandler.ts +++ b/client/electron/ai/handlers/sessionAnalyzeHandler.ts @@ -1,155 +1,157 @@ -/** - * AI 课堂多模态分析 Handler - * - * 处理 ai_session_analyze IPC 请求,调用 AI 网关对课堂关键帧与音频段进行多模态分析。 - * 支持本地 Ollama 降级:优先调用本地多模态模型,失败后降级到远程网关。 - * 对应端点:POST /api/v1/multimodal/analyze-session - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateVisionMulti } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_session_analyze — POST /api/v1/multimodal/analyze-session - */ -function register(): void { - safeHandle( - 'ai_session_analyze', - async ( - _event, - args: { - keyframes: Array<{ - timestamp: number; // 已转为秒 - imageBase64: string; - changeType: string; - }>; - audioSegments: Array<{ - timestampStart: number; // 已转为秒 - timestampEnd: number; - audioText: string | null; - }>; - duration: number; // 已转为秒 - language?: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - const kfCount = args.keyframes?.length ?? 0; - const segCount = args.audioSegments?.length ?? 0; - logger.info(`[AI] [session-analyze] IPC received: keyframes=${kfCount}, audioSegments=${segCount}, duration=${args.duration}s, language=${args.language ?? 'zh'}, hasAuth=${!!args.authToken}`); - - const reqBody = { - keyframes: args.keyframes.map(kf => ({ - timestamp: kf.timestamp, - image_base64: kf.imageBase64, - change_type: kf.changeType, - })), - audio_segments: args.audioSegments.map(seg => ({ - timestamp_start: seg.timestampStart, - timestamp_end: seg.timestampEnd, - audio_text: seg.audioText, - })), - duration: args.duration, - language: args.language ?? 'zh', - }; - - logger.info(`[AI] [session-analyze] Target: ${gatewayUrl()}/api/v1/multimodal/analyze-session`); - - interface AnalyzeSessionResp { - content: string; - keyframes_analyzed: number; - model_used: string; - } - - try { - // 本地 Ollama 降级链 - const localHandler = async (): Promise => { - // 从 keyframes 中提取 imageBase64 数组 - const imagesBase64 = args.keyframes.map(kf => kf.imageBase64); - - // 构造包含时间轴信息和音频段文本的 prompt - const timelineParts: string[] = []; - for (const kf of args.keyframes) { - timelineParts.push(`[${kf.timestamp}s] 画面变化类型:${kf.changeType}`); - } - - const audioParts: string[] = []; - for (const seg of args.audioSegments) { - if (seg.audioText) { - audioParts.push(`[${seg.timestampStart}s - ${seg.timestampEnd}s] 音频内容:${seg.audioText}`); - } - } - - const prompt = [ - `请对以下课堂内容进行多模态分析。课程总时长:${args.duration}秒。`, - '', - '=== 关键帧时间轴 ===', - ...timelineParts, - '', - ...(audioParts.length > 0 - ? ['=== 音频段内容 ===', ...audioParts, ''] - : []), - '请综合分析课堂内容,包括知识点提取、教学结构分析、重点难点标注等。', - `语言:${args.language ?? 'zh'}`, - ].join('\n'); - - const result = await generateVisionMulti( - imagesBase64, - prompt, - '你是一个专业的课堂内容分析助手,擅长从视觉和音频信息中提取教学结构化知识。', - { temperature: 0.3, maxTokens: 4096 }, - ); - - return { - content: result.content, - keyframes_analyzed: imagesBase64.length, - model_used: result.model, - }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/multimodal/analyze-session', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 120000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [session-analyze] ✔ Success (${source}): content_length=${resp.content?.length ?? 0}, keyframes_analyzed=${resp.keyframes_analyzed}, model=${resp.model_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - content: resp.content, - keyframesAnalyzed: resp.keyframes_analyzed, - modelUsed: resp.model_used, - source, - requestId, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [session-analyze] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [session-analyze] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_session_analyze', - name: 'AI 课堂多模态分析', - version: '1.0.0', - register, -}; +/** + * AI 课堂多模态分析 Handler + * + * 处理 ai_session_analyze IPC 请求,调用 AI 网关对课堂关键帧与音频段进行多模态分析。 + * 支持本地 Ollama 降级:优先调用本地多模态模型,失败后降级到远程网关。 + * 对应端点:POST /api/v1/multimodal/analyze-session + * + * @ai-context: 课堂会话分析 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateVisionMulti } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_session_analyze — POST /api/v1/multimodal/analyze-session + */ +function register(): void { + safeHandle( + 'ai_session_analyze', + async ( + _event, + args: { + keyframes: Array<{ + timestamp: number; // 已转为秒 + imageBase64: string; + changeType: string; + }>; + audioSegments: Array<{ + timestampStart: number; // 已转为秒 + timestampEnd: number; + audioText: string | null; + }>; + duration: number; // 已转为秒 + language?: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + const kfCount = args.keyframes?.length ?? 0; + const segCount = args.audioSegments?.length ?? 0; + logger.info(`[AI] [session-analyze] IPC received: keyframes=${kfCount}, audioSegments=${segCount}, duration=${args.duration}s, language=${args.language ?? 'zh'}, hasAuth=${!!args.authToken}`); + + const reqBody = { + keyframes: args.keyframes.map(kf => ({ + timestamp: kf.timestamp, + image_base64: kf.imageBase64, + change_type: kf.changeType, + })), + audio_segments: args.audioSegments.map(seg => ({ + timestamp_start: seg.timestampStart, + timestamp_end: seg.timestampEnd, + audio_text: seg.audioText, + })), + duration: args.duration, + language: args.language ?? 'zh', + }; + + logger.info(`[AI] [session-analyze] Target: ${gatewayUrl()}/api/v1/multimodal/analyze-session`); + + interface AnalyzeSessionResp { + content: string; + keyframes_analyzed: number; + model_used: string; + } + + try { + // 本地 Ollama 降级链 + const localHandler = async (): Promise => { + // 从 keyframes 中提取 imageBase64 数组 + const imagesBase64 = args.keyframes.map(kf => kf.imageBase64); + + // 构造包含时间轴信息和音频段文本的 prompt + const timelineParts: string[] = []; + for (const kf of args.keyframes) { + timelineParts.push(`[${kf.timestamp}s] 画面变化类型:${kf.changeType}`); + } + + const audioParts: string[] = []; + for (const seg of args.audioSegments) { + if (seg.audioText) { + audioParts.push(`[${seg.timestampStart}s - ${seg.timestampEnd}s] 音频内容:${seg.audioText}`); + } + } + + const prompt = [ + `请对以下课堂内容进行多模态分析。课程总时长:${args.duration}秒。`, + '', + '=== 关键帧时间轴 ===', + ...timelineParts, + '', + ...(audioParts.length > 0 + ? ['=== 音频段内容 ===', ...audioParts, ''] + : []), + '请综合分析课堂内容,包括知识点提取、教学结构分析、重点难点标注等。', + `语言:${args.language ?? 'zh'}`, + ].join('\n'); + + const result = await generateVisionMulti( + imagesBase64, + prompt, + '你是一个专业的课堂内容分析助手,擅长从视觉和音频信息中提取教学结构化知识。', + { temperature: 0.3, maxTokens: 4096 }, + ); + + return { + content: result.content, + keyframes_analyzed: imagesBase64.length, + model_used: result.model, + }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/multimodal/analyze-session', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 120000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [session-analyze] ✔ Success (${source}): content_length=${resp.content?.length ?? 0}, keyframes_analyzed=${resp.keyframes_analyzed}, model=${resp.model_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + content: resp.content, + keyframesAnalyzed: resp.keyframes_analyzed, + modelUsed: resp.model_used, + source, + requestId, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [session-analyze] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [session-analyze] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_session_analyze', + name: 'AI 课堂多模态分析', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/socraticHandler.ts b/client/electron/ai/handlers/socraticHandler.ts index b946af46..00a6b311 100644 --- a/client/electron/ai/handlers/socraticHandler.ts +++ b/client/electron/ai/handlers/socraticHandler.ts @@ -1,281 +1,283 @@ -/** - * 苏格拉底追问功能 Handler - * - * 处理 ai_socratic / ai_socratic_evaluate / ai_socratic_deepening IPC 请求, - * 调用 AI 网关实现苏格拉底式追问、评估与深化。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// 公共类型 -// ================================================================ - -interface BackendHistoryItem { - role: 'tutor' | 'learner'; - content: string; -} - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * 注册苏格拉底相关的全部 IPC handler - */ -function register(): void { - /** - * ai_socratic — POST /api/v1/ai/socratic - */ - safeHandle( - 'ai_socratic', - async ( - _event, - args: { - topic: string; - history?: BackendHistoryItem[] | null; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [socratic] IPC received: topic_length=${args.topic.length}, history=${args.history?.length ?? 0}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [socratic] Topic preview: ${args.topic.slice(0, 80)}`); - - const reqBody = { - topic: args.topic, - history: args.history ?? null, - }; - - logger.info(`[AI] [socratic] Target: ${gatewayUrl()}/api/v1/ai/socratic`); - - interface SocraticResp { - question: string; - hint: string; - thinking_direction: string; - depth_level: number; - turn_count: number; - status: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `作为苏格拉底式导师,针对主题“${args.topic}”生成一个引导性问题,返回JSON: {"question": "...", "hint": "...", "thinking_direction": "...", "depth_level": 1, "turn_count": 1, "status": "ok"}`; - const result = await generateText(prompt, '你是一个苏格拉底式学习导师。请仅返回JSON。', { temperature: 0.7, maxTokens: 512 }); - const parsed = JSON.parse(result.content); - return { question: parsed.question ?? '', hint: parsed.hint ?? '', thinking_direction: parsed.thinking_direction ?? '', depth_level: parsed.depth_level ?? 1, turn_count: parsed.turn_count ?? 1, status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/socratic', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 60000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [socratic] ✔ Success (${source}): depth=${resp.depth_level}, turn=${resp.turn_count}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - question: resp.question, - hint: resp.hint, - thinkingDirection: resp.thinking_direction, - depthLevel: resp.depth_level, - turnCount: resp.turn_count, - status: resp.status, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [socratic] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [socratic] Error cause: ${error.cause}`); - throw error; - } - }, - ); - - /** - * ai_socratic_evaluate — POST /api/v1/ai/socratic/evaluate - */ - safeHandle( - 'ai_socratic_evaluate', - async ( - _event, - args: { - topic: string; - question: string; - answer: string; - history?: BackendHistoryItem[]; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [socratic-eval] IPC received: topic_length=${args.topic.length}, question_length=${args.question.length}, answer_length=${args.answer.length}, history=${args.history?.length ?? 0}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [socratic-eval] Topic: ${args.topic.slice(0, 60)}, Q: ${args.question.slice(0, 60)}`); - - const reqBody = { - topic: args.topic, - question: args.question, - answer: args.answer, - history: args.history ?? [], - }; - - logger.info(`[AI] [socratic-eval] Target: ${gatewayUrl()}/api/v1/ai/socratic/evaluate`); - - interface SocraticEvaluateResp { - dimensions: { accuracy: number; completeness: number; logic: number; expression: number }; - feedback: string; - encouragement: string; - status: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `评估学生对问题的回答,返回JSON: {"dimensions": {"accuracy": 70, "completeness": 65, "logic": 75, "expression": 80}, "feedback": "...", "encouragement": "...", "status": "ok"}`; - const result = await generateText(prompt, '你是一个苏格拉底式评估助手。请仅返回JSON。', { temperature: 0.4, maxTokens: 512 }); - const parsed = JSON.parse(result.content); - return { dimensions: parsed.dimensions ?? { accuracy: 60, completeness: 60, logic: 60, expression: 60 }, feedback: parsed.feedback ?? '', encouragement: parsed.encouragement ?? '继续加油!', status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/socratic/evaluate', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 60000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [socratic-eval] ✔ Success (${source}): accuracy=${resp.dimensions.accuracy}, completeness=${resp.dimensions.completeness}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - dimensions: resp.dimensions, - feedback: resp.feedback, - encouragement: resp.encouragement, - status: resp.status, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [socratic-eval] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [socratic-eval] Error cause: ${error.cause}`); - throw error; - } - }, - ); - - /** - * ai_socratic_deepening — POST /api/v1/ai/socratic/deepening - */ - safeHandle( - 'ai_socratic_deepening', - async ( - _event, - args: { - topic: string; - dialogueSummary: string; - history?: BackendHistoryItem[]; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [socratic-deep] IPC received: topic_length=${args.topic.length}, summary_length=${args.dialogueSummary.length}, history=${args.history?.length ?? 0}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [socratic-deep] Topic: ${args.topic.slice(0, 60)}, Summary preview: ${args.dialogueSummary.slice(0, 80)}`); - - // 前端 camelCase dialogueSummary → 后端 snake_case dialogue_summary - const reqBody = { - topic: args.topic, - dialogue_summary: args.dialogueSummary, - history: args.history ?? [], - }; - - logger.info(`[AI] [socratic-deep] Target: ${gatewayUrl()}/api/v1/ai/socratic/deepening`); - - interface AngleResp { - key: string; - label: string; - question: string; - } - interface SocraticDeepeningResp { - angles: AngleResp[]; - status: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `针对主题“${args.topic}”的对话摘要,生成深化探索角度,返回JSON: {"angles": [{"key": "...", "label": "...", "question": "..."}], "status": "ok"}`; - const result = await generateText(prompt, '你是一个苏格拉底式深化探索助手。请仅返回JSON。', { temperature: 0.7, maxTokens: 1024 }); - const parsed = JSON.parse(result.content); - return { angles: parsed.angles ?? [], status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/socratic/deepening', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 60000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [socratic-deep] ✔ Success (${source}): angles=${resp.angles.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - angles: resp.angles.map((a: { key: string; label: string; question: string }) => ({ - key: a.key, - label: a.label, - question: a.question, - })), - status: resp.status, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [socratic-deep] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [socratic-deep] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_socratic', - name: 'AI 苏格拉底追问', - version: '1.0.0', - register, -}; +/** + * 苏格拉底追问功能 Handler + * + * 处理 ai_socratic / ai_socratic_evaluate / ai_socratic_deepening IPC 请求, + * 调用 AI 网关实现苏格拉底式追问、评估与深化。 + * + * @ai-context: 苏格拉底追问(含评估/深化) IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// 公共类型 +// ================================================================ + +interface BackendHistoryItem { + role: 'tutor' | 'learner'; + content: string; +} + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * 注册苏格拉底相关的全部 IPC handler + */ +function register(): void { + /** + * ai_socratic — POST /api/v1/ai/socratic + */ + safeHandle( + 'ai_socratic', + async ( + _event, + args: { + topic: string; + history?: BackendHistoryItem[] | null; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [socratic] IPC received: topic_length=${args.topic.length}, history=${args.history?.length ?? 0}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [socratic] Topic preview: ${args.topic.slice(0, 80)}`); + + const reqBody = { + topic: args.topic, + history: args.history ?? null, + }; + + logger.info(`[AI] [socratic] Target: ${gatewayUrl()}/api/v1/ai/socratic`); + + interface SocraticResp { + question: string; + hint: string; + thinking_direction: string; + depth_level: number; + turn_count: number; + status: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `作为苏格拉底式导师,针对主题“${args.topic}”生成一个引导性问题,返回JSON: {"question": "...", "hint": "...", "thinking_direction": "...", "depth_level": 1, "turn_count": 1, "status": "ok"}`; + const result = await generateText(prompt, '你是一个苏格拉底式学习导师。请仅返回JSON。', { temperature: 0.7, maxTokens: 512 }); + const parsed = JSON.parse(result.content); + return { question: parsed.question ?? '', hint: parsed.hint ?? '', thinking_direction: parsed.thinking_direction ?? '', depth_level: parsed.depth_level ?? 1, turn_count: parsed.turn_count ?? 1, status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/socratic', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 60000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [socratic] ✔ Success (${source}): depth=${resp.depth_level}, turn=${resp.turn_count}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + question: resp.question, + hint: resp.hint, + thinkingDirection: resp.thinking_direction, + depthLevel: resp.depth_level, + turnCount: resp.turn_count, + status: resp.status, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [socratic] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [socratic] Error cause: ${error.cause}`); + throw error; + } + }, + ); + + /** + * ai_socratic_evaluate — POST /api/v1/ai/socratic/evaluate + */ + safeHandle( + 'ai_socratic_evaluate', + async ( + _event, + args: { + topic: string; + question: string; + answer: string; + history?: BackendHistoryItem[]; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [socratic-eval] IPC received: topic_length=${args.topic.length}, question_length=${args.question.length}, answer_length=${args.answer.length}, history=${args.history?.length ?? 0}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [socratic-eval] Topic: ${args.topic.slice(0, 60)}, Q: ${args.question.slice(0, 60)}`); + + const reqBody = { + topic: args.topic, + question: args.question, + answer: args.answer, + history: args.history ?? [], + }; + + logger.info(`[AI] [socratic-eval] Target: ${gatewayUrl()}/api/v1/ai/socratic/evaluate`); + + interface SocraticEvaluateResp { + dimensions: { accuracy: number; completeness: number; logic: number; expression: number }; + feedback: string; + encouragement: string; + status: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `评估学生对问题的回答,返回JSON: {"dimensions": {"accuracy": 70, "completeness": 65, "logic": 75, "expression": 80}, "feedback": "...", "encouragement": "...", "status": "ok"}`; + const result = await generateText(prompt, '你是一个苏格拉底式评估助手。请仅返回JSON。', { temperature: 0.4, maxTokens: 512 }); + const parsed = JSON.parse(result.content); + return { dimensions: parsed.dimensions ?? { accuracy: 60, completeness: 60, logic: 60, expression: 60 }, feedback: parsed.feedback ?? '', encouragement: parsed.encouragement ?? '继续加油!', status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/socratic/evaluate', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 60000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [socratic-eval] ✔ Success (${source}): accuracy=${resp.dimensions.accuracy}, completeness=${resp.dimensions.completeness}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + dimensions: resp.dimensions, + feedback: resp.feedback, + encouragement: resp.encouragement, + status: resp.status, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [socratic-eval] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [socratic-eval] Error cause: ${error.cause}`); + throw error; + } + }, + ); + + /** + * ai_socratic_deepening — POST /api/v1/ai/socratic/deepening + */ + safeHandle( + 'ai_socratic_deepening', + async ( + _event, + args: { + topic: string; + dialogueSummary: string; + history?: BackendHistoryItem[]; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [socratic-deep] IPC received: topic_length=${args.topic.length}, summary_length=${args.dialogueSummary.length}, history=${args.history?.length ?? 0}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [socratic-deep] Topic: ${args.topic.slice(0, 60)}, Summary preview: ${args.dialogueSummary.slice(0, 80)}`); + + // 前端 camelCase dialogueSummary → 后端 snake_case dialogue_summary + const reqBody = { + topic: args.topic, + dialogue_summary: args.dialogueSummary, + history: args.history ?? [], + }; + + logger.info(`[AI] [socratic-deep] Target: ${gatewayUrl()}/api/v1/ai/socratic/deepening`); + + interface AngleResp { + key: string; + label: string; + question: string; + } + interface SocraticDeepeningResp { + angles: AngleResp[]; + status: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `针对主题“${args.topic}”的对话摘要,生成深化探索角度,返回JSON: {"angles": [{"key": "...", "label": "...", "question": "..."}], "status": "ok"}`; + const result = await generateText(prompt, '你是一个苏格拉底式深化探索助手。请仅返回JSON。', { temperature: 0.7, maxTokens: 1024 }); + const parsed = JSON.parse(result.content); + return { angles: parsed.angles ?? [], status: 'ok', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/socratic/deepening', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 60000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [socratic-deep] ✔ Success (${source}): angles=${resp.angles.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + angles: resp.angles.map((a: { key: string; label: string; question: string }) => ({ + key: a.key, + label: a.label, + question: a.question, + })), + status: resp.status, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [socratic-deep] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [socratic-deep] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_socratic', + name: 'AI 苏格拉底追问', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/summarizeHandler.ts b/client/electron/ai/handlers/summarizeHandler.ts index b3e3a3ef..81244efa 100644 --- a/client/electron/ai/handlers/summarizeHandler.ts +++ b/client/electron/ai/handlers/summarizeHandler.ts @@ -1,113 +1,115 @@ -/** - * AI 摘要功能 Handler - * - * 处理 ai_summarize IPC 请求,调用 AI 网关生成文本摘要。 - * 支持本地 Ollama 降级:优先调用本地模型,失败后降级到远程网关。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_summarize — POST /api/v1/ai/summarize - * 接收前端 camelCase 参数,转为后端 snake_case 请求体, - * 再将后端 snake_case 响应转回 camelCase。 - */ -function register(): void { - safeHandle( - 'ai_summarize', - async ( - _event, - args: { - text: string; - maxLength?: number; - style?: string; - language?: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [summarize] IPC received: text_length=${args.text.length}, style=${args.style ?? 'default'}, language=${args.language ?? 'auto'}, maxLength=${args.maxLength ?? 'none'}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [summarize] Text preview: ${args.text.slice(0, 80)}...`); - - const reqBody = { - text: args.text, - options: { - ...(args.maxLength != null && { max_length: args.maxLength }), - ...(args.style != null && { style: args.style }), - ...(args.language != null && { language: args.language }), - }, - }; - - logger.info(`[AI] [summarize] Target: ${gatewayUrl()}/api/v1/ai/summarize`); - - interface SummarizeResp { - summary: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - // 本地 Ollama 降级链 - const localHandler = async (): Promise => { - const styleHint = args.style ? `,风格:${args.style}` : ''; - const langHint = args.language ? `,语言:${args.language}` : ''; - const lenHint = args.maxLength ? `,字数控制在${args.maxLength}字以内` : ''; - const prompt = `请对以下内容进行摘要${styleHint}${langHint}${lenHint}:\n\n${args.text}`; - const result = await generateText(prompt, '你是一个专业的学习笔记摘要助手,擅长提炼核心要点。', { temperature: 0.5, maxTokens: 2048 }); - return { - summary: result.content, - model: result.model, - tokens_used: result.tokens_used, - latency_ms: result.latency_ms, - }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/summarize', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 90000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [summarize] ✔ Success (${source}): model=${resp.model}, tokens=${resp.tokens_used}, backend_latency=${resp.latency_ms}ms, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - summary: resp.summary, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [summarize] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [summarize] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_summarize', - name: 'AI 文本摘要', - version: '1.0.0', - register, -}; +/** + * AI 摘要功能 Handler + * + * 处理 ai_summarize IPC 请求,调用 AI 网关生成文本摘要。 + * 支持本地 Ollama 降级:优先调用本地模型,失败后降级到远程网关。 + * + * @ai-context: 笔记摘要 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_summarize — POST /api/v1/ai/summarize + * 接收前端 camelCase 参数,转为后端 snake_case 请求体, + * 再将后端 snake_case 响应转回 camelCase。 + */ +function register(): void { + safeHandle( + 'ai_summarize', + async ( + _event, + args: { + text: string; + maxLength?: number; + style?: string; + language?: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [summarize] IPC received: text_length=${args.text.length}, style=${args.style ?? 'default'}, language=${args.language ?? 'auto'}, maxLength=${args.maxLength ?? 'none'}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [summarize] Text preview: ${args.text.slice(0, 80)}...`); + + const reqBody = { + text: args.text, + options: { + ...(args.maxLength != null && { max_length: args.maxLength }), + ...(args.style != null && { style: args.style }), + ...(args.language != null && { language: args.language }), + }, + }; + + logger.info(`[AI] [summarize] Target: ${gatewayUrl()}/api/v1/ai/summarize`); + + interface SummarizeResp { + summary: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + // 本地 Ollama 降级链 + const localHandler = async (): Promise => { + const styleHint = args.style ? `,风格:${args.style}` : ''; + const langHint = args.language ? `,语言:${args.language}` : ''; + const lenHint = args.maxLength ? `,字数控制在${args.maxLength}字以内` : ''; + const prompt = `请对以下内容进行摘要${styleHint}${langHint}${lenHint}:\n\n${args.text}`; + const result = await generateText(prompt, '你是一个专业的学习笔记摘要助手,擅长提炼核心要点。', { temperature: 0.5, maxTokens: 2048 }); + return { + summary: result.content, + model: result.model, + tokens_used: result.tokens_used, + latency_ms: result.latency_ms, + }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/summarize', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 90000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [summarize] ✔ Success (${source}): model=${resp.model}, tokens=${resp.tokens_used}, backend_latency=${resp.latency_ms}ms, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + summary: resp.summary, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [summarize] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [summarize] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_summarize', + name: 'AI 文本摘要', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/tagHandler.ts b/client/electron/ai/handlers/tagHandler.ts index 1d9ed683..5368c420 100644 --- a/client/electron/ai/handlers/tagHandler.ts +++ b/client/electron/ai/handlers/tagHandler.ts @@ -1,188 +1,190 @@ -/** - * AI 标签/内容分类功能 Handler - * - * 处理 ai_tag_content 和 ai_sort_inspiration IPC 请求, - * 调用 AI 网关进行内容分类和灵感归档。 - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateText } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * 注册标签/内容分类相关的所有 IPC handler - */ -function register(): void { - /** - * ai_tag_content — POST /api/v1/ai/tag-content - */ - safeHandle( - 'ai_tag_content', - async ( - _event, - args: { - content: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [tag] IPC received: content_length=${args.content.length}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [tag] Content preview: ${args.content.slice(0, 80)}...`); - - const reqBody = { content: args.content }; - - logger.info(`[AI] [tag] Target: ${gatewayUrl()}/api/v1/ai/tag-content`); - - interface TagContentResp { - content_nature: string; - cognitive_depth: string; - subject: string; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `请对以下内容进行分类,返回JSON格式: {"content_nature": "...", "cognitive_depth": "...", "subject": "..."}\n\n内容:\n${args.content}`; - const result = await generateText(prompt, '你是一个内容分类助手,擅长判断内容的性质、认知深度和学科。请仅返回JSON。', { temperature: 0.3, maxTokens: 512 }); - try { - const parsed = JSON.parse(result.content); - return { content_nature: parsed.content_nature ?? 'unknown', cognitive_depth: parsed.cognitive_depth ?? 'unknown', subject: parsed.subject ?? 'unknown', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - } catch { - return { content_nature: 'unknown', cognitive_depth: 'unknown', subject: 'unknown', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - } - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/tag-content', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 30000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [tag] ✔ Success (${source}): nature=${resp.content_nature}, depth=${resp.cognitive_depth}, subject=${resp.subject}, model=${resp.model}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - contentNature: resp.content_nature, - cognitiveDepth: resp.cognitive_depth, - subject: resp.subject, - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [tag] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [tag] Error cause: ${error.cause}`); - throw error; - } - }, - ); - - /** - * ai_sort_inspiration — POST /api/v1/ai/sort-inspiration - */ - safeHandle( - 'ai_sort_inspiration', - async ( - _event, - args: { - content: string; - existingTags?: Record; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [sort-insp] IPC received: content_length=${args.content.length}, existingTags=${args.existingTags ? Object.keys(args.existingTags).length : 0}, hasAuth=${!!args.authToken}`); - logger.debug(`[AI] [sort-insp] Content preview: ${args.content.slice(0, 80)}...`); - - const reqBody = { - content: args.content, - existing_tags: args.existingTags, - }; - - logger.info(`[AI] [sort-insp] Target: ${gatewayUrl()}/api/v1/ai/sort-inspiration`); - - interface SortSuggestionResp { - category: string; - reason: string; - confidence: number; - suggested_action: string; - } - interface SortInspirationResp { - suggestions: SortSuggestionResp[]; - model: string; - tokens_used: number; - latency_ms: number; - } - - try { - const localHandler = async (): Promise => { - const prompt = `请对以下灵感内容进行归档建议,返回JSON格式: {"suggestions": [{"category": "...", "reason": "...", "confidence": 0.8, "suggested_action": "..."}]}\n\n内容:\n${args.content}`; - const result = await generateText(prompt, '你是一个灵感归档助手,擅长为灵感内容推荐分类和归档建议。请仅返回JSON。', { temperature: 0.4, maxTokens: 1024 }); - try { - const parsed = JSON.parse(result.content); - return { suggestions: parsed.suggestions ?? [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - } catch { - return { suggestions: [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; - } - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/ai/sort-inspiration', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 30000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [sort-insp] ✔ Success (${source}): suggestions=${resp.suggestions.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - suggestions: resp.suggestions.map((s) => ({ - category: s.category, - reason: s.reason, - confidence: s.confidence, - suggestedAction: s.suggested_action, - })), - model: resp.model, - tokensUsed: resp.tokens_used, - latencyMs: resp.latency_ms, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [sort-insp] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [sort-insp] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_tag', - name: 'AI 标签与萤火海沟分类', - version: '1.0.0', - register, -}; +/** + * AI 标签/内容分类功能 Handler + * + * 处理 ai_tag_content 和 ai_sort_inspiration IPC 请求, + * 调用 AI 网关进行内容分类和灵感归档。 + * + * @ai-context: 内容打标 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateText } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * 注册标签/内容分类相关的所有 IPC handler + */ +function register(): void { + /** + * ai_tag_content — POST /api/v1/ai/tag-content + */ + safeHandle( + 'ai_tag_content', + async ( + _event, + args: { + content: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [tag] IPC received: content_length=${args.content.length}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [tag] Content preview: ${args.content.slice(0, 80)}...`); + + const reqBody = { content: args.content }; + + logger.info(`[AI] [tag] Target: ${gatewayUrl()}/api/v1/ai/tag-content`); + + interface TagContentResp { + content_nature: string; + cognitive_depth: string; + subject: string; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `请对以下内容进行分类,返回JSON格式: {"content_nature": "...", "cognitive_depth": "...", "subject": "..."}\n\n内容:\n${args.content}`; + const result = await generateText(prompt, '你是一个内容分类助手,擅长判断内容的性质、认知深度和学科。请仅返回JSON。', { temperature: 0.3, maxTokens: 512 }); + try { + const parsed = JSON.parse(result.content); + return { content_nature: parsed.content_nature ?? 'unknown', cognitive_depth: parsed.cognitive_depth ?? 'unknown', subject: parsed.subject ?? 'unknown', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + } catch { + return { content_nature: 'unknown', cognitive_depth: 'unknown', subject: 'unknown', model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + } + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/tag-content', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 30000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [tag] ✔ Success (${source}): nature=${resp.content_nature}, depth=${resp.cognitive_depth}, subject=${resp.subject}, model=${resp.model}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + contentNature: resp.content_nature, + cognitiveDepth: resp.cognitive_depth, + subject: resp.subject, + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [tag] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [tag] Error cause: ${error.cause}`); + throw error; + } + }, + ); + + /** + * ai_sort_inspiration — POST /api/v1/ai/sort-inspiration + */ + safeHandle( + 'ai_sort_inspiration', + async ( + _event, + args: { + content: string; + existingTags?: Record; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [sort-insp] IPC received: content_length=${args.content.length}, existingTags=${args.existingTags ? Object.keys(args.existingTags).length : 0}, hasAuth=${!!args.authToken}`); + logger.debug(`[AI] [sort-insp] Content preview: ${args.content.slice(0, 80)}...`); + + const reqBody = { + content: args.content, + existing_tags: args.existingTags, + }; + + logger.info(`[AI] [sort-insp] Target: ${gatewayUrl()}/api/v1/ai/sort-inspiration`); + + interface SortSuggestionResp { + category: string; + reason: string; + confidence: number; + suggested_action: string; + } + interface SortInspirationResp { + suggestions: SortSuggestionResp[]; + model: string; + tokens_used: number; + latency_ms: number; + } + + try { + const localHandler = async (): Promise => { + const prompt = `请对以下灵感内容进行归档建议,返回JSON格式: {"suggestions": [{"category": "...", "reason": "...", "confidence": 0.8, "suggested_action": "..."}]}\n\n内容:\n${args.content}`; + const result = await generateText(prompt, '你是一个灵感归档助手,擅长为灵感内容推荐分类和归档建议。请仅返回JSON。', { temperature: 0.4, maxTokens: 1024 }); + try { + const parsed = JSON.parse(result.content); + return { suggestions: parsed.suggestions ?? [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + } catch { + return { suggestions: [], model: result.model, tokens_used: result.tokens_used, latency_ms: result.latency_ms }; + } + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/ai/sort-inspiration', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 30000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [sort-insp] ✔ Success (${source}): suggestions=${resp.suggestions.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + suggestions: resp.suggestions.map((s) => ({ + category: s.category, + reason: s.reason, + confidence: s.confidence, + suggestedAction: s.suggested_action, + })), + model: resp.model, + tokensUsed: resp.tokens_used, + latencyMs: resp.latency_ms, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [sort-insp] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [sort-insp] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_tag', + name: 'AI 标签与萤火海沟分类', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/videoAnalyzeHandler.ts b/client/electron/ai/handlers/videoAnalyzeHandler.ts index cba01e0a..a8ed64cc 100644 --- a/client/electron/ai/handlers/videoAnalyzeHandler.ts +++ b/client/electron/ai/handlers/videoAnalyzeHandler.ts @@ -1,107 +1,109 @@ -/** - * AI 视频分析功能 Handler - * - * 处理 ai_video_analyze IPC 请求,调用 AI 网关对视频文件进行多模态分析。 - * 不支持本地 Ollama 降级(Ollama 不支持视频处理),仅走远程网关。 - * 对应端点:POST /api/v1/multimodal/analyze-video(multipart/form-data) - */ - -import { readFile } from 'fs/promises'; -import * as path from 'path'; -import { app } from 'electron'; -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { gatewayUrl, postMultipart, type AIFeatureDef } from '../utils.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_video_analyze — POST /api/v1/multimodal/analyze-video - */ -function register(): void { - safeHandle( - 'ai_video_analyze', - async ( - _event, - args: { - filePath: string; - duration?: number; - language?: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - logger.info(`[AI] [video-analyze] IPC received: filePath=${args.filePath}, duration=${args.duration ?? 'N/A'}, language=${args.language ?? 'zh'}, hasAuth=${!!args.authToken}`); - - logger.info(`[AI] [video-analyze] Target: ${gatewayUrl()}/api/v1/multimodal/analyze-video`); - - interface AnalyzeVideoResp { - content: string; - keyframes_analyzed: number; - model_used: string; - } - - try { - // SEC: 路径安全校验 — 仅允许读取应用数据目录或临时目录(与 main.ts fs:read-file 保持一致) - const resolvedPath = path.resolve(args.filePath); - const appDataPath = app.getPath('userData'); - const tempPath = app.getPath('temp'); - if (!resolvedPath.startsWith(appDataPath) && !resolvedPath.startsWith(tempPath)) { - throw new Error(`[AI] [video-analyze] File path not allowed: ${resolvedPath}`); - } - - // 主进程读取视频文件 - const fileBuffer = await readFile(resolvedPath); - const fileName = args.filePath.split(/[\\/]/).pop() ?? 'recording.webm'; - - // 构造 FormData - const blob = new Blob([fileBuffer], { type: 'video/webm' }); - const formData = new FormData(); - formData.append('video_file', blob, fileName); - if (args.duration !== undefined) formData.append('duration', String(args.duration)); - if (args.language) formData.append('language', args.language); - - logger.info(`[AI] [video-analyze] File loaded: ${fileName}, size=${fileBuffer.length} bytes`); - - // 直接调用远程网关(Ollama 不支持视频处理,无本地降级) - const { data: resp, requestId } = await postMultipart( - '/api/v1/multimodal/analyze-video', - formData, - args.authToken, - args.userApiKey, - 300000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [video-analyze] ✔ Success (remote): content_length=${resp.content?.length ?? 0}, keyframes_analyzed=${resp.keyframes_analyzed}, model=${resp.model_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - content: resp.content, - keyframesAnalyzed: resp.keyframes_analyzed, - modelUsed: resp.model_used, - source: 'remote' as const, - requestId, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [video-analyze] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [video-analyze] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_video_analyze', - name: 'AI 视频分析', - version: '1.0.0', - register, -}; +/** + * AI 视频分析功能 Handler + * + * 处理 ai_video_analyze IPC 请求,调用 AI 网关对视频文件进行多模态分析。 + * 不支持本地 Ollama 降级(Ollama 不支持视频处理),仅走远程网关。 + * 对应端点:POST /api/v1/multimodal/analyze-video(multipart/form-data) + * + * @ai-context: 视频分析(multipart 上传) IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { readFile } from 'fs/promises'; +import * as path from 'path'; +import { app } from 'electron'; +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { gatewayUrl, postMultipart, type AIFeatureDef } from '../utils.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_video_analyze — POST /api/v1/multimodal/analyze-video + */ +function register(): void { + safeHandle( + 'ai_video_analyze', + async ( + _event, + args: { + filePath: string; + duration?: number; + language?: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + logger.info(`[AI] [video-analyze] IPC received: filePath=${args.filePath}, duration=${args.duration ?? 'N/A'}, language=${args.language ?? 'zh'}, hasAuth=${!!args.authToken}`); + + logger.info(`[AI] [video-analyze] Target: ${gatewayUrl()}/api/v1/multimodal/analyze-video`); + + interface AnalyzeVideoResp { + content: string; + keyframes_analyzed: number; + model_used: string; + } + + try { + // SEC: 路径安全校验 — 仅允许读取应用数据目录或临时目录(与 main.ts fs:read-file 保持一致) + const resolvedPath = path.resolve(args.filePath); + const appDataPath = app.getPath('userData'); + const tempPath = app.getPath('temp'); + if (!resolvedPath.startsWith(appDataPath) && !resolvedPath.startsWith(tempPath)) { + throw new Error(`[AI] [video-analyze] File path not allowed: ${resolvedPath}`); + } + + // 主进程读取视频文件 + const fileBuffer = await readFile(resolvedPath); + const fileName = args.filePath.split(/[\\/]/).pop() ?? 'recording.webm'; + + // 构造 FormData + const blob = new Blob([fileBuffer], { type: 'video/webm' }); + const formData = new FormData(); + formData.append('video_file', blob, fileName); + if (args.duration !== undefined) formData.append('duration', String(args.duration)); + if (args.language) formData.append('language', args.language); + + logger.info(`[AI] [video-analyze] File loaded: ${fileName}, size=${fileBuffer.length} bytes`); + + // 直接调用远程网关(Ollama 不支持视频处理,无本地降级) + const { data: resp, requestId } = await postMultipart( + '/api/v1/multimodal/analyze-video', + formData, + args.authToken, + args.userApiKey, + 300000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [video-analyze] ✔ Success (remote): content_length=${resp.content?.length ?? 0}, keyframes_analyzed=${resp.keyframes_analyzed}, model=${resp.model_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + content: resp.content, + keyframesAnalyzed: resp.keyframes_analyzed, + modelUsed: resp.model_used, + source: 'remote' as const, + requestId, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [video-analyze] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [video-analyze] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_video_analyze', + name: 'AI 视频分析', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/handlers/visionExtractHandler.ts b/client/electron/ai/handlers/visionExtractHandler.ts index bfa58410..9e904529 100644 --- a/client/electron/ai/handlers/visionExtractHandler.ts +++ b/client/electron/ai/handlers/visionExtractHandler.ts @@ -1,130 +1,132 @@ -/** - * AI 视觉提取功能 Handler - * - * 处理 ai_vision_extract IPC 请求,调用 AI 网关对图片进行多模态内容提取。 - * 支持本地 Ollama 降级:优先调用本地多模态模型,失败后降级到远程网关。 - * 对应端点:POST /api/v1/vision/extract - */ - -import { safeHandle } from '../../ipcUtils.js'; -import { logger } from '../../logger.js'; -import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; -import { generateVision } from '../ollama/OllamaProvider.js'; - -// ================================================================ -// IPC Handler -// ================================================================ - -/** - * ai_vision_extract — POST /api/v1/vision/extract - */ -function register(): void { - safeHandle( - 'ai_vision_extract', - async ( - _event, - args: { - imageBase64: string; - language?: string; - mode?: string; - authToken?: string; - userApiKey?: string; - }, - ) => { - const startMs = Date.now(); - const base64Len = args.imageBase64?.length ?? 0; - logger.info(`[AI] [vision-extract] IPC received: image_base64_length=${base64Len}, language=${args.language ?? 'zh'}, mode=${args.mode ?? 'auto'}, hasAuth=${!!args.authToken}`); - - const reqBody = { - image_base64: args.imageBase64, - language: args.language ?? 'zh', - mode: args.mode ?? 'auto', - }; - - logger.info(`[AI] [vision-extract] Target: ${gatewayUrl()}/api/v1/vision/extract`); - - interface CodeBlockResp { - language: string; - code: string; - } - interface VisionExtractResp { - text: string; - formulas: string[]; - diagrams: string[]; - key_points: string[]; - code_blocks: CodeBlockResp[]; - concepts: string[]; - confidence: number; - model_used: string; - processing_time_ms: number; - mode: string; - } - - try { - // 本地 Ollama 降级链 - const localHandler = async (): Promise => { - const prompt = `请对这张图片进行内容提取。提取所有可见文本、公式、图表描述、关键要点、代码块和核心概念。\n语言:${args.language ?? 'zh'}\n模式:${args.mode ?? 'auto'}`; - const result = await generateVision(args.imageBase64, prompt, '你是一个专业的视觉内容提取助手,擅长从图片中提取结构化信息。', { temperature: 0.3, maxTokens: 4096 }); - return { - text: result.content, - formulas: [], - diagrams: [], - key_points: [], - code_blocks: [], - concepts: [], - confidence: result.content.trim() ? 0.85 : 0.3, - model_used: result.model, - processing_time_ms: result.latency_ms, - mode: args.mode ?? 'auto', - }; - }; - - const { data: resp, source, requestId } = await callWithLocalFallback( - '/api/v1/vision/extract', - reqBody, - localHandler, - args.authToken, - args.userApiKey, - 90000, - ); - - const elapsed = Date.now() - startMs; - logger.info(`[AI] [vision-extract] ✔ Success (${source}): text_length=${resp.text?.length ?? 0}, formulas=${resp.formulas?.length ?? 0}, concepts=${resp.concepts?.length ?? 0}, confidence=${resp.confidence}, model=${resp.model_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); - return { - text: resp.text, - formulas: resp.formulas ?? [], - diagrams: resp.diagrams ?? [], - keyPoints: resp.key_points ?? [], - codeBlocks: (resp.code_blocks ?? []).map((cb) => ({ - language: cb.language, - code: cb.code, - })), - concepts: resp.concepts ?? [], - confidence: resp.confidence, - modelUsed: resp.model_used, - processingTimeMs: resp.processing_time_ms, - mode: resp.mode, - requestId, - source, - }; - } catch (err) { - const elapsed = Date.now() - startMs; - const error = err instanceof Error ? err : new Error(String(err)); - logger.error(`[AI] [vision-extract] ✖ Failed after ${elapsed}ms: ${error.message}`); - if (error.cause) logger.error(`[AI] [vision-extract] Error cause: ${error.cause}`); - throw error; - } - }, - ); -} - -// ================================================================ -// 功能定义导出 -// ================================================================ - -export const feature: AIFeatureDef = { - id: 'ai_vision_extract', - name: 'AI 视觉内容提取', - version: '1.0.0', - register, -}; +/** + * AI 视觉提取功能 Handler + * + * 处理 ai_vision_extract IPC 请求,调用 AI 网关对图片进行多模态内容提取。 + * 支持本地 Ollama 降级:优先调用本地多模态模型,失败后降级到远程网关。 + * 对应端点:POST /api/v1/vision/extract + * + * @ai-context: 视觉提取(截图 OCR/理解) IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。 + */ + +import { safeHandle } from '../../ipcUtils.js'; +import { logger } from '../../logger.js'; +import { callWithLocalFallback, gatewayUrl, type AIFeatureDef } from '../utils.js'; +import { generateVision } from '../ollama/OllamaProvider.js'; + +// ================================================================ +// IPC Handler +// ================================================================ + +/** + * ai_vision_extract — POST /api/v1/vision/extract + */ +function register(): void { + safeHandle( + 'ai_vision_extract', + async ( + _event, + args: { + imageBase64: string; + language?: string; + mode?: string; + authToken?: string; + userApiKey?: string; + }, + ) => { + const startMs = Date.now(); + const base64Len = args.imageBase64?.length ?? 0; + logger.info(`[AI] [vision-extract] IPC received: image_base64_length=${base64Len}, language=${args.language ?? 'zh'}, mode=${args.mode ?? 'auto'}, hasAuth=${!!args.authToken}`); + + const reqBody = { + image_base64: args.imageBase64, + language: args.language ?? 'zh', + mode: args.mode ?? 'auto', + }; + + logger.info(`[AI] [vision-extract] Target: ${gatewayUrl()}/api/v1/vision/extract`); + + interface CodeBlockResp { + language: string; + code: string; + } + interface VisionExtractResp { + text: string; + formulas: string[]; + diagrams: string[]; + key_points: string[]; + code_blocks: CodeBlockResp[]; + concepts: string[]; + confidence: number; + model_used: string; + processing_time_ms: number; + mode: string; + } + + try { + // 本地 Ollama 降级链 + const localHandler = async (): Promise => { + const prompt = `请对这张图片进行内容提取。提取所有可见文本、公式、图表描述、关键要点、代码块和核心概念。\n语言:${args.language ?? 'zh'}\n模式:${args.mode ?? 'auto'}`; + const result = await generateVision(args.imageBase64, prompt, '你是一个专业的视觉内容提取助手,擅长从图片中提取结构化信息。', { temperature: 0.3, maxTokens: 4096 }); + return { + text: result.content, + formulas: [], + diagrams: [], + key_points: [], + code_blocks: [], + concepts: [], + confidence: result.content.trim() ? 0.85 : 0.3, + model_used: result.model, + processing_time_ms: result.latency_ms, + mode: args.mode ?? 'auto', + }; + }; + + const { data: resp, source, requestId } = await callWithLocalFallback( + '/api/v1/vision/extract', + reqBody, + localHandler, + args.authToken, + args.userApiKey, + 90000, + ); + + const elapsed = Date.now() - startMs; + logger.info(`[AI] [vision-extract] ✔ Success (${source}): text_length=${resp.text?.length ?? 0}, formulas=${resp.formulas?.length ?? 0}, concepts=${resp.concepts?.length ?? 0}, confidence=${resp.confidence}, model=${resp.model_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`); + return { + text: resp.text, + formulas: resp.formulas ?? [], + diagrams: resp.diagrams ?? [], + keyPoints: resp.key_points ?? [], + codeBlocks: (resp.code_blocks ?? []).map((cb) => ({ + language: cb.language, + code: cb.code, + })), + concepts: resp.concepts ?? [], + confidence: resp.confidence, + modelUsed: resp.model_used, + processingTimeMs: resp.processing_time_ms, + mode: resp.mode, + requestId, + source, + }; + } catch (err) { + const elapsed = Date.now() - startMs; + const error = err instanceof Error ? err : new Error(String(err)); + logger.error(`[AI] [vision-extract] ✖ Failed after ${elapsed}ms: ${error.message}`); + if (error.cause) logger.error(`[AI] [vision-extract] Error cause: ${error.cause}`); + throw error; + } + }, + ); +} + +// ================================================================ +// 功能定义导出 +// ================================================================ + +export const feature: AIFeatureDef = { + id: 'ai_vision_extract', + name: 'AI 视觉内容提取', + version: '1.0.0', + register, +}; diff --git a/client/electron/ai/index.ts b/client/electron/ai/index.ts index 7f4638a9..433e1371 100644 --- a/client/electron/ai/index.ts +++ b/client/electron/ai/index.ts @@ -1,86 +1,88 @@ -/** - * AI Handler 统一注册入口 - * - * 汇总所有 AI 功能 handler,提供 registerAIHandlers() 函数 - * 一次性注册全部 AI IPC handler。 - */ - -import { logger } from '../logger.js'; -import type { AIFeatureDef } from './utils.js'; -import { registerOllamaHandlers, initOllama } from './ollama/index.js'; -import { registerStreamHandler } from './streamHandler.js'; - -// 导入所有 AI 功能模块 -import { feature as summarizeFeature } from './handlers/summarizeHandler.js'; -import { feature as flashcardFeature } from './handlers/flashcardHandler.js'; -import { feature as evaluateFeature } from './handlers/evaluateHandler.js'; -import { feature as feynmanFeature } from './handlers/feynmanHandler.js'; -import { feature as tagFeature } from './handlers/tagHandler.js'; -import { feature as recommendFeature } from './handlers/recommendHandler.js'; -import { feature as optimizeCardFeature } from './handlers/optimizeCardHandler.js'; -import { feature as anchorPointFeature } from './handlers/anchorPointHandler.js'; -import { feature as socraticFeature } from './handlers/socraticHandler.js'; -import { feature as predictFeature } from './handlers/predictHandler.js'; -import { feature as rescueFeature } from './handlers/rescueHandler.js'; -import { feature as visionExtractFeature } from './handlers/visionExtractHandler.js'; -import { feature as sessionAnalyzeFeature } from './handlers/sessionAnalyzeHandler.js'; -import { feature as videoAnalyzeFeature } from './handlers/videoAnalyzeHandler.js'; -import { feature as mergeNotesFeature } from './handlers/mergeNotesHandler.js'; - -// ================================================================ -// 功能注册表 -// ================================================================ - -/** 所有已注册的 AI 功能模块 */ -const features: AIFeatureDef[] = [ - summarizeFeature, - flashcardFeature, - evaluateFeature, - feynmanFeature, - tagFeature, - recommendFeature, - optimizeCardFeature, - anchorPointFeature, - socraticFeature, - predictFeature, - rescueFeature, - visionExtractFeature, - sessionAnalyzeFeature, - videoAnalyzeFeature, - mergeNotesFeature, -]; - -// ================================================================ -// 统一注册函数 -// ================================================================ - -/** - * 注册所有 AI IPC Handler - * - * 遍历功能注册表,依次调用每个功能的 register() 方法, - * 将对应的 safeHandle 绑定到 ipcMain。 - * 同时注册 Ollama 本地推理相关 IPC handler。 - */ -export function registerAIHandlers(): void { - logger.info(`[AI] Registering ${features.length} AI feature(s)...`); - for (const feat of features) { - feat.register(); - logger.info(`[AI] Registered: ${feat.name} (${feat.id}) v${feat.version}`); - } - - // 注册 Ollama 本地推理 IPC handler - registerOllamaHandlers(); - - // 注册流式输出 IPC handler - registerStreamHandler(); - - logger.info('[AI] All AI handlers registered successfully'); -} - -/** - * 初始化 AI 模块(包括 Ollama 配置加载与检测) - * 应在应用启动时、registerAIHandlers() 之前调用 - */ -export async function initAIModule(): Promise { - await initOllama(); -} +/** + * AI Handler 统一注册入口 + * + * 汇总所有 AI 功能 handler,提供 registerAIHandlers() 函数 + * 一次性注册全部 AI IPC handler。 + * + * @ai-context: AI 模块注册引擎:收集全部 AIFeatureDef 并注册 IPC;新增 AI 功能在此登记 features 数组。 + */ + +import { logger } from '../logger.js'; +import type { AIFeatureDef } from './utils.js'; +import { registerOllamaHandlers, initOllama } from './ollama/index.js'; +import { registerStreamHandler } from './streamHandler.js'; + +// 导入所有 AI 功能模块 +import { feature as summarizeFeature } from './handlers/summarizeHandler.js'; +import { feature as flashcardFeature } from './handlers/flashcardHandler.js'; +import { feature as evaluateFeature } from './handlers/evaluateHandler.js'; +import { feature as feynmanFeature } from './handlers/feynmanHandler.js'; +import { feature as tagFeature } from './handlers/tagHandler.js'; +import { feature as recommendFeature } from './handlers/recommendHandler.js'; +import { feature as optimizeCardFeature } from './handlers/optimizeCardHandler.js'; +import { feature as anchorPointFeature } from './handlers/anchorPointHandler.js'; +import { feature as socraticFeature } from './handlers/socraticHandler.js'; +import { feature as predictFeature } from './handlers/predictHandler.js'; +import { feature as rescueFeature } from './handlers/rescueHandler.js'; +import { feature as visionExtractFeature } from './handlers/visionExtractHandler.js'; +import { feature as sessionAnalyzeFeature } from './handlers/sessionAnalyzeHandler.js'; +import { feature as videoAnalyzeFeature } from './handlers/videoAnalyzeHandler.js'; +import { feature as mergeNotesFeature } from './handlers/mergeNotesHandler.js'; + +// ================================================================ +// 功能注册表 +// ================================================================ + +/** 所有已注册的 AI 功能模块 */ +const features: AIFeatureDef[] = [ + summarizeFeature, + flashcardFeature, + evaluateFeature, + feynmanFeature, + tagFeature, + recommendFeature, + optimizeCardFeature, + anchorPointFeature, + socraticFeature, + predictFeature, + rescueFeature, + visionExtractFeature, + sessionAnalyzeFeature, + videoAnalyzeFeature, + mergeNotesFeature, +]; + +// ================================================================ +// 统一注册函数 +// ================================================================ + +/** + * 注册所有 AI IPC Handler + * + * 遍历功能注册表,依次调用每个功能的 register() 方法, + * 将对应的 safeHandle 绑定到 ipcMain。 + * 同时注册 Ollama 本地推理相关 IPC handler。 + */ +export function registerAIHandlers(): void { + logger.info(`[AI] Registering ${features.length} AI feature(s)...`); + for (const feat of features) { + feat.register(); + logger.info(`[AI] Registered: ${feat.name} (${feat.id}) v${feat.version}`); + } + + // 注册 Ollama 本地推理 IPC handler + registerOllamaHandlers(); + + // 注册流式输出 IPC handler + registerStreamHandler(); + + logger.info('[AI] All AI handlers registered successfully'); +} + +/** + * 初始化 AI 模块(包括 Ollama 配置加载与检测) + * 应在应用启动时、registerAIHandlers() 之前调用 + */ +export async function initAIModule(): Promise { + await initOllama(); +} diff --git a/client/electron/ai/ollama/OllamaProvider.ts b/client/electron/ai/ollama/OllamaProvider.ts index 682e009c..5292734e 100644 --- a/client/electron/ai/ollama/OllamaProvider.ts +++ b/client/electron/ai/ollama/OllamaProvider.ts @@ -1,242 +1,244 @@ -/** - * Ollama 本地推理 — OpenAI 兼容推理客户端 - * - * 通过 Ollama 的 OpenAI 兼容 API(/v1/chat/completions)执行推理, - * 支持文本生成、单图视觉、多图分析三种模式。 - * 返回格式与远程 AI Gateway 保持一致。 - */ - -import { logger } from '../../logger.js'; -import { getOllamaConfig } from './config.js'; - -// ================================================================ -// 类型定义 -// ================================================================ - -/** 统一推理结果(与 AI Gateway 响应格式一致) */ -export interface OllamaInferenceResult { - content: string; - model: string; - tokens_used: number; - latency_ms: number; -} - -/** 超时配置 */ -const TIMEOUTS = { - text: 60_000, // 文本生成 60s - vision: 120_000, // 单图视觉 120s - multiVision: 180_000, // 多图分析 180s -}; - -// ================================================================ -// 内部辅助 -// ================================================================ - -/** 构建 OpenAI 兼容请求体 */ -function buildChatRequest( - messages: Array<{ role: string; content: unknown }>, - model: string, - temperature: number, - maxTokens: number, -) { - return { - model, - messages, - temperature, - max_tokens: maxTokens, - stream: false, - }; -} - -/** 执行 OpenAI 兼容 chat/completions 请求 */ -async function chatCompletion( - messages: Array<{ role: string; content: unknown }>, - model: string, - timeoutMs: number, - temperature = 0.7, - maxTokens = 2048, -): Promise { - const config = getOllamaConfig(); - const url = `${config.baseUrl}/v1/chat/completions`; - const startTime = Date.now(); - - const body = buildChatRequest(messages, model, temperature, maxTokens); - - logger.info(`[Ollama] → POST ${url} model=${model}, messages=${messages.length}`); - - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeoutMs); - - let resp: Response; - try { - resp = await fetch(url, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(body), - signal: controller.signal, - }); - } catch (err: unknown) { - clearTimeout(timeoutId); - const e = err as { name?: string; message?: string }; - if (e.name === 'AbortError') { - throw new Error(`[Ollama] Inference timeout after ${timeoutMs}ms`); - } - throw new Error(`[Ollama] Network error: ${e.message || String(err)}`); - } finally { - clearTimeout(timeoutId); - } - - const latencyMs = Date.now() - startTime; - - if (!resp.ok) { - const detail = await resp.text().catch(() => 'unknown'); - logger.error(`[Ollama] ✖ HTTP ${resp.status} (${latencyMs}ms): ${detail.slice(0, 300)}`); - throw new Error(`[Ollama] HTTP ${resp.status}: ${detail.slice(0, 200)}`); - } - - const data = await resp.json() as { - choices?: Array<{ message?: { content?: string } }>; - usage?: { total_tokens?: number }; - model?: string; - }; - - const content = data.choices?.[0]?.message?.content || ''; - const tokensUsed = data.usage?.total_tokens || 0; - const usedModel = data.model || model; - - logger.info(`[Ollama] ← Success (${latencyMs}ms): model=${usedModel}, tokens=${tokensUsed}, content_length=${content.length}`); - - return { - content, - model: usedModel, - tokens_used: tokensUsed, - latency_ms: latencyMs, - }; -} - -// ================================================================ -// 公共 API -// ================================================================ - -/** - * 文本生成(对应 summarize、evaluate、flashcard、tag 等功能) - * - * @param prompt 用户 prompt - * @param systemPrompt 系统 prompt - * @param options 可选参数 - */ -export async function generateText( - prompt: string, - systemPrompt = '', - options?: { temperature?: number; maxTokens?: number; model?: string }, -): Promise { - const config = getOllamaConfig(); - const model = options?.model || config.models.text; - - const messages: Array<{ role: string; content: unknown }> = []; - if (systemPrompt) { - messages.push({ role: 'system', content: systemPrompt }); - } - messages.push({ role: 'user', content: prompt }); - - return chatCompletion( - messages, - model, - TIMEOUTS.text, - options?.temperature ?? 0.7, - options?.maxTokens ?? 2048, - ); -} - -/** - * 单图视觉分析(对应 vision_extract) - * - * @param imageBase64 图片 base64(不含 data URI 前缀) - * @param prompt 分析 prompt - * @param systemPrompt 系统 prompt - */ -export async function generateVision( - imageBase64: string, - prompt: string, - systemPrompt = '', - options?: { temperature?: number; maxTokens?: number; model?: string }, -): Promise { - const config = getOllamaConfig(); - const model = options?.model || config.models.vision; - - // 确保 base64 不含 data URI 前缀 - const cleanBase64 = imageBase64.startsWith('data:image') - ? imageBase64.split(',', 2)[1] || imageBase64 - : imageBase64; - - const messages: Array<{ role: string; content: unknown }> = []; - if (systemPrompt) { - messages.push({ role: 'system', content: systemPrompt }); - } - messages.push({ - role: 'user', - content: [ - { - type: 'image_url', - image_url: { url: `data:image/png;base64,${cleanBase64}` }, - }, - { - type: 'text', - text: prompt, - }, - ], - }); - - return chatCompletion( - messages, - model, - TIMEOUTS.vision, - options?.temperature ?? 0.3, - options?.maxTokens ?? 4096, - ); -} - -/** - * 多图联合分析(对应 multimodal_analyze) - * - * @param imagesBase64 多张图片 base64 数组 - * @param prompt 分析 prompt - * @param systemPrompt 系统 prompt - */ -export async function generateVisionMulti( - imagesBase64: string[], - prompt: string, - systemPrompt = '', - options?: { temperature?: number; maxTokens?: number; model?: string }, -): Promise { - const config = getOllamaConfig(); - const model = options?.model || config.models.vision; - - const messages: Array<{ role: string; content: unknown }> = []; - if (systemPrompt) { - messages.push({ role: 'system', content: systemPrompt }); - } - - // 构建多图 + 文本的 content 数组 - const contentParts: Array> = []; - for (const img of imagesBase64) { - const cleanBase64 = img.startsWith('data:image') - ? img.split(',', 2)[1] || img - : img; - contentParts.push({ - type: 'image_url', - image_url: { url: `data:image/png;base64,${cleanBase64}` }, - }); - } - contentParts.push({ type: 'text', text: prompt }); - - messages.push({ role: 'user', content: contentParts }); - - return chatCompletion( - messages, - model, - TIMEOUTS.multiVision, - options?.temperature ?? 0.3, - options?.maxTokens ?? 4096, - ); -} +/** + * Ollama 本地推理 — OpenAI 兼容推理客户端 + * + * 通过 Ollama 的 OpenAI 兼容 API(/v1/chat/completions)执行推理, + * 支持文本生成、单图视觉、多图分析三种模式。 + * 返回格式与远程 AI Gateway 保持一致。 + * + * @ai-context: 本地 Ollama 推理封装(OpenAI 兼容 /v1/chat/completions):供各 handler 的 localHandler 使用,prompt 需适配本地小模型。 + */ + +import { logger } from '../../logger.js'; +import { getOllamaConfig } from './config.js'; + +// ================================================================ +// 类型定义 +// ================================================================ + +/** 统一推理结果(与 AI Gateway 响应格式一致) */ +export interface OllamaInferenceResult { + content: string; + model: string; + tokens_used: number; + latency_ms: number; +} + +/** 超时配置 */ +const TIMEOUTS = { + text: 60_000, // 文本生成 60s + vision: 120_000, // 单图视觉 120s + multiVision: 180_000, // 多图分析 180s +}; + +// ================================================================ +// 内部辅助 +// ================================================================ + +/** 构建 OpenAI 兼容请求体 */ +function buildChatRequest( + messages: Array<{ role: string; content: unknown }>, + model: string, + temperature: number, + maxTokens: number, +) { + return { + model, + messages, + temperature, + max_tokens: maxTokens, + stream: false, + }; +} + +/** 执行 OpenAI 兼容 chat/completions 请求 */ +async function chatCompletion( + messages: Array<{ role: string; content: unknown }>, + model: string, + timeoutMs: number, + temperature = 0.7, + maxTokens = 2048, +): Promise { + const config = getOllamaConfig(); + const url = `${config.baseUrl}/v1/chat/completions`; + const startTime = Date.now(); + + const body = buildChatRequest(messages, model, temperature, maxTokens); + + logger.info(`[Ollama] → POST ${url} model=${model}, messages=${messages.length}`); + + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + + let resp: Response; + try { + resp = await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + signal: controller.signal, + }); + } catch (err: unknown) { + clearTimeout(timeoutId); + const e = err as { name?: string; message?: string }; + if (e.name === 'AbortError') { + throw new Error(`[Ollama] Inference timeout after ${timeoutMs}ms`); + } + throw new Error(`[Ollama] Network error: ${e.message || String(err)}`); + } finally { + clearTimeout(timeoutId); + } + + const latencyMs = Date.now() - startTime; + + if (!resp.ok) { + const detail = await resp.text().catch(() => 'unknown'); + logger.error(`[Ollama] ✖ HTTP ${resp.status} (${latencyMs}ms): ${detail.slice(0, 300)}`); + throw new Error(`[Ollama] HTTP ${resp.status}: ${detail.slice(0, 200)}`); + } + + const data = await resp.json() as { + choices?: Array<{ message?: { content?: string } }>; + usage?: { total_tokens?: number }; + model?: string; + }; + + const content = data.choices?.[0]?.message?.content || ''; + const tokensUsed = data.usage?.total_tokens || 0; + const usedModel = data.model || model; + + logger.info(`[Ollama] ← Success (${latencyMs}ms): model=${usedModel}, tokens=${tokensUsed}, content_length=${content.length}`); + + return { + content, + model: usedModel, + tokens_used: tokensUsed, + latency_ms: latencyMs, + }; +} + +// ================================================================ +// 公共 API +// ================================================================ + +/** + * 文本生成(对应 summarize、evaluate、flashcard、tag 等功能) + * + * @param prompt 用户 prompt + * @param systemPrompt 系统 prompt + * @param options 可选参数 + */ +export async function generateText( + prompt: string, + systemPrompt = '', + options?: { temperature?: number; maxTokens?: number; model?: string }, +): Promise { + const config = getOllamaConfig(); + const model = options?.model || config.models.text; + + const messages: Array<{ role: string; content: unknown }> = []; + if (systemPrompt) { + messages.push({ role: 'system', content: systemPrompt }); + } + messages.push({ role: 'user', content: prompt }); + + return chatCompletion( + messages, + model, + TIMEOUTS.text, + options?.temperature ?? 0.7, + options?.maxTokens ?? 2048, + ); +} + +/** + * 单图视觉分析(对应 vision_extract) + * + * @param imageBase64 图片 base64(不含 data URI 前缀) + * @param prompt 分析 prompt + * @param systemPrompt 系统 prompt + */ +export async function generateVision( + imageBase64: string, + prompt: string, + systemPrompt = '', + options?: { temperature?: number; maxTokens?: number; model?: string }, +): Promise { + const config = getOllamaConfig(); + const model = options?.model || config.models.vision; + + // 确保 base64 不含 data URI 前缀 + const cleanBase64 = imageBase64.startsWith('data:image') + ? imageBase64.split(',', 2)[1] || imageBase64 + : imageBase64; + + const messages: Array<{ role: string; content: unknown }> = []; + if (systemPrompt) { + messages.push({ role: 'system', content: systemPrompt }); + } + messages.push({ + role: 'user', + content: [ + { + type: 'image_url', + image_url: { url: `data:image/png;base64,${cleanBase64}` }, + }, + { + type: 'text', + text: prompt, + }, + ], + }); + + return chatCompletion( + messages, + model, + TIMEOUTS.vision, + options?.temperature ?? 0.3, + options?.maxTokens ?? 4096, + ); +} + +/** + * 多图联合分析(对应 multimodal_analyze) + * + * @param imagesBase64 多张图片 base64 数组 + * @param prompt 分析 prompt + * @param systemPrompt 系统 prompt + */ +export async function generateVisionMulti( + imagesBase64: string[], + prompt: string, + systemPrompt = '', + options?: { temperature?: number; maxTokens?: number; model?: string }, +): Promise { + const config = getOllamaConfig(); + const model = options?.model || config.models.vision; + + const messages: Array<{ role: string; content: unknown }> = []; + if (systemPrompt) { + messages.push({ role: 'system', content: systemPrompt }); + } + + // 构建多图 + 文本的 content 数组 + const contentParts: Array> = []; + for (const img of imagesBase64) { + const cleanBase64 = img.startsWith('data:image') + ? img.split(',', 2)[1] || img + : img; + contentParts.push({ + type: 'image_url', + image_url: { url: `data:image/png;base64,${cleanBase64}` }, + }); + } + contentParts.push({ type: 'text', text: prompt }); + + messages.push({ role: 'user', content: contentParts }); + + return chatCompletion( + messages, + model, + TIMEOUTS.multiVision, + options?.temperature ?? 0.3, + options?.maxTokens ?? 4096, + ); +} diff --git a/client/electron/ai/ollama/OllamaService.ts b/client/electron/ai/ollama/OllamaService.ts index 6f35afa9..b607d1ec 100644 --- a/client/electron/ai/ollama/OllamaService.ts +++ b/client/electron/ai/ollama/OllamaService.ts @@ -1,349 +1,224 @@ -/** - * Ollama 本地推理 — 服务检测与模型管理 - * - * 职责: - * - 检测 Ollama 可执行文件是否存在 - * - 检测 Ollama 服务是否正在运行 - * - 获取已拉取模型列表 - * - 触发模型拉取(流式进度) - * - 健康缓存(30s TTL) - */ - -import { existsSync } from 'fs'; -import * as path from 'path'; -import { logger } from '../../logger.js'; -import { getOllamaConfig } from './config.js'; - -// ================================================================ -// 类型定义 -// ================================================================ - -/** Ollama 安装与运行状态 */ -export interface OllamaStatus { - installed: boolean; - running: boolean; - models: string[]; - version?: string; - lastChecked: number; -} - -/** 模型拉取进度回调 */ -export interface PullProgressData { - model: string; - status: 'downloading' | 'verifying' | 'complete' | 'error'; - percent: number; - completedBytes?: number; - totalBytes?: number; - error?: string; -} - -// ================================================================ -// 常量 -// ================================================================ - -/** 健康缓存 TTL(ms) */ -const HEALTH_CACHE_TTL = 30_000; - -/** 检测请求超时(ms) */ -const DETECT_TIMEOUT = 3_000; - -// ================================================================ -// 运行时状态 -// ================================================================ - -let _cachedStatus: OllamaStatus | null = null; - -// ================================================================ -// 安装检测 -// ================================================================ - -/** 获取当前平台 Ollama 可执行文件的可能路径 */ -function getOllamaBinaryPaths(): string[] { - const home = process.env.USERPROFILE || process.env.HOME || ''; - const localAppData = process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'); - - switch (process.platform) { - case 'win32': - return [ - path.join(localAppData, 'Programs', 'Ollama', 'ollama.exe'), - path.join(localAppData, 'Ollama', 'ollama.exe'), - 'C:\\Program Files\\Ollama\\ollama.exe', - ]; - case 'darwin': - return [ - '/usr/local/bin/ollama', - '/opt/homebrew/bin/ollama', - path.join(home, '.ollama', 'bin', 'ollama'), - ]; - case 'linux': - return [ - '/usr/bin/ollama', - '/usr/local/bin/ollama', - path.join(home, '.ollama', 'bin', 'ollama'), - ]; - default: - return []; - } -} - -/** 检测 Ollama 是否已安装 */ -export function isOllamaInstalled(): boolean { - const paths = getOllamaBinaryPaths(); - return paths.some((p) => existsSync(p)); -} - -// ================================================================ -// 服务检测 -// ================================================================ - -/** - * 检测 Ollama 服务是否正在运行,并获取模型列表 - * 使用 /api/tags 端点(GET),超时 3s - */ -async function detectOllamaService(): Promise<{ running: boolean; models: string[]; version?: string }> { - const config = getOllamaConfig(); - const baseUrl = config.baseUrl; - - try { - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), DETECT_TIMEOUT); - - const resp = await fetch(`${baseUrl}/api/tags`, { - method: 'GET', - signal: controller.signal, - }); - clearTimeout(timeoutId); - - if (!resp.ok) { - return { running: false, models: [] }; - } - - const data = await resp.json() as { models?: Array<{ name: string }> }; - const models = (data.models || []).map((m) => m.name); - - // 尝试获取版本号(/api/version 端点) - let version: string | undefined; - try { - const vController = new AbortController(); - const vTimeoutId = setTimeout(() => vController.abort(), 2000); - const vResp = await fetch(`${baseUrl}/api/version`, { signal: vController.signal }); - clearTimeout(vTimeoutId); - if (vResp.ok) { - const vData = await vResp.json() as { version?: string }; - version = vData.version; - } - } catch { - // 版本获取失败不影响主流程 - } - - return { running: true, models, version }; - } catch { - return { running: false, models: [] }; - } -} - -// ================================================================ -// 公共 API -// ================================================================ - -/** - * 获取 Ollama 完整状态(带缓存) - * 缓存 30s,避免频繁探测 - */ -export async function getOllamaStatus(forceRefresh = false): Promise { - // 检查缓存是否有效 - if (!forceRefresh && _cachedStatus && (Date.now() - _cachedStatus.lastChecked < HEALTH_CACHE_TTL)) { - return _cachedStatus; - } - - const installed = isOllamaInstalled(); - let running = false; - let models: string[] = []; - let version: string | undefined; - - if (installed) { - const result = await detectOllamaService(); - running = result.running; - models = result.models; - version = result.version; - } - - _cachedStatus = { - installed, - running, - models, - version, - lastChecked: Date.now(), - }; - - logger.debug(`[Ollama] Status: installed=${installed}, running=${running}, models=[${models.join(', ')}], version=${version ?? 'unknown'}`); - return _cachedStatus; -} - -/** - * 快速判断 Ollama 是否可用(已启用 + 正在运行) - * 用于 AI Handler 降级链判断,不触发网络请求(使用缓存) - */ -export function isOllamaAvailable(): boolean { - if (!_cachedStatus) return false; - // 缓存过期则视为不可用(下次 getOllamaStatus 会刷新) - if (Date.now() - _cachedStatus.lastChecked > HEALTH_CACHE_TTL) return false; - return _cachedStatus.running; -} - -/** - * 拉取模型(流式进度) - * @param modelName 模型名称(如 'qwen2.5:7b') - * @param onProgress 进度回调 - */ -export async function pullModel( - modelName: string, - onProgress?: (progress: PullProgressData) => void, -): Promise { - const config = getOllamaConfig(); - const baseUrl = config.baseUrl; - - logger.info(`[Ollama] Pulling model: ${modelName}`); - - const resp = await fetch(`${baseUrl}/api/pull`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name: modelName, stream: true }), - }); - - if (!resp.ok) { - const detail = await resp.text().catch(() => 'unknown error'); - throw new Error(`Ollama pull failed: HTTP ${resp.status} - ${detail}`); - } - - if (!resp.body) { - throw new Error('Ollama pull: no response body'); - } - - // 流式读取 NDJSON 进度 - const reader = resp.body.getReader(); - const decoder = new TextDecoder(); - let buffer = ''; - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - - buffer += decoder.decode(value, { stream: true }); - const lines = buffer.split('\n'); - buffer = lines.pop() || ''; - - for (const line of lines) { - if (!line.trim()) continue; - try { - const data = JSON.parse(line) as { - status?: string; - completed?: number; - total?: number; - error?: string; - }; - - if (data.error) { - onProgress?.({ - model: modelName, - status: 'error', - percent: 0, - error: data.error, - }); - throw new Error(`Ollama pull error: ${data.error}`); - } - - const status = data.status || ''; - if (status === 'success') { - onProgress?.({ model: modelName, status: 'complete', percent: 100 }); - logger.info(`[Ollama] Model pulled successfully: ${modelName}`); - // 刷新缓存 - _cachedStatus = null; - return; - } - - // 下载进度 - if (data.total && data.completed != null) { - const percent = Math.round((data.completed / data.total) * 100); - onProgress?.({ - model: modelName, - status: 'downloading', - percent, - completedBytes: data.completed, - totalBytes: data.total, - }); - } else if (status.includes('verif')) { - onProgress?.({ model: modelName, status: 'verifying', percent: 99 }); - } - } catch (e) { - if (e instanceof Error && e.message.startsWith('Ollama pull error')) throw e; - // JSON 解析失败,跳过该行 - } - } - } - - // 流结束但未收到 success - onProgress?.({ model: modelName, status: 'complete', percent: 100 }); +/** + * Ollama 本地推理 — 服务检测与模型管理 + * + * 职责: + * - 检测 Ollama 可执行文件是否存在 + * - 检测 Ollama 服务是否正在运行 + * - 获取已拉取模型列表 + * - 触发模型拉取(流式进度) + * - 健康缓存(30s TTL) + * + * @ai-context: Ollama 检测与状态服务:安装路径探测(Win/mac/Linux 三平台)+ /api/tags 服务探测 + 30s 状态缓存;未安装时全部静默失败(零打扰原则)。2026-07 拆分:模型管理在 ollamaModelManager.ts。 + */ + +import { existsSync } from 'fs'; +import * as path from 'path'; +import { logger } from '../../logger.js'; +import { getOllamaConfig } from './config.js'; + +// ================================================================ +// 类型定义 +// ================================================================ + +/** Ollama 安装与运行状态 */ +export interface OllamaStatus { + installed: boolean; + running: boolean; + models: string[]; + version?: string; + lastChecked: number; +} + +/** 模型拉取进度回调 */ +export interface PullProgressData { + model: string; + status: 'downloading' | 'verifying' | 'complete' | 'error'; + percent: number; + completedBytes?: number; + totalBytes?: number; + error?: string; +} + +// ================================================================ +// 常量 +// ================================================================ + +/** 健康缓存 TTL(ms) */ +const HEALTH_CACHE_TTL = 30_000; + +/** 检测请求超时(ms) */ +const DETECT_TIMEOUT = 3_000; + +// ================================================================ +// 运行时状态 +// ================================================================ + +let _cachedStatus: OllamaStatus | null = null; + +// ================================================================ +// 安装检测 +// ================================================================ + +/** 获取当前平台 Ollama 可执行文件的可能路径 */ +function getOllamaBinaryPaths(): string[] { + const home = process.env.USERPROFILE || process.env.HOME || ''; + const localAppData = process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'); + + switch (process.platform) { + case 'win32': + return [ + path.join(localAppData, 'Programs', 'Ollama', 'ollama.exe'), + path.join(localAppData, 'Ollama', 'ollama.exe'), + 'C:\\Program Files\\Ollama\\ollama.exe', + ]; + case 'darwin': + return [ + '/usr/local/bin/ollama', + '/opt/homebrew/bin/ollama', + path.join(home, '.ollama', 'bin', 'ollama'), + ]; + case 'linux': + return [ + '/usr/bin/ollama', + '/usr/local/bin/ollama', + path.join(home, '.ollama', 'bin', 'ollama'), + ]; + default: + return []; + } +} + +/** 检测 Ollama 是否已安装 */ +export function isOllamaInstalled(): boolean { + const paths = getOllamaBinaryPaths(); + return paths.some((p) => existsSync(p)); +} + +// ================================================================ +// 服务检测 +// ================================================================ + +/** + * 检测 Ollama 服务是否正在运行,并获取模型列表 + * 使用 /api/tags 端点(GET),超时 3s + */ +async function detectOllamaService(): Promise<{ running: boolean; models: string[]; version?: string }> { + const config = getOllamaConfig(); + const baseUrl = config.baseUrl; + + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), DETECT_TIMEOUT); + + const resp = await fetch(`${baseUrl}/api/tags`, { + method: 'GET', + signal: controller.signal, + }); + clearTimeout(timeoutId); + + if (!resp.ok) { + return { running: false, models: [] }; + } + + const data = await resp.json() as { models?: Array<{ name: string }> }; + const models = (data.models || []).map((m) => m.name); + + // 尝试获取版本号(/api/version 端点) + let version: string | undefined; + try { + const vController = new AbortController(); + const vTimeoutId = setTimeout(() => vController.abort(), 2000); + const vResp = await fetch(`${baseUrl}/api/version`, { signal: vController.signal }); + clearTimeout(vTimeoutId); + if (vResp.ok) { + const vData = await vResp.json() as { version?: string }; + version = vData.version; + } + } catch { + // 版本获取失败不影响主流程 + } + + return { running: true, models, version }; + } catch { + return { running: false, models: [] }; + } +} + +// ================================================================ +// 公共 API +// ================================================================ + +/** + * 获取 Ollama 完整状态(带缓存) + * 缓存 30s,避免频繁探测 + */ +export async function getOllamaStatus(forceRefresh = false): Promise { + // 检查缓存是否有效 + if (!forceRefresh && _cachedStatus && (Date.now() - _cachedStatus.lastChecked < HEALTH_CACHE_TTL)) { + return _cachedStatus; + } + + const installed = isOllamaInstalled(); + let running = false; + let models: string[] = []; + let version: string | undefined; + + if (installed) { + const result = await detectOllamaService(); + running = result.running; + models = result.models; + version = result.version; + } + + _cachedStatus = { + installed, + running, + models, + version, + lastChecked: Date.now(), + }; + + logger.debug(`[Ollama] Status: installed=${installed}, running=${running}, models=[${models.join(', ')}], version=${version ?? 'unknown'}`); + return _cachedStatus; +} + +/** + * 快速判断 Ollama 是否可用(已启用 + 正在运行) + * 用于 AI Handler 降级链判断,不触发网络请求(使用缓存) + */ +/** 使状态缓存失效(模型增删后由 ollamaModelManager 调用) */ +export function invalidateStatusCache(): void { _cachedStatus = null; } -/** - * 删除本地模型 - * @param modelName 模型名称(如 'qwen2.5:7b') - */ -export async function deleteModel(modelName: string): Promise { - const config = getOllamaConfig(); - const baseUrl = config.baseUrl; - - logger.info(`[Ollama] Deleting model: ${modelName}`); - - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 30_000); - - try { - const resp = await fetch(`${baseUrl}/api/delete`, { - method: 'DELETE', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name: modelName }), - signal: controller.signal, - }); - clearTimeout(timeoutId); - - if (!resp.ok) { - const detail = await resp.text().catch(() => 'unknown error'); - throw new Error(`Ollama delete failed: HTTP ${resp.status} - ${detail}`); - } - - logger.info(`[Ollama] Model deleted successfully: ${modelName}`); - // 清除缓存,下次获取状态时刷新模型列表 - _cachedStatus = null; - } catch (e) { - clearTimeout(timeoutId); - if (e instanceof Error && e.name === 'AbortError') { - throw new Error('Ollama delete timed out'); - } - throw e; - } -} - -/** - * 应用启动时执行初始检测(如果 autoDetect 开启) - */ -export async function initOllamaDetection(): Promise { - const config = getOllamaConfig(); - if (!config.autoDetect) { - logger.info('[Ollama] Auto-detect disabled, skipping initial detection'); - return; - } - - // 异步检测,不阻塞启动 - getOllamaStatus(true).then((status) => { - if (status.installed && status.running) { - logger.info(`[Ollama] Detected running Ollama v${status.version ?? '?'} with ${status.models.length} model(s)`); - } else if (status.installed) { - logger.info('[Ollama] Ollama installed but not running'); - } - }).catch(() => { - // 静默失败 - }); -} +export function isOllamaAvailable(): boolean { + if (!_cachedStatus) return false; + // 缓存过期则视为不可用(下次 getOllamaStatus 会刷新) + if (Date.now() - _cachedStatus.lastChecked > HEALTH_CACHE_TTL) return false; + return _cachedStatus.running; +} + +/** + * 应用启动时执行初始检测(如果 autoDetect 开启) + */ +export async function initOllamaDetection(): Promise { + const config = getOllamaConfig(); + if (!config.autoDetect) { + logger.info('[Ollama] Auto-detect disabled, skipping initial detection'); + return; + } + + // 异步检测,不阻塞启动 + getOllamaStatus(true).then((status) => { + if (status.installed && status.running) { + logger.info(`[Ollama] Detected running Ollama v${status.version ?? '?'} with ${status.models.length} model(s)`); + } else if (status.installed) { + logger.info('[Ollama] Ollama installed but not running'); + } + }).catch(() => { + // 静默失败 + }); +} + +// ─── 向后兼容 re-export(模型管理已拆至 ollamaModelManager.ts) ─── +export { pullModel, deleteModel } from './ollamaModelManager.js'; diff --git a/client/electron/ai/ollama/config.ts b/client/electron/ai/ollama/config.ts index 29028333..2711cd7a 100644 --- a/client/electron/ai/ollama/config.ts +++ b/client/electron/ai/ollama/config.ts @@ -1,152 +1,154 @@ -/** - * Ollama 本地推理 — 配置持久化模块 - * - * 配置文件统一存放于 userData/ollama-config.json, - * 与现有 ai-gateway-config.json、storage-config.json 同级。 - */ - -import { app } from 'electron'; -import * as path from 'path'; -import { readFile, writeFile } from 'fs/promises'; -import { logger } from '../../logger.js'; - -// ================================================================ -// 类型定义 -// ================================================================ - -/** 模型映射配置 */ -export interface OllamaModelMapping { - /** 通用文本模型 */ - text: string; - /** 多模态视觉模型 */ - vision: string; -} - -/** Ollama 本地推理用户配置 */ -export interface OllamaConfig { - /** 用户是否启用本地推理 */ - enabled: boolean; - /** Ollama 服务地址 */ - baseUrl: string; - /** 模型映射 */ - models: OllamaModelMapping; - /** 是否启动时自动检测 Ollama */ - autoDetect: boolean; - /** 模型下载镜像地址(国内加速),空字符串表示使用默认 */ - registryMirror: string; -} - -// ================================================================ -// 常量 -// ================================================================ - -const CONFIG_FILE_NAME = 'ollama-config.json'; - -/** 默认配置 */ -const DEFAULT_CONFIG: OllamaConfig = { - enabled: false, - baseUrl: 'http://localhost:11434', - models: { - text: 'qwen2.5:7b', - vision: 'qwen2.5vl:7b', - }, - autoDetect: true, - registryMirror: '', -}; - -// ================================================================ -// 运行时状态 -// ================================================================ - -let _config: OllamaConfig | null = null; - -// ================================================================ -// 公共 API -// ================================================================ - -/** 获取配置文件完整路径 */ -export function getConfigPath(): string { - return path.join(app.getPath('userData'), CONFIG_FILE_NAME); -} - -/** - * 获取当前 Ollama 配置 - * 首次调用时从文件加载,后续直接返回内存缓存 - */ -export function getOllamaConfig(): OllamaConfig { - if (_config) return { ..._config }; - return { ...DEFAULT_CONFIG }; -} - -/** - * 应用启动时从持久化文件加载配置 - * 在 registerOllamaHandlers 之前调用 - */ -export async function loadOllamaConfig(): Promise { - try { - const configPath = getConfigPath(); - const raw = await readFile(configPath, 'utf-8'); - const parsed = JSON.parse(raw); - _config = { - enabled: typeof parsed.enabled === 'boolean' ? parsed.enabled : DEFAULT_CONFIG.enabled, - baseUrl: typeof parsed.baseUrl === 'string' && parsed.baseUrl.trim() - ? parsed.baseUrl.trim().replace(/\/$/, '') - : DEFAULT_CONFIG.baseUrl, - models: { - text: parsed.models?.text || DEFAULT_CONFIG.models.text, - vision: parsed.models?.vision || DEFAULT_CONFIG.models.vision, - }, - autoDetect: typeof parsed.autoDetect === 'boolean' ? parsed.autoDetect : DEFAULT_CONFIG.autoDetect, - registryMirror: typeof parsed.registryMirror === 'string' ? parsed.registryMirror.trim() : DEFAULT_CONFIG.registryMirror, - }; - logger.info(`[Ollama] Config loaded: enabled=${_config.enabled}, baseUrl=${_config.baseUrl}, text=${_config.models.text}, vision=${_config.models.vision}`); - } catch { - // 文件不存在或解析失败,使用默认配置 - _config = { ...DEFAULT_CONFIG }; - logger.info('[Ollama] No persisted config found, using defaults'); - } -} - -/** - * 更新 Ollama 配置并持久化 - * 支持部分更新(merge 语义) - */ -export async function updateOllamaConfig(partial: Partial): Promise { - const current = getOllamaConfig(); - const updated: OllamaConfig = { - enabled: partial.enabled ?? current.enabled, - baseUrl: partial.baseUrl - ? partial.baseUrl.trim().replace(/\/$/, '') - : current.baseUrl, - models: { - text: partial.models?.text ?? current.models.text, - vision: partial.models?.vision ?? current.models.vision, - }, - autoDetect: partial.autoDetect ?? current.autoDetect, - registryMirror: partial.registryMirror !== undefined - ? partial.registryMirror.trim() - : current.registryMirror, - }; - - _config = updated; - - // 持久化到文件 - try { - const configPath = getConfigPath(); - await writeFile(configPath, JSON.stringify(updated, null, 2), 'utf-8'); - logger.info(`[Ollama] Config saved: enabled=${updated.enabled}, baseUrl=${updated.baseUrl}`); - } catch (err) { - logger.error('[Ollama] Failed to persist config', err); - } - - return { ...updated }; -} - -/** - * 判断本地推理是否可用(enabled + 配置有效) - * 注意:此函数不检测 Ollama 是否实际运行,仅检查配置开关 - */ -export function isLocalInferenceEnabled(): boolean { - const config = getOllamaConfig(); - return config.enabled; -} +/** + * Ollama 本地推理 — 配置持久化模块 + * + * 配置文件统一存放于 userData/ollama-config.json, + * 与现有 ai-gateway-config.json、storage-config.json 同级。 + * + * @ai-context: Ollama 配置持久化(userData/ollama-config.json 路径不可改):baseUrl/enabled/autoDetect/镜像地址;渲染进程经 IPC 读写。 + */ + +import { app } from 'electron'; +import * as path from 'path'; +import { readFile, writeFile } from 'fs/promises'; +import { logger } from '../../logger.js'; + +// ================================================================ +// 类型定义 +// ================================================================ + +/** 模型映射配置 */ +export interface OllamaModelMapping { + /** 通用文本模型 */ + text: string; + /** 多模态视觉模型 */ + vision: string; +} + +/** Ollama 本地推理用户配置 */ +export interface OllamaConfig { + /** 用户是否启用本地推理 */ + enabled: boolean; + /** Ollama 服务地址 */ + baseUrl: string; + /** 模型映射 */ + models: OllamaModelMapping; + /** 是否启动时自动检测 Ollama */ + autoDetect: boolean; + /** 模型下载镜像地址(国内加速),空字符串表示使用默认 */ + registryMirror: string; +} + +// ================================================================ +// 常量 +// ================================================================ + +const CONFIG_FILE_NAME = 'ollama-config.json'; + +/** 默认配置 */ +const DEFAULT_CONFIG: OllamaConfig = { + enabled: false, + baseUrl: 'http://localhost:11434', + models: { + text: 'qwen2.5:7b', + vision: 'qwen2.5vl:7b', + }, + autoDetect: true, + registryMirror: '', +}; + +// ================================================================ +// 运行时状态 +// ================================================================ + +let _config: OllamaConfig | null = null; + +// ================================================================ +// 公共 API +// ================================================================ + +/** 获取配置文件完整路径 */ +export function getConfigPath(): string { + return path.join(app.getPath('userData'), CONFIG_FILE_NAME); +} + +/** + * 获取当前 Ollama 配置 + * 首次调用时从文件加载,后续直接返回内存缓存 + */ +export function getOllamaConfig(): OllamaConfig { + if (_config) return { ..._config }; + return { ...DEFAULT_CONFIG }; +} + +/** + * 应用启动时从持久化文件加载配置 + * 在 registerOllamaHandlers 之前调用 + */ +export async function loadOllamaConfig(): Promise { + try { + const configPath = getConfigPath(); + const raw = await readFile(configPath, 'utf-8'); + const parsed = JSON.parse(raw); + _config = { + enabled: typeof parsed.enabled === 'boolean' ? parsed.enabled : DEFAULT_CONFIG.enabled, + baseUrl: typeof parsed.baseUrl === 'string' && parsed.baseUrl.trim() + ? parsed.baseUrl.trim().replace(/\/$/, '') + : DEFAULT_CONFIG.baseUrl, + models: { + text: parsed.models?.text || DEFAULT_CONFIG.models.text, + vision: parsed.models?.vision || DEFAULT_CONFIG.models.vision, + }, + autoDetect: typeof parsed.autoDetect === 'boolean' ? parsed.autoDetect : DEFAULT_CONFIG.autoDetect, + registryMirror: typeof parsed.registryMirror === 'string' ? parsed.registryMirror.trim() : DEFAULT_CONFIG.registryMirror, + }; + logger.info(`[Ollama] Config loaded: enabled=${_config.enabled}, baseUrl=${_config.baseUrl}, text=${_config.models.text}, vision=${_config.models.vision}`); + } catch { + // 文件不存在或解析失败,使用默认配置 + _config = { ...DEFAULT_CONFIG }; + logger.info('[Ollama] No persisted config found, using defaults'); + } +} + +/** + * 更新 Ollama 配置并持久化 + * 支持部分更新(merge 语义) + */ +export async function updateOllamaConfig(partial: Partial): Promise { + const current = getOllamaConfig(); + const updated: OllamaConfig = { + enabled: partial.enabled ?? current.enabled, + baseUrl: partial.baseUrl + ? partial.baseUrl.trim().replace(/\/$/, '') + : current.baseUrl, + models: { + text: partial.models?.text ?? current.models.text, + vision: partial.models?.vision ?? current.models.vision, + }, + autoDetect: partial.autoDetect ?? current.autoDetect, + registryMirror: partial.registryMirror !== undefined + ? partial.registryMirror.trim() + : current.registryMirror, + }; + + _config = updated; + + // 持久化到文件 + try { + const configPath = getConfigPath(); + await writeFile(configPath, JSON.stringify(updated, null, 2), 'utf-8'); + logger.info(`[Ollama] Config saved: enabled=${updated.enabled}, baseUrl=${updated.baseUrl}`); + } catch (err) { + logger.error('[Ollama] Failed to persist config', err); + } + + return { ...updated }; +} + +/** + * 判断本地推理是否可用(enabled + 配置有效) + * 注意:此函数不检测 Ollama 是否实际运行,仅检查配置开关 + */ +export function isLocalInferenceEnabled(): boolean { + const config = getOllamaConfig(); + return config.enabled; +} diff --git a/client/electron/ai/ollama/index.ts b/client/electron/ai/ollama/index.ts index ef1143a4..1c7326d8 100644 --- a/client/electron/ai/ollama/index.ts +++ b/client/electron/ai/ollama/index.ts @@ -1,122 +1,124 @@ -/** - * Ollama 本地推理 — IPC Handler 注册入口 - * - * 注册 Ollama 相关 IPC channel: - * - ollama:get-status → 返回 OllamaStatus - * - ollama:set-config → 更新配置 - * - ollama:pull-model → 触发模型下载(流式进度推送) - */ - -import { ipcMain, BrowserWindow } from 'electron'; -import { logger } from '../../logger.js'; -import { getOllamaStatus, pullModel, deleteModel, initOllamaDetection } from './OllamaService.js'; -import { loadOllamaConfig, updateOllamaConfig, getOllamaConfig } from './config.js'; - -// ================================================================ -// IPC Handler 注册 -// ================================================================ - -/** - * 注册所有 Ollama 相关 IPC Handler - * 在 registerAIHandlers() 中调用 - */ -export function registerOllamaHandlers(): void { - logger.info('[Ollama] Registering IPC handlers...'); - - // ---- 获取状态 ---- - ipcMain.handle('ollama:get-status', async (_event, forceRefresh?: boolean) => { - try { - const status = await getOllamaStatus(forceRefresh ?? false); - const config = getOllamaConfig(); - return { status, config }; - } catch (err) { - logger.error('[Ollama] get-status failed:', err); - return { - status: { installed: false, running: false, models: [], lastChecked: Date.now() }, - config: getOllamaConfig(), - }; - } - }); - - // ---- 更新配置 ---- - ipcMain.handle('ollama:set-config', async (_event, partial: Record) => { - try { - const updated = await updateOllamaConfig(partial); - logger.info(`[Ollama] Config updated via IPC: enabled=${updated.enabled}`); - return updated; - } catch (err) { - logger.error('[Ollama] set-config failed:', err); - throw err; - } - }); - - // ---- 拉取模型 ---- - ipcMain.handle('ollama:pull-model', async (event, modelName: string) => { - if (!modelName || typeof modelName !== 'string') { - throw new Error('Invalid model name'); - } - - logger.info(`[Ollama] Pull model requested: ${modelName}`); - - // 获取发送进度的窗口 - const senderWindow = BrowserWindow.fromWebContents(event.sender); - - try { - await pullModel(modelName, (progress) => { - // 向渲染进程推送进度 - if (senderWindow && !senderWindow.isDestroyed()) { - senderWindow.webContents.send('ollama:pull-progress', progress); - } - }); - return { success: true }; - } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); - logger.error(`[Ollama] Pull model failed: ${errorMsg}`); - // 推送错误进度 - if (senderWindow && !senderWindow.isDestroyed()) { - senderWindow.webContents.send('ollama:pull-progress', { - model: modelName, - status: 'error', - percent: 0, - error: errorMsg, - }); - } - throw err; - } - }); - - // ---- 删除模型 ---- - ipcMain.handle('ollama:delete-model', async (_event, modelName: string) => { - if (!modelName || typeof modelName !== 'string') { - throw new Error('Invalid model name'); - } - - logger.info(`[Ollama] Delete model requested: ${modelName}`); - - try { - await deleteModel(modelName); - return { success: true }; - } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); - logger.error(`[Ollama] Delete model failed: ${errorMsg}`); - throw err; - } - }); - - logger.info('[Ollama] All IPC handlers registered'); -} - -/** - * 初始化 Ollama 模块 - * 在应用启动时调用(registerAIHandlers 之前) - */ -export async function initOllama(): Promise { - await loadOllamaConfig(); - await initOllamaDetection(); -} - -// 统一导出 -export { getOllamaStatus, pullModel, deleteModel } from './OllamaService.js'; -export { getOllamaConfig, updateOllamaConfig, isLocalInferenceEnabled } from './config.js'; -export { generateText, generateVision, generateVisionMulti } from './OllamaProvider.js'; -export { isOllamaAvailable } from './OllamaService.js'; +/** + * Ollama 本地推理 — IPC Handler 注册入口 + * + * 注册 Ollama 相关 IPC channel: + * - ollama:get-status → 返回 OllamaStatus + * - ollama:set-config → 更新配置 + * - ollama:pull-model → 触发模型下载(流式进度推送) + * + * @ai-context: Ollama 模块 IPC 注册出口(状态/配置/模型管理通道)。 + */ + +import { ipcMain, BrowserWindow } from 'electron'; +import { logger } from '../../logger.js'; +import { getOllamaStatus, pullModel, deleteModel, initOllamaDetection } from './OllamaService.js'; +import { loadOllamaConfig, updateOllamaConfig, getOllamaConfig } from './config.js'; + +// ================================================================ +// IPC Handler 注册 +// ================================================================ + +/** + * 注册所有 Ollama 相关 IPC Handler + * 在 registerAIHandlers() 中调用 + */ +export function registerOllamaHandlers(): void { + logger.info('[Ollama] Registering IPC handlers...'); + + // ---- 获取状态 ---- + ipcMain.handle('ollama:get-status', async (_event, forceRefresh?: boolean) => { + try { + const status = await getOllamaStatus(forceRefresh ?? false); + const config = getOllamaConfig(); + return { status, config }; + } catch (err) { + logger.error('[Ollama] get-status failed:', err); + return { + status: { installed: false, running: false, models: [], lastChecked: Date.now() }, + config: getOllamaConfig(), + }; + } + }); + + // ---- 更新配置 ---- + ipcMain.handle('ollama:set-config', async (_event, partial: Record) => { + try { + const updated = await updateOllamaConfig(partial); + logger.info(`[Ollama] Config updated via IPC: enabled=${updated.enabled}`); + return updated; + } catch (err) { + logger.error('[Ollama] set-config failed:', err); + throw err; + } + }); + + // ---- 拉取模型 ---- + ipcMain.handle('ollama:pull-model', async (event, modelName: string) => { + if (!modelName || typeof modelName !== 'string') { + throw new Error('Invalid model name'); + } + + logger.info(`[Ollama] Pull model requested: ${modelName}`); + + // 获取发送进度的窗口 + const senderWindow = BrowserWindow.fromWebContents(event.sender); + + try { + await pullModel(modelName, (progress) => { + // 向渲染进程推送进度 + if (senderWindow && !senderWindow.isDestroyed()) { + senderWindow.webContents.send('ollama:pull-progress', progress); + } + }); + return { success: true }; + } catch (err) { + const errorMsg = err instanceof Error ? err.message : String(err); + logger.error(`[Ollama] Pull model failed: ${errorMsg}`); + // 推送错误进度 + if (senderWindow && !senderWindow.isDestroyed()) { + senderWindow.webContents.send('ollama:pull-progress', { + model: modelName, + status: 'error', + percent: 0, + error: errorMsg, + }); + } + throw err; + } + }); + + // ---- 删除模型 ---- + ipcMain.handle('ollama:delete-model', async (_event, modelName: string) => { + if (!modelName || typeof modelName !== 'string') { + throw new Error('Invalid model name'); + } + + logger.info(`[Ollama] Delete model requested: ${modelName}`); + + try { + await deleteModel(modelName); + return { success: true }; + } catch (err) { + const errorMsg = err instanceof Error ? err.message : String(err); + logger.error(`[Ollama] Delete model failed: ${errorMsg}`); + throw err; + } + }); + + logger.info('[Ollama] All IPC handlers registered'); +} + +/** + * 初始化 Ollama 模块 + * 在应用启动时调用(registerAIHandlers 之前) + */ +export async function initOllama(): Promise { + await loadOllamaConfig(); + await initOllamaDetection(); +} + +// 统一导出 +export { getOllamaStatus, pullModel, deleteModel } from './OllamaService.js'; +export { getOllamaConfig, updateOllamaConfig, isLocalInferenceEnabled } from './config.js'; +export { generateText, generateVision, generateVisionMulti } from './OllamaProvider.js'; +export { isOllamaAvailable } from './OllamaService.js'; diff --git a/client/electron/ai/ollama/ollamaModelManager.ts b/client/electron/ai/ollama/ollamaModelManager.ts new file mode 100644 index 00000000..970ea206 --- /dev/null +++ b/client/electron/ai/ollama/ollamaModelManager.ts @@ -0,0 +1,148 @@ +/** + * Ollama 模型管理(拉取/删除) + * + * @ai-context: 从 OllamaService.ts 拆出。pullModel 流式读取 /api/pull + * 的 NDJSON 进度(downloading→verifying→complete),progress 回调供 + * IPC 转发到渲染进程进度条;操作成功后必须 invalidateStatusCache() + * 使状态缓存失效,否则模型列表不刷新。 + * @ai-context: 模型下载走用户配置的 baseUrl(含国内镜像支持,见 + * ollama/config.ts);deleteModel 30s 超时。 + */ +import { logger } from '../../logger.js'; +import { getOllamaConfig } from './config.js'; +import { invalidateStatusCache, type PullProgressData } from './OllamaService.js'; + +/** + * 拉取模型(流式进度) + * @param modelName 模型名称(如 'qwen2.5:7b') + * @param onProgress 进度回调 + */ +export async function pullModel( + modelName: string, + onProgress?: (progress: PullProgressData) => void, +): Promise { + const config = getOllamaConfig(); + const baseUrl = config.baseUrl; + + logger.info(`[Ollama] Pulling model: ${modelName}`); + + const resp = await fetch(`${baseUrl}/api/pull`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name: modelName, stream: true }), + }); + + if (!resp.ok) { + const detail = await resp.text().catch(() => 'unknown error'); + throw new Error(`Ollama pull failed: HTTP ${resp.status} - ${detail}`); + } + + if (!resp.body) { + throw new Error('Ollama pull: no response body'); + } + + // 流式读取 NDJSON 进度 + const reader = resp.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ''; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split('\n'); + buffer = lines.pop() || ''; + + for (const line of lines) { + if (!line.trim()) continue; + try { + const data = JSON.parse(line) as { + status?: string; + completed?: number; + total?: number; + error?: string; + }; + + if (data.error) { + onProgress?.({ + model: modelName, + status: 'error', + percent: 0, + error: data.error, + }); + throw new Error(`Ollama pull error: ${data.error}`); + } + + const status = data.status || ''; + if (status === 'success') { + onProgress?.({ model: modelName, status: 'complete', percent: 100 }); + logger.info(`[Ollama] Model pulled successfully: ${modelName}`); + // 刷新缓存 + invalidateStatusCache(); + return; + } + + // 下载进度 + if (data.total && data.completed != null) { + const percent = Math.round((data.completed / data.total) * 100); + onProgress?.({ + model: modelName, + status: 'downloading', + percent, + completedBytes: data.completed, + totalBytes: data.total, + }); + } else if (status.includes('verif')) { + onProgress?.({ model: modelName, status: 'verifying', percent: 99 }); + } + } catch (e) { + if (e instanceof Error && e.message.startsWith('Ollama pull error')) throw e; + // JSON 解析失败,跳过该行 + } + } + } + + // 流结束但未收到 success + onProgress?.({ model: modelName, status: 'complete', percent: 100 }); + invalidateStatusCache(); +} + +/** + * 删除本地模型 + * @param modelName 模型名称(如 'qwen2.5:7b') + */ +export async function deleteModel(modelName: string): Promise { + const config = getOllamaConfig(); + const baseUrl = config.baseUrl; + + logger.info(`[Ollama] Deleting model: ${modelName}`); + + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 30_000); + + try { + const resp = await fetch(`${baseUrl}/api/delete`, { + method: 'DELETE', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name: modelName }), + signal: controller.signal, + }); + clearTimeout(timeoutId); + + if (!resp.ok) { + const detail = await resp.text().catch(() => 'unknown error'); + throw new Error(`Ollama delete failed: HTTP ${resp.status} - ${detail}`); + } + + logger.info(`[Ollama] Model deleted successfully: ${modelName}`); + // 清除缓存,下次获取状态时刷新模型列表 + invalidateStatusCache(); + } catch (e) { + clearTimeout(timeoutId); + if (e instanceof Error && e.name === 'AbortError') { + throw new Error('Ollama delete timed out'); + } + throw e; + } +} diff --git a/client/electron/ai/streamHandler.ts b/client/electron/ai/streamHandler.ts index 7002c364..d1f6a933 100644 --- a/client/electron/ai/streamHandler.ts +++ b/client/electron/ai/streamHandler.ts @@ -1,152 +1,154 @@ -/** - * AI 流式输出 IPC Handler - * - * 处理 ai:stream:start IPC 请求,通过 postJsonStream() 获取 SSE 流, - * 将 chunk 以 50ms 节流推送到渲染进程。 - * - * 通信协议: - * - 渲染进程 → 主进程:ipcRenderer.invoke('ai:stream:start', { requestId, method, payload }) - * - 主进程 → 渲染进程: - * - 'ai:stream:chunk' { requestId, chunk } - * - 'ai:stream:end' { requestId } - * - 'ai:stream:error' { requestId, error } - */ - -import { safeHandle } from '../ipcUtils.js'; -import { logger } from '../logger.js'; -import { postJsonStream } from './utils.js'; - -// ================================================================ -// 节流配置 -// ================================================================ - -/** IPC chunk 推送节流间隔(ms),防止高频 chunk 风暴 */ -const CHUNK_THROTTLE_MS = 50; - -/** 活跃的流式请求 AbortController 映射(requestId → controller) */ -const activeStreams = new Map(); - -// ================================================================ -// IPC Handler 注册 -// ================================================================ - -/** - * 注册 ai:stream:start handler - * - * 渲染进程通过 invoke 发起流式请求,主进程逐 chunk 推送到渲染进程。 - * 使用 50ms 节流合并高频 chunk,防止 IPC 风暴。 - */ -export function registerStreamHandler(): void { - safeHandle( - 'ai:stream:start', - async ( - event, - args: { - requestId: string; - /** API 路径,如 /api/v1/ai/summarize/stream */ - method: string; - /** 请求体 */ - payload: Record; - /** 认证 token */ - authToken?: string; - /** 用户 API Key */ - userApiKey?: string; - }, - ) => { - const { requestId, method, payload, authToken, userApiKey } = args; - const sender = event.sender; - - logger.info(`[AI] [stream] Start: requestId=${requestId}, method=${method}`); - - // 为该流式请求创建 AbortController - const abortController = new AbortController(); - activeStreams.set(requestId, abortController); - - // 50ms 节流缓冲 - let chunkBuffer = ''; - let throttleTimer: ReturnType | null = null; - let cancelled = false; - - /** 将缓冲区内的 chunk 一次性推送到渲染进程 */ - function flushChunks(): void { - if (cancelled || !chunkBuffer) return; - if (sender.isDestroyed()) return; - sender.send('ai:stream:chunk', { requestId, chunk: chunkBuffer }); - chunkBuffer = ''; - throttleTimer = null; - } - - try { - const stream = postJsonStream( - method, - payload, - authToken, - userApiKey, - ); - - for await (const chunk of stream) { - if (cancelled || abortController.signal.aborted) { - cancelled = true; - break; - } - - chunkBuffer += chunk; - - // 启动节流定时器(仅在无定时器运行时) - if (!throttleTimer) { - throttleTimer = setTimeout(flushChunks, CHUNK_THROTTLE_MS); - } - } - - // 流结束:刷出剩余缓冲 - if (throttleTimer) { - clearTimeout(throttleTimer); - throttleTimer = null; - } - flushChunks(); - - // 推送结束信号 - if (!cancelled && !sender.isDestroyed()) { - sender.send('ai:stream:end', { requestId }); - } - - logger.info(`[AI] [stream] Complete: requestId=${requestId}`); - return { ok: true, requestId }; - } catch (err) { - // 流异常:刷出剩余缓冲,推送错误信号 - if (throttleTimer) { - clearTimeout(throttleTimer); - throttleTimer = null; - } - flushChunks(); - - const errorMessage = err instanceof Error ? err.message : String(err); - logger.error(`[AI] [stream] Error: requestId=${requestId}, error=${errorMessage}`); - - if (!cancelled && !sender.isDestroyed()) { - sender.send('ai:stream:error', { requestId, error: errorMessage }); - } - - return { ok: false, requestId, error: errorMessage }; - } finally { - activeStreams.delete(requestId); - } - }, - ); - - // 注册取消流式请求的 handler - safeHandle( - 'ai:stream:cancel', - async (_event, args: { requestId: string }) => { - const { requestId } = args; - logger.info(`[AI] [stream] Cancel requested: requestId=${requestId}`); - const controller = activeStreams.get(requestId); - if (controller) { - controller.abort(); - activeStreams.delete(requestId); - logger.info(`[AI] [stream] Cancelled: requestId=${requestId}`); - } - return { ok: true }; - }, - ); -} +/** + * AI 流式输出 IPC Handler + * + * 处理 ai:stream:start IPC 请求,通过 postJsonStream() 获取 SSE 流, + * 将 chunk 以 50ms 节流推送到渲染进程。 + * + * 通信协议: + * - 渲染进程 → 主进程:ipcRenderer.invoke('ai:stream:start', { requestId, method, payload }) + * - 主进程 → 渲染进程: + * - 'ai:stream:chunk' { requestId, chunk } + * - 'ai:stream:end' { requestId } + * - 'ai:stream:error' { requestId, error } + * + * @ai-context: AI 流式请求 IPC(ai:stream:start):postJsonStream 逐 chunk 经 ai:stream:chunk/end/error 事件推回渲染进程,requestId 关联。 + */ + +import { safeHandle } from '../ipcUtils.js'; +import { logger } from '../logger.js'; +import { postJsonStream } from './utils.js'; + +// ================================================================ +// 节流配置 +// ================================================================ + +/** IPC chunk 推送节流间隔(ms),防止高频 chunk 风暴 */ +const CHUNK_THROTTLE_MS = 50; + +/** 活跃的流式请求 AbortController 映射(requestId → controller) */ +const activeStreams = new Map(); + +// ================================================================ +// IPC Handler 注册 +// ================================================================ + +/** + * 注册 ai:stream:start handler + * + * 渲染进程通过 invoke 发起流式请求,主进程逐 chunk 推送到渲染进程。 + * 使用 50ms 节流合并高频 chunk,防止 IPC 风暴。 + */ +export function registerStreamHandler(): void { + safeHandle( + 'ai:stream:start', + async ( + event, + args: { + requestId: string; + /** API 路径,如 /api/v1/ai/summarize/stream */ + method: string; + /** 请求体 */ + payload: Record; + /** 认证 token */ + authToken?: string; + /** 用户 API Key */ + userApiKey?: string; + }, + ) => { + const { requestId, method, payload, authToken, userApiKey } = args; + const sender = event.sender; + + logger.info(`[AI] [stream] Start: requestId=${requestId}, method=${method}`); + + // 为该流式请求创建 AbortController + const abortController = new AbortController(); + activeStreams.set(requestId, abortController); + + // 50ms 节流缓冲 + let chunkBuffer = ''; + let throttleTimer: ReturnType | null = null; + let cancelled = false; + + /** 将缓冲区内的 chunk 一次性推送到渲染进程 */ + function flushChunks(): void { + if (cancelled || !chunkBuffer) return; + if (sender.isDestroyed()) return; + sender.send('ai:stream:chunk', { requestId, chunk: chunkBuffer }); + chunkBuffer = ''; + throttleTimer = null; + } + + try { + const stream = postJsonStream( + method, + payload, + authToken, + userApiKey, + ); + + for await (const chunk of stream) { + if (cancelled || abortController.signal.aborted) { + cancelled = true; + break; + } + + chunkBuffer += chunk; + + // 启动节流定时器(仅在无定时器运行时) + if (!throttleTimer) { + throttleTimer = setTimeout(flushChunks, CHUNK_THROTTLE_MS); + } + } + + // 流结束:刷出剩余缓冲 + if (throttleTimer) { + clearTimeout(throttleTimer); + throttleTimer = null; + } + flushChunks(); + + // 推送结束信号 + if (!cancelled && !sender.isDestroyed()) { + sender.send('ai:stream:end', { requestId }); + } + + logger.info(`[AI] [stream] Complete: requestId=${requestId}`); + return { ok: true, requestId }; + } catch (err) { + // 流异常:刷出剩余缓冲,推送错误信号 + if (throttleTimer) { + clearTimeout(throttleTimer); + throttleTimer = null; + } + flushChunks(); + + const errorMessage = err instanceof Error ? err.message : String(err); + logger.error(`[AI] [stream] Error: requestId=${requestId}, error=${errorMessage}`); + + if (!cancelled && !sender.isDestroyed()) { + sender.send('ai:stream:error', { requestId, error: errorMessage }); + } + + return { ok: false, requestId, error: errorMessage }; + } finally { + activeStreams.delete(requestId); + } + }, + ); + + // 注册取消流式请求的 handler + safeHandle( + 'ai:stream:cancel', + async (_event, args: { requestId: string }) => { + const { requestId } = args; + logger.info(`[AI] [stream] Cancel requested: requestId=${requestId}`); + const controller = activeStreams.get(requestId); + if (controller) { + controller.abort(); + activeStreams.delete(requestId); + logger.info(`[AI] [stream] Cancelled: requestId=${requestId}`); + } + return { ok: true }; + }, + ); +} diff --git a/client/electron/ai/utils.ts b/client/electron/ai/utils.ts index 9b35e88b..a37a245f 100644 --- a/client/electron/ai/utils.ts +++ b/client/electron/ai/utils.ts @@ -1,505 +1,42 @@ -/** - * AI 网关公共工具函数 - * - * 提取自 aiHandlers.ts,包含所有 AI handler 共用的 - * POST 请求辅助函数、网关地址管理和功能注册表接口定义。 - */ - -import { app } from 'electron'; -import * as path from 'path'; -import { randomUUID } from 'crypto'; -import { readFile, writeFile } from 'fs/promises'; -import { logger } from '../logger.js'; -import { isLocalInferenceEnabled } from './ollama/config.js'; -import { isOllamaAvailable } from './ollama/OllamaService.js'; - -// ================================================================ -// 常量 -// ================================================================ - -const DEFAULT_GATEWAY_URL = 'https://entropydecrease.com'; -const GATEWAY_CONFIG_FILE = 'ai-gateway-config.json'; - -// ── 运行时网关地址(渲染进程通过 IPC 同步) ── -let _runtimeGatewayUrl: string | null = null; - -/** 记录 gatewayUrl() 是否已打印过首次解析日志,避免重复输出 */ -let _gatewayFirstResolveLogged = false; - -/** - * 判定当前是否为开发模式 - * 可靠依据:electron:dev 脚本设置 NODE_ENV=development,安装包运行时 app.isPackaged=true - */ -export function isDevMode(): boolean { - return process.env.NODE_ENV === 'development' || !app.isPackaged; -} - -/** - * 获取 AI 网关地址 - * - * 按模式分流优先级: - * - 开发模式:环境变量 > 运行时 IPC > 默认值 - * - 生产模式:运行时 IPC > 持久化文件(已存入_runtimeGatewayUrl) > 环境变量 > 默认值 - */ -export function gatewayUrl(): string { - const url = _resolveGatewayUrl(); - if (!_gatewayFirstResolveLogged) { - _gatewayFirstResolveLogged = true; - const dev = isDevMode(); - const source = dev - ? (process.env.VITE_AI_GATEWAY_URL - ? `env (VITE_AI_GATEWAY_URL=${process.env.VITE_AI_GATEWAY_URL})` - : _runtimeGatewayUrl - ? 'runtime (IPC)' - : 'DEFAULT (hardcoded fallback)') - : (_runtimeGatewayUrl - ? 'runtime (IPC/persisted)' - : process.env.VITE_AI_GATEWAY_URL - ? `env (VITE_AI_GATEWAY_URL=${process.env.VITE_AI_GATEWAY_URL})` - : 'DEFAULT (hardcoded fallback)'); - logger.info(`[AI] Gateway URL resolved: ${url} [source: ${source}, mode: ${dev ? 'dev' : 'prod'}]`); - if (!process.env.VITE_AI_GATEWAY_URL && !_runtimeGatewayUrl) { - logger.warn('[AI] Gateway URL fell back to DEFAULT. Set VITE_AI_GATEWAY_URL in .env or configure via AI settings.'); - } - } - return url; -} - -/** 内部解析逻辑,按模式分流优先级 */ -function _resolveGatewayUrl(): string { - if (isDevMode()) { - // 开发模式:环境变量优先,持久化不覆盖开发配置 - return process.env.VITE_AI_GATEWAY_URL || _runtimeGatewayUrl || DEFAULT_GATEWAY_URL; - } - // 生产模式:运行时/持久化 > 环境变量 > 默认值 - return _runtimeGatewayUrl || process.env.VITE_AI_GATEWAY_URL || DEFAULT_GATEWAY_URL; -} - -/** - * 设置运行时网关地址(由渲染进程通过 IPC 调用) - * 同时持久化到 userData 目录,确保主进程重启后仍可用 - */ -export async function setRuntimeGatewayUrl(url: string): Promise { - _runtimeGatewayUrl = url; - // 重置首次解析日志标记,使下次 gatewayUrl() 重新打印来源 - _gatewayFirstResolveLogged = false; - logger.info(`[AI] Runtime gateway URL set via IPC: ${url}`); - // 开发模式不写入持久化文件,防止调试数据污染生产配置 - if (isDevMode()) { - logger.info('[AI] Dev mode: skip persisting gateway URL to file'); - return; - } - // 持久化到文件 - try { - const configPath = path.join(app.getPath('userData'), GATEWAY_CONFIG_FILE); - await writeFile(configPath, JSON.stringify({ gatewayUrl: url }), 'utf-8'); - } catch (err) { - logger.error('[AI-Gateway] Failed to persist gateway URL', err); - } -} - -/** - * 应用启动时从持久化文件加载网关地址 - * 在 registerAIHandlers 之前调用 - */ -export async function loadPersistedGatewayUrl(): Promise { - if (isDevMode()) { - logger.info('[AI] Dev mode: skip loading persisted gateway URL (using .env config)'); - return; - } - try { - const configPath = path.join(app.getPath('userData'), GATEWAY_CONFIG_FILE); - const raw = await readFile(configPath, 'utf-8'); - const config = JSON.parse(raw); - if (config.gatewayUrl) { - _runtimeGatewayUrl = config.gatewayUrl; - logger.info(`[AI] Loaded persisted gateway URL from file: ${config.gatewayUrl}`); - } - } catch { - // 文件不存在或解析失败,静默忽略 - } -} - -// ================================================================ -// AI 功能注册表接口定义 -// ================================================================ - -/** - * AI 功能定义接口 - * - * 每个 AI handler 文件导出一个符合此接口的对象, - * 由 ai/index.ts 统一收集并注册到 IPC 系统。 - */ -export interface AIFeatureDef { - /** 功能唯一标识符,对应 IPC channel 名称 */ - id: string; - /** 功能显示名称 */ - name: string; - /** 功能版本 */ - version: string; - /** 注册函数,由注册引擎调用 */ - register: () => void; -} - -// ================================================================ -// 通用 POST 请求辅助函数 -// ================================================================ - -/** - * 通用 POST 请求辅助函数: - * 1. 将请求体序列化为 JSON - * 2. 如有 authToken,添加 Authorization header - * 3. HTTP 失败时抛出包含状态码和详情的错误字符串 - * 4. 返回解析后的 JSON 响应 - */ -export async function postJson( - apiPath: string, - body: TReq, - authToken?: string, - userApiKey?: string, - timeoutMs: number = 60000, -): Promise<{ data: TRes; requestId: string | undefined }> { - const base = gatewayUrl(); - if (!base) { - throw new Error('[AI] Gateway URL not configured. Set VITE_AI_GATEWAY_URL in .env or configure via AI settings'); - } - const url = `${base}${apiPath}`; - const startTime = Date.now(); - const clientRequestId = randomUUID(); - - // ── 请求前日志 ── - logger.info(`[AI] → POST ${url} [req-id: ${clientRequestId}]`); - logger.debug(`[AI] Request config: timeout=${timeoutMs}ms, hasAuth=${!!authToken}, hasUserKey=${!!userApiKey}, bodyKeys=${Object.keys(body as Record).join(',')}`); - - const headers: Record = { - 'Content-Type': 'application/json', - 'X-Request-ID': clientRequestId, - }; - if (authToken) { - headers['Authorization'] = `Bearer ${authToken}`; - } - if (userApiKey) { - headers['X-User-API-Key'] = userApiKey; - } - - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeoutMs); - - let resp: Response; - try { - resp = await fetch(url, { - method: 'POST', - headers, - body: JSON.stringify(body), - signal: controller.signal, - }); - } catch (networkError: unknown) { - const elapsed = Date.now() - startTime; - const err = networkError as { name?: string; message?: string; cause?: unknown }; - if (err.name === 'AbortError') { - logger.error(`[AI] ✖ TIMEOUT ${url} after ${elapsed}ms`); - throw new Error(`Request timeout after ${timeoutMs}ms`); - } - // 详细网络错误诊断 - const cause = err.cause ? String(err.cause) : ''; - const errDetail = err.message || String(networkError); - logger.error(`[AI] ✖ NETWORK_ERROR ${url} after ${elapsed}ms: ${errDetail}${cause ? ` (cause: ${cause})` : ''}`); - // 识别常见网络错误码 - if (/ECONNREFUSED/i.test(errDetail)) { - logger.error('[AI] Hint: Connection refused — check if AI Gateway service is running and the URL is correct'); - } else if (/ENOTFOUND/i.test(errDetail)) { - logger.error('[AI] Hint: DNS resolution failed — check the gateway URL hostname'); - } else if (/ETIMEDOUT/i.test(errDetail)) { - logger.error('[AI] Hint: Connection timed out — check network connectivity and firewall rules'); - } - throw new Error(`Network error: ${errDetail}`); - } finally { - clearTimeout(timeoutId); - } - - const elapsed = Date.now() - startTime; - const requestId = resp.headers.get('ai-gateway-request-id') ?? undefined; - - if (!resp.ok) { - const detail = await resp.text().catch(() => 'unknown error'); - // 截取响应体前 500 字符防止日志爆炸 - const detailPreview = detail.length > 500 ? `${detail.slice(0, 500)}...(+${detail.length - 500} chars)` : detail; - logger.error(`[AI] ✖ HTTP ${resp.status} ${url} (${elapsed}ms) [req-id: ${requestId ?? clientRequestId}]: ${detailPreview}`); - throw new Error(`HTTP ${resp.status}: ${detail}`); - } - - logger.info(`[AI] ← ${resp.status} ${url} (${elapsed}ms)${requestId ? ` [req-id: ${requestId}]` : ''}`); - - try { - const data = (await resp.json()) as TRes; - return { data, requestId }; - } catch (e) { - logger.error(`[AI] Response JSON parse error for ${url}: ${e}`); - throw new Error(`Response parse error: ${e}`); - } -} - -/** - * Multipart POST 请求辅助函数: - * 1. 不设置 Content-Type header(Node.js fetch 自动设置 multipart/form-data; boundary=...) - * 2. body 直接传 FormData(不做 JSON.stringify) - * 3. 默认超时 300000ms(5 分钟,视频文件较大) - * 4. 其余逻辑(gatewayUrl、AbortController、日志、request-id、错误处理)与 postJson 保持一致 - */ -export async function postMultipart( - apiPath: string, - formData: FormData, - authToken?: string, - userApiKey?: string, - timeoutMs: number = 300000, -): Promise<{ data: TRes; requestId: string | undefined }> { - const base = gatewayUrl(); - if (!base) { - throw new Error('[AI] Gateway URL not configured. Set VITE_AI_GATEWAY_URL in .env or configure via AI settings'); - } - const url = `${base}${apiPath}`; - const startTime = Date.now(); - const clientRequestId = randomUUID(); - - // ── 请求前日志 ── - logger.info(`[AI] → POST ${url} [req-id: ${clientRequestId}]`); - logger.debug(`[AI] Request config: timeout=${timeoutMs}ms, hasAuth=${!!authToken}, hasUserKey=${!!userApiKey}, body=FormData`); - - const headers: Record = { - 'X-Request-ID': clientRequestId, - }; - if (authToken) { - headers['Authorization'] = `Bearer ${authToken}`; - } - if (userApiKey) { - headers['X-User-API-Key'] = userApiKey; - } - - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeoutMs); - - let resp: Response; - try { - resp = await fetch(url, { - method: 'POST', - headers, - body: formData, - signal: controller.signal, - }); - } catch (networkError: unknown) { - const elapsed = Date.now() - startTime; - const err = networkError as { name?: string; message?: string; cause?: unknown }; - if (err.name === 'AbortError') { - logger.error(`[AI] ✖ TIMEOUT ${url} after ${elapsed}ms`); - throw new Error(`Request timeout after ${timeoutMs}ms`); - } - // 详细网络错误诊断 - const cause = err.cause ? String(err.cause) : ''; - const errDetail = err.message || String(networkError); - logger.error(`[AI] ✖ NETWORK_ERROR ${url} after ${elapsed}ms: ${errDetail}${cause ? ` (cause: ${cause})` : ''}`); - // 识别常见网络错误码 - if (/ECONNREFUSED/i.test(errDetail)) { - logger.error('[AI] Hint: Connection refused — check if AI Gateway service is running and the URL is correct'); - } else if (/ENOTFOUND/i.test(errDetail)) { - logger.error('[AI] Hint: DNS resolution failed — check the gateway URL hostname'); - } else if (/ETIMEDOUT/i.test(errDetail)) { - logger.error('[AI] Hint: Connection timed out — check network connectivity and firewall rules'); - } - throw new Error(`Network error: ${errDetail}`); - } finally { - clearTimeout(timeoutId); - } - - const elapsed = Date.now() - startTime; - const requestId = resp.headers.get('ai-gateway-request-id') ?? undefined; - - if (!resp.ok) { - const detail = await resp.text().catch(() => 'unknown error'); - // 截取响应体前 500 字符防止日志爆炸 - const detailPreview = detail.length > 500 ? `${detail.slice(0, 500)}...(+${detail.length - 500} chars)` : detail; - logger.error(`[AI] ✖ HTTP ${resp.status} ${url} (${elapsed}ms) [req-id: ${requestId ?? clientRequestId}]: ${detailPreview}`); - throw new Error(`HTTP ${resp.status}: ${detail}`); - } - - logger.info(`[AI] ← ${resp.status} ${url} (${elapsed}ms)${requestId ? ` [req-id: ${requestId}]` : ''}`); - - try { - const data = (await resp.json()) as TRes; - return { data, requestId }; - } catch (e) { - logger.error(`[AI] Response JSON parse error for ${url}: ${e}`); - throw new Error(`Response parse error: ${e}`); - } -} - -// ================================================================ -// 本地 Ollama 降级链 -// ================================================================ - -/** - * 带本地 Ollama 降级的调用函数 - * - * 逻辑: - * 1. 检查 OllamaConfig.enabled && OllamaService.isRunning() - * 2. 是 → 调用 localHandler(),成功则返回 { source: 'local' } - * 3. 本地失败/未启用 → 调用现有 postJson()(远程 AI Gateway) - * - * @param apiPath 远程 API 路径 - * @param body 请求体 - * @param localHandler 本地 Ollama 调用函数 - * @param authToken 认证 token - * @param userApiKey 用户 API Key - * @param timeoutMs 远程调用超时 - */ -export async function callWithLocalFallback( - apiPath: string, - body: TReq, - localHandler: () => Promise, - authToken?: string, - userApiKey?: string, - timeoutMs: number = 60000, -): Promise<{ data: TRes; source: 'local' | 'remote'; requestId?: string }> { - // 检查本地 Ollama 是否可用 - if (isLocalInferenceEnabled() && isOllamaAvailable()) { - try { - const localResult = await localHandler(); - logger.info(`[AI] ← Local Ollama success for ${apiPath}`); - return { data: localResult, source: 'local' }; - } catch (localErr) { - const errMsg = localErr instanceof Error ? localErr.message : String(localErr); - logger.warn(`[AI] Local Ollama failed for ${apiPath}, falling back to remote: ${errMsg}`); - // 本地失败,降级到远程 - } - } - - // 远程 AI Gateway 调用 - const { data, requestId } = await postJson( - apiPath, - body, - authToken, - userApiKey, - timeoutMs, - ); - return { data, source: 'remote', requestId }; -} - -// ================================================================ -// 流式 POST 请求辅助函数(SSE 解析) -// ================================================================ - -/** - * 流式 POST 请求:解析 SSE data: 行,逐 chunk yield 文本 - * - * @param apiPath API 路径(如 /api/v1/ai/summarize/stream) - * @param body 请求体 - * @param authToken 认证 token - * @param userApiKey 用户 API Key - * @param timeoutMs 超时时间 - */ -export async function* postJsonStream( - apiPath: string, - body: TReq, - authToken?: string, - userApiKey?: string, - timeoutMs: number = 300000, -): AsyncGenerator { - const base = gatewayUrl(); - if (!base) { - throw new Error('[AI] Gateway URL not configured'); - } - const url = `${base}${apiPath}`; - const clientRequestId = randomUUID(); - - logger.info(`[AI] → POST (stream) ${url} [req-id: ${clientRequestId}]`); - - const headers: Record = { - 'Content-Type': 'application/json', - 'X-Request-ID': clientRequestId, - }; - if (authToken) { - headers['Authorization'] = `Bearer ${authToken}`; - } - if (userApiKey) { - headers['X-User-API-Key'] = userApiKey; - } - - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeoutMs); - - let resp: Response; - try { - resp = await fetch(url, { - method: 'POST', - headers, - body: JSON.stringify(body), - signal: controller.signal, - }); - } catch (networkError: unknown) { - const err = networkError as { name?: string; message?: string }; - if (err.name === 'AbortError') { - throw new Error(`Stream request timeout after ${timeoutMs}ms`); - } - throw new Error(`Stream network error: ${err.message || String(networkError)}`); - } finally { - clearTimeout(timeoutId); - } - - const requestId = resp.headers.get('ai-gateway-request-id') ?? undefined; - - if (!resp.ok) { - const detail = await resp.text().catch(() => 'unknown error'); - logger.error(`[AI] ✖ Stream HTTP ${resp.status} ${url} [req-id: ${requestId ?? clientRequestId}]: ${detail.slice(0, 200)}`); - throw new Error(`Stream HTTP ${resp.status}: ${detail}`); - } - - logger.info(`[AI] ← Stream started ${url}${requestId ? ` [req-id: ${requestId}]` : ''}`); - - if (!resp.body) { - throw new Error('Stream response body is null'); - } - - const reader = resp.body.getReader(); - const decoder = new TextDecoder(); - let buffer = ''; - - try { - while (true) { - const { done, value } = await reader.read(); - if (done) break; - - buffer += decoder.decode(value, { stream: true }); - - // 按 \n\n 分割 SSE 事件 - const events = buffer.split('\n\n'); - buffer = events.pop() || ''; - - for (const event of events) { - const lines = event.split('\n'); - for (const line of lines) { - if (line.startsWith('data: ')) { - const data = line.slice(6).trim(); - if (data === '[DONE]') { - return; - } - try { - const parsed = JSON.parse(data); - if (parsed.error) { - throw new Error(`Stream error: ${parsed.error}`); - } - if (parsed.chunk) { - yield parsed.chunk; - } - } catch (e) { - // JSON 解析失败,尝试作为纯文本 - if (data && data !== '[DONE]') { - yield data; - } - } - } - } - } - } - } finally { - reader.releaseLock(); - } -} +/** + * AI 网关公共工具 — 统一出口 barrel + * + * @ai-context: 2026-07 拆分——地址管理在 gatewayConfig、HTTP 请求在 + * gatewayHttp、SSE 流式在 gatewayStream;本文件保留 AIFeatureDef 接口 + * 定义并 re-export 全部符号,全部 handler 的旧导入路径零改动。 + */ + +// ================================================================ +// AI 功能注册表接口定义 +// ================================================================ + +/** + * AI 功能定义接口 + * + * 每个 AI handler 文件导出一个符合此接口的对象, + * 由 ai/index.ts 统一收集并注册到 IPC 系统。 + */ +export interface AIFeatureDef { + /** 功能唯一标识符,对应 IPC channel 名称 */ + id: string; + /** 功能显示名称 */ + name: string; + /** 功能版本 */ + version: string; + /** 注册函数,由注册引擎调用 */ + register: () => void; +} + +// ================================================================ +// 向后兼容 re-export +// ================================================================ + +export { + isDevMode, gatewayUrl, setRuntimeGatewayUrl, loadPersistedGatewayUrl, +} from './gatewayConfig.js'; +export { + postJson, postMultipart, callWithLocalFallback, +} from './gatewayHttp.js'; +export { + postJsonStream, +} from './gatewayStream.js'; diff --git a/client/electron/audioCapture.ts b/client/electron/audioCapture.ts index 54c8420a..85757a9b 100644 --- a/client/electron/audioCapture.ts +++ b/client/electron/audioCapture.ts @@ -1,201 +1,203 @@ -/** - * Electron 主进程系统音频捕获模块 - * - * 架构: - * 1. 主进程使用 desktopCapturer.getSources({ types: ['screen'] }) 枚举屏幕源作为音频环回候选 - * 2. 将音频 sourceId 传递给渲染进程 - * 3. 渲染进程通过 getUserMedia + chromeMediaSource: 'desktop' 获取 MediaStream - * 4. 渲染进程使用 Web Audio API (AudioContext + ScriptProcessor) 切片 - * 5. PCM 数据块通过 IPC 回传主进程,添加单调时间戳后推送给消费者 - */ - -import { desktopCapturer, DesktopCapturerSource, BrowserWindow } from 'electron'; -import { logger } from './logger'; - -// ================================================================ -// 类型定义 -// ================================================================ - -/** 音频源信息 */ -export interface AudioSourceInfo { - id: string; - name: string; -} - -/** 音频捕获配置 */ -export interface AudioCaptureOptions { - chunkDurationMs: number; // 音频块时长(ms),默认 5000 - sampleRate: number; // 采样率,默认 16000 - channels: number; // 声道数,默认 1(单声道) -} - -/** 音频块数据(主进程 → 渲染进程) */ -export interface AudioChunk { - audioBuffer: ArrayBuffer; // PCM Float32 数据 - sampleRate: number; - channels: number; - durationMs: number; - timestamp: number; // 单调递增时间戳 (ms) -} - -/** 渲染进程上报的原始音频块 */ -interface RendererAudioChunk { - audioBuffer: ArrayBuffer; - sampleRate: number; - channels: number; - durationMs: number; -} - -// ================================================================ -// 默认配置 -// ================================================================ - -const DEFAULT_OPTIONS: AudioCaptureOptions = { - chunkDurationMs: 5000, - sampleRate: 16000, - channels: 1, -}; - -/** 单调递增时间戳生成器 */ -let lastTimestamp = 0; -function monotonicTimestamp(): number { - const now = Date.now(); - lastTimestamp = now > lastTimestamp ? now : lastTimestamp + 1; - return lastTimestamp; -} - -// ================================================================ -// 音频源枚举 -// ================================================================ - -/** - * 列出所有可用的系统音频源 - * - * Electron 中系统音频环回(WASAPI Loopback)通过桌面捕获源实现: - * 任意 screen/window 源均可配合 getUserMedia({ chromeMediaSource: 'desktop' }) - * 捕获系统音频。因此这里枚举 screen 类型源作为音频采集候选。 - */ -export async function listAudioSources(): Promise { - const sources: DesktopCapturerSource[] = await desktopCapturer.getSources({ - types: ['screen'], - thumbnailSize: { width: 1, height: 1 }, // 枚举不需要缩略图 - }); - - return sources.map((src) => ({ - id: src.id, - name: `系统音频 - ${src.name}`, - })); -} - -// ================================================================ -// 音频捕获管理器 -// ================================================================ - -export class AudioCapture { - private readonly options: AudioCaptureOptions; - private readonly onChunk: (chunk: AudioChunk) => void; - private capturing = false; - private disposed = false; - private boundWin: BrowserWindow | null = null; - - constructor( - options: Partial, - onChunk: (chunk: AudioChunk) => void, - ) { - this.options = { ...DEFAULT_OPTIONS, ...options }; - this.onChunk = onChunk; - } - - /** 是否正在捕获 */ - get isCapturing(): boolean { - return this.capturing; - } - - /** 当前配置(只读) */ - get config(): Readonly { - return this.options; - } - - /** - * 开始音频捕获 - * - * 1. 如果未指定 sourceId,自动选择第一个可用的系统音频源 - * 2. 向渲染进程发送启动指令(含 sourceId + 配置) - * 3. 渲染进程负责 getUserMedia 和音频切片 - */ - async start(win: BrowserWindow, sourceId?: string): Promise { - if (this.capturing || this.disposed) return; - - // 解析音频源 - let resolvedSourceId = sourceId ?? null; - if (!resolvedSourceId) { - const sources = await listAudioSources(); - if (sources.length === 0) { - console.warn('[AudioCapture] 未找到可用的系统音频源'); - throw new Error('No audio source available'); - } - resolvedSourceId = sources[0].id; - logger.info(`[AudioCapture] 自动选择音频源: ${sources[0].name} (${resolvedSourceId})`); - } - - this.capturing = true; - this.boundWin = win; - - logger.info( - `[AudioCapture] 开始捕获, sourceId=${resolvedSourceId}, ` + - `chunkDurationMs=${this.options.chunkDurationMs}, ` + - `sampleRate=${this.options.sampleRate}, channels=${this.options.channels}`, - ); - - // 通知渲染进程开始音频采集 - if (!win.isDestroyed()) { - win.webContents.send('audio_capture_do_start', { - sourceId: resolvedSourceId, - options: this.options, - }); - } - } - - /** - * 停止音频捕获 - */ - stop(): void { - if (!this.capturing) return; - - this.capturing = false; - logger.info('[AudioCapture] 停止捕获'); - - // 通知渲染进程停止音频采集 - if (this.boundWin && !this.boundWin.isDestroyed()) { - this.boundWin.webContents.send('audio_capture_do_stop'); - } - this.boundWin = null; - } - - /** - * 接收来自渲染进程的音频块数据 - * 由 IPC handler 调用,添加单调时间戳后通过回调发出 - */ - handleRendererChunk(data: RendererAudioChunk): void { - if (!this.capturing || this.disposed) return; - - const chunk: AudioChunk = { - audioBuffer: data.audioBuffer, - sampleRate: data.sampleRate, - channels: data.channels, - durationMs: data.durationMs, - timestamp: monotonicTimestamp(), - }; - - this.onChunk(chunk); - } - - /** - * 销毁实例,释放所有资源 - */ - dispose(): void { - this.stop(); - this.disposed = true; - logger.info('[AudioCapture] 已销毁'); - } -} +/** + * Electron 主进程系统音频捕获模块 + * + * 架构: + * 1. 主进程使用 desktopCapturer.getSources({ types: ['screen'] }) 枚举屏幕源作为音频环回候选 + * 2. 将音频 sourceId 传递给渲染进程 + * 3. 渲染进程通过 getUserMedia + chromeMediaSource: 'desktop' 获取 MediaStream + * 4. 渲染进程使用 Web Audio API (AudioContext + ScriptProcessor) 切片 + * 5. PCM 数据块通过 IPC 回传主进程,添加单调时间戳后推送给消费者 + * + * @ai-context: 系统音频捕获:渲染进程 getDisplayMedia 采集、主进程聚合分块。 + */ + +import { desktopCapturer, DesktopCapturerSource, BrowserWindow } from 'electron'; +import { logger } from './logger'; + +// ================================================================ +// 类型定义 +// ================================================================ + +/** 音频源信息 */ +export interface AudioSourceInfo { + id: string; + name: string; +} + +/** 音频捕获配置 */ +export interface AudioCaptureOptions { + chunkDurationMs: number; // 音频块时长(ms),默认 5000 + sampleRate: number; // 采样率,默认 16000 + channels: number; // 声道数,默认 1(单声道) +} + +/** 音频块数据(主进程 → 渲染进程) */ +export interface AudioChunk { + audioBuffer: ArrayBuffer; // PCM Float32 数据 + sampleRate: number; + channels: number; + durationMs: number; + timestamp: number; // 单调递增时间戳 (ms) +} + +/** 渲染进程上报的原始音频块 */ +interface RendererAudioChunk { + audioBuffer: ArrayBuffer; + sampleRate: number; + channels: number; + durationMs: number; +} + +// ================================================================ +// 默认配置 +// ================================================================ + +const DEFAULT_OPTIONS: AudioCaptureOptions = { + chunkDurationMs: 5000, + sampleRate: 16000, + channels: 1, +}; + +/** 单调递增时间戳生成器 */ +let lastTimestamp = 0; +function monotonicTimestamp(): number { + const now = Date.now(); + lastTimestamp = now > lastTimestamp ? now : lastTimestamp + 1; + return lastTimestamp; +} + +// ================================================================ +// 音频源枚举 +// ================================================================ + +/** + * 列出所有可用的系统音频源 + * + * Electron 中系统音频环回(WASAPI Loopback)通过桌面捕获源实现: + * 任意 screen/window 源均可配合 getUserMedia({ chromeMediaSource: 'desktop' }) + * 捕获系统音频。因此这里枚举 screen 类型源作为音频采集候选。 + */ +export async function listAudioSources(): Promise { + const sources: DesktopCapturerSource[] = await desktopCapturer.getSources({ + types: ['screen'], + thumbnailSize: { width: 1, height: 1 }, // 枚举不需要缩略图 + }); + + return sources.map((src) => ({ + id: src.id, + name: `系统音频 - ${src.name}`, + })); +} + +// ================================================================ +// 音频捕获管理器 +// ================================================================ + +export class AudioCapture { + private readonly options: AudioCaptureOptions; + private readonly onChunk: (chunk: AudioChunk) => void; + private capturing = false; + private disposed = false; + private boundWin: BrowserWindow | null = null; + + constructor( + options: Partial, + onChunk: (chunk: AudioChunk) => void, + ) { + this.options = { ...DEFAULT_OPTIONS, ...options }; + this.onChunk = onChunk; + } + + /** 是否正在捕获 */ + get isCapturing(): boolean { + return this.capturing; + } + + /** 当前配置(只读) */ + get config(): Readonly { + return this.options; + } + + /** + * 开始音频捕获 + * + * 1. 如果未指定 sourceId,自动选择第一个可用的系统音频源 + * 2. 向渲染进程发送启动指令(含 sourceId + 配置) + * 3. 渲染进程负责 getUserMedia 和音频切片 + */ + async start(win: BrowserWindow, sourceId?: string): Promise { + if (this.capturing || this.disposed) return; + + // 解析音频源 + let resolvedSourceId = sourceId ?? null; + if (!resolvedSourceId) { + const sources = await listAudioSources(); + if (sources.length === 0) { + console.warn('[AudioCapture] 未找到可用的系统音频源'); + throw new Error('No audio source available'); + } + resolvedSourceId = sources[0].id; + logger.info(`[AudioCapture] 自动选择音频源: ${sources[0].name} (${resolvedSourceId})`); + } + + this.capturing = true; + this.boundWin = win; + + logger.info( + `[AudioCapture] 开始捕获, sourceId=${resolvedSourceId}, ` + + `chunkDurationMs=${this.options.chunkDurationMs}, ` + + `sampleRate=${this.options.sampleRate}, channels=${this.options.channels}`, + ); + + // 通知渲染进程开始音频采集 + if (!win.isDestroyed()) { + win.webContents.send('audio_capture_do_start', { + sourceId: resolvedSourceId, + options: this.options, + }); + } + } + + /** + * 停止音频捕获 + */ + stop(): void { + if (!this.capturing) return; + + this.capturing = false; + logger.info('[AudioCapture] 停止捕获'); + + // 通知渲染进程停止音频采集 + if (this.boundWin && !this.boundWin.isDestroyed()) { + this.boundWin.webContents.send('audio_capture_do_stop'); + } + this.boundWin = null; + } + + /** + * 接收来自渲染进程的音频块数据 + * 由 IPC handler 调用,添加单调时间戳后通过回调发出 + */ + handleRendererChunk(data: RendererAudioChunk): void { + if (!this.capturing || this.disposed) return; + + const chunk: AudioChunk = { + audioBuffer: data.audioBuffer, + sampleRate: data.sampleRate, + channels: data.channels, + durationMs: data.durationMs, + timestamp: monotonicTimestamp(), + }; + + this.onChunk(chunk); + } + + /** + * 销毁实例,释放所有资源 + */ + dispose(): void { + this.stop(); + this.disposed = true; + logger.info('[AudioCapture] 已销毁'); + } +} diff --git a/client/electron/captureHandlers.ts b/client/electron/captureHandlers.ts index b0b3423e..2422be10 100644 --- a/client/electron/captureHandlers.ts +++ b/client/electron/captureHandlers.ts @@ -1,421 +1,26 @@ -/** - * 屏幕截图 & 系统音频 & 视频录制 IPC Handler - * - * 从 main.ts 拆分而来,管理截图采集、音频捕获和视频录制的生命周期。 - */ - -import { BrowserWindow, ipcMain, desktopCapturer } from 'electron'; -import { ScreenCapture } from './screenCapture.js'; -import type { ScreenCaptureOptions, ScreenshotFrameData } from './screenCapture.js'; -import { AudioCapture, listAudioSources } from './audioCapture.js'; -import type { AudioCaptureOptions, AudioChunk } from './audioCapture.js'; -import { VideoRecorder } from './videoRecorder.js'; -import type { VideoRecordOptions } from './videoRecorder.js'; -import { safeHandle, getMainWindowId } from './ipcUtils.js'; -import { logger } from './logger.js'; -import { scoreAndFilterWindows } from './windowScorer.js'; - -// ================================================================ -// 模块级状态 -// ================================================================ - -/** 当前活跃的截图采集实例 */ -let activeCapture: ScreenCapture | null = null; - -/** 当前活跃的音频捕获实例 */ -let activeAudioCapture: AudioCapture | null = null; - -/** @ai-context Path C 全程录制:当前活跃的视频录制实例 */ -let activeVideoRecorder: VideoRecorder | null = null; - -/** screen_capture_start 防抖:500ms 内多次调用只响应最后一次 */ -let startDebounceTimer: ReturnType | null = null; -const START_DEBOUNCE_MS = 500; - -/** 单调递增会话标识,用于防止 stop 后残留的 debounce 重启采集 */ -let captureSessionToken = 0; - -/** 窗口监听轮询定时器 */ -let windowWatchTimer: ReturnType | null = null; - -/** 上一次窗口列表的 id 集合(用于 diff 检测变化) */ -let lastWindowIds: Set = new Set(); - -const WINDOW_WATCH_INTERVAL_MS = 3000; - -// ================================================================ -// 公共 API -// ================================================================ - -/** - * 注册所有截图 & 音频相关的 IPC handler - */ -export function registerCaptureHandlers(): void { - // ---- 屏幕截图 ---- - - safeHandle( - 'screen_capture_start', - async (event, options: ScreenCaptureOptions) => { - // 防抖:500ms 内多次调用只响应最后一次 - if (startDebounceTimer) { - clearTimeout(startDebounceTimer); - startDebounceTimer = null; - } - - // 记录本次会话 token,用于 debounce 回调时校验是否仍然有效 - const token = ++captureSessionToken; - - return new Promise<{ success: boolean }>((resolve) => { - startDebounceTimer = setTimeout(() => { - startDebounceTimer = null; - - // 如果在 debounce 期间调用了 stop(token 已变),放弃本次启动 - if (token !== captureSessionToken) { - logger.info('[IPC] screen_capture_start debounce 已过期(stop 后残留),跳过'); - resolve({ success: false }); - return; - } - - // 幂等:先清理旧实例 - if (activeCapture) { - activeCapture.dispose(); - activeCapture = null; - } - - const senderWin = BrowserWindow.fromWebContents(event.sender); - - // 对采集参数做边界校验,防止非法值导致主进程异常 - const safeOptions = options || {}; - if (typeof safeOptions.interval === 'number' && (safeOptions.interval < 100 || safeOptions.interval > 60000)) { - safeOptions.interval = 5000; - } - - activeCapture = new ScreenCapture(safeOptions, (frame: ScreenshotFrameData) => { - if (senderWin && !senderWin.isDestroyed()) { - senderWin.webContents.send('screen_capture_frame', frame); - } - }); - - activeCapture.start(); - logger.info('[IPC] screen_capture_start 已启动(防抖后)'); - resolve({ success: true }); - }, START_DEBOUNCE_MS); - }); - }, - ); - - safeHandle('screen_capture_stop', async () => { - // 递增 token,使残留的 debounce 回调失效 - captureSessionToken++; - - // 清理防抖定时器 - if (startDebounceTimer) { - clearTimeout(startDebounceTimer); - startDebounceTimer = null; - } - - if (activeCapture) { - activeCapture.dispose(); - activeCapture = null; - logger.info('[IPC] screen_capture_stop 已停止'); - } - return { success: true }; - }); - - safeHandle('screen_list_windows', async () => { - try { - const sources = await desktopCapturer.getSources({ - types: ['window'], - thumbnailSize: { width: 240, height: 135 }, - }); - - const rawWindows = sources.map((src) => { - const thumb = src.thumbnail.isEmpty() ? src.thumbnail : src.thumbnail.resize({ width: 120 }); - return { - id: src.id, - title: src.name, - thumbnail: thumb.toDataURL(), - }; - }); - - // 智能评分、过滤与排序 - return scoreAndFilterWindows(rawWindows); - } catch (err) { - logger.error('[IPC] screen_list_windows failed:', err); - return []; - } - }); - - // ---- 窗口变化监听(轮询) ---- - - safeHandle('screen_watch_windows_start', async () => { - if (windowWatchTimer) return { success: true }; // 已在监听 - - logger.info('[IPC] 窗口监听已启动, interval=' + WINDOW_WATCH_INTERVAL_MS + 'ms'); - - windowWatchTimer = setInterval(async () => { - try { - const sources = await desktopCapturer.getSources({ - types: ['window'], - thumbnailSize: { width: 240, height: 135 }, - }); - - const currentIds = new Set(sources.map((s) => s.id)); - - // 检测是否有变化(新增或关闭窗口) - const hasChanged = - currentIds.size !== lastWindowIds.size || - [...currentIds].some((id) => !lastWindowIds.has(id)); - - if (hasChanged) { - lastWindowIds = currentIds; - - const rawWindows = sources.map((src) => { - const thumb = src.thumbnail.isEmpty() ? src.thumbnail : src.thumbnail.resize({ width: 120 }); - return { id: src.id, title: src.name, thumbnail: thumb.toDataURL() }; - }); - - const scored = scoreAndFilterWindows(rawWindows); - - // 推送到渲染进程 - const mainWindowId = getMainWindowId(); - if (mainWindowId) { - const win = BrowserWindow.fromId(mainWindowId); - if (win && !win.isDestroyed()) { - win.webContents.send('screen_windows_changed', scored); - } - } - } - } catch (err) { - logger.error('[IPC] window watch poll error:', err); - } - }, WINDOW_WATCH_INTERVAL_MS); - - return { success: true }; - }); - - safeHandle('screen_watch_windows_stop', async () => { - if (windowWatchTimer) { - clearInterval(windowWatchTimer); - windowWatchTimer = null; - lastWindowIds = new Set(); - logger.info('[IPC] 窗口监听已停止'); - } - return { success: true }; - }); - - // ---- 系统音频捕获 ---- - - safeHandle('audio_list_sources', async () => { - try { - return await listAudioSources(); - } catch (err) { - logger.error('[IPC] audio_list_sources failed:', err); - return []; - } - }); - - safeHandle( - 'audio_capture_start', - async (event, options?: Partial & { sourceId?: string }) => { - if (activeAudioCapture) { - activeAudioCapture.dispose(); - activeAudioCapture = null; - } - - const senderWin = BrowserWindow.fromWebContents(event.sender); - if (!senderWin || senderWin.isDestroyed()) { - return { success: false, error: 'No valid window' }; - } - - const captureOptions: Partial = { - chunkDurationMs: options?.chunkDurationMs, - sampleRate: options?.sampleRate, - channels: options?.channels, - }; - - activeAudioCapture = new AudioCapture(captureOptions, (chunk: AudioChunk) => { - if (senderWin && !senderWin.isDestroyed()) { - senderWin.webContents.send('audio_capture_chunk', chunk); - } - }); - - try { - await activeAudioCapture.start(senderWin, options?.sourceId); - logger.info('[IPC] audio_capture_start 已启动'); - return { success: true }; - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - logger.error('[IPC] audio_capture_start failed:', message); - activeAudioCapture.dispose(); - activeAudioCapture = null; - return { success: false, error: message }; - } - }, - ); - - safeHandle('audio_capture_stop', async () => { - if (activeAudioCapture) { - activeAudioCapture.dispose(); - activeAudioCapture = null; - logger.info('[IPC] audio_capture_stop 已停止'); - } - return { success: true }; - }); - - ipcMain.on( - 'audio_capture_chunk', - (_event, data: unknown) => { - // SEC-005: sender 验证,仅接受主窗口的音频数据 - const mainId = getMainWindowId(); - if (mainId !== null && _event.sender.id !== mainId) { - logger.warn( - `[IPC] Sender verification failed for "audio_capture_chunk": ` + - `expected sender.id=${mainId}, got ${_event.sender.id}` - ); - return; - } - - // SEC: 运行时类型断言 — 防止恶意或格式错误的数据 - if ( - !data || - typeof data !== 'object' || - !('audioBuffer' in data) || - typeof (data as Record).sampleRate !== 'number' || - typeof (data as Record).channels !== 'number' || - typeof (data as Record).durationMs !== 'number' - ) { - logger.warn('[IPC] audio_capture_chunk: invalid data format, dropping chunk'); - return; - } - - const chunk = data as { audioBuffer: ArrayBuffer; sampleRate: number; channels: number; durationMs: number }; - if (activeAudioCapture && activeAudioCapture.isCapturing) { - activeAudioCapture.handleRendererChunk(chunk); - } - }, - ); - - // ---- Path C 视频录制 ---- - - safeHandle( - 'video_record_start', - async (event, sourceId: string, options?: VideoRecordOptions) => { - // 幂等:先清理旧实例 - if (activeVideoRecorder) { - activeVideoRecorder.dispose(); - activeVideoRecorder = null; - } - - const senderWin = BrowserWindow.fromWebContents(event.sender); - if (!senderWin || senderWin.isDestroyed()) { - return { success: false, error: 'No valid window' }; - } - - activeVideoRecorder = new VideoRecorder(options); - activeVideoRecorder.bindWindow(senderWin); - - try { - activeVideoRecorder.startRecording(sourceId, options); - logger.info('[IPC] video_record_start 已启动'); - return { success: true }; - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - logger.error('[IPC] video_record_start failed:', message); - activeVideoRecorder.dispose(); - activeVideoRecorder = null; - return { success: false, error: message }; - } - }, - ); - - safeHandle('video_record_stop', async () => { - if (!activeVideoRecorder) { - return { success: false, error: 'No active recording' }; - } - try { - const filePath = await activeVideoRecorder.stopRecording(); - const finalStatus = activeVideoRecorder.status; - logger.info('[IPC] video_record_stop 已完成'); - activeVideoRecorder.dispose(); - activeVideoRecorder = null; - return { success: true, filePath, finalStatus }; - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - logger.error('[IPC] video_record_stop failed:', message); - activeVideoRecorder?.dispose(); - activeVideoRecorder = null; - return { success: false, error: message }; - } - }); - - safeHandle('video_record_pause', async () => { - activeVideoRecorder?.pauseRecording(); - return { success: true }; - }); - - safeHandle('video_record_resume', async () => { - activeVideoRecorder?.resumeRecording(); - return { success: true }; - }); - - safeHandle('video_record_status', async () => { - return activeVideoRecorder?.status ?? { - isRecording: false, isPaused: false, duration: 0, fileSizeBytes: 0, filePath: null, - }; - }); - - // 渲染进程回传视频数据块 - ipcMain.on('video_record_chunk', (_event, chunkBuffer: ArrayBuffer) => { - // SEC-005: sender 验证 - const mainId = getMainWindowId(); - if (mainId !== null && _event.sender.id !== mainId) { - logger.warn( - `[IPC] Sender verification failed for "video_record_chunk": ` + - `expected sender.id=${mainId}, got ${_event.sender.id}` - ); - return; - } - activeVideoRecorder?.handleRendererChunk(chunkBuffer); - }); - - // 渲染进程上报录制错误 - ipcMain.on('video_record_error', (_event, errorInfo: { message: string }) => { - const mainId = getMainWindowId(); - if (mainId !== null && _event.sender.id !== mainId) { - logger.warn( - `[IPC] Sender verification failed for "video_record_error": ` + - `expected sender.id=${mainId}, got ${_event.sender.id}` - ); - return; - } - activeVideoRecorder?.handleRendererError(errorInfo); - }); -} - -// ================================================================ -// 清理 -// ================================================================ - -/** - * 释放所有活跃的采集实例 - */ -export function disposeCaptureHandlers(): void { - // 清理防抖定时器 - if (startDebounceTimer) { - clearTimeout(startDebounceTimer); - startDebounceTimer = null; - } - if (activeCapture) { - activeCapture.dispose(); - activeCapture = null; - } - if (activeAudioCapture) { - activeAudioCapture.dispose(); - activeAudioCapture = null; - } - if (activeVideoRecorder) { - activeVideoRecorder.dispose(); - activeVideoRecorder = null; - } -} +/** + * 屏幕截图 & 系统音频 & 视频录制 IPC Handler — 编排入口 + * + * @ai-context: 2026-07 拆分——屏幕截图/窗口监听在 screenCaptureHandlers、 + * 音频/视频在 mediaCaptureHandlers;本文件仅保留注册与清理编排, + * main.ts 的调用点(registerCaptureHandlers/disposeCaptureHandlers) + * 签名不变。 + */ +import { registerScreenCaptureHandlers, disposeScreenCaptureHandlers } from './screenCaptureHandlers.js'; +import { registerMediaCaptureHandlers, disposeMediaCaptureHandlers } from './mediaCaptureHandlers.js'; + +/** + * 注册所有截图 & 音频 & 视频相关的 IPC handler + */ +export function registerCaptureHandlers(): void { + registerScreenCaptureHandlers(); + registerMediaCaptureHandlers(); +} + +/** + * 释放所有活跃的采集实例 + */ +export function disposeCaptureHandlers(): void { + disposeScreenCaptureHandlers(); + disposeMediaCaptureHandlers(); +} diff --git a/client/electron/cspPolicy.ts b/client/electron/cspPolicy.ts new file mode 100644 index 00000000..60408ca5 --- /dev/null +++ b/client/electron/cspPolicy.ts @@ -0,0 +1,62 @@ +/** + * CSP 安全策略注入(SEC-005) + * + * @ai-context: 从 main.ts 拆出。connect-src 白名单每次请求动态计算, + * 确保用户运行时修改网关 URL 立即生效。生产 script-src 必须保留 + * 'wasm-unsafe-eval'——否则 automerge WASM 被 CSP 拦截、顶层 import + * 失败、应用卡启动画面(仅放开 WASM 编译,不放开 JS eval)。 + * @ai-context: 开发模式需 unsafe-eval + worker-src blob:(Vite 8 HMR + * 用 blob: 创建 SharedWorker)。修改 CSP 前必须全链路回归启动流程。 + */ +import { session } from 'electron'; +import { logger } from './logger.js'; +import { gatewayUrl } from './ai/utils.js'; + +/** 生产网关默认域(与 ai/utils DEFAULT_GATEWAY_URL 保持一致) */ +const DEFAULT_GATEWAY = 'https://entropydecrease.com'; + +/** + * 动态构建 connect-src 白名单 + * 每次请求时重新计算,确保运行时网关 URL 变更(如用户通过设置页修改)能及时生效 + */ +function buildExtraConnectSrc(): string { + const extraOrigins = new Set(); + // 当前运行时网关 URL(可能已被用户通过 IPC 修改) + const currentGateway = gatewayUrl(); + if (currentGateway && currentGateway !== DEFAULT_GATEWAY) { + extraOrigins.add(currentGateway); + } + // 环境变量中的 API 地址 + const configuredApi = process.env.VITE_API_BASE_URL || ''; + if (configuredApi && configuredApi !== DEFAULT_GATEWAY) { + extraOrigins.add(configuredApi); + } + return extraOrigins.size > 0 ? ` ${[...extraOrigins].join(' ')}` : ''; +} + +/** + * 注入 CSP 响应头(app ready 后调用一次) + */ +export function installCspPolicy(isDev: boolean): void { + try { + session.defaultSession.webRequest.onHeadersReceived((details, callback) => { + const extraConnectSrc = buildExtraConnectSrc(); + // 开发环境:允许 unsafe-inline/unsafe-eval(Vite HMR 需要),worker-src 需要 blob: + // 生产环境:禁止 unsafe-eval,保留 unsafe-inline(Tailwind 运行时需要) + const csp = isDev + ? `default-src 'self' 'unsafe-inline' 'unsafe-eval' http://localhost:* ws://localhost:*; worker-src 'self' blob: http://localhost:*; connect-src 'self' http://localhost:* ws://localhost:* https://*.supabase.co wss://*.supabase.co https://entropydecrease.com wss://entropydecrease.com${extraConnectSrc}; img-src 'self' data: blob: https://*.supabase.co; font-src 'self' data:;` + : `default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://*.supabase.co; font-src 'self' data:; connect-src 'self' https://*.supabase.co wss://*.supabase.co https://entropydecrease.com wss://entropydecrease.com${extraConnectSrc}; frame-ancestors 'none';`; + + callback({ + responseHeaders: { + ...details.responseHeaders, + 'Content-Security-Policy': [csp], + }, + }); + }); + logger.info(`[SEC] CSP policy injected (${isDev ? 'development' : 'production'} mode, dynamic gateway tracking enabled)`); + } catch (err) { + // CSP 注入失败时记录错误但不阻塞启动 + logger.error('[SEC] Failed to inject CSP policy', err); + } +} diff --git a/client/electron/db/dbFileMigrator.ts b/client/electron/db/dbFileMigrator.ts index 0b37900e..28f835bd 100644 --- a/client/electron/db/dbFileMigrator.ts +++ b/client/electron/db/dbFileMigrator.ts @@ -1,239 +1,241 @@ -/** - * 数据库文件迁移模块 - * - * 负责将 SQLite 数据库文件(含 WAL/SHM)从一个目录复制到另一个目录, - * 包含完整性校验和备份功能。 - * - * 注意:WAL checkpoint 应在调用本模块之前由 sqliteService.checkpointAndClose() 完成。 - */ - -import { copyFile, mkdir, stat, access, rm } from 'fs/promises'; -import { createHash } from 'crypto'; -import { createReadStream } from 'fs'; -import * as path from 'path'; -import Database from 'better-sqlite3'; -import { logger } from '../logger.js'; - -// ================================================================ -// 类型定义 -// ================================================================ - -export interface MigrationResult { - success: boolean; - sourcePath: string; - targetPath: string; - error?: string; - filesCopied?: string[]; -} - -// ================================================================ -// 常量 -// ================================================================ - -const DB_FILES = ['keban.db', 'keban.db-wal', 'keban.db-shm']; - -// ================================================================ -// 内部工具函数 -// ================================================================ - -/** - * 计算文件的 SHA-256 哈希 - */ -function computeFileHash(filePath: string): Promise { - return new Promise((resolve, reject) => { - const hash = createHash('sha256'); - const stream = createReadStream(filePath); - stream.on('data', (data) => hash.update(data)); - stream.on('end', () => resolve(hash.digest('hex'))); - stream.on('error', reject); - }); -} - -/** - * 检查文件是否存在 - */ -async function fileExists(filePath: string): Promise { - try { - await access(filePath); - return true; - } catch { - return false; - } -} - -/** - * 检查目标磁盘可用空间是否足够 - */ -async function checkDiskSpace(targetDir: string, requiredBytes: number): Promise { - try { - // 使用 fs.statfs(Node.js 18.15+)检查磁盘空间 - const { statfs } = await import('fs/promises'); - const stats = await statfs(targetDir); - const availableBytes = stats.bavail * stats.bsize; - return availableBytes >= requiredBytes * 1.1; // 留 10% 余量 - } catch (err) { - const errInfo = err instanceof Error ? err.message : String(err); - logger.warn(`[DBMigrator] Failed to check disk space, proceeding anyway: ${errInfo}`); - return true; // 无法检查时不阻塞 - } -} - -/** - * 清理失败的迁移(删除目标目录中的数据库文件副本) - */ -async function cleanupFailedMigration(targetDir: string): Promise { - for (const fileName of DB_FILES) { - const filePath = path.join(targetDir, fileName); - try { - if (await fileExists(filePath)) { - await rm(filePath); - logger.info(`[DBMigrator] Cleaned up failed copy: ${fileName}`); - } - } catch (err) { - logger.error(`[DBMigrator] Failed to cleanup ${fileName}`, err); - } - } -} - -// ================================================================ -// 公共 API -// ================================================================ - -/** - * 迁移数据库文件从源目录到目标目录 - * - * 复制 keban.db / keban.db-wal / keban.db-shm,并在每个文件复制后 - * 进行 SHA-256 完整性校验。校验失败时自动清理已复制文件。 - */ -export async function migrateDatabaseFiles( - sourceDir: string, - targetDir: string, -): Promise { - const sourceDb = path.join(sourceDir, 'keban.db'); - - // 1. 检查源数据库存在 - if (!(await fileExists(sourceDb))) { - return { - success: false, - sourcePath: sourceDir, - targetPath: targetDir, - error: '源数据库文件不存在: ' + sourceDb, - }; - } - - try { - // 2. 确保目标目录存在 - await mkdir(targetDir, { recursive: true }); - - // 3. 检查磁盘空间 - const sourceStats = await stat(sourceDb); - let totalSize = sourceStats.size; - - // 计算所有存在的文件大小 - for (const fileName of DB_FILES) { - const filePath = path.join(sourceDir, fileName); - if (await fileExists(filePath)) { - const fileStat = await stat(filePath); - totalSize += fileStat.size; - } - } - - const hasSpace = await checkDiskSpace(targetDir, totalSize); - if (!hasSpace) { - return { - success: false, - sourcePath: sourceDir, - targetPath: targetDir, - error: '目标磁盘空间不足,请确保至少有 ' + Math.ceil(totalSize * 1.1 / 1024 / 1024) + ' MB 可用空间', - }; - } - - // 4. 复制所有数据库文件 - const copiedFiles: string[] = []; - - for (const fileName of DB_FILES) { - const sourcePath = path.join(sourceDir, fileName); - const targetPath = path.join(targetDir, fileName); - - if (await fileExists(sourcePath)) { - logger.info(`[DBMigrator] Copying ${fileName}...`); - await copyFile(sourcePath, targetPath); - copiedFiles.push(fileName); - - // 5. 校验完整性(SHA-256) - const sourceHash = await computeFileHash(sourcePath); - const targetHash = await computeFileHash(targetPath); - - if (sourceHash !== targetHash) { - // 校验失败,清理已复制文件 - logger.error(`[DBMigrator] Hash mismatch for ${fileName}`); - await cleanupFailedMigration(targetDir); - return { - success: false, - sourcePath: sourceDir, - targetPath: targetDir, - error: `文件完整性校验失败: ${fileName}`, - }; - } - - logger.info(`[DBMigrator] ${fileName} copied and verified`); - } - } - - logger.info(`[DBMigrator] Migration completed: ${copiedFiles.length} files copied`); - return { - success: true, - sourcePath: sourceDir, - targetPath: targetDir, - filesCopied: copiedFiles, - }; - } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); - logger.error('[DBMigrator] Migration failed', err); - await cleanupFailedMigration(targetDir); - return { - success: false, - sourcePath: sourceDir, - targetPath: targetDir, - error: '迁移失败: ' + errorMsg, - }; - } -} - -/** - * 验证数据库文件完整性 - * - * 使用 SQLite PRAGMA integrity_check 检测数据库是否完好。 - */ -export function verifyDatabaseIntegrity(dbPath: string): boolean { - let tempDb: Database.Database | null = null; - try { - tempDb = new Database(dbPath, { readonly: true }); - const result = tempDb.pragma('integrity_check', { simple: true }); - const ok = result === 'ok'; - logger.info(`[DBMigrator] Integrity check: ${result}`); - return ok; - } catch (err) { - logger.error('[DBMigrator] Integrity check failed', err); - return false; - } finally { - if (tempDb) { - try { tempDb.close(); } catch { /* ignore */ } - } - } -} - -/** - * 为旧路径数据库创建备份 - * 将 keban.db / keban.db-wal / keban.db-shm 各复制为 .bak(同目录) - */ -export async function createBackup(dbDir: string): Promise { - for (const fileName of DB_FILES) { - const sourcePath = path.join(dbDir, fileName); - const backupPath = path.join(dbDir, fileName + '.bak'); - if (await fileExists(sourcePath)) { - await copyFile(sourcePath, backupPath); - logger.info(`[DBMigrator] Backup created: ${fileName}.bak`); - } - } -} +/** + * 数据库文件迁移模块 + * + * 负责将 SQLite 数据库文件(含 WAL/SHM)从一个目录复制到另一个目录, + * 包含完整性校验和备份功能。 + * + * 注意:WAL checkpoint 应在调用本模块之前由 sqliteService.checkpointAndClose() 完成。 + * + * @ai-context: SQLite 数据库文件迁移(keban.db/-wal/-shm 三文件为存量用户数据标识,永久豁免品牌改名):复制后校验、旧库改 .bak。 + */ + +import { copyFile, mkdir, stat, access, rm } from 'fs/promises'; +import { createHash } from 'crypto'; +import { createReadStream } from 'fs'; +import * as path from 'path'; +import Database from 'better-sqlite3'; +import { logger } from '../logger.js'; + +// ================================================================ +// 类型定义 +// ================================================================ + +export interface MigrationResult { + success: boolean; + sourcePath: string; + targetPath: string; + error?: string; + filesCopied?: string[]; +} + +// ================================================================ +// 常量 +// ================================================================ + +const DB_FILES = ['keban.db', 'keban.db-wal', 'keban.db-shm']; + +// ================================================================ +// 内部工具函数 +// ================================================================ + +/** + * 计算文件的 SHA-256 哈希 + */ +function computeFileHash(filePath: string): Promise { + return new Promise((resolve, reject) => { + const hash = createHash('sha256'); + const stream = createReadStream(filePath); + stream.on('data', (data) => hash.update(data)); + stream.on('end', () => resolve(hash.digest('hex'))); + stream.on('error', reject); + }); +} + +/** + * 检查文件是否存在 + */ +async function fileExists(filePath: string): Promise { + try { + await access(filePath); + return true; + } catch { + return false; + } +} + +/** + * 检查目标磁盘可用空间是否足够 + */ +async function checkDiskSpace(targetDir: string, requiredBytes: number): Promise { + try { + // 使用 fs.statfs(Node.js 18.15+)检查磁盘空间 + const { statfs } = await import('fs/promises'); + const stats = await statfs(targetDir); + const availableBytes = stats.bavail * stats.bsize; + return availableBytes >= requiredBytes * 1.1; // 留 10% 余量 + } catch (err) { + const errInfo = err instanceof Error ? err.message : String(err); + logger.warn(`[DBMigrator] Failed to check disk space, proceeding anyway: ${errInfo}`); + return true; // 无法检查时不阻塞 + } +} + +/** + * 清理失败的迁移(删除目标目录中的数据库文件副本) + */ +async function cleanupFailedMigration(targetDir: string): Promise { + for (const fileName of DB_FILES) { + const filePath = path.join(targetDir, fileName); + try { + if (await fileExists(filePath)) { + await rm(filePath); + logger.info(`[DBMigrator] Cleaned up failed copy: ${fileName}`); + } + } catch (err) { + logger.error(`[DBMigrator] Failed to cleanup ${fileName}`, err); + } + } +} + +// ================================================================ +// 公共 API +// ================================================================ + +/** + * 迁移数据库文件从源目录到目标目录 + * + * 复制 keban.db / keban.db-wal / keban.db-shm,并在每个文件复制后 + * 进行 SHA-256 完整性校验。校验失败时自动清理已复制文件。 + */ +export async function migrateDatabaseFiles( + sourceDir: string, + targetDir: string, +): Promise { + const sourceDb = path.join(sourceDir, 'keban.db'); + + // 1. 检查源数据库存在 + if (!(await fileExists(sourceDb))) { + return { + success: false, + sourcePath: sourceDir, + targetPath: targetDir, + error: '源数据库文件不存在: ' + sourceDb, + }; + } + + try { + // 2. 确保目标目录存在 + await mkdir(targetDir, { recursive: true }); + + // 3. 检查磁盘空间 + const sourceStats = await stat(sourceDb); + let totalSize = sourceStats.size; + + // 计算所有存在的文件大小 + for (const fileName of DB_FILES) { + const filePath = path.join(sourceDir, fileName); + if (await fileExists(filePath)) { + const fileStat = await stat(filePath); + totalSize += fileStat.size; + } + } + + const hasSpace = await checkDiskSpace(targetDir, totalSize); + if (!hasSpace) { + return { + success: false, + sourcePath: sourceDir, + targetPath: targetDir, + error: '目标磁盘空间不足,请确保至少有 ' + Math.ceil(totalSize * 1.1 / 1024 / 1024) + ' MB 可用空间', + }; + } + + // 4. 复制所有数据库文件 + const copiedFiles: string[] = []; + + for (const fileName of DB_FILES) { + const sourcePath = path.join(sourceDir, fileName); + const targetPath = path.join(targetDir, fileName); + + if (await fileExists(sourcePath)) { + logger.info(`[DBMigrator] Copying ${fileName}...`); + await copyFile(sourcePath, targetPath); + copiedFiles.push(fileName); + + // 5. 校验完整性(SHA-256) + const sourceHash = await computeFileHash(sourcePath); + const targetHash = await computeFileHash(targetPath); + + if (sourceHash !== targetHash) { + // 校验失败,清理已复制文件 + logger.error(`[DBMigrator] Hash mismatch for ${fileName}`); + await cleanupFailedMigration(targetDir); + return { + success: false, + sourcePath: sourceDir, + targetPath: targetDir, + error: `文件完整性校验失败: ${fileName}`, + }; + } + + logger.info(`[DBMigrator] ${fileName} copied and verified`); + } + } + + logger.info(`[DBMigrator] Migration completed: ${copiedFiles.length} files copied`); + return { + success: true, + sourcePath: sourceDir, + targetPath: targetDir, + filesCopied: copiedFiles, + }; + } catch (err) { + const errorMsg = err instanceof Error ? err.message : String(err); + logger.error('[DBMigrator] Migration failed', err); + await cleanupFailedMigration(targetDir); + return { + success: false, + sourcePath: sourceDir, + targetPath: targetDir, + error: '迁移失败: ' + errorMsg, + }; + } +} + +/** + * 验证数据库文件完整性 + * + * 使用 SQLite PRAGMA integrity_check 检测数据库是否完好。 + */ +export function verifyDatabaseIntegrity(dbPath: string): boolean { + let tempDb: Database.Database | null = null; + try { + tempDb = new Database(dbPath, { readonly: true }); + const result = tempDb.pragma('integrity_check', { simple: true }); + const ok = result === 'ok'; + logger.info(`[DBMigrator] Integrity check: ${result}`); + return ok; + } catch (err) { + logger.error('[DBMigrator] Integrity check failed', err); + return false; + } finally { + if (tempDb) { + try { tempDb.close(); } catch { /* ignore */ } + } + } +} + +/** + * 为旧路径数据库创建备份 + * 将 keban.db / keban.db-wal / keban.db-shm 各复制为 .bak(同目录) + */ +export async function createBackup(dbDir: string): Promise { + for (const fileName of DB_FILES) { + const sourcePath = path.join(dbDir, fileName); + const backupPath = path.join(dbDir, fileName + '.bak'); + if (await fileExists(sourcePath)) { + await copyFile(sourcePath, backupPath); + logger.info(`[DBMigrator] Backup created: ${fileName}.bak`); + } + } +} diff --git a/client/electron/db/dbIpcHandlers.ts b/client/electron/db/dbIpcHandlers.ts new file mode 100644 index 00000000..e0d39e55 --- /dev/null +++ b/client/electron/db/dbIpcHandlers.ts @@ -0,0 +1,158 @@ +/** + * 数据访问 IPC handlers(db:*,v1.0.0) + * + * @ai-context: 从 main.ts 拆出。安全模型:表名白名单 + 方法白名单, + * 不暴露原始 SQL 给渲染进程;ALLOWED_TABLES 与 schema.ts 建表清单 + * 必须同步维护,新增业务表需两处登记。 + * @ai-context: SqliteRow 以 Record+id 约束替代 any(动态表名场景 + * 无法静态推导具体行类型,这是类型收窄的边界)。 + */ +import { safeHandle } from '../ipcUtils.js'; +import { getConnection } from './sqliteService.js'; +import SqliteRepository from './sqliteRepository.js'; + +/** 动态表名场景下的通用行类型(替代 any 的受控收窄) */ +type SqliteRow = Record & { id: string }; + +/** 允许的表名白名单(防止 SQL 注入,不暴露原始 SQL) */ +const ALLOWED_TABLES = new Set([ + 'notes', 'note_folders', 'flashcard_decks', 'flashcards', + 'flashcard_reviews', 'feynman_notes', 'feynman_summaries', + 'feynman_weak_points', 'operation_log', 'app_settings', + 'sync_conflicts', 'offline_queue', 'study_check_ins', + 'achievements', 'pomodoro_goals', 'pomodoro_sessions', + 'pomodoro_settings', 'window_captures', 'consent', + 'user_profile', 'inspirations', 'search_index', +]); + +/** camelCase → snake_case(用于表名映射) */ +const TABLE_NAME_MAP: Record = { + notes: 'notes', + noteFolders: 'note_folders', + flashcardDecks: 'flashcard_decks', + flashcards: 'flashcards', + flashcardReviews: 'flashcard_reviews', + feynmanNotes: 'feynman_notes', + feynmanSummaries: 'feynman_summaries', + feynmanWeakPoints: 'feynman_weak_points', + operationLog: 'operation_log', + appSettings: 'app_settings', + syncConflicts: 'sync_conflicts', + offlineQueue: 'offline_queue', + studyCheckIns: 'study_check_ins', + achievements: 'achievements', + pomodoroGoals: 'pomodoro_goals', + pomodoroSessions: 'pomodoro_sessions', + pomodoroSettings: 'pomodoro_settings', + windowCaptures: 'window_captures', + consent: 'consent', + userProfile: 'user_profile', + inspirations: 'inspirations', + searchIndex: 'search_index', +}; + +function resolveTable(table: string): string { + const snakeName = TABLE_NAME_MAP[table] || table; + if (!ALLOWED_TABLES.has(snakeName)) { + throw new Error(`[DB] Table "${table}" is not in the allowed whitelist`); + } + return snakeName; +} + +/** + * 注册全部 db:* IPC handlers(app ready 后调用一次) + */ +export function registerDbIpcHandlers(): void { + /** db:query — 查询:接收 { table, method, args } → 调用 SqliteRepository 对应方法 */ + safeHandle('db:query', async (_event, params: { table: string; method: string; args?: unknown[] }) => { + const tableName = resolveTable(params.table); + const repo = new SqliteRepository(tableName); + const allowedMethods = ['getAll', 'getById', 'count'] as const; + const method = params.method as (typeof allowedMethods)[number]; + if (!allowedMethods.includes(method)) { + throw new Error(`[DB] Query method "${params.method}" is not allowed`); + } + const fn = repo[method]; + if (typeof fn !== 'function') { + throw new Error(`[DB] Method "${params.method}" does not exist on repository`); + } + return await (fn as (...args: unknown[]) => Promise).call(repo, ...(params.args ?? [])); + }); + + /** db:insert — 插入:接收 { table, item } → create() */ + safeHandle('db:insert', async (_event, params: { table: string; item: Record }) => { + const tableName = resolveTable(params.table); + const repo = new SqliteRepository(tableName); + return await repo.create(params.item as SqliteRow); + }); + + /** db:update — 更新:接收 { table, id, changes } → update() */ + safeHandle('db:update', async (_event, params: { table: string; id: string; changes: Record }) => { + const tableName = resolveTable(params.table); + const repo = new SqliteRepository(tableName); + return await repo.update(params.id, params.changes as Partial); + }); + + /** db:delete — 删除:接收 { table, id } → delete() */ + safeHandle('db:delete', async (_event, params: { table: string; id: string }) => { + const tableName = resolveTable(params.table); + const repo = new SqliteRepository(tableName); + return await repo.delete(params.id); + }); + + /** db:search — 搜索:LIKE 模糊匹配(FTS5 在 T0.5 实现) */ + safeHandle('db:search', async (_event, params: { table: string; query: string }) => { + const tableName = resolveTable(params.table); + const dbConn = getConnection(); + const like = `%${params.query}%`; + // 对 notes 表搜索 title 和 content,其余表搜索所有 TEXT 列 + if (tableName === 'notes') { + return dbConn.prepare( + `SELECT * FROM notes WHERE title LIKE ? OR content LIKE ?` + ).all(like, like); + } + // 通用回退:获取表的 TEXT 列并搜索 + const colInfo = dbConn.prepare(`PRAGMA table_info("${tableName}")`).all() as Array<{ name: string; type: string }>; + const textCols = colInfo.filter((c) => c.type === 'TEXT' && c.name !== 'id'); + if (textCols.length === 0) return []; + const where = textCols.map((c) => `"${c.name}" LIKE ?`).join(' OR '); + return dbConn.prepare(`SELECT * FROM "${tableName}" WHERE ${where}`).all(...textCols.map(() => like)); + }); + + /** db:batch — 批量操作:事务执行 */ + safeHandle('db:batch', async (_event, params: { operations: Array<{ type: string; table: string; [key: string]: unknown }> }) => { + const dbConn = getConnection(); + + const txn = dbConn.transaction(() => { + for (const op of params.operations) { + const tableName = resolveTable(op.table as string); + switch (op.type) { + case 'insert': { + const item = op.item as Record; + const cols = Object.keys(item); + const placeholders = cols.map(() => '?').join(', '); + const sql = `INSERT INTO "${tableName}" (${cols.map((c) => `"${c}"`).join(', ')}) VALUES (${placeholders})`; + dbConn.prepare(sql).run(...Object.values(item)); + break; + } + case 'update': { + const changes = op.changes as Record; + const entries = Object.entries(changes); + if (entries.length === 0) break; + const setClauses = entries.map(([col]) => `"${col}" = ?`).join(', '); + const sql = `UPDATE "${tableName}" SET ${setClauses} WHERE id = ?`; + dbConn.prepare(sql).run(...entries.map(([, v]) => v), op.id as string); + break; + } + case 'delete': + dbConn.prepare(`DELETE FROM "${tableName}" WHERE id = ?`).run(op.id as string); + break; + default: + throw new Error(`[DB] Unknown batch operation type: ${op.type}`); + } + } + }); + txn(); + return { success: true }; + }); +} diff --git a/client/electron/db/fts5Search.ts b/client/electron/db/fts5Search.ts index d547e951..e5492bbd 100644 --- a/client/electron/db/fts5Search.ts +++ b/client/electron/db/fts5Search.ts @@ -1,135 +1,137 @@ -/** - * 基于 SQLite FTS5 的全文搜索引擎 - * unicode61 分词器 + BM25 排序,为笔记/闪卡/灵感等提供本地全文搜索。 - */ -import type Database from 'better-sqlite3'; -import { getConnection } from './sqliteService.js'; -import { logger } from '../logger.js'; - -// ================================================================ -// 类型定义 -// ================================================================ - -export interface SearchOptions { - table?: string; // 限定搜索表 - limit?: number; // 结果数量上限,默认 20 - offset?: number; // 偏移量 - highlight?: boolean; // 是否返回高亮片段 -} - -export interface SearchResult { - id: string; - table: string; - title: string; - snippet: string; // 匹配片段(高亮可选) - rank: number; // BM25 排序分数 -} - -export interface IndexTableInput { - name: string; - rows: Array<{ id: string; title?: string; content: string }>; -} - -// ================================================================ -// FTS5 虚拟表 DDL -// ================================================================ - -const FTS5_DDL = /* sql */ ` -CREATE VIRTUAL TABLE IF NOT EXISTS fts_content USING fts5( - id UNINDEXED, table_name UNINDEXED, title, content, - tokenize='unicode61 remove_diacritics 2' -);`; - -// ================================================================ -// 公共 API -// ================================================================ - -/** 创建 FTS5 虚拟表(幂等) */ -export function initializeFTS(db: Database.Database): void { - db.exec(FTS5_DDL); - logger.info('[FTS5] Full-text search virtual table initialized'); -} - -/** 索引或更新一条文档(先删后插保证幂等) */ -export function indexDocument(table: string, id: string, title: string, content: string): void { - const db = getConnection(); - db.prepare(`DELETE FROM fts_content WHERE id = ? AND table_name = ?`).run(id, table); - db.prepare(`INSERT INTO fts_content (id, table_name, title, content) VALUES (?, ?, ?, ?)`) - .run(id, table, title, content); -} - -/** 从全文索引中删除一条文档 */ -export function removeDocument(table: string, id: string): void { - getConnection() - .prepare(`DELETE FROM fts_content WHERE id = ? AND table_name = ?`) - .run(id, table); -} - -/** - * 执行全文搜索 - * - * 使用 FTS5 MATCH + BM25 排序 + snippet 高亮。 - * query 支持 FTS5 查询语法(AND、OR、NOT、前缀 *)。 - */ -export function search(query: string, options?: SearchOptions): SearchResult[] { - if (!query?.trim()) return []; - - const db = getConnection(); - const limit = options?.limit ?? 20; - const offset = options?.offset ?? 0; - const useHighlight = options?.highlight ?? true; - - const snippetFn = useHighlight - ? `snippet(fts_content, 3, '', '', '...', 64)` - : `snippet(fts_content, 3, '', '', '...', 64)`; - - const hasTableFilter = !!options?.table; - const whereClause = hasTableFilter - ? `WHERE fts_content MATCH ? AND table_name = ?` - : `WHERE fts_content MATCH ?`; - - const sql = /* sql */ ` - SELECT id, table_name, title, - ${snippetFn} as snippet, - bm25(fts_content) as rank - FROM fts_content - ${whereClause} - ORDER BY rank - LIMIT ? OFFSET ?`; - - const params: (string | number)[] = hasTableFilter - ? [query, options!.table!, limit, offset] - : [query, limit, offset]; - - try { - const rows = db.prepare(sql).all(...params) as Array<{ - id: string; table_name: string; title: string; snippet: string; rank: number; - }>; - return rows.map((r) => ({ - id: r.id, table: r.table_name, title: r.title, snippet: r.snippet, rank: r.rank, - })); - } catch (err) { - logger.error('[FTS5] Search failed', err); - return []; - } -} - -/** 批量重建全文索引(事务内先清空再逐表写入) */ -export function rebuildIndex(tables: IndexTableInput[]): void { - const db = getConnection(); - const insertStmt = db.prepare( - `INSERT INTO fts_content (id, table_name, title, content) VALUES (?, ?, ?, ?)`, - ); - - const transaction = db.transaction(() => { - db.exec(`DELETE FROM fts_content`); - for (const t of tables) { - for (const row of t.rows) { - insertStmt.run(row.id, t.name, row.title ?? '', row.content); - } - } - }); - - transaction(); - logger.info(`[FTS5] Index rebuilt for ${tables.length} table(s)`); -} +/** + * 基于 SQLite FTS5 的全文搜索引擎 + * unicode61 分词器 + BM25 排序,为笔记/闪卡/灵感等提供本地全文搜索。 + * + * @ai-context: SQLite FTS5 全文搜索封装(若可用),LIKE 搜索的升级路径。 + */ +import type Database from 'better-sqlite3'; +import { getConnection } from './sqliteService.js'; +import { logger } from '../logger.js'; + +// ================================================================ +// 类型定义 +// ================================================================ + +export interface SearchOptions { + table?: string; // 限定搜索表 + limit?: number; // 结果数量上限,默认 20 + offset?: number; // 偏移量 + highlight?: boolean; // 是否返回高亮片段 +} + +export interface SearchResult { + id: string; + table: string; + title: string; + snippet: string; // 匹配片段(高亮可选) + rank: number; // BM25 排序分数 +} + +export interface IndexTableInput { + name: string; + rows: Array<{ id: string; title?: string; content: string }>; +} + +// ================================================================ +// FTS5 虚拟表 DDL +// ================================================================ + +const FTS5_DDL = /* sql */ ` +CREATE VIRTUAL TABLE IF NOT EXISTS fts_content USING fts5( + id UNINDEXED, table_name UNINDEXED, title, content, + tokenize='unicode61 remove_diacritics 2' +);`; + +// ================================================================ +// 公共 API +// ================================================================ + +/** 创建 FTS5 虚拟表(幂等) */ +export function initializeFTS(db: Database.Database): void { + db.exec(FTS5_DDL); + logger.info('[FTS5] Full-text search virtual table initialized'); +} + +/** 索引或更新一条文档(先删后插保证幂等) */ +export function indexDocument(table: string, id: string, title: string, content: string): void { + const db = getConnection(); + db.prepare(`DELETE FROM fts_content WHERE id = ? AND table_name = ?`).run(id, table); + db.prepare(`INSERT INTO fts_content (id, table_name, title, content) VALUES (?, ?, ?, ?)`) + .run(id, table, title, content); +} + +/** 从全文索引中删除一条文档 */ +export function removeDocument(table: string, id: string): void { + getConnection() + .prepare(`DELETE FROM fts_content WHERE id = ? AND table_name = ?`) + .run(id, table); +} + +/** + * 执行全文搜索 + * + * 使用 FTS5 MATCH + BM25 排序 + snippet 高亮。 + * query 支持 FTS5 查询语法(AND、OR、NOT、前缀 *)。 + */ +export function search(query: string, options?: SearchOptions): SearchResult[] { + if (!query?.trim()) return []; + + const db = getConnection(); + const limit = options?.limit ?? 20; + const offset = options?.offset ?? 0; + const useHighlight = options?.highlight ?? true; + + const snippetFn = useHighlight + ? `snippet(fts_content, 3, '', '', '...', 64)` + : `snippet(fts_content, 3, '', '', '...', 64)`; + + const hasTableFilter = !!options?.table; + const whereClause = hasTableFilter + ? `WHERE fts_content MATCH ? AND table_name = ?` + : `WHERE fts_content MATCH ?`; + + const sql = /* sql */ ` + SELECT id, table_name, title, + ${snippetFn} as snippet, + bm25(fts_content) as rank + FROM fts_content + ${whereClause} + ORDER BY rank + LIMIT ? OFFSET ?`; + + const params: (string | number)[] = hasTableFilter + ? [query, options!.table!, limit, offset] + : [query, limit, offset]; + + try { + const rows = db.prepare(sql).all(...params) as Array<{ + id: string; table_name: string; title: string; snippet: string; rank: number; + }>; + return rows.map((r) => ({ + id: r.id, table: r.table_name, title: r.title, snippet: r.snippet, rank: r.rank, + })); + } catch (err) { + logger.error('[FTS5] Search failed', err); + return []; + } +} + +/** 批量重建全文索引(事务内先清空再逐表写入) */ +export function rebuildIndex(tables: IndexTableInput[]): void { + const db = getConnection(); + const insertStmt = db.prepare( + `INSERT INTO fts_content (id, table_name, title, content) VALUES (?, ?, ?, ?)`, + ); + + const transaction = db.transaction(() => { + db.exec(`DELETE FROM fts_content`); + for (const t of tables) { + for (const row of t.rows) { + insertStmt.run(row.id, t.name, row.title ?? '', row.content); + } + } + }); + + transaction(); + logger.info(`[FTS5] Index rebuilt for ${tables.length} table(s)`); +} diff --git a/client/electron/db/migration.ts b/client/electron/db/migration.ts index 831e49fa..d80f654b 100644 --- a/client/electron/db/migration.ts +++ b/client/electron/db/migration.ts @@ -1,196 +1,198 @@ -/** - * 数据迁移脚本(IndexedDB → SQLite) - * - * 协调模式:渲染进程读取 IndexedDB → IPC → 主进程写入 SQLite。 - * 迁移前自动备份、失败保留 IndexedDB 可重试、脚本幂等执行。 - */ - -import type Database from 'better-sqlite3'; -import { getConnection } from './sqliteService.js'; -import { logger } from '../logger.js'; - -// ================================================================ -// 类型 & 常量 -// ================================================================ - -export interface MigrationStatus { - completed: boolean; - currentTable: string; - tablesTotal: number; - tablesCompleted: number; - rowsMigrated: number; - error?: string; -} - -/** Dexie 表名 → SQLite 表名映射 */ -const TABLE_MAPPING: Array<{ dexie: string; sqlite: string }> = [ - { dexie: 'notes', sqlite: 'notes' }, - { dexie: 'noteFolders', sqlite: 'note_folders' }, - { dexie: 'flashcardDecks', sqlite: 'flashcard_decks' }, - { dexie: 'flashcards', sqlite: 'flashcards' }, - { dexie: 'flashcardReviews', sqlite: 'flashcard_reviews' }, - { dexie: 'feynmanNotes', sqlite: 'feynman_notes' }, - { dexie: 'feynmanSummaries', sqlite: 'feynman_summaries' }, - { dexie: 'feynmanWeakPoints', sqlite: 'feynman_weak_points' }, - { dexie: 'pomodoroSessions', sqlite: 'pomodoro_sessions' }, - { dexie: 'pomodoroSettings', sqlite: 'pomodoro_settings' }, - { dexie: 'appSettings', sqlite: 'app_settings' }, - { dexie: 'operationLog', sqlite: 'operation_log' }, - { dexie: 'syncConflicts', sqlite: 'sync_conflicts' }, - { dexie: 'offlineQueue', sqlite: 'offline_queue' }, - { dexie: 'studyCheckIns', sqlite: 'study_check_ins' }, - { dexie: 'achievements', sqlite: 'achievements' }, - { dexie: 'pomodoroGoals', sqlite: 'pomodoro_goals' }, - { dexie: 'windowCaptures', sqlite: 'window_captures' }, - { dexie: 'consent', sqlite: 'consent' }, - { dexie: 'userProfile', sqlite: 'user_profile' }, - { dexie: 'inspirations', sqlite: 'inspirations' }, -]; - -/** 合法的 SQLite 表名集合 */ -const VALID_SQLITE_TABLES = new Set(TABLE_MAPPING.map((m) => m.sqlite)); - -/** camelCase → snake_case */ -function toSnake(s: string): string { - return s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`); -} - -// ================================================================ -// 核心 -// ================================================================ - -/** 检查是否需要迁移:无 migrationComplete 标记 + SQLite 无业务数据 → 需要迁移 */ -export function needsMigration(db: Database.Database): boolean { - try { - const row = db.prepare(`SELECT value FROM app_settings WHERE "key" = 'migrationComplete'`).get() as { value: string } | undefined; - if (row?.value === 'true') return false; - const notesCount = db.prepare('SELECT COUNT(*) AS cnt FROM notes').get() as { cnt: number }; - if (notesCount.cnt > 0) return false; - return true; - } catch (err) { - logger.error('[Migration] Failed to check migration status', err); - return false; - } -} - -/** - * 导入单表数据到 SQLite(INSERT OR REPLACE) - * - * @param sqliteTable - SQLite 表名(snake_case,需在白名单内) - * @param rows - 数据行数组(camelCase keys,由渲染进程发送) - * @returns 成功插入的行数 - */ -export function importTable(sqliteTable: string, rows: Record[]): number { - if (!VALID_SQLITE_TABLES.has(sqliteTable)) { - throw new Error(`[Migration] Table "${sqliteTable}" is not in the migration whitelist`); - } - - const db = getConnection(); - if (rows.length === 0) { - logger.info(`[Migration] Table "${sqliteTable}" — 0 rows to import, skipping`); - return 0; - } - - // 构建列名(从第一行推断,camelCase → snake_case) - const cols = Object.keys(rows[0]).map(toSnake); - - const placeholders = cols.map(() => '?').join(', '); - const colList = cols.map((c) => `"${c}"`).join(', '); - const sql = `INSERT OR REPLACE INTO "${sqliteTable}" (${colList}) VALUES (${placeholders})`; - const stmt = db.prepare(sql); - - const txn = db.transaction((items: Record[]) => { - for (const item of items) { - const values = Object.keys(item).map((k) => { - const val = item[k]; - // 自动 JSON 序列化对象/数组字段 - if (val !== null && typeof val === 'object' && !(val instanceof Date)) { - return JSON.stringify(val); - } - // boolean → INTEGER - if (typeof val === 'boolean') return val ? 1 : 0; - // Date → ISO string - if (val instanceof Date) return val.toISOString(); - return val; - }); - stmt.run(...values); - } - }); - - txn(rows); - logger.info(`[Migration] Imported ${rows.length} rows into "${sqliteTable}"`); - return rows.length; -} - -/** - * 标记迁移完成 - * - * 写入 migrationComplete 标记到 app_settings + 运行 PRAGMA integrity_check - */ -export function completeMigration(db: Database.Database): { ok: boolean; integrity: string } { - const now = new Date().toISOString(); - - db.prepare( - `INSERT OR REPLACE INTO app_settings (id, "key", value, updated_at) VALUES (?, 'migrationComplete', 'true', ?)` - ).run(crypto.randomUUID(), now); - - // 运行完整性检查 - const result = db.pragma('integrity_check', { simple: true }) as string; - const ok = result === 'ok'; - - if (ok) { - logger.info('[Migration] Migration completed successfully, integrity check passed'); - } else { - logger.error(`[Migration] Integrity check failed: ${result}`); - } - - return { ok, integrity: result }; -} - -// ================================================================ -// IPC handler 注册 -// ================================================================ - -/** - * 注册迁移相关 IPC handler(在 main.ts 的 app.whenReady 中调用) - * - * 需要外部传入 safeHandle 以避免循环依赖。 - */ -export function registerMigrationHandlers( - safeHandle: (channel: string, handler: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => Promise) => void, -): void { - const db = getConnection(); - - /** migration:check — 检查是否需要迁移 */ - safeHandle('migration:check', async () => { - const needed = needsMigration(db); - logger.info(`[Migration] Check result: ${needed ? 'migration needed' : 'no migration needed'}`); - return { needed, tableMapping: TABLE_MAPPING }; - }); - - /** migration:import-table — 导入单表数据 */ - safeHandle('migration:import-table', async (_event, params: { table: string; rows: Record[] }) => { - try { - const count = importTable(params.table, params.rows); - return { success: true, rowsImported: count }; - } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - logger.error(`[Migration] Failed to import table "${params.table}"`, err); - return { success: false, error: msg }; - } - }); - - /** migration:complete — 标记迁移完成 */ - safeHandle('migration:complete', async () => { - try { - const result = completeMigration(db); - return { success: result.ok, integrity: result.integrity }; - } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - logger.error('[Migration] Failed to complete migration', err); - return { success: false, error: msg }; - } - }); - - logger.info('[Migration] Migration IPC handlers registered'); -} +/** + * 数据迁移脚本(IndexedDB → SQLite) + * + * 协调模式:渲染进程读取 IndexedDB → IPC → 主进程写入 SQLite。 + * 迁移前自动备份、失败保留 IndexedDB 可重试、脚本幂等执行。 + * + * @ai-context: IndexedDB→SQLite 数据迁移 IPC:表映射/分批导入;safeHandle 经参数注入避免循环依赖。 + */ + +import type Database from 'better-sqlite3'; +import { getConnection } from './sqliteService.js'; +import { logger } from '../logger.js'; + +// ================================================================ +// 类型 & 常量 +// ================================================================ + +export interface MigrationStatus { + completed: boolean; + currentTable: string; + tablesTotal: number; + tablesCompleted: number; + rowsMigrated: number; + error?: string; +} + +/** Dexie 表名 → SQLite 表名映射 */ +const TABLE_MAPPING: Array<{ dexie: string; sqlite: string }> = [ + { dexie: 'notes', sqlite: 'notes' }, + { dexie: 'noteFolders', sqlite: 'note_folders' }, + { dexie: 'flashcardDecks', sqlite: 'flashcard_decks' }, + { dexie: 'flashcards', sqlite: 'flashcards' }, + { dexie: 'flashcardReviews', sqlite: 'flashcard_reviews' }, + { dexie: 'feynmanNotes', sqlite: 'feynman_notes' }, + { dexie: 'feynmanSummaries', sqlite: 'feynman_summaries' }, + { dexie: 'feynmanWeakPoints', sqlite: 'feynman_weak_points' }, + { dexie: 'pomodoroSessions', sqlite: 'pomodoro_sessions' }, + { dexie: 'pomodoroSettings', sqlite: 'pomodoro_settings' }, + { dexie: 'appSettings', sqlite: 'app_settings' }, + { dexie: 'operationLog', sqlite: 'operation_log' }, + { dexie: 'syncConflicts', sqlite: 'sync_conflicts' }, + { dexie: 'offlineQueue', sqlite: 'offline_queue' }, + { dexie: 'studyCheckIns', sqlite: 'study_check_ins' }, + { dexie: 'achievements', sqlite: 'achievements' }, + { dexie: 'pomodoroGoals', sqlite: 'pomodoro_goals' }, + { dexie: 'windowCaptures', sqlite: 'window_captures' }, + { dexie: 'consent', sqlite: 'consent' }, + { dexie: 'userProfile', sqlite: 'user_profile' }, + { dexie: 'inspirations', sqlite: 'inspirations' }, +]; + +/** 合法的 SQLite 表名集合 */ +const VALID_SQLITE_TABLES = new Set(TABLE_MAPPING.map((m) => m.sqlite)); + +/** camelCase → snake_case */ +function toSnake(s: string): string { + return s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`); +} + +// ================================================================ +// 核心 +// ================================================================ + +/** 检查是否需要迁移:无 migrationComplete 标记 + SQLite 无业务数据 → 需要迁移 */ +export function needsMigration(db: Database.Database): boolean { + try { + const row = db.prepare(`SELECT value FROM app_settings WHERE "key" = 'migrationComplete'`).get() as { value: string } | undefined; + if (row?.value === 'true') return false; + const notesCount = db.prepare('SELECT COUNT(*) AS cnt FROM notes').get() as { cnt: number }; + if (notesCount.cnt > 0) return false; + return true; + } catch (err) { + logger.error('[Migration] Failed to check migration status', err); + return false; + } +} + +/** + * 导入单表数据到 SQLite(INSERT OR REPLACE) + * + * @param sqliteTable - SQLite 表名(snake_case,需在白名单内) + * @param rows - 数据行数组(camelCase keys,由渲染进程发送) + * @returns 成功插入的行数 + */ +export function importTable(sqliteTable: string, rows: Record[]): number { + if (!VALID_SQLITE_TABLES.has(sqliteTable)) { + throw new Error(`[Migration] Table "${sqliteTable}" is not in the migration whitelist`); + } + + const db = getConnection(); + if (rows.length === 0) { + logger.info(`[Migration] Table "${sqliteTable}" — 0 rows to import, skipping`); + return 0; + } + + // 构建列名(从第一行推断,camelCase → snake_case) + const cols = Object.keys(rows[0]).map(toSnake); + + const placeholders = cols.map(() => '?').join(', '); + const colList = cols.map((c) => `"${c}"`).join(', '); + const sql = `INSERT OR REPLACE INTO "${sqliteTable}" (${colList}) VALUES (${placeholders})`; + const stmt = db.prepare(sql); + + const txn = db.transaction((items: Record[]) => { + for (const item of items) { + const values = Object.keys(item).map((k) => { + const val = item[k]; + // 自动 JSON 序列化对象/数组字段 + if (val !== null && typeof val === 'object' && !(val instanceof Date)) { + return JSON.stringify(val); + } + // boolean → INTEGER + if (typeof val === 'boolean') return val ? 1 : 0; + // Date → ISO string + if (val instanceof Date) return val.toISOString(); + return val; + }); + stmt.run(...values); + } + }); + + txn(rows); + logger.info(`[Migration] Imported ${rows.length} rows into "${sqliteTable}"`); + return rows.length; +} + +/** + * 标记迁移完成 + * + * 写入 migrationComplete 标记到 app_settings + 运行 PRAGMA integrity_check + */ +export function completeMigration(db: Database.Database): { ok: boolean; integrity: string } { + const now = new Date().toISOString(); + + db.prepare( + `INSERT OR REPLACE INTO app_settings (id, "key", value, updated_at) VALUES (?, 'migrationComplete', 'true', ?)` + ).run(crypto.randomUUID(), now); + + // 运行完整性检查 + const result = db.pragma('integrity_check', { simple: true }) as string; + const ok = result === 'ok'; + + if (ok) { + logger.info('[Migration] Migration completed successfully, integrity check passed'); + } else { + logger.error(`[Migration] Integrity check failed: ${result}`); + } + + return { ok, integrity: result }; +} + +// ================================================================ +// IPC handler 注册 +// ================================================================ + +/** + * 注册迁移相关 IPC handler(在 main.ts 的 app.whenReady 中调用) + * + * 需要外部传入 safeHandle 以避免循环依赖。 + */ +export function registerMigrationHandlers( + safeHandle: (channel: string, handler: (event: Electron.IpcMainInvokeEvent, ...args: Args) => Promise) => void, +): void { + const db = getConnection(); + + /** migration:check — 检查是否需要迁移 */ + safeHandle('migration:check', async () => { + const needed = needsMigration(db); + logger.info(`[Migration] Check result: ${needed ? 'migration needed' : 'no migration needed'}`); + return { needed, tableMapping: TABLE_MAPPING }; + }); + + /** migration:import-table — 导入单表数据 */ + safeHandle('migration:import-table', async (_event, params: { table: string; rows: Record[] }) => { + try { + const count = importTable(params.table, params.rows); + return { success: true, rowsImported: count }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + logger.error(`[Migration] Failed to import table "${params.table}"`, err); + return { success: false, error: msg }; + } + }); + + /** migration:complete — 标记迁移完成 */ + safeHandle('migration:complete', async () => { + try { + const result = completeMigration(db); + return { success: result.ok, integrity: result.integrity }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + logger.error('[Migration] Failed to complete migration', err); + return { success: false, error: msg }; + } + }); + + logger.info('[Migration] Migration IPC handlers registered'); +} diff --git a/client/electron/db/schema.ts b/client/electron/db/schema.ts index a477fff3..fee521b7 100644 --- a/client/electron/db/schema.ts +++ b/client/electron/db/schema.ts @@ -1,212 +1,214 @@ -/** - * SQLite Schema DDL — 全部建表语句 + 索引 + 初始化入口 - * 列类型映射: string→TEXT, number→REAL/INTEGER, boolean→INTEGER, Date→TEXT(ISO), Array/Object→TEXT(JSON) - */ -import type Database from 'better-sqlite3'; - -export const SCHEMA_VERSION = 4; - -export const SCHEMA_DDL = /* sql */ ` -CREATE TABLE IF NOT EXISTS pomodoro_sessions ( - id TEXT PRIMARY KEY, mode TEXT NOT NULL CHECK (mode IN ('class','self_study')), - subject TEXT, duration INTEGER NOT NULL CHECK (duration > 0), - actual_duration INTEGER NOT NULL CHECK (actual_duration >= 0), - completed_at TEXT NOT NULL, interrupted INTEGER NOT NULL DEFAULT 0, goal TEXT -); -CREATE TABLE IF NOT EXISTS pomodoro_settings ( - id TEXT PRIMARY KEY, work_duration INTEGER NOT NULL DEFAULT 25, - short_break_duration INTEGER NOT NULL DEFAULT 5, long_break_duration INTEGER NOT NULL DEFAULT 15, - long_break_interval INTEGER NOT NULL DEFAULT 4, auto_start_break INTEGER NOT NULL DEFAULT 0, - auto_start_work INTEGER NOT NULL DEFAULT 0, sound_enabled INTEGER NOT NULL DEFAULT 1, - notification_enabled INTEGER NOT NULL DEFAULT 1, class_duration INTEGER NOT NULL DEFAULT 45 -); -CREATE TABLE IF NOT EXISTS notes ( - id TEXT PRIMARY KEY, title TEXT NOT NULL DEFAULT '', content TEXT NOT NULL DEFAULT '', - template TEXT NOT NULL DEFAULT 'free' CHECK (template IN ('outline','cornell','mindmap','free','qa','blank','video')), - folder_id TEXT, tags TEXT NOT NULL DEFAULT '[]', created_at TEXT NOT NULL, updated_at TEXT NOT NULL, - word_count INTEGER NOT NULL DEFAULT 0, pinned INTEGER NOT NULL DEFAULT 0, video_note_type TEXT, - FOREIGN KEY (folder_id) REFERENCES note_folders(id) ON DELETE SET NULL -); -CREATE TABLE IF NOT EXISTS note_folders ( - id TEXT PRIMARY KEY, name TEXT NOT NULL, parent_id TEXT, color TEXT, - created_at TEXT NOT NULL, "order" INTEGER NOT NULL DEFAULT 0, - FOREIGN KEY (parent_id) REFERENCES note_folders(id) ON DELETE SET NULL -); -CREATE TABLE IF NOT EXISTS flashcard_decks ( - id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT, parent_id TEXT, color TEXT, - created_at TEXT NOT NULL, updated_at TEXT NOT NULL, "order" INTEGER NOT NULL DEFAULT 0, - FOREIGN KEY (parent_id) REFERENCES flashcard_decks(id) ON DELETE SET NULL -); -CREATE TABLE IF NOT EXISTS flashcards ( - id TEXT PRIMARY KEY, deck_id TEXT NOT NULL, front TEXT NOT NULL DEFAULT '', - back TEXT NOT NULL DEFAULT '', type TEXT NOT NULL DEFAULT 'basic' CHECK (type IN ('basic','cloze','multi_choice')), - ease_factor REAL NOT NULL DEFAULT 2.5, "interval" REAL NOT NULL DEFAULT 0, - repetitions INTEGER NOT NULL DEFAULT 0, lapses INTEGER NOT NULL DEFAULT 0, - due_date TEXT NOT NULL, last_review_date TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, - source_note_id TEXT, "order" INTEGER NOT NULL DEFAULT 0, - FOREIGN KEY (deck_id) REFERENCES flashcard_decks(id) ON DELETE CASCADE, - FOREIGN KEY (source_note_id) REFERENCES notes(id) ON DELETE SET NULL -); -CREATE TABLE IF NOT EXISTS flashcard_reviews ( - id TEXT PRIMARY KEY, card_id TEXT NOT NULL, deck_id TEXT NOT NULL, - rating INTEGER NOT NULL CHECK (rating BETWEEN 1 AND 4), - ease_factor_before REAL NOT NULL, ease_factor_after REAL NOT NULL, - interval_before REAL NOT NULL, interval_after REAL NOT NULL, - reviewed_at TEXT NOT NULL, time_spent REAL NOT NULL DEFAULT 0, - confidence TEXT CHECK (confidence IS NULL OR confidence IN ('low','medium','high')), - golden_error INTEGER, - FOREIGN KEY (card_id) REFERENCES flashcards(id) ON DELETE CASCADE, - FOREIGN KEY (deck_id) REFERENCES flashcard_decks(id) ON DELETE CASCADE -); -CREATE TABLE IF NOT EXISTS feynman_notes ( - id TEXT PRIMARY KEY, concept TEXT NOT NULL, explanation TEXT NOT NULL DEFAULT '', - status TEXT NOT NULL DEFAULT 'not_started' CHECK (status IN ('not_started','in_progress','completed')), - current_step INTEGER NOT NULL DEFAULT 1 CHECK (current_step BETWEEN 1 AND 4), - self_rating INTEGER CHECK (self_rating IS NULL OR self_rating BETWEEN 1 AND 5), - created_at TEXT NOT NULL, updated_at TEXT NOT NULL, completed_at TEXT -); -CREATE TABLE IF NOT EXISTS feynman_summaries ( - id TEXT PRIMARY KEY, note_id TEXT NOT NULL, summary TEXT NOT NULL DEFAULT '', - created_at TEXT NOT NULL, updated_at TEXT NOT NULL, - FOREIGN KEY (note_id) REFERENCES feynman_notes(id) ON DELETE CASCADE -); -CREATE TABLE IF NOT EXISTS feynman_weak_points ( - id TEXT PRIMARY KEY, note_id TEXT NOT NULL, text TEXT NOT NULL DEFAULT '', - position TEXT NOT NULL DEFAULT '{}', mastered INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, - FOREIGN KEY (note_id) REFERENCES feynman_notes(id) ON DELETE CASCADE -); -CREATE TABLE IF NOT EXISTS operation_log ( - id TEXT PRIMARY KEY, entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, - operation TEXT NOT NULL CHECK (operation IN ('create','update','delete')), - payload TEXT, created_at TEXT NOT NULL, synced INTEGER NOT NULL DEFAULT 0, - version INTEGER NOT NULL DEFAULT 0, device_id TEXT NOT NULL DEFAULT '', patch TEXT -); -CREATE TABLE IF NOT EXISTS app_settings ( - id TEXT PRIMARY KEY, "key" TEXT NOT NULL UNIQUE, value TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL -); -CREATE TABLE IF NOT EXISTS sync_conflicts ( - id TEXT PRIMARY KEY, entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, - local_data TEXT NOT NULL, remote_data TEXT NOT NULL, - local_version INTEGER NOT NULL, remote_version INTEGER NOT NULL, - status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','resolved-local','resolved-remote','resolved-manual')), - created_at TEXT NOT NULL, resolved_at TEXT -); -CREATE TABLE IF NOT EXISTS offline_queue ( - id TEXT PRIMARY KEY, entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, - operation TEXT NOT NULL CHECK (operation IN ('create','update','delete')), - payload TEXT, version INTEGER NOT NULL DEFAULT 0, device_id TEXT NOT NULL DEFAULT '', - created_at TEXT NOT NULL, retry_count INTEGER NOT NULL DEFAULT 0, next_retry_at REAL -); -CREATE TABLE IF NOT EXISTS study_check_ins ( - id TEXT PRIMARY KEY, "date" TEXT NOT NULL UNIQUE, check_in_time TEXT NOT NULL, - modules_used TEXT NOT NULL DEFAULT '[]', streak_days INTEGER NOT NULL DEFAULT 0 -); -CREATE TABLE IF NOT EXISTS achievements ( - id TEXT PRIMARY KEY, "key" TEXT NOT NULL UNIQUE, title TEXT NOT NULL, - description TEXT NOT NULL DEFAULT '', icon TEXT NOT NULL DEFAULT '', unlocked_at TEXT NOT NULL -); -CREATE TABLE IF NOT EXISTS pomodoro_goals ( - id TEXT PRIMARY KEY, text TEXT NOT NULL, use_count INTEGER NOT NULL DEFAULT 0, last_used_at TEXT NOT NULL -); -CREATE TABLE IF NOT EXISTS window_captures ( - id TEXT PRIMARY KEY, note_id TEXT, target_window TEXT NOT NULL DEFAULT '', - mode TEXT NOT NULL DEFAULT 'vision' CHECK (mode IN ('vision','audio','both')), - status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','paused','completed')), - segments TEXT NOT NULL DEFAULT '[]', started_at TEXT NOT NULL, ended_at TEXT, total_duration REAL, - FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE SET NULL -); -CREATE TABLE IF NOT EXISTS consent ( - id TEXT PRIMARY KEY, type TEXT NOT NULL CHECK (type IN ('privacy','terms')), - version TEXT NOT NULL, accepted_at TEXT NOT NULL -); -CREATE TABLE IF NOT EXISTS user_profile ( - id TEXT PRIMARY KEY, user_id TEXT NOT NULL, email TEXT NOT NULL DEFAULT '', - display_name TEXT NOT NULL DEFAULT '', bio TEXT NOT NULL DEFAULT '', - avatar_url TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL -); -CREATE TABLE IF NOT EXISTS inspirations ( - id TEXT PRIMARY KEY, content TEXT NOT NULL DEFAULT '', tags TEXT NOT NULL DEFAULT '{}', - tags_manually_edited INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, - sort_status TEXT CHECK (sort_status IS NULL OR sort_status IN ('pending','sorting','sorted','confirmed','transformed')), - sort_result TEXT -); -CREATE TABLE IF NOT EXISTS predictions ( - id TEXT PRIMARY KEY, - note_id TEXT NOT NULL, - question TEXT NOT NULL, - user_guess TEXT, - ai_answer TEXT NOT NULL, - accuracy TEXT CHECK(accuracy IN ('correct', 'partial', 'incorrect')), - difficulty INTEGER, - related_concepts TEXT, - created_at TEXT NOT NULL, - FOREIGN KEY (note_id) REFERENCES notes(id) -); -CREATE TABLE IF NOT EXISTS search_index ( - id INTEGER PRIMARY KEY AUTOINCREMENT, note_id TEXT NOT NULL, - tokens TEXT NOT NULL DEFAULT '[]', title TEXT NOT NULL DEFAULT '', - content TEXT NOT NULL DEFAULT '', updated_at REAL NOT NULL DEFAULT 0, - entity_id TEXT, entity_type TEXT, - FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE -); --- 高频查询列索引 -CREATE INDEX IF NOT EXISTS idx_notes_folder_id ON notes(folder_id); -CREATE INDEX IF NOT EXISTS idx_flashcards_deck_id ON flashcards(deck_id); -CREATE INDEX IF NOT EXISTS idx_pomodoro_sessions_completed_at ON pomodoro_sessions(completed_at); -CREATE INDEX IF NOT EXISTS idx_flashcard_reviews_reviewed_at ON flashcard_reviews(reviewed_at); -CREATE INDEX IF NOT EXISTS idx_feynman_notes_created_at ON feynman_notes(created_at); -CREATE INDEX IF NOT EXISTS idx_predictions_note_id ON predictions(note_id); -CREATE INDEX IF NOT EXISTS idx_predictions_created_at ON predictions(created_at); -`; - -/** v3 迁移 DDL:CRDT 同步引擎元数据表(条件执行) */ -export const SCHEMA_V3_DDL = /* sql */ ` -CREATE TABLE IF NOT EXISTS crdt_docs ( - table_name TEXT PRIMARY KEY, - snapshot TEXT NOT NULL DEFAULT '', - last_heads TEXT NOT NULL DEFAULT '', - updated_at TEXT NOT NULL -); -CREATE TABLE IF NOT EXISTS crdt_changes ( - seq INTEGER PRIMARY KEY AUTOINCREMENT, - table_name TEXT NOT NULL, - entity_id TEXT NOT NULL, - changeset TEXT NOT NULL, - operation TEXT NOT NULL CHECK (operation IN ('create','update','delete')), - created_at TEXT NOT NULL -); -CREATE INDEX IF NOT EXISTS idx_crdt_changes_table_name ON crdt_changes(table_name); -`; - -/** 执行 DDL 并设置 PRAGMA user_version。幂等调用(CREATE IF NOT EXISTS)。 */ -export function initializeSchema(db: Database.Database): void { - db.exec(SCHEMA_DDL); - - // v2 迁移:FSRS-5 扩展字段(条件 ALTER TABLE,幂等) - const currentVersion = db.pragma('user_version', { simple: true }) as number; - if (currentVersion < 2) { - try { - db.exec(`ALTER TABLE flashcards ADD COLUMN stability REAL DEFAULT NULL`); - } catch { /* 列已存在 */ } - try { - db.exec(`ALTER TABLE flashcards ADD COLUMN difficulty REAL DEFAULT NULL`); - } catch { /* 列已存在 */ } - } - - // v3 迁移:CRDT 同步引擎元数据表 - if (currentVersion < 3) { - db.exec(SCHEMA_V3_DDL); - } - - // v4 迁移:search_index 表增加 entity_id 和 entity_type 列 - if (currentVersion < 4) { - try { - db.exec(`ALTER TABLE search_index ADD COLUMN entity_id TEXT`); - } catch { /* 列已存在 */ } - try { - db.exec(`ALTER TABLE search_index ADD COLUMN entity_type TEXT`); - } catch { /* 列已存在 */ } - } - - db.pragma(`user_version = ${SCHEMA_VERSION}`); -} +/** + * SQLite Schema DDL — 全部建表语句 + 索引 + 初始化入口 + * 列类型映射: string→TEXT, number→REAL/INTEGER, boolean→INTEGER, Date→TEXT(ISO), Array/Object→TEXT(JSON) + * + * @ai-context: SQLite 建表 DDL 唯一权威源——新增表需同步 dbIpcHandlers.ALLOWED_TABLES 白名单。 + */ +import type Database from 'better-sqlite3'; + +export const SCHEMA_VERSION = 4; + +export const SCHEMA_DDL = /* sql */ ` +CREATE TABLE IF NOT EXISTS pomodoro_sessions ( + id TEXT PRIMARY KEY, mode TEXT NOT NULL CHECK (mode IN ('class','self_study')), + subject TEXT, duration INTEGER NOT NULL CHECK (duration > 0), + actual_duration INTEGER NOT NULL CHECK (actual_duration >= 0), + completed_at TEXT NOT NULL, interrupted INTEGER NOT NULL DEFAULT 0, goal TEXT +); +CREATE TABLE IF NOT EXISTS pomodoro_settings ( + id TEXT PRIMARY KEY, work_duration INTEGER NOT NULL DEFAULT 25, + short_break_duration INTEGER NOT NULL DEFAULT 5, long_break_duration INTEGER NOT NULL DEFAULT 15, + long_break_interval INTEGER NOT NULL DEFAULT 4, auto_start_break INTEGER NOT NULL DEFAULT 0, + auto_start_work INTEGER NOT NULL DEFAULT 0, sound_enabled INTEGER NOT NULL DEFAULT 1, + notification_enabled INTEGER NOT NULL DEFAULT 1, class_duration INTEGER NOT NULL DEFAULT 45 +); +CREATE TABLE IF NOT EXISTS notes ( + id TEXT PRIMARY KEY, title TEXT NOT NULL DEFAULT '', content TEXT NOT NULL DEFAULT '', + template TEXT NOT NULL DEFAULT 'free' CHECK (template IN ('outline','cornell','mindmap','free','qa','blank','video')), + folder_id TEXT, tags TEXT NOT NULL DEFAULT '[]', created_at TEXT NOT NULL, updated_at TEXT NOT NULL, + word_count INTEGER NOT NULL DEFAULT 0, pinned INTEGER NOT NULL DEFAULT 0, video_note_type TEXT, + FOREIGN KEY (folder_id) REFERENCES note_folders(id) ON DELETE SET NULL +); +CREATE TABLE IF NOT EXISTS note_folders ( + id TEXT PRIMARY KEY, name TEXT NOT NULL, parent_id TEXT, color TEXT, + created_at TEXT NOT NULL, "order" INTEGER NOT NULL DEFAULT 0, + FOREIGN KEY (parent_id) REFERENCES note_folders(id) ON DELETE SET NULL +); +CREATE TABLE IF NOT EXISTS flashcard_decks ( + id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT, parent_id TEXT, color TEXT, + created_at TEXT NOT NULL, updated_at TEXT NOT NULL, "order" INTEGER NOT NULL DEFAULT 0, + FOREIGN KEY (parent_id) REFERENCES flashcard_decks(id) ON DELETE SET NULL +); +CREATE TABLE IF NOT EXISTS flashcards ( + id TEXT PRIMARY KEY, deck_id TEXT NOT NULL, front TEXT NOT NULL DEFAULT '', + back TEXT NOT NULL DEFAULT '', type TEXT NOT NULL DEFAULT 'basic' CHECK (type IN ('basic','cloze','multi_choice')), + ease_factor REAL NOT NULL DEFAULT 2.5, "interval" REAL NOT NULL DEFAULT 0, + repetitions INTEGER NOT NULL DEFAULT 0, lapses INTEGER NOT NULL DEFAULT 0, + due_date TEXT NOT NULL, last_review_date TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, + source_note_id TEXT, "order" INTEGER NOT NULL DEFAULT 0, + FOREIGN KEY (deck_id) REFERENCES flashcard_decks(id) ON DELETE CASCADE, + FOREIGN KEY (source_note_id) REFERENCES notes(id) ON DELETE SET NULL +); +CREATE TABLE IF NOT EXISTS flashcard_reviews ( + id TEXT PRIMARY KEY, card_id TEXT NOT NULL, deck_id TEXT NOT NULL, + rating INTEGER NOT NULL CHECK (rating BETWEEN 1 AND 4), + ease_factor_before REAL NOT NULL, ease_factor_after REAL NOT NULL, + interval_before REAL NOT NULL, interval_after REAL NOT NULL, + reviewed_at TEXT NOT NULL, time_spent REAL NOT NULL DEFAULT 0, + confidence TEXT CHECK (confidence IS NULL OR confidence IN ('low','medium','high')), + golden_error INTEGER, + FOREIGN KEY (card_id) REFERENCES flashcards(id) ON DELETE CASCADE, + FOREIGN KEY (deck_id) REFERENCES flashcard_decks(id) ON DELETE CASCADE +); +CREATE TABLE IF NOT EXISTS feynman_notes ( + id TEXT PRIMARY KEY, concept TEXT NOT NULL, explanation TEXT NOT NULL DEFAULT '', + status TEXT NOT NULL DEFAULT 'not_started' CHECK (status IN ('not_started','in_progress','completed')), + current_step INTEGER NOT NULL DEFAULT 1 CHECK (current_step BETWEEN 1 AND 4), + self_rating INTEGER CHECK (self_rating IS NULL OR self_rating BETWEEN 1 AND 5), + created_at TEXT NOT NULL, updated_at TEXT NOT NULL, completed_at TEXT +); +CREATE TABLE IF NOT EXISTS feynman_summaries ( + id TEXT PRIMARY KEY, note_id TEXT NOT NULL, summary TEXT NOT NULL DEFAULT '', + created_at TEXT NOT NULL, updated_at TEXT NOT NULL, + FOREIGN KEY (note_id) REFERENCES feynman_notes(id) ON DELETE CASCADE +); +CREATE TABLE IF NOT EXISTS feynman_weak_points ( + id TEXT PRIMARY KEY, note_id TEXT NOT NULL, text TEXT NOT NULL DEFAULT '', + position TEXT NOT NULL DEFAULT '{}', mastered INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, + FOREIGN KEY (note_id) REFERENCES feynman_notes(id) ON DELETE CASCADE +); +CREATE TABLE IF NOT EXISTS operation_log ( + id TEXT PRIMARY KEY, entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, + operation TEXT NOT NULL CHECK (operation IN ('create','update','delete')), + payload TEXT, created_at TEXT NOT NULL, synced INTEGER NOT NULL DEFAULT 0, + version INTEGER NOT NULL DEFAULT 0, device_id TEXT NOT NULL DEFAULT '', patch TEXT +); +CREATE TABLE IF NOT EXISTS app_settings ( + id TEXT PRIMARY KEY, "key" TEXT NOT NULL UNIQUE, value TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS sync_conflicts ( + id TEXT PRIMARY KEY, entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, + local_data TEXT NOT NULL, remote_data TEXT NOT NULL, + local_version INTEGER NOT NULL, remote_version INTEGER NOT NULL, + status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','resolved-local','resolved-remote','resolved-manual')), + created_at TEXT NOT NULL, resolved_at TEXT +); +CREATE TABLE IF NOT EXISTS offline_queue ( + id TEXT PRIMARY KEY, entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, + operation TEXT NOT NULL CHECK (operation IN ('create','update','delete')), + payload TEXT, version INTEGER NOT NULL DEFAULT 0, device_id TEXT NOT NULL DEFAULT '', + created_at TEXT NOT NULL, retry_count INTEGER NOT NULL DEFAULT 0, next_retry_at REAL +); +CREATE TABLE IF NOT EXISTS study_check_ins ( + id TEXT PRIMARY KEY, "date" TEXT NOT NULL UNIQUE, check_in_time TEXT NOT NULL, + modules_used TEXT NOT NULL DEFAULT '[]', streak_days INTEGER NOT NULL DEFAULT 0 +); +CREATE TABLE IF NOT EXISTS achievements ( + id TEXT PRIMARY KEY, "key" TEXT NOT NULL UNIQUE, title TEXT NOT NULL, + description TEXT NOT NULL DEFAULT '', icon TEXT NOT NULL DEFAULT '', unlocked_at TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS pomodoro_goals ( + id TEXT PRIMARY KEY, text TEXT NOT NULL, use_count INTEGER NOT NULL DEFAULT 0, last_used_at TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS window_captures ( + id TEXT PRIMARY KEY, note_id TEXT, target_window TEXT NOT NULL DEFAULT '', + mode TEXT NOT NULL DEFAULT 'vision' CHECK (mode IN ('vision','audio','both')), + status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','paused','completed')), + segments TEXT NOT NULL DEFAULT '[]', started_at TEXT NOT NULL, ended_at TEXT, total_duration REAL, + FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE SET NULL +); +CREATE TABLE IF NOT EXISTS consent ( + id TEXT PRIMARY KEY, type TEXT NOT NULL CHECK (type IN ('privacy','terms')), + version TEXT NOT NULL, accepted_at TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS user_profile ( + id TEXT PRIMARY KEY, user_id TEXT NOT NULL, email TEXT NOT NULL DEFAULT '', + display_name TEXT NOT NULL DEFAULT '', bio TEXT NOT NULL DEFAULT '', + avatar_url TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS inspirations ( + id TEXT PRIMARY KEY, content TEXT NOT NULL DEFAULT '', tags TEXT NOT NULL DEFAULT '{}', + tags_manually_edited INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, + sort_status TEXT CHECK (sort_status IS NULL OR sort_status IN ('pending','sorting','sorted','confirmed','transformed')), + sort_result TEXT +); +CREATE TABLE IF NOT EXISTS predictions ( + id TEXT PRIMARY KEY, + note_id TEXT NOT NULL, + question TEXT NOT NULL, + user_guess TEXT, + ai_answer TEXT NOT NULL, + accuracy TEXT CHECK(accuracy IN ('correct', 'partial', 'incorrect')), + difficulty INTEGER, + related_concepts TEXT, + created_at TEXT NOT NULL, + FOREIGN KEY (note_id) REFERENCES notes(id) +); +CREATE TABLE IF NOT EXISTS search_index ( + id INTEGER PRIMARY KEY AUTOINCREMENT, note_id TEXT NOT NULL, + tokens TEXT NOT NULL DEFAULT '[]', title TEXT NOT NULL DEFAULT '', + content TEXT NOT NULL DEFAULT '', updated_at REAL NOT NULL DEFAULT 0, + entity_id TEXT, entity_type TEXT, + FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE +); +-- 高频查询列索引 +CREATE INDEX IF NOT EXISTS idx_notes_folder_id ON notes(folder_id); +CREATE INDEX IF NOT EXISTS idx_flashcards_deck_id ON flashcards(deck_id); +CREATE INDEX IF NOT EXISTS idx_pomodoro_sessions_completed_at ON pomodoro_sessions(completed_at); +CREATE INDEX IF NOT EXISTS idx_flashcard_reviews_reviewed_at ON flashcard_reviews(reviewed_at); +CREATE INDEX IF NOT EXISTS idx_feynman_notes_created_at ON feynman_notes(created_at); +CREATE INDEX IF NOT EXISTS idx_predictions_note_id ON predictions(note_id); +CREATE INDEX IF NOT EXISTS idx_predictions_created_at ON predictions(created_at); +`; + +/** v3 迁移 DDL:CRDT 同步引擎元数据表(条件执行) */ +export const SCHEMA_V3_DDL = /* sql */ ` +CREATE TABLE IF NOT EXISTS crdt_docs ( + table_name TEXT PRIMARY KEY, + snapshot TEXT NOT NULL DEFAULT '', + last_heads TEXT NOT NULL DEFAULT '', + updated_at TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS crdt_changes ( + seq INTEGER PRIMARY KEY AUTOINCREMENT, + table_name TEXT NOT NULL, + entity_id TEXT NOT NULL, + changeset TEXT NOT NULL, + operation TEXT NOT NULL CHECK (operation IN ('create','update','delete')), + created_at TEXT NOT NULL +); +CREATE INDEX IF NOT EXISTS idx_crdt_changes_table_name ON crdt_changes(table_name); +`; + +/** 执行 DDL 并设置 PRAGMA user_version。幂等调用(CREATE IF NOT EXISTS)。 */ +export function initializeSchema(db: Database.Database): void { + db.exec(SCHEMA_DDL); + + // v2 迁移:FSRS-5 扩展字段(条件 ALTER TABLE,幂等) + const currentVersion = db.pragma('user_version', { simple: true }) as number; + if (currentVersion < 2) { + try { + db.exec(`ALTER TABLE flashcards ADD COLUMN stability REAL DEFAULT NULL`); + } catch { /* 列已存在 */ } + try { + db.exec(`ALTER TABLE flashcards ADD COLUMN difficulty REAL DEFAULT NULL`); + } catch { /* 列已存在 */ } + } + + // v3 迁移:CRDT 同步引擎元数据表 + if (currentVersion < 3) { + db.exec(SCHEMA_V3_DDL); + } + + // v4 迁移:search_index 表增加 entity_id 和 entity_type 列 + if (currentVersion < 4) { + try { + db.exec(`ALTER TABLE search_index ADD COLUMN entity_id TEXT`); + } catch { /* 列已存在 */ } + try { + db.exec(`ALTER TABLE search_index ADD COLUMN entity_type TEXT`); + } catch { /* 列已存在 */ } + } + + db.pragma(`user_version = ${SCHEMA_VERSION}`); +} diff --git a/client/electron/db/sqliteRepository.ts b/client/electron/db/sqliteRepository.ts index cfaeba60..092c7686 100644 --- a/client/electron/db/sqliteRepository.ts +++ b/client/electron/db/sqliteRepository.ts @@ -1,195 +1,197 @@ -/** - * SQLite 通用仓库 — 实现 IRepository 接口 - * - * 在 Electron 主进程中直接调用 better-sqlite3(不走 IPC)。 - * 自动处理 camelCase ↔ snake_case 转换、JSON 序列化/反序列化、boolean ↔ INTEGER 映射。 - */ - -import type { IRepository } from '../../src/lib/storage/interfaces'; -import type Database from 'better-sqlite3'; -import { getConnection } from './sqliteService'; - -// ================================================================ -// 工具函数 -// ================================================================ - -/** camelCase → snake_case */ -function toSnake(s: string): string { - return s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`); -} - -/** snake_case → camelCase */ -function toCamel(s: string): string { - return s.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase()); -} - -// ================================================================ -// 每张表的元数据:哪些列是 JSON / Boolean -// ================================================================ - -interface TableMeta { - jsonFields: string[]; // camelCase 字段名,值需 JSON.stringify / JSON.parse - boolFields: string[]; // camelCase 字段名,SQLite 中为 INTEGER(0/1) -} - -const TABLE_META: Record = { - notes: { jsonFields: ['tags'], boolFields: ['pinned'] }, - flashcards: { jsonFields: [], boolFields: [] }, - flashcardReviews: { jsonFields: [], boolFields: ['goldenError'] }, - feynmanWeakPoints: { jsonFields: ['position'], boolFields: ['mastered'] }, - operationLog: { jsonFields: [], boolFields: ['synced'] }, - syncConflicts: { jsonFields: [], boolFields: [] }, - offlineQueue: { jsonFields: [], boolFields: [] }, - studyCheckIns: { jsonFields: ['modulesUsed'], boolFields: [] }, - windowCaptures: { jsonFields: ['segments'], boolFields: [] }, - inspirations: { jsonFields: ['tags', 'sortResult'], boolFields: ['tagsManuallyEdited'] }, - searchIndex: { jsonFields: ['tokens'], boolFields: [] }, - pomodoroSessions: { jsonFields: [], boolFields: ['interrupted'] }, - pomodoroSettings: { jsonFields: [], boolFields: ['autoStartBreak', 'autoStartWork', 'soundEnabled', 'notificationEnabled'] }, -}; - -function getMeta(tableName: string): TableMeta { - return TABLE_META[tableName] ?? { jsonFields: [], boolFields: [] }; -} - -// ================================================================ -// 行 ↔ 实体转换 -// ================================================================ - -/** SQLite 行(snake_case keys)→ TypeScript 实体(camelCase keys) */ -function rowToEntity(row: Record, meta: TableMeta): T { - const jsonSet = new Set(meta.jsonFields); - const boolSet = new Set(meta.boolFields); - const result: Record = {}; - - for (const [snakeKey, raw] of Object.entries(row)) { - const camelKey = toCamel(snakeKey); - if (jsonSet.has(camelKey) && typeof raw === 'string') { - try { result[camelKey] = JSON.parse(raw); } catch { result[camelKey] = raw; } - } else if (boolSet.has(camelKey)) { - result[camelKey] = raw === 1 || raw === true; - } else { - result[camelKey] = raw; - } - } - return result as T; -} - -/** TypeScript 实体(camelCase keys)→ SQL 参数对象(snake_case keys) */ -function entityToRow(entity: Record, meta: TableMeta): Record { - const jsonSet = new Set(meta.jsonFields); - const boolSet = new Set(meta.boolFields); - const row: Record = {}; - - for (const [camelKey, value] of Object.entries(entity)) { - const snakeKey = toSnake(camelKey); - if (value === undefined) continue; - if (jsonSet.has(camelKey)) { - row[snakeKey] = JSON.stringify(value); - } else if (boolSet.has(camelKey)) { - row[snakeKey] = value ? 1 : 0; - } else { - row[snakeKey] = value; - } - } - return row; -} - -// ================================================================ -// SQL 安全工具 -// ================================================================ - -/** 用双引号包裹列名,防止 SQLite 保留字冲突 */ -function q(col: string): string { - return `"${col}"`; -} - -// ================================================================ -// SqliteRepository -// ================================================================ - -export default class SqliteRepository implements IRepository { - private tableName: string; - private meta: TableMeta; - - constructor(tableName: string) { - this.tableName = tableName; - this.meta = getMeta(tableName); - } - - private get db(): Database.Database { - return getConnection(); - } - - async getAll(): Promise { - const rows = this.db.prepare(`SELECT * FROM ${this.tableName}`).all() as Record[]; - return rows.map((r) => rowToEntity(r, this.meta)); - } - - async getById(id: string): Promise { - const row = this.db.prepare(`SELECT * FROM ${this.tableName} WHERE id = ?`).get(id) as - | Record - | undefined; - return row ? rowToEntity(row, this.meta) : undefined; - } - - async create(item: Omit & { id: string }): Promise { - const row = entityToRow(item as unknown as Record, this.meta); - const cols = Object.keys(row); - const placeholders = cols.map(() => '?').join(', '); - const sql = `INSERT INTO ${this.tableName} (${cols.map(q).join(', ')}) VALUES (${placeholders})`; - this.db.prepare(sql).run(...Object.values(row)); - return item.id; - } - - async update(id: string, changes: Partial): Promise { - const row = entityToRow(changes as Record, this.meta); - const entries = Object.entries(row); - if (entries.length === 0) return; - const setClauses = entries.map(([col]) => `${q(col)} = ?`).join(', '); - const sql = `UPDATE ${this.tableName} SET ${setClauses} WHERE id = ?`; - this.db.prepare(sql).run(...entries.map(([, v]) => v), id); - } - - async delete(id: string): Promise { - this.db.prepare(`DELETE FROM ${this.tableName} WHERE id = ?`).run(id); - } - - async find(predicate: (item: T) => boolean): Promise { - const all = await this.getAll(); - return all.filter(predicate); - } - - async bulkCreate(items: (Omit & { id: string })[]): Promise { - if (items.length === 0) return []; - const rows = items.map((item) => entityToRow(item as unknown as Record, this.meta)); - const cols = Object.keys(rows[0]); - const placeholders = cols.map(() => '?').join(', '); - const sql = `INSERT INTO ${this.tableName} (${cols.map(q).join(', ')}) VALUES (${placeholders})`; - const stmt = this.db.prepare(sql); - - const txn = this.db.transaction((entries: Record[]) => { - for (const entry of entries) { - stmt.run(...cols.map((c) => entry[c])); - } - }); - txn(rows); - return items.map((item) => item.id); - } - - async bulkDelete(ids: string[]): Promise { - if (ids.length === 0) return; - const placeholders = ids.map(() => '?').join(', '); - const sql = `DELETE FROM ${this.tableName} WHERE id IN (${placeholders})`; - this.db.prepare(sql).run(...ids); - } - - async count(): Promise { - const row = this.db.prepare(`SELECT COUNT(*) AS cnt FROM ${this.tableName}`).get() as { cnt: number }; - return row.cnt; - } - - async clear(): Promise { - this.db.prepare(`DELETE FROM ${this.tableName}`).run(); - } -} +/** + * SQLite 通用仓库 — 实现 IRepository 接口 + * + * 在 Electron 主进程中直接调用 better-sqlite3(不走 IPC)。 + * 自动处理 camelCase ↔ snake_case 转换、JSON 序列化/反序列化、boolean ↔ INTEGER 映射。 + * + * @ai-context: SQLite 通用仓储(泛型 CRUD),表名由调用方经白名单校验后传入。 + */ + +import type { IRepository } from '../../src/lib/storage/interfaces'; +import type Database from 'better-sqlite3'; +import { getConnection } from './sqliteService'; + +// ================================================================ +// 工具函数 +// ================================================================ + +/** camelCase → snake_case */ +function toSnake(s: string): string { + return s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`); +} + +/** snake_case → camelCase */ +function toCamel(s: string): string { + return s.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase()); +} + +// ================================================================ +// 每张表的元数据:哪些列是 JSON / Boolean +// ================================================================ + +interface TableMeta { + jsonFields: string[]; // camelCase 字段名,值需 JSON.stringify / JSON.parse + boolFields: string[]; // camelCase 字段名,SQLite 中为 INTEGER(0/1) +} + +const TABLE_META: Record = { + notes: { jsonFields: ['tags'], boolFields: ['pinned'] }, + flashcards: { jsonFields: [], boolFields: [] }, + flashcardReviews: { jsonFields: [], boolFields: ['goldenError'] }, + feynmanWeakPoints: { jsonFields: ['position'], boolFields: ['mastered'] }, + operationLog: { jsonFields: [], boolFields: ['synced'] }, + syncConflicts: { jsonFields: [], boolFields: [] }, + offlineQueue: { jsonFields: [], boolFields: [] }, + studyCheckIns: { jsonFields: ['modulesUsed'], boolFields: [] }, + windowCaptures: { jsonFields: ['segments'], boolFields: [] }, + inspirations: { jsonFields: ['tags', 'sortResult'], boolFields: ['tagsManuallyEdited'] }, + searchIndex: { jsonFields: ['tokens'], boolFields: [] }, + pomodoroSessions: { jsonFields: [], boolFields: ['interrupted'] }, + pomodoroSettings: { jsonFields: [], boolFields: ['autoStartBreak', 'autoStartWork', 'soundEnabled', 'notificationEnabled'] }, +}; + +function getMeta(tableName: string): TableMeta { + return TABLE_META[tableName] ?? { jsonFields: [], boolFields: [] }; +} + +// ================================================================ +// 行 ↔ 实体转换 +// ================================================================ + +/** SQLite 行(snake_case keys)→ TypeScript 实体(camelCase keys) */ +function rowToEntity(row: Record, meta: TableMeta): T { + const jsonSet = new Set(meta.jsonFields); + const boolSet = new Set(meta.boolFields); + const result: Record = {}; + + for (const [snakeKey, raw] of Object.entries(row)) { + const camelKey = toCamel(snakeKey); + if (jsonSet.has(camelKey) && typeof raw === 'string') { + try { result[camelKey] = JSON.parse(raw); } catch { result[camelKey] = raw; } + } else if (boolSet.has(camelKey)) { + result[camelKey] = raw === 1 || raw === true; + } else { + result[camelKey] = raw; + } + } + return result as T; +} + +/** TypeScript 实体(camelCase keys)→ SQL 参数对象(snake_case keys) */ +function entityToRow(entity: Record, meta: TableMeta): Record { + const jsonSet = new Set(meta.jsonFields); + const boolSet = new Set(meta.boolFields); + const row: Record = {}; + + for (const [camelKey, value] of Object.entries(entity)) { + const snakeKey = toSnake(camelKey); + if (value === undefined) continue; + if (jsonSet.has(camelKey)) { + row[snakeKey] = JSON.stringify(value); + } else if (boolSet.has(camelKey)) { + row[snakeKey] = value ? 1 : 0; + } else { + row[snakeKey] = value; + } + } + return row; +} + +// ================================================================ +// SQL 安全工具 +// ================================================================ + +/** 用双引号包裹列名,防止 SQLite 保留字冲突 */ +function q(col: string): string { + return `"${col}"`; +} + +// ================================================================ +// SqliteRepository +// ================================================================ + +export default class SqliteRepository implements IRepository { + private tableName: string; + private meta: TableMeta; + + constructor(tableName: string) { + this.tableName = tableName; + this.meta = getMeta(tableName); + } + + private get db(): Database.Database { + return getConnection(); + } + + async getAll(): Promise { + const rows = this.db.prepare(`SELECT * FROM ${this.tableName}`).all() as Record[]; + return rows.map((r) => rowToEntity(r, this.meta)); + } + + async getById(id: string): Promise { + const row = this.db.prepare(`SELECT * FROM ${this.tableName} WHERE id = ?`).get(id) as + | Record + | undefined; + return row ? rowToEntity(row, this.meta) : undefined; + } + + async create(item: Omit & { id: string }): Promise { + const row = entityToRow(item as unknown as Record, this.meta); + const cols = Object.keys(row); + const placeholders = cols.map(() => '?').join(', '); + const sql = `INSERT INTO ${this.tableName} (${cols.map(q).join(', ')}) VALUES (${placeholders})`; + this.db.prepare(sql).run(...Object.values(row)); + return item.id; + } + + async update(id: string, changes: Partial): Promise { + const row = entityToRow(changes as Record, this.meta); + const entries = Object.entries(row); + if (entries.length === 0) return; + const setClauses = entries.map(([col]) => `${q(col)} = ?`).join(', '); + const sql = `UPDATE ${this.tableName} SET ${setClauses} WHERE id = ?`; + this.db.prepare(sql).run(...entries.map(([, v]) => v), id); + } + + async delete(id: string): Promise { + this.db.prepare(`DELETE FROM ${this.tableName} WHERE id = ?`).run(id); + } + + async find(predicate: (item: T) => boolean): Promise { + const all = await this.getAll(); + return all.filter(predicate); + } + + async bulkCreate(items: (Omit & { id: string })[]): Promise { + if (items.length === 0) return []; + const rows = items.map((item) => entityToRow(item as unknown as Record, this.meta)); + const cols = Object.keys(rows[0]); + const placeholders = cols.map(() => '?').join(', '); + const sql = `INSERT INTO ${this.tableName} (${cols.map(q).join(', ')}) VALUES (${placeholders})`; + const stmt = this.db.prepare(sql); + + const txn = this.db.transaction((entries: Record[]) => { + for (const entry of entries) { + stmt.run(...cols.map((c) => entry[c])); + } + }); + txn(rows); + return items.map((item) => item.id); + } + + async bulkDelete(ids: string[]): Promise { + if (ids.length === 0) return; + const placeholders = ids.map(() => '?').join(', '); + const sql = `DELETE FROM ${this.tableName} WHERE id IN (${placeholders})`; + this.db.prepare(sql).run(...ids); + } + + async count(): Promise { + const row = this.db.prepare(`SELECT COUNT(*) AS cnt FROM ${this.tableName}`).get() as { cnt: number }; + return row.cnt; + } + + async clear(): Promise { + this.db.prepare(`DELETE FROM ${this.tableName}`).run(); + } +} diff --git a/client/electron/db/sqliteService.ts b/client/electron/db/sqliteService.ts index 852c63c0..311df798 100644 --- a/client/electron/db/sqliteService.ts +++ b/client/electron/db/sqliteService.ts @@ -1,151 +1,153 @@ -/** - * SQLite 服务(单例) - * - * 管理 better-sqlite3 连接的初始化、获取与关闭。 - * 数据库文件默认存储于 Electron userData/keban.db。 - * WAL 模式 + 外键约束在初始化时自动开启。 - */ - -import Database from 'better-sqlite3'; -import { logger } from '../logger.js'; - -// ================================================================ -// 模块级状态 -// ================================================================ - -/** 单例数据库连接引用 */ -let db: Database.Database | null = null; - -/** 当前数据库文件路径(initialize 成功后记录) */ -let currentDbPath: string | null = null; - -// ================================================================ -// 公共 API -// ================================================================ - -/** - * 初始化 SQLite 连接 - * - * @param dbPath - 可选自定义数据库路径;省略时使用 `userData/keban.db` - * @returns 已初始化的 Database 实例 - * - * 幂等调用:若连接已存在则直接返回,不会重复创建。 - */ -export function initialize(dbPath?: string): Database.Database { - if (db) { - logger.info('[SQLite] Connection already initialized, returning existing instance'); - return db; - } - - const resolvedPath = dbPath; - if (!resolvedPath) { - throw new Error('[SQLite] dbPath is required — resolve the path before calling initialize()'); - } - logger.info(`[SQLite] Initializing database at: ${resolvedPath}`); - - try { - db = new Database(resolvedPath); - - // 开启 WAL 模式:提升并发读写性能,减少锁竞争 - db.pragma('journal_mode = WAL'); - logger.info('[SQLite] WAL mode enabled'); - - // 开启外键约束:保证引用完整性 - db.pragma('foreign_keys = ON'); - logger.info('[SQLite] Foreign key constraints enabled'); - - // 设置 busy timeout(5 秒),避免 WAL checkpoint 期间立即报 SQLITE_BUSY - db.pragma('busy_timeout = 5000'); - - logger.info('[SQLite] Database initialized successfully'); - currentDbPath = resolvedPath; - return db; - } catch (err) { - db = null; - logger.error('[SQLite] Failed to initialize database', err); - throw err; - } -} - -/** - * 获取已初始化的数据库连接 - * - * @throws 若尚未调用 `initialize()` 则抛出错误 - */ -export function getConnection(): Database.Database { - if (!db) { - const msg = '[SQLite] Database not initialized — call initialize() first'; - logger.error(msg); - throw new Error(msg); - } - return db; -} - -/** - * 安全关闭数据库连接 - * - * 幂等调用:连接已关闭或从未初始化时静默返回。 - */ -export function close(): void { - if (!db) { - logger.info('[SQLite] No active connection to close'); - return; - } - - try { - db.close(); - logger.info('[SQLite] Database connection closed'); - } catch (err) { - logger.error('[SQLite] Error while closing database', err); - } finally { - db = null; - currentDbPath = null; - } -} - -/** - * 获取当前数据库文件路径 - * - * @returns 已初始化时返回路径字符串,否则返回 null - */ -export function getDbPath(): string | null { - return currentDbPath; -} - -/** - * 执行 WAL checkpoint 并安全关闭连接 - * 用于路径迁移前确保所有数据已写入主数据库文件 - */ -export function checkpointAndClose(): void { - if (!db) { - logger.info('[SQLite] No active connection to checkpoint'); - return; - } - try { - logger.info('[SQLite] Performing WAL checkpoint before close...'); - db.pragma('wal_checkpoint(TRUNCATE)'); - logger.info('[SQLite] WAL checkpoint completed'); - } catch (err) { - logger.error('[SQLite] WAL checkpoint failed, proceeding with close', err); - } finally { - try { - db.close(); - logger.info('[SQLite] Database connection closed after checkpoint'); - } catch (closeErr) { - logger.error('[SQLite] Error closing database after checkpoint', closeErr); - } finally { - db = null; - currentDbPath = null; - } - } -} - -/** - * 重新初始化数据库连接到新路径 - * 先关闭现有连接,再以新路径创建新连接 - */ -export function reinitialize(newDbPath: string): Database.Database { - logger.info(`[SQLite] Reinitializing database at: ${newDbPath}`); - close(); - return initialize(newDbPath); -} +/** + * SQLite 服务(单例) + * + * 管理 better-sqlite3 连接的初始化、获取与关闭。 + * 数据库文件默认存储于 Electron userData/keban.db。 + * WAL 模式 + 外键约束在初始化时自动开启。 + * + * @ai-context: SQLite 连接生命周期(initialize/reinitialize/checkpointAndClose);库文件 userData/keban.db 为存量数据标识,永久豁免改名。 + */ + +import Database from 'better-sqlite3'; +import { logger } from '../logger.js'; + +// ================================================================ +// 模块级状态 +// ================================================================ + +/** 单例数据库连接引用 */ +let db: Database.Database | null = null; + +/** 当前数据库文件路径(initialize 成功后记录) */ +let currentDbPath: string | null = null; + +// ================================================================ +// 公共 API +// ================================================================ + +/** + * 初始化 SQLite 连接 + * + * @param dbPath - 可选自定义数据库路径;省略时使用 `userData/keban.db` + * @returns 已初始化的 Database 实例 + * + * 幂等调用:若连接已存在则直接返回,不会重复创建。 + */ +export function initialize(dbPath?: string): Database.Database { + if (db) { + logger.info('[SQLite] Connection already initialized, returning existing instance'); + return db; + } + + const resolvedPath = dbPath; + if (!resolvedPath) { + throw new Error('[SQLite] dbPath is required — resolve the path before calling initialize()'); + } + logger.info(`[SQLite] Initializing database at: ${resolvedPath}`); + + try { + db = new Database(resolvedPath); + + // 开启 WAL 模式:提升并发读写性能,减少锁竞争 + db.pragma('journal_mode = WAL'); + logger.info('[SQLite] WAL mode enabled'); + + // 开启外键约束:保证引用完整性 + db.pragma('foreign_keys = ON'); + logger.info('[SQLite] Foreign key constraints enabled'); + + // 设置 busy timeout(5 秒),避免 WAL checkpoint 期间立即报 SQLITE_BUSY + db.pragma('busy_timeout = 5000'); + + logger.info('[SQLite] Database initialized successfully'); + currentDbPath = resolvedPath; + return db; + } catch (err) { + db = null; + logger.error('[SQLite] Failed to initialize database', err); + throw err; + } +} + +/** + * 获取已初始化的数据库连接 + * + * @throws 若尚未调用 `initialize()` 则抛出错误 + */ +export function getConnection(): Database.Database { + if (!db) { + const msg = '[SQLite] Database not initialized — call initialize() first'; + logger.error(msg); + throw new Error(msg); + } + return db; +} + +/** + * 安全关闭数据库连接 + * + * 幂等调用:连接已关闭或从未初始化时静默返回。 + */ +export function close(): void { + if (!db) { + logger.info('[SQLite] No active connection to close'); + return; + } + + try { + db.close(); + logger.info('[SQLite] Database connection closed'); + } catch (err) { + logger.error('[SQLite] Error while closing database', err); + } finally { + db = null; + currentDbPath = null; + } +} + +/** + * 获取当前数据库文件路径 + * + * @returns 已初始化时返回路径字符串,否则返回 null + */ +export function getDbPath(): string | null { + return currentDbPath; +} + +/** + * 执行 WAL checkpoint 并安全关闭连接 + * 用于路径迁移前确保所有数据已写入主数据库文件 + */ +export function checkpointAndClose(): void { + if (!db) { + logger.info('[SQLite] No active connection to checkpoint'); + return; + } + try { + logger.info('[SQLite] Performing WAL checkpoint before close...'); + db.pragma('wal_checkpoint(TRUNCATE)'); + logger.info('[SQLite] WAL checkpoint completed'); + } catch (err) { + logger.error('[SQLite] WAL checkpoint failed, proceeding with close', err); + } finally { + try { + db.close(); + logger.info('[SQLite] Database connection closed after checkpoint'); + } catch (closeErr) { + logger.error('[SQLite] Error closing database after checkpoint', closeErr); + } finally { + db = null; + currentDbPath = null; + } + } +} + +/** + * 重新初始化数据库连接到新路径 + * 先关闭现有连接,再以新路径创建新连接 + */ +export function reinitialize(newDbPath: string): Database.Database { + logger.info(`[SQLite] Reinitializing database at: ${newDbPath}`); + close(); + return initialize(newDbPath); +} diff --git a/client/electron/db/storageConfig.ts b/client/electron/db/storageConfig.ts index 6eb2168c..797d7d22 100644 --- a/client/electron/db/storageConfig.ts +++ b/client/electron/db/storageConfig.ts @@ -1,81 +1,83 @@ -/** - * 存储路径配置管理 - * - * 将自定义存储路径持久化到 userData/storage-config.json, - * 确保主进程启动时能读取用户的路径偏好。 - * 配置文件始终存放在 app.getPath('userData'),即使用户选择了自定义数据路径。 - */ - -import { app } from 'electron'; -import * as path from 'path'; -import { readFile, writeFile, access } from 'fs/promises'; -import { logger } from '../logger.js'; - -// ================================================================ -// 类型定义 -// ================================================================ - -interface StorageConfig { - customStoragePath: string | null; -} - -// ================================================================ -// 常量 -// ================================================================ - -const CONFIG_FILENAME = 'storage-config.json'; - -// ================================================================ -// 公共 API -// ================================================================ - -/** 返回配置文件完整路径 */ -export function getConfigFilePath(): string { - return path.join(app.getPath('userData'), CONFIG_FILENAME); -} - -/** 读取自定义存储路径,无配置时返回 null */ -export async function getCustomStoragePath(): Promise { - try { - const configPath = getConfigFilePath(); - try { - await access(configPath); - } catch { - return null; - } - const raw = await readFile(configPath, 'utf-8'); - const config: StorageConfig = JSON.parse(raw); - return config.customStoragePath ?? null; - } catch (err) { - logger.error('[StorageConfig] Failed to read config', err); - return null; - } -} - -/** 持久化自定义存储路径 */ -export async function saveCustomStoragePath(dirPath: string): Promise { - const configPath = getConfigFilePath(); - const config: StorageConfig = { customStoragePath: dirPath }; - await writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8'); - logger.info(`[StorageConfig] Saved custom storage path: ${dirPath}`); -} - -/** 清除自定义路径配置(恢复默认) */ -export async function clearCustomStoragePath(): Promise { - const configPath = getConfigFilePath(); - const config: StorageConfig = { customStoragePath: null }; - await writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8'); - logger.info('[StorageConfig] Cleared custom storage path, using default'); -} - -/** - * 解析最终数据库文件路径 - * 优先使用自定义路径,否则回退到 userData/keban.db - */ -export async function resolveDbPath(): Promise { - const customPath = await getCustomStoragePath(); - if (customPath) { - return path.join(customPath, 'keban.db'); - } - return path.join(app.getPath('userData'), 'keban.db'); -} +/** + * 存储路径配置管理 + * + * 将自定义存储路径持久化到 userData/storage-config.json, + * 确保主进程启动时能读取用户的路径偏好。 + * 配置文件始终存放在 app.getPath('userData'),即使用户选择了自定义数据路径。 + * + * @ai-context: 自定义存储路径配置持久化;resolveDbPath 回退 userData/keban.db(豁免标识)。 + */ + +import { app } from 'electron'; +import * as path from 'path'; +import { readFile, writeFile, access } from 'fs/promises'; +import { logger } from '../logger.js'; + +// ================================================================ +// 类型定义 +// ================================================================ + +interface StorageConfig { + customStoragePath: string | null; +} + +// ================================================================ +// 常量 +// ================================================================ + +const CONFIG_FILENAME = 'storage-config.json'; + +// ================================================================ +// 公共 API +// ================================================================ + +/** 返回配置文件完整路径 */ +export function getConfigFilePath(): string { + return path.join(app.getPath('userData'), CONFIG_FILENAME); +} + +/** 读取自定义存储路径,无配置时返回 null */ +export async function getCustomStoragePath(): Promise { + try { + const configPath = getConfigFilePath(); + try { + await access(configPath); + } catch { + return null; + } + const raw = await readFile(configPath, 'utf-8'); + const config: StorageConfig = JSON.parse(raw); + return config.customStoragePath ?? null; + } catch (err) { + logger.error('[StorageConfig] Failed to read config', err); + return null; + } +} + +/** 持久化自定义存储路径 */ +export async function saveCustomStoragePath(dirPath: string): Promise { + const configPath = getConfigFilePath(); + const config: StorageConfig = { customStoragePath: dirPath }; + await writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8'); + logger.info(`[StorageConfig] Saved custom storage path: ${dirPath}`); +} + +/** 清除自定义路径配置(恢复默认) */ +export async function clearCustomStoragePath(): Promise { + const configPath = getConfigFilePath(); + const config: StorageConfig = { customStoragePath: null }; + await writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8'); + logger.info('[StorageConfig] Cleared custom storage path, using default'); +} + +/** + * 解析最终数据库文件路径 + * 优先使用自定义路径,否则回退到 userData/keban.db + */ +export async function resolveDbPath(): Promise { + const customPath = await getCustomStoragePath(); + if (customPath) { + return path.join(customPath, 'keban.db'); + } + return path.join(app.getPath('userData'), 'keban.db'); +} diff --git a/client/electron/envLoader.ts b/client/electron/envLoader.ts new file mode 100644 index 00000000..51ad7b2f --- /dev/null +++ b/client/electron/envLoader.ts @@ -0,0 +1,91 @@ +/** + * 环境变量加载(主进程启动早期) + * + * @ai-context: 从 main.ts 拆出。开发模式读 client/.env + .env.test + * (与 Vite dev server 一致);生产模式读 Vite 构建生成的 + * dist-electron/build-config.json(.env.production 仅用于构建阶段, + * 不打包进安装包)。系统环境变量永不被覆盖。 + * @ai-context: loadEnvironment 为显式副作用入口,仅 main.ts 启动时 + * 调用一次;本模块导入本身无副作用。 + */ +import * as path from 'path'; +import { readFileSync, existsSync } from 'fs'; +import { isDevMode } from './ai/utils.js'; + +/** + * 简易 .env 解析器:读取文件并注入 process.env + * @param overrideKeys 记录本次写入的 key,允许后续 .env. 覆盖 + */ +function loadEnvFile(filePath: string, overrideKeys: Set): void { + if (!existsSync(filePath)) return; + try { + const content = readFileSync(filePath, 'utf-8'); + for (const line of content.split('\n')) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith('#')) continue; + const eqIdx = trimmed.indexOf('='); + if (eqIdx === -1) continue; + const key = trimmed.slice(0, eqIdx).trim(); + let value = trimmed.slice(eqIdx + 1).trim(); + // 移除首尾引号 + if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { + value = value.slice(1, -1); + } + if (key) { + // 不覆盖系统环境变量,但允许 .env. 覆盖 .env 基础值 + if (!(key in process.env) || overrideKeys.has(key)) { + process.env[key] = value; + overrideKeys.add(key); + } + } + } + } catch { + // .env 文件加载失败不阻塞启动 + } +} + +/** + * 从 Vite 构建时生成的 build-config.json 读取环境变量 + * 该文件由 vite.config.ts 中的 electronBuildConfigPlugin 在 vite build 时生成, + * 位于 dist-electron/build-config.json,随 asar 一起打包。 + */ +function loadBuildConfig(dirname: string): void { + try { + // __dirname 在编译后为 dist-electron/electron/,build-config.json 在 dist-electron/ + const configPath = path.resolve(dirname, '..', 'build-config.json'); + if (!existsSync(configPath)) return; + const raw = readFileSync(configPath, 'utf-8'); + const config = JSON.parse(raw) as Record; + for (const [key, value] of Object.entries(config)) { + // 不覆盖系统环境变量(如 cross-env 设置的值) + if (value && !(key in process.env)) { + process.env[key] = value; + } + } + } catch { + // build-config.json 加载失败不阻塞启动 + } +} + +/** + * 按运行模式加载环境变量(main.ts 启动时调用一次) + * @param dirname 调用方的 __dirname(编译后为 dist-electron/electron/) + */ +export function loadEnvironment(dirname: string): void { + if (isDevMode()) { + // 开发模式:从 .env 文件加载(electron:dev 由 cross-env 设置 NODE_ENV=development) + // __dirname 在编译后为 dist-electron/electron/,需回退到 client/ 根目录 + const clientRoot = path.resolve(dirname, '..', '..'); + const envKeys = new Set(); + loadEnvFile(path.join(clientRoot, '.env'), envKeys); + loadEnvFile(path.join(clientRoot, '.env.test'), envKeys); + } else { + // 生产模式:从构建时生成的 build-config.json 读取(不依赖 .env 文件) + loadBuildConfig(dirname); + } + + // 仅开发模式禁用 Electron 安全警告,生产环境保留 + if (isDevMode()) { + process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'; + } +} diff --git a/client/electron/ipc/channels.ts b/client/electron/ipc/channels.ts index 3fcdca11..ef2a7178 100644 --- a/client/electron/ipc/channels.ts +++ b/client/electron/ipc/channels.ts @@ -1,104 +1,106 @@ -/** - * IPC Channel 名称集中管理 - * - * 所有 Electron IPC channel 常量集中定义于此文件, - * 便于全局搜索、重构及 preload 白名单维护。 - */ -export const IPC_CHANNELS = { - // AI 相关 - AI_SUMMARIZE: 'ai_summarize', - AI_GENERATE_CARDS: 'ai_generate_cards', - AI_EVALUATE: 'ai_evaluate', - AI_RECOMMEND_DURATION: 'ai_recommend_duration', - AI_FEYNMAN_QUESTION: 'ai_feynman_question', - AI_FEYNMAN_EVALUATE_ANSWERS: 'ai_feynman_evaluate_answers', - AI_OPTIMIZE_CARD: 'ai_optimize_card', - AI_TAG_CONTENT: 'ai_tag_content', - AI_SORT_INSPIRATION: 'ai_sort_inspiration', - AI_ANCHOR_POINT: 'ai_anchor_point', - AI_SOCRATIC: 'ai_socratic', - AI_SOCRATIC_EVALUATE: 'ai_socratic_evaluate', - AI_SOCRATIC_DEEPENING: 'ai_socratic_deepening', - AI_PREDICT: 'ai_predict', - AI_RESCUE: 'ai_rescue', - AI_SET_GATEWAY_URL: 'ai:set-gateway-url', - - // 采集相关 - SCREEN_LIST_WINDOWS: 'screen_list_windows', - SCREEN_WATCH_WINDOWS_START: 'screen_watch_windows_start', - SCREEN_WATCH_WINDOWS_STOP: 'screen_watch_windows_stop', - SCREEN_WINDOWS_CHANGED: 'screen_windows_changed', - SCREEN_CAPTURE_START: 'screen_capture_start', - SCREEN_CAPTURE_STOP: 'screen_capture_stop', - SCREEN_CAPTURE_FRAME: 'screen_capture_frame', - AUDIO_LIST_SOURCES: 'audio_list_sources', - AUDIO_CAPTURE_START: 'audio_capture_start', - AUDIO_CAPTURE_STOP: 'audio_capture_stop', - AUDIO_CAPTURE_CHUNK: 'audio_capture_chunk', - AUDIO_CAPTURE_DO_START: 'audio_capture_do_start', - AUDIO_CAPTURE_DO_STOP: 'audio_capture_do_stop', - - // Path C 视频录制 - VIDEO_RECORD_START: 'video_record_start', - VIDEO_RECORD_STOP: 'video_record_stop', - VIDEO_RECORD_PAUSE: 'video_record_pause', - VIDEO_RECORD_RESUME: 'video_record_resume', - VIDEO_RECORD_STATUS: 'video_record_status', - VIDEO_RECORD_CHUNK: 'video_record_chunk', - VIDEO_RECORD_STARTED: 'video_record_started', - VIDEO_RECORD_STOPPED: 'video_record_stopped', - VIDEO_RECORD_ERROR: 'video_record_error', - VIDEO_RECORD_DO_START: 'video_record_do_start', - VIDEO_RECORD_DO_STOP: 'video_record_do_stop', - - // 文件系统 - FS_READ_FILE: 'fs:read-file', - - // 存储路径 - STORAGE_CHANGE_PATH: 'storage:change-path', - STORAGE_GET_ACTIVE_PATH: 'storage:get-active-path', - - // 数据库操作 - DB_QUERY: 'db:query', - DB_INSERT: 'db:insert', - DB_UPDATE: 'db:update', - DB_DELETE: 'db:delete', - DB_SEARCH: 'db:search', - DB_BATCH: 'db:batch', - - // 数据迁移 - MIGRATION_CHECK: 'migration:check', - MIGRATION_IMPORT_TABLE: 'migration:import-table', - MIGRATION_COMPLETE: 'migration:complete', - - // 备份 - BACKUP_SAVE: 'backup:save', - BACKUP_OPEN: 'backup:open', - - // 自动更新 - UPDATE_CHECK: 'update:check', - UPDATE_DOWNLOAD: 'update:download', - UPDATE_INSTALL: 'update:install', - UPDATE_SET_AUTO_CHECK: 'update:set-auto-check', - UPDATE_STATUS: 'update-status', - - // 窗口控制 - WINDOW_MINIMIZE: 'window:minimize', - WINDOW_MAXIMIZE: 'window:maximize', - WINDOW_CLOSE: 'window:close', - WINDOW_IS_MAXIMIZED: 'window:isMaximized', - WINDOW_CLOSE_ACTION: 'window:close-action', - WINDOW_CLOSING: 'window:closing', - WINDOW_MAXIMIZED_CHANGED: 'window:maximized-changed', - - // 系统 - APP_GET_VERSION: 'get-app-version', - GET_DEFAULT_STORAGE_PATH: 'get-default-storage-path', - DIALOG_SELECT_DIRECTORY: 'dialog:selectDirectory', - - // 同步 - SYNC_BEFORE_QUIT: 'sync:before-quit', - SYNC_QUIT_COMPLETE: 'sync:quit-complete', -} as const; - -export type IpcChannel = (typeof IPC_CHANNELS)[keyof typeof IPC_CHANNELS]; +/** + * IPC Channel 名称集中管理 + * + * 所有 Electron IPC channel 常量集中定义于此文件, + * 便于全局搜索、重构及 preload 白名单维护。 + * + * @ai-context: IPC channel 名称常量表——渲染/主进程通道契约,改名需两侧同步。 + */ +export const IPC_CHANNELS = { + // AI 相关 + AI_SUMMARIZE: 'ai_summarize', + AI_GENERATE_CARDS: 'ai_generate_cards', + AI_EVALUATE: 'ai_evaluate', + AI_RECOMMEND_DURATION: 'ai_recommend_duration', + AI_FEYNMAN_QUESTION: 'ai_feynman_question', + AI_FEYNMAN_EVALUATE_ANSWERS: 'ai_feynman_evaluate_answers', + AI_OPTIMIZE_CARD: 'ai_optimize_card', + AI_TAG_CONTENT: 'ai_tag_content', + AI_SORT_INSPIRATION: 'ai_sort_inspiration', + AI_ANCHOR_POINT: 'ai_anchor_point', + AI_SOCRATIC: 'ai_socratic', + AI_SOCRATIC_EVALUATE: 'ai_socratic_evaluate', + AI_SOCRATIC_DEEPENING: 'ai_socratic_deepening', + AI_PREDICT: 'ai_predict', + AI_RESCUE: 'ai_rescue', + AI_SET_GATEWAY_URL: 'ai:set-gateway-url', + + // 采集相关 + SCREEN_LIST_WINDOWS: 'screen_list_windows', + SCREEN_WATCH_WINDOWS_START: 'screen_watch_windows_start', + SCREEN_WATCH_WINDOWS_STOP: 'screen_watch_windows_stop', + SCREEN_WINDOWS_CHANGED: 'screen_windows_changed', + SCREEN_CAPTURE_START: 'screen_capture_start', + SCREEN_CAPTURE_STOP: 'screen_capture_stop', + SCREEN_CAPTURE_FRAME: 'screen_capture_frame', + AUDIO_LIST_SOURCES: 'audio_list_sources', + AUDIO_CAPTURE_START: 'audio_capture_start', + AUDIO_CAPTURE_STOP: 'audio_capture_stop', + AUDIO_CAPTURE_CHUNK: 'audio_capture_chunk', + AUDIO_CAPTURE_DO_START: 'audio_capture_do_start', + AUDIO_CAPTURE_DO_STOP: 'audio_capture_do_stop', + + // Path C 视频录制 + VIDEO_RECORD_START: 'video_record_start', + VIDEO_RECORD_STOP: 'video_record_stop', + VIDEO_RECORD_PAUSE: 'video_record_pause', + VIDEO_RECORD_RESUME: 'video_record_resume', + VIDEO_RECORD_STATUS: 'video_record_status', + VIDEO_RECORD_CHUNK: 'video_record_chunk', + VIDEO_RECORD_STARTED: 'video_record_started', + VIDEO_RECORD_STOPPED: 'video_record_stopped', + VIDEO_RECORD_ERROR: 'video_record_error', + VIDEO_RECORD_DO_START: 'video_record_do_start', + VIDEO_RECORD_DO_STOP: 'video_record_do_stop', + + // 文件系统 + FS_READ_FILE: 'fs:read-file', + + // 存储路径 + STORAGE_CHANGE_PATH: 'storage:change-path', + STORAGE_GET_ACTIVE_PATH: 'storage:get-active-path', + + // 数据库操作 + DB_QUERY: 'db:query', + DB_INSERT: 'db:insert', + DB_UPDATE: 'db:update', + DB_DELETE: 'db:delete', + DB_SEARCH: 'db:search', + DB_BATCH: 'db:batch', + + // 数据迁移 + MIGRATION_CHECK: 'migration:check', + MIGRATION_IMPORT_TABLE: 'migration:import-table', + MIGRATION_COMPLETE: 'migration:complete', + + // 备份 + BACKUP_SAVE: 'backup:save', + BACKUP_OPEN: 'backup:open', + + // 自动更新 + UPDATE_CHECK: 'update:check', + UPDATE_DOWNLOAD: 'update:download', + UPDATE_INSTALL: 'update:install', + UPDATE_SET_AUTO_CHECK: 'update:set-auto-check', + UPDATE_STATUS: 'update-status', + + // 窗口控制 + WINDOW_MINIMIZE: 'window:minimize', + WINDOW_MAXIMIZE: 'window:maximize', + WINDOW_CLOSE: 'window:close', + WINDOW_IS_MAXIMIZED: 'window:isMaximized', + WINDOW_CLOSE_ACTION: 'window:close-action', + WINDOW_CLOSING: 'window:closing', + WINDOW_MAXIMIZED_CHANGED: 'window:maximized-changed', + + // 系统 + APP_GET_VERSION: 'get-app-version', + GET_DEFAULT_STORAGE_PATH: 'get-default-storage-path', + DIALOG_SELECT_DIRECTORY: 'dialog:selectDirectory', + + // 同步 + SYNC_BEFORE_QUIT: 'sync:before-quit', + SYNC_QUIT_COMPLETE: 'sync:quit-complete', +} as const; + +export type IpcChannel = (typeof IPC_CHANNELS)[keyof typeof IPC_CHANNELS]; diff --git a/client/electron/ipcUtils.ts b/client/electron/ipcUtils.ts index 7bd0653c..8cef3021 100644 --- a/client/electron/ipcUtils.ts +++ b/client/electron/ipcUtils.ts @@ -1,141 +1,141 @@ -/** - * IPC 安全注册工具 - * - * 在注册新 handler 前先 removeHandler,确保幂等注册, - * 防止 macOS activate 事件导致 createWindow() 被多次调用时 - * 触发 "Attempted to register a second handler" 崩溃。 - * - * SEC-005: 新增 IPC sender 验证机制,仅允许主窗口的 webContents - * 调用已注册的 IPC handler,防止恶意渲染进程注入调用。 - * - * @ai-context Electron 主进程 IPC 安全加固 - */ - -import { ipcMain } from 'electron'; -import { logger } from './logger.js'; - -// ================================================================ -// 主窗口 webContents ID 管理(SEC-005) -// ================================================================ - -/** 主窗口 webContents.id,用于 IPC sender 验证;null 表示未设置(跳过验证) */ -let mainWindowWebContentsId: number | null = null; - -/** - * 设置主窗口 webContents.id,用于 IPC sender 验证。 - * 应在 main.ts 中创建主窗口后立即调用。 - * - * @param id - 主窗口 webContents.id - * @ai-context main.ts 在 app.whenReady() 中调用 - */ -export function setMainWindowId(id: number): void { - mainWindowWebContentsId = id; - logger.info(`[IPC] Main window ID set: ${id}`); -} - -/** - * 获取当前主窗口 webContents.id。 - * - * @returns 主窗口 webContents.id,未设置时返回 null - * @ai-context 用于调试或外部模块查询 - */ -export function getMainWindowId(): number | null { - return mainWindowWebContentsId; -} - -// ================================================================ -// 类型安全 handler 签名 -// ================================================================ - -/** - * 支持类型安全的 handler 签名: - * 允许 handler 声明具体参数类型,内部通过断言适配 ipcMain.handle 的 unknown[] 签名。 - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type TypedHandler = ( - event: Electron.IpcMainInvokeEvent, - ...args: T -) => Promise; - -// ================================================================ -// 安全注册 -// ================================================================ - -/** - * 幂等注册 IPC handler,并可选启用 sender 验证。 - * - * - 注册前先 removeHandler,防止重复注册崩溃。 - * - 若已调用 setMainWindowId,则执行 sender 验证: - * 不匹配的 sender 将被拒绝并记录告警日志。 - * - 若 mainWindowId 未设置(null),则跳过验证(开发容错)。 - * - * @param channel - IPC 频道名称 - * @param handler - 处理函数 - * @ai-context main.ts 中所有 safeHandle 调用均经过此函数 - */ -export function safeHandle( - channel: string, - handler: TypedHandler, -): void { - ipcMain.removeHandler(channel); - - // 包装 handler 以执行 sender 验证 - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const wrappedHandler = async (event: Electron.IpcMainInvokeEvent, ...args: any[]): Promise => { - // sender 验证:仅允许主窗口 webContents 调用 - if (mainWindowWebContentsId !== null && event.sender.id !== mainWindowWebContentsId) { - logger.warn( - `[IPC] Sender verification failed for channel "${channel}": ` + - `expected sender.id=${mainWindowWebContentsId}, got ${event.sender.id}` - ); - throw new Error(`IPC sender verification failed for channel: ${channel}`); - } - - return handler(event, ...args as T); - }; - - ipcMain.handle(channel, wrappedHandler as any); -} - -// ================================================================ -// IPC 消息批量化(渲染进程侧防抖工具) -// ================================================================ - -/** - * IPC 消息防抖:相同 channel 的连续调用在一帧内合并为最后一次请求。 - * - * 适用于渲染进程频繁触发的 IPC 调用(如窗口 resize 事件、输入状态同步等), - * 通过 queueMicrotask 将同一事件循环内的多次调用合并为最后一次。 - * - * @param channel - IPC 频道名称 - * @param handler - 实际处理函数(仅处理最后一次请求的参数) - * @ai-context 用于高频 IPC 场景(如滚动位置同步、窗口状态更新) - */ -export function safeHandleBatched( - channel: string, - handler: TypedHandler, -): void { - let pendingArgs: { event: Electron.IpcMainInvokeEvent; args: T } | null = null; - let scheduled = false; - - const batchedHandler: TypedHandler = (event, ...args) => { - pendingArgs = { event, args }; - - if (!scheduled) { - scheduled = true; - queueMicrotask(async () => { - scheduled = false; - if (pendingArgs) { - const { event: ev, args: a } = pendingArgs; - pendingArgs = null; - return handler(ev, ...a); - } - }); - } - - // 返回一个 resolved promise(批量化场景调用方不依赖即时返回值) - return Promise.resolve(undefined); - }; - - safeHandle(channel, batchedHandler); -} +/** + * IPC 安全注册工具 + * + * 在注册新 handler 前先 removeHandler,确保幂等注册, + * 防止 macOS activate 事件导致 createWindow() 被多次调用时 + * 触发 "Attempted to register a second handler" 崩溃。 + * + * SEC-005: 新增 IPC sender 验证机制,仅允许主窗口的 webContents + * 调用已注册的 IPC handler,防止恶意渲染进程注入调用。 + * + * @ai-context Electron 主进程 IPC 安全加固 + */ + +import { ipcMain } from 'electron'; +import { logger } from './logger.js'; + +// ================================================================ +// 主窗口 webContents ID 管理(SEC-005) +// ================================================================ + +/** 主窗口 webContents.id,用于 IPC sender 验证;null 表示未设置(跳过验证) */ +let mainWindowWebContentsId: number | null = null; + +/** + * 设置主窗口 webContents.id,用于 IPC sender 验证。 + * 应在 main.ts 中创建主窗口后立即调用。 + * + * @param id - 主窗口 webContents.id + * @ai-context main.ts 在 app.whenReady() 中调用 + */ +export function setMainWindowId(id: number): void { + mainWindowWebContentsId = id; + logger.info(`[IPC] Main window ID set: ${id}`); +} + +/** + * 获取当前主窗口 webContents.id。 + * + * @returns 主窗口 webContents.id,未设置时返回 null + * @ai-context 用于调试或外部模块查询 + */ +export function getMainWindowId(): number | null { + return mainWindowWebContentsId; +} + +// ================================================================ +// 类型安全 handler 签名 +// ================================================================ + +/** + * 支持类型安全的 handler 签名: + * 允许 handler 声明具体参数类型,内部通过断言适配 ipcMain.handle 的 unknown[] 签名。 + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type TypedHandler = ( + event: Electron.IpcMainInvokeEvent, + ...args: T +) => Promise; + +// ================================================================ +// 安全注册 +// ================================================================ + +/** + * 幂等注册 IPC handler,并可选启用 sender 验证。 + * + * - 注册前先 removeHandler,防止重复注册崩溃。 + * - 若已调用 setMainWindowId,则执行 sender 验证: + * 不匹配的 sender 将被拒绝并记录告警日志。 + * - 若 mainWindowId 未设置(null),则跳过验证(开发容错)。 + * + * @param channel - IPC 频道名称 + * @param handler - 处理函数 + * @ai-context main.ts 中所有 safeHandle 调用均经过此函数 + */ +export function safeHandle( + channel: string, + handler: TypedHandler, +): void { + ipcMain.removeHandler(channel); + + // 包装 handler 以执行 sender 验证 + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const wrappedHandler = async (event: Electron.IpcMainInvokeEvent, ...args: unknown[]): Promise => { + // sender 验证:仅允许主窗口 webContents 调用 + if (mainWindowWebContentsId !== null && event.sender.id !== mainWindowWebContentsId) { + logger.warn( + `[IPC] Sender verification failed for channel "${channel}": ` + + `expected sender.id=${mainWindowWebContentsId}, got ${event.sender.id}` + ); + throw new Error(`IPC sender verification failed for channel: ${channel}`); + } + + return handler(event, ...args as T); + }; + + ipcMain.handle(channel, wrappedHandler as Parameters[1]); +} + +// ================================================================ +// IPC 消息批量化(渲染进程侧防抖工具) +// ================================================================ + +/** + * IPC 消息防抖:相同 channel 的连续调用在一帧内合并为最后一次请求。 + * + * 适用于渲染进程频繁触发的 IPC 调用(如窗口 resize 事件、输入状态同步等), + * 通过 queueMicrotask 将同一事件循环内的多次调用合并为最后一次。 + * + * @param channel - IPC 频道名称 + * @param handler - 实际处理函数(仅处理最后一次请求的参数) + * @ai-context 用于高频 IPC 场景(如滚动位置同步、窗口状态更新) + */ +export function safeHandleBatched( + channel: string, + handler: TypedHandler, +): void { + let pendingArgs: { event: Electron.IpcMainInvokeEvent; args: T } | null = null; + let scheduled = false; + + const batchedHandler: TypedHandler = (event, ...args) => { + pendingArgs = { event, args }; + + if (!scheduled) { + scheduled = true; + queueMicrotask(async () => { + scheduled = false; + if (pendingArgs) { + const { event: ev, args: a } = pendingArgs; + pendingArgs = null; + return handler(ev, ...a); + } + }); + } + + // 返回一个 resolved promise(批量化场景调用方不依赖即时返回值) + return Promise.resolve(undefined); + }; + + safeHandle(channel, batchedHandler); +} diff --git a/client/electron/logger.ts b/client/electron/logger.ts index fb81de89..375930d3 100644 --- a/client/electron/logger.ts +++ b/client/electron/logger.ts @@ -1,118 +1,120 @@ -/** - * 文件日志模块 - * - * 将应用日志写入 userData/logs/ 目录,每次启动生成独立日志文件。 - * 提供 info / warn / error / crash 四个级别,crash 额外记录进程状态。 - * fs 写入失败时静默降级到 console.error。 - */ - -import { app } from 'electron'; -import * as fs from 'fs'; -import { mkdir } from 'fs/promises'; -import * as path from 'path'; - -class Logger { - private stream: fs.WriteStream | null = null; - private initialized = false; - - /** 初始化日志目录和文件流(异步,需在 app ready 后调用) */ - async initLogger(): Promise { - if (this.initialized) return; - this.initialized = true; - - try { - const logsDir = path.join(app.getPath('userData'), 'logs'); - await mkdir(logsDir, { recursive: true }); - - const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); - const logFile = path.join(logsDir, `app-${timestamp}.log`); - this.stream = fs.createWriteStream(logFile, { flags: 'a' }); - this.stream.write(`# KeBan log started at ${new Date().toISOString()}\n`); - } catch (err) { - console.error('[Logger] Failed to initialize file logger:', err); - this.stream = null; - } - } - - /** 同步降级:若尚未初始化则跳过文件写入,仅输出控制台 */ - private ensureInit(): void { - // 初始化已由 initLogger() 异步完成,此处仅做安全守卫 - if (!this.initialized) { - console.warn('[Logger] Logger not yet initialized, file output skipped'); - } - } - - private write(level: string, message: string, extra?: string): void { - this.ensureInit(); - const ts = new Date().toISOString(); - const line = `[${ts}] [${level}] ${message}\n`; - const fullLine = extra ? `${line}${extra}\n` : line; - - // 始终输出到控制台 - if (level === 'ERROR' || level === 'CRASH') { - console.error(fullLine.trimEnd()); - } else if (level === 'WARN') { - console.warn(fullLine.trimEnd()); - } else if (level === 'DEBUG') { - console.debug(fullLine.trimEnd()); - } else { - console.log(fullLine.trimEnd()); - } - - // 写入文件(失败时静默降级) - if (this.stream) { - try { - this.stream.write(fullLine); - } catch { - // 静默降级 - } - } - } - - debug(msg: string): void { - this.write('DEBUG', msg); - } - - info(msg: string): void { - this.write('INFO', msg); - } - - warn(msg: string): void { - this.write('WARN', msg); - } - - error(msg: string, error?: unknown): void { - const extra = error instanceof Error ? error.stack ?? '' : error ? String(error) : undefined; - this.write('ERROR', msg, extra); - } - - /** 严重错误:除错误信息外还记录进程状态快照 */ - crash(msg: string, error?: unknown): void { - const parts: string[] = []; - - if (error instanceof Error) { - parts.push(error.stack ?? error.message); - } else if (error) { - parts.push(String(error)); - } - - try { - const mem = process.memoryUsage(); - parts.push( - `--- Process State ---`, - `pid: ${process.pid}`, - `uptime: ${process.uptime()}s`, - `memory: rss=${Math.round(mem.rss / 1048576)}MB heap=${Math.round(mem.heapUsed / 1048576)}/${Math.round(mem.heapTotal / 1048576)}MB`, - `electron: ${process.versions.electron ?? 'N/A'}`, - `node: ${process.versions.node}`, - `platform: ${process.platform} ${process.arch}`, - ); - } catch { - parts.push('--- Process State: unavailable ---'); - } - - this.write('CRASH', msg, parts.join('\n')); - } -} - -export const logger = new Logger(); +/** + * 文件日志模块 + * + * 将应用日志写入 userData/logs/ 目录,每次启动生成独立日志文件。 + * 提供 info / warn / error / crash 四个级别,crash 额外记录进程状态。 + * fs 写入失败时静默降级到 console.error。 + * + * @ai-context: 主进程日志系统(文件流 + 控制台),crash 级别写独立崩溃日志;initLogger 须在 app ready 后调用。 + */ + +import { app } from 'electron'; +import * as fs from 'fs'; +import { mkdir } from 'fs/promises'; +import * as path from 'path'; + +class Logger { + private stream: fs.WriteStream | null = null; + private initialized = false; + + /** 初始化日志目录和文件流(异步,需在 app ready 后调用) */ + async initLogger(): Promise { + if (this.initialized) return; + this.initialized = true; + + try { + const logsDir = path.join(app.getPath('userData'), 'logs'); + await mkdir(logsDir, { recursive: true }); + + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); + const logFile = path.join(logsDir, `app-${timestamp}.log`); + this.stream = fs.createWriteStream(logFile, { flags: 'a' }); + this.stream.write(`# EntropyDecrease log started at ${new Date().toISOString()}\n`); + } catch (err) { + console.error('[Logger] Failed to initialize file logger:', err); + this.stream = null; + } + } + + /** 同步降级:若尚未初始化则跳过文件写入,仅输出控制台 */ + private ensureInit(): void { + // 初始化已由 initLogger() 异步完成,此处仅做安全守卫 + if (!this.initialized) { + console.warn('[Logger] Logger not yet initialized, file output skipped'); + } + } + + private write(level: string, message: string, extra?: string): void { + this.ensureInit(); + const ts = new Date().toISOString(); + const line = `[${ts}] [${level}] ${message}\n`; + const fullLine = extra ? `${line}${extra}\n` : line; + + // 始终输出到控制台 + if (level === 'ERROR' || level === 'CRASH') { + console.error(fullLine.trimEnd()); + } else if (level === 'WARN') { + console.warn(fullLine.trimEnd()); + } else if (level === 'DEBUG') { + console.debug(fullLine.trimEnd()); + } else { + console.log(fullLine.trimEnd()); + } + + // 写入文件(失败时静默降级) + if (this.stream) { + try { + this.stream.write(fullLine); + } catch { + // 静默降级 + } + } + } + + debug(msg: string): void { + this.write('DEBUG', msg); + } + + info(msg: string): void { + this.write('INFO', msg); + } + + warn(msg: string): void { + this.write('WARN', msg); + } + + error(msg: string, error?: unknown): void { + const extra = error instanceof Error ? error.stack ?? '' : error ? String(error) : undefined; + this.write('ERROR', msg, extra); + } + + /** 严重错误:除错误信息外还记录进程状态快照 */ + crash(msg: string, error?: unknown): void { + const parts: string[] = []; + + if (error instanceof Error) { + parts.push(error.stack ?? error.message); + } else if (error) { + parts.push(String(error)); + } + + try { + const mem = process.memoryUsage(); + parts.push( + `--- Process State ---`, + `pid: ${process.pid}`, + `uptime: ${process.uptime()}s`, + `memory: rss=${Math.round(mem.rss / 1048576)}MB heap=${Math.round(mem.heapUsed / 1048576)}/${Math.round(mem.heapTotal / 1048576)}MB`, + `electron: ${process.versions.electron ?? 'N/A'}`, + `node: ${process.versions.node}`, + `platform: ${process.platform} ${process.arch}`, + ); + } catch { + parts.push('--- Process State: unavailable ---'); + } + + this.write('CRASH', msg, parts.join('\n')); + } +} + +export const logger = new Logger(); diff --git a/client/electron/main.ts b/client/electron/main.ts index 86b015e0..96e7fe66 100644 --- a/client/electron/main.ts +++ b/client/electron/main.ts @@ -1,717 +1,278 @@ -/** - * Electron 主进程入口 - * - * 应用生命周期管理、单实例锁、IPC handler 注册。 - * 窗口创建 → windowManager.ts - * 托盘管理 → trayManager.ts - * AI 网关代理 → ai/index.ts + ai/handlers/*.ts - * 截图/音频采集 → captureHandlers.ts - */ - -import { app, BrowserWindow, Menu, dialog, session } from 'electron'; -import * as path from 'path'; -import { writeFile, readFile } from 'fs/promises'; -import { readFileSync, existsSync } from 'fs'; -import { safeHandle, setMainWindowId } from './ipcUtils.js'; -import { logger } from './logger.js'; -import { registerAIHandlers, initAIModule } from './ai/index.js'; -import { loadPersistedGatewayUrl, setRuntimeGatewayUrl, gatewayUrl, isDevMode } from './ai/utils.js'; -import { initAutoUpdater, checkForUpdate, downloadUpdate, installUpdate, destroyAutoUpdater, setAutoCheckEnabled } from './updater.js'; -import { createMainWindow, saveCloseChoice, completeSyncBeforeQuit } from './windowManager.js'; -import { destroyTray } from './trayManager.js'; -import { registerCaptureHandlers, disposeCaptureHandlers } from './captureHandlers.js'; -import { mcpManager } from './mcpManager.js'; -import { initialize, getConnection, close as closeDb, checkpointAndClose, reinitialize, getDbPath } from './db/sqliteService.js'; -import { initializeSchema } from './db/schema.js'; -import { saveCustomStoragePath, resolveDbPath } from './db/storageConfig.js'; -import { migrateDatabaseFiles, verifyDatabaseIntegrity, createBackup } from './db/dbFileMigrator.js'; -import SqliteRepository from './db/sqliteRepository.js'; -import { registerMigrationHandlers } from './db/migration.js'; - -// ================================================================ -// 性能优化:启用 GPU 光栅化与零拷贝 -// ================================================================ -app.commandLine.appendSwitch('enable-gpu-rasterization'); -app.commandLine.appendSwitch('enable-zero-copy'); -app.commandLine.appendSwitch('enable-features', 'WebGLDraftExtensions,SharedArrayBuffer'); - -// Windows: ANGLE + Direct3D 11 -// 注意:值必须是 'd3d11',曾误写为 'gl' 导致 ANGLE 被锁定 OpenGL 后端, -// 引发 WEBGL_lose_context 缺失、上下文异常及渲染卡顿 -if (process.platform === 'win32') { - app.commandLine.appendSwitch('use-angle', 'd3d11'); -} - -// macOS: Metal -if (process.platform === 'darwin') { - app.commandLine.appendSwitch('enable-metal', '1'); -} - -// ================================================================ -// 环境变量加载 -// ================================================================ -// 开发模式:从 .env 文件加载(与 Vite dev server 保持一致) -// 生产模式:从 Vite 构建时生成的 build-config.json 读取 -// (.env.production 仅用于 Vite 构建阶段,不打包进安装包) -// ================================================================ - -/** - * 简易 .env 解析器:读取文件并注入 process.env - * @param overrideKeys 记录本次写入的 key,允许后续 .env. 覆盖 - */ -function loadEnvFile(filePath: string, overrideKeys: Set): void { - if (!existsSync(filePath)) return; - try { - const content = readFileSync(filePath, 'utf-8'); - for (const line of content.split('\n')) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith('#')) continue; - const eqIdx = trimmed.indexOf('='); - if (eqIdx === -1) continue; - const key = trimmed.slice(0, eqIdx).trim(); - let value = trimmed.slice(eqIdx + 1).trim(); - // 移除首尾引号 - if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { - value = value.slice(1, -1); - } - if (key) { - // 不覆盖系统环境变量,但允许 .env. 覆盖 .env 基础值 - if (!(key in process.env) || overrideKeys.has(key)) { - process.env[key] = value; - overrideKeys.add(key); - } - } - } - } catch { - // .env 文件加载失败不阻塞启动 - } -} - -/** - * 从 Vite 构建时生成的 build-config.json 读取环境变量 - * 该文件由 vite.config.ts 中的 electronBuildConfigPlugin 在 vite build 时生成, - * 位于 dist-electron/build-config.json,随 asar 一起打包。 - */ -function loadBuildConfig(): void { - try { - // __dirname 在编译后为 dist-electron/electron/,build-config.json 在 dist-electron/ - const configPath = path.resolve(__dirname, '..', 'build-config.json'); - if (!existsSync(configPath)) return; - const raw = readFileSync(configPath, 'utf-8'); - const config = JSON.parse(raw) as Record; - for (const [key, value] of Object.entries(config)) { - // 不覆盖系统环境变量(如 cross-env 设置的值) - if (value && !(key in process.env)) { - process.env[key] = value; - } - } - } catch { - // build-config.json 加载失败不阻塞启动 - } -} - -if (isDevMode()) { - // 开发模式:从 .env 文件加载(electron:dev 由 cross-env 设置 NODE_ENV=development) - // __dirname 在编译后为 dist-electron/electron/,需回退到 client/ 根目录 - const clientRoot = path.resolve(__dirname, '..', '..'); - const envKeys = new Set(); - loadEnvFile(path.join(clientRoot, '.env'), envKeys); - loadEnvFile(path.join(clientRoot, '.env.test'), envKeys); -} else { - // 生产模式:从构建时生成的 build-config.json 读取(不依赖 .env 文件) - loadBuildConfig(); -} - -// 仅开发模式禁用 Electron 安全警告,生产环境保留 -if (isDevMode()) { - process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'; -} - -// ================================================================ -// 模块级状态 -// ================================================================ - -/** 标记应用是否正在退出(区分"最小化到托盘"与"真正退出") */ -const isQuittingRef = { value: false }; - -/** v1.1.0: 存储路径切换互斥锁 */ -let isChangingPath = false; - -/** 主窗口引用 */ -let mainWindow: BrowserWindow | null = null; - -// ================================================================ -// 退出辅助 -// ================================================================ - -/** 确认退出应用 */ -function performQuit(): void { - isQuittingRef.value = true; - app.quit(); -} - -// ================================================================ -// 单实例锁 — 防止重复启动导致多个后台进程 -// ================================================================ - -const gotTheLock = app.requestSingleInstanceLock(); - -if (!gotTheLock) { - app.quit(); -} else { - app.on('second-instance', () => { - const win = BrowserWindow.getAllWindows()[0]; - if (win) { - if (win.isMinimized()) win.restore(); - if (!win.isVisible()) win.show(); - win.focus(); - } - }); - - // ================================================================ - // 应用生命周期 - // ================================================================ - - process.on('uncaughtException', (error) => { - logger.crash('Uncaught Exception', error); - }); - - process.on('unhandledRejection', (reason) => { - const error = reason instanceof Error ? reason : new Error(String(reason)); - logger.crash('Unhandled Rejection', error); - }); - - app.whenReady().then(async () => { - // 异步初始化日志系统(创建日志目录和文件流) - await logger.initLogger(); - logger.info('App ready'); - - // ================================================================ - // SEC-005: CSP 安全策略注入(动态跟踪运行时网关 URL) - // ================================================================ - const isDev = isDevMode(); - - try { - /** - * 动态构建 connect-src 白名单 - * 每次请求时重新计算,确保运行时网关 URL 变更(如用户通过设置页修改)能及时生效 - */ - function buildExtraConnectSrc(): string { - const extraOrigins = new Set(); - // 当前运行时网关 URL(可能已被用户通过 IPC 修改) - const currentGateway = gatewayUrl(); - if (currentGateway && currentGateway !== 'https://entropydecrease.com') { - extraOrigins.add(currentGateway); - } - // 环境变量中的 API 地址 - const configuredApi = process.env.VITE_API_BASE_URL || ''; - if (configuredApi && configuredApi !== 'https://entropydecrease.com') { - extraOrigins.add(configuredApi); - } - return extraOrigins.size > 0 ? ` ${[...extraOrigins].join(' ')}` : ''; - } - - session.defaultSession.webRequest.onHeadersReceived((details, callback) => { - const extraConnectSrc = buildExtraConnectSrc(); - // 开发环境:允许 unsafe-inline/unsafe-eval(Vite HMR 需要),worker-src 需要 blob:(Vite 8 HMR 客户端用 blob: 创建 SharedWorker) - // 生产环境:禁止 unsafe-eval,保留 unsafe-inline(Tailwind 运行时需要); - // script-src 必须保留 'wasm-unsafe-eval',否则 automerge 的 WASM 模块被 CSP 拦截, - // 导致顶层 import 失败、React 无法挂载、应用卡在启动画面(仅放开 WASM 编译,不放开 JS eval) - const csp = isDev - ? `default-src 'self' 'unsafe-inline' 'unsafe-eval' http://localhost:* ws://localhost:*; worker-src 'self' blob: http://localhost:*; connect-src 'self' http://localhost:* ws://localhost:* https://*.supabase.co wss://*.supabase.co https://entropydecrease.com wss://entropydecrease.com${extraConnectSrc}; img-src 'self' data: blob: https://*.supabase.co; font-src 'self' data:;` - : `default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://*.supabase.co; font-src 'self' data:; connect-src 'self' https://*.supabase.co wss://*.supabase.co https://entropydecrease.com wss://entropydecrease.com${extraConnectSrc}; frame-ancestors 'none';`; - - callback({ - responseHeaders: { - ...details.responseHeaders, - 'Content-Security-Policy': [csp], - }, - }); - }); - logger.info(`[SEC] CSP policy injected (${isDev ? 'development' : 'production'} mode, dynamic gateway tracking enabled)`); - } catch (err) { - // CSP 注入失败时记录错误但不阻塞启动 - logger.error('[SEC] Failed to inject CSP policy', err); - } - - // 加载持久化的 AI 网关地址(在注册 handler 之前,确保 handler 可用正确的 URL) - await loadPersistedGatewayUrl(); - logger.info(`[AI] Gateway URL resolved: ${gatewayUrl()}`); - // 初始化 AI 模块(加载 Ollama 配置、执行检测),须在注册 handler 之前完成 - await initAIModule(); - registerAIHandlers(); - registerCaptureHandlers(); - - // v1.0.0: 初始化 SQLite 数据库 - const defaultDbPath = await resolveDbPath(); - const sqliteDb = initialize(defaultDbPath); - initializeSchema(sqliteDb); - logger.info('[DB] SQLite initialized and schema ready'); - - // v1.0.0: 注册数据迁移 IPC handlers(IndexedDB → SQLite) - registerMigrationHandlers(safeHandle); - - // 隐藏默认 Electron 菜单栏 - Menu.setApplicationMenu(null); - - // AI 网关地址同步(渲染进程 → 主进程) - safeHandle('ai:set-gateway-url', async (_event, url: string) => { - // SEC: URL 白名单验证 — 仅允许受信任的域名 - const allowedDomains = ['entropydecrease.com', 'localhost', '127.0.0.1']; - let parsedUrl: URL; - try { - parsedUrl = new URL(url); - } catch { - throw new Error('无效的网关 URL 格式'); - } - if (!allowedDomains.some(d => parsedUrl.hostname === d || parsedUrl.hostname.endsWith('.' + d))) { - throw new Error('不允许的网关域名'); - } - if (parsedUrl.protocol !== 'https:' && parsedUrl.hostname !== 'localhost' && parsedUrl.hostname !== '127.0.0.1') { - throw new Error('生产环境必须使用 HTTPS'); - } - - await setRuntimeGatewayUrl(url); - return { success: true }; - }); - - // 通用 IPC handlers - safeHandle('get-app-version', async () => { - return app.getVersion(); - }); - - safeHandle('get-default-storage-path', async () => { - return app.getPath('userData'); - }); - - // 文件读取 IPC handler(仅允许读取应用数据目录或临时目录下的文件) - safeHandle('fs:read-file', async (_event, filePath: string) => { - const appDataPath = app.getPath('userData'); - const tempPath = app.getPath('temp'); - const resolvedPath = path.resolve(filePath); - - if (!resolvedPath.startsWith(appDataPath) && !resolvedPath.startsWith(tempPath)) { - throw new Error('不允许读取该路径的文件'); - } - - const buffer = await readFile(resolvedPath); - return buffer.buffer; // 返回 ArrayBuffer - }); - - safeHandle('dialog:selectDirectory', async (_event, options?: { title?: string; defaultPath?: string }) => { - const result = await dialog.showOpenDialog({ - title: options?.title || '选择数据存储目录', - defaultPath: options?.defaultPath, - properties: ['openDirectory', 'createDirectory'], - }); - - if (result.canceled || result.filePaths.length === 0) { - return { canceled: true, path: null }; - } - - return { canceled: false, path: result.filePaths[0] }; - }); - - // v1.1.0: 获取当前实际使用的存储路径 - safeHandle('storage:get-active-path', async () => { - return getDbPath() ?? await resolveDbPath(); - }); - - // v1.1.0: 存储路径切换(含数据迁移) - safeHandle('storage:change-path', async (_event, args: { newPath: string }) => { - if (isChangingPath) { - return { success: false, error: '正在处理路径切换,请稍后重试' }; - } - - isChangingPath = true; - const previousPath = path.dirname(getDbPath() ?? await resolveDbPath()); - - try { - const { newPath } = args; - - // 1. 验证路径不同 - const normalizedNew = path.resolve(newPath); - const normalizedOld = path.resolve(previousPath); - if (normalizedNew === normalizedOld) { - return { success: false, error: '新路径与当前路径相同' }; - } - - logger.info(`[Storage] Switching storage path: ${normalizedOld} → ${normalizedNew}`); - - // 2. 为旧数据库创建备份 - await createBackup(normalizedOld); - - // 3. WAL checkpoint 并关闭旧连接 - checkpointAndClose(); - - // 4. 迁移数据库文件 - const migrationResult = await migrateDatabaseFiles(normalizedOld, normalizedNew); - if (!migrationResult.success) { - logger.error('[Storage] Migration failed:', migrationResult.error); - // 回滚:重新打开旧路径 - try { - const oldDbPath = path.join(normalizedOld, 'keban.db'); - reinitialize(oldDbPath); - initializeSchema(getConnection()); - } catch (rollbackErr) { - logger.error('[Storage] Rollback after migration failure also failed!', rollbackErr); - } - return { success: false, error: migrationResult.error }; - } - - // 5. 验证新数据库完整性 - const newDbPath = path.join(normalizedNew, 'keban.db'); - if (!verifyDatabaseIntegrity(newDbPath)) { - logger.error('[Storage] Integrity check failed for new database'); - // 回滚 - try { - const oldDbPath = path.join(normalizedOld, 'keban.db'); - reinitialize(oldDbPath); - initializeSchema(getConnection()); - } catch (rollbackErr) { - logger.error('[Storage] Rollback after integrity check failure also failed!', rollbackErr); - } - return { success: false, error: '新数据库完整性校验失败,已回滚到原路径' }; - } - - // 6. 重新连接到新路径 - reinitialize(newDbPath); - initializeSchema(getConnection()); - - // 7. 持久化新路径配置 - await saveCustomStoragePath(normalizedNew); - - logger.info(`[Storage] Path switch completed: ${normalizedNew}`); - return { - success: true, - previousPath: normalizedOld, - newPath: normalizedNew, - }; - } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); - logger.error('[Storage] Path switch failed', err); - - // 尝试回滚到旧路径 - try { - const oldDbPath = path.join(previousPath, 'keban.db'); - reinitialize(oldDbPath); - initializeSchema(getConnection()); - logger.info('[Storage] Rolled back to previous path'); - } catch (rollbackErr) { - logger.error('[Storage] Rollback also failed!', rollbackErr); - } - - return { success: false, error: '路径切换失败: ' + errorMsg }; - } finally { - isChangingPath = false; - } - }); - - // 创建主窗口(内部会创建托盘) - mainWindow = createMainWindow(isQuittingRef, performQuit); - - // SEC-005: 设置主窗口 ID 以启用 IPC sender 验证 - setMainWindowId(mainWindow.webContents.id); - - initAutoUpdater(mainWindow); - - // ---- 窗口控制 IPC handlers ---- - safeHandle('window:minimize', async () => { - if (mainWindow) mainWindow.minimize(); - return { success: true }; - }); - - safeHandle('window:maximize', async () => { - if (mainWindow) { - if (mainWindow.isMaximized()) { - mainWindow.unmaximize(); - } else { - mainWindow.maximize(); - } - } - return { success: true }; - }); - - safeHandle('window:close', async () => { - if (mainWindow) mainWindow.close(); - return { success: true }; - }); - - safeHandle('window:isMaximized', async () => { - return mainWindow ? mainWindow.isMaximized() : false; - }); - - safeHandle('window:close-action', async (_event, action: 'quit' | 'minimize' | 'cancel', remember: boolean) => { - if (!mainWindow) return; - - if (remember) { - await saveCloseChoice(action); - } - - if (action === 'quit') { - performQuit(); - } else if (action === 'minimize') { - mainWindow.hide(); - } - }); - - // 更新相关 IPC handler - safeHandle('update:check', async () => { - checkForUpdate(); - return { success: true }; - }); - - safeHandle('update:download', async () => { - downloadUpdate(); - return { success: true }; - }); - - safeHandle('update:install', async () => { - installUpdate(); - return { success: true }; - }); - - safeHandle('update:set-auto-check', async (_event, enabled: boolean) => { - setAutoCheckEnabled(enabled); - return { success: true }; - }); - - // 退出前同步完成通知(渲染进程 → 主进程) - safeHandle('sync:quit-complete', async () => { - completeSyncBeforeQuit(); - return { success: true }; - }); - - // ================================================================ - // v1.0.0: 数据访问 IPC handlers (db:*) - // ================================================================ - - /** 允许的表名白名单(防止 SQL 注入,不暴露原始 SQL) */ - const ALLOWED_TABLES = new Set([ - 'notes', 'note_folders', 'flashcard_decks', 'flashcards', - 'flashcard_reviews', 'feynman_notes', 'feynman_summaries', - 'feynman_weak_points', 'operation_log', 'app_settings', - 'sync_conflicts', 'offline_queue', 'study_check_ins', - 'achievements', 'pomodoro_goals', 'pomodoro_sessions', - 'pomodoro_settings', 'window_captures', 'consent', - 'user_profile', 'inspirations', 'search_index', - ]); - - /** camelCase → snake_case(用于表名映射) */ - const TABLE_NAME_MAP: Record = { - notes: 'notes', - noteFolders: 'note_folders', - flashcardDecks: 'flashcard_decks', - flashcards: 'flashcards', - flashcardReviews: 'flashcard_reviews', - feynmanNotes: 'feynman_notes', - feynmanSummaries: 'feynman_summaries', - feynmanWeakPoints: 'feynman_weak_points', - operationLog: 'operation_log', - appSettings: 'app_settings', - syncConflicts: 'sync_conflicts', - offlineQueue: 'offline_queue', - studyCheckIns: 'study_check_ins', - achievements: 'achievements', - pomodoroGoals: 'pomodoro_goals', - pomodoroSessions: 'pomodoro_sessions', - pomodoroSettings: 'pomodoro_settings', - windowCaptures: 'window_captures', - consent: 'consent', - userProfile: 'user_profile', - inspirations: 'inspirations', - searchIndex: 'search_index', - }; - - function resolveTable(table: string): string { - const snakeName = TABLE_NAME_MAP[table] || table; - if (!ALLOWED_TABLES.has(snakeName)) { - throw new Error(`[DB] Table "${table}" is not in the allowed whitelist`); - } - return snakeName; - } - - /** db:query — 查询:接收 { table, method, args } → 调用 SqliteRepository 对应方法 */ - safeHandle('db:query', async (_event, params: { table: string; method: string; args?: unknown[] }) => { - const tableName = resolveTable(params.table); - const repo = new SqliteRepository(tableName); - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- 动态表名场景无法约束具体类型 - const method = params.method as keyof SqliteRepository; - const allowedMethods = ['getAll', 'getById', 'count']; - if (!allowedMethods.includes(method)) { - throw new Error(`[DB] Query method "${params.method}" is not allowed`); - } - const fn = (repo as any)[method]; - if (typeof fn !== 'function') { - throw new Error(`[DB] Method "${params.method}" does not exist on repository`); - } - return await fn.call(repo, ...(params.args ?? [])); - }); - - /** db:insert — 插入:接收 { table, item } → create() */ - safeHandle('db:insert', async (_event, params: { table: string; item: Record }) => { - const tableName = resolveTable(params.table); - const repo = new SqliteRepository(tableName); - return await repo.create(params.item as any); - }); - - /** db:update — 更新:接收 { table, id, changes } → update() */ - safeHandle('db:update', async (_event, params: { table: string; id: string; changes: Record }) => { - const tableName = resolveTable(params.table); - const repo = new SqliteRepository(tableName); - return await repo.update(params.id, params.changes as any); - }); - - /** db:delete — 删除:接收 { table, id } → delete() */ - safeHandle('db:delete', async (_event, params: { table: string; id: string }) => { - const tableName = resolveTable(params.table); - const repo = new SqliteRepository(tableName); - return await repo.delete(params.id); - }); - - /** db:search — 搜索:LIKE 模糊匹配(FTS5 在 T0.5 实现) */ - safeHandle('db:search', async (_event, params: { table: string; query: string }) => { - const tableName = resolveTable(params.table); - const dbConn = getConnection(); - const like = `%${params.query}%`; - // 对 notes 表搜索 title 和 content,其余表搜索所有 TEXT 列 - if (tableName === 'notes') { - return dbConn.prepare( - `SELECT * FROM notes WHERE title LIKE ? OR content LIKE ?` - ).all(like, like); - } - // 通用回退:获取表的 TEXT 列并搜索 - const colInfo = dbConn.prepare(`PRAGMA table_info("${tableName}")`).all() as Array<{ name: string; type: string }>; - const textCols = colInfo.filter((c) => c.type === 'TEXT' && c.name !== 'id'); - if (textCols.length === 0) return []; - const where = textCols.map((c) => `"${c.name}" LIKE ?`).join(' OR '); - return dbConn.prepare(`SELECT * FROM "${tableName}" WHERE ${where}`).all(...textCols.map(() => like)); - }); - - /** db:batch — 批量操作:事务执行 */ - safeHandle('db:batch', async (_event, params: { operations: Array<{ type: string; table: string; [key: string]: unknown }> }) => { - const dbConn = getConnection(); - - const txn = dbConn.transaction(() => { - for (const op of params.operations) { - const tableName = resolveTable(op.table as string); - switch (op.type) { - case 'insert': { - const item = op.item as Record; - const cols = Object.keys(item); - const placeholders = cols.map(() => '?').join(', '); - const sql = `INSERT INTO "${tableName}" (${cols.map((c) => `"${c}"`).join(', ')}) VALUES (${placeholders})`; - dbConn.prepare(sql).run(...Object.values(item)); - break; - } - case 'update': { - const changes = op.changes as Record; - const entries = Object.entries(changes); - if (entries.length === 0) break; - const setClauses = entries.map(([col]) => `"${col}" = ?`).join(', '); - const sql = `UPDATE "${tableName}" SET ${setClauses} WHERE id = ?`; - dbConn.prepare(sql).run(...entries.map(([, v]) => v), op.id as string); - break; - } - case 'delete': - dbConn.prepare(`DELETE FROM "${tableName}" WHERE id = ?`).run(op.id as string); - break; - default: - throw new Error(`[DB] Unknown batch operation type: ${op.type}`); - } - } - }); - txn(); - return { success: true }; - }); - - // ================================================================ - // v0.9.0: 备份相关 IPC handlers - // ================================================================ - - /** - * 显示保存对话框并将备份数据写入文件 - */ - safeHandle('backup:save', async (_event, data: string, defaultName?: string) => { - const filename = defaultName || `entropy-decrease-backup-${new Date().toISOString().slice(0, 10)}.json`; - - const result = await dialog.showSaveDialog({ - title: '保存备份文件', - defaultPath: filename, - filters: [ - { name: '熵减备份文件', extensions: ['json'] }, - { name: '所有文件', extensions: ['*'] }, - ], - }); - - if (result.canceled || !result.filePath) { - return { success: false, canceled: true, path: null }; - } - - try { - await writeFile(result.filePath, data, 'utf-8'); - return { success: true, canceled: false, path: result.filePath }; - } catch (err) { - const msg = err instanceof Error ? err.message : '写入失败'; - return { success: false, canceled: false, path: null, error: msg }; - } - }); - - /** - * 显示打开对话框,选择备份文件并读取内容 - */ - safeHandle('backup:open', async () => { - const result = await dialog.showOpenDialog({ - title: '选择备份文件', - filters: [ - { name: '熵减备份文件', extensions: ['json'] }, - { name: '所有文件', extensions: ['*'] }, - ], - properties: ['openFile'], - }); - - if (result.canceled || result.filePaths.length === 0) { - return { success: false, canceled: true, content: null }; - } - - try { - const content = await readFile(result.filePaths[0], 'utf-8'); - return { success: true, canceled: false, content, path: result.filePaths[0] }; - } catch (err) { - const msg = err instanceof Error ? err.message : '读取失败'; - return { success: false, canceled: false, content: null, error: msg }; - } - }); - - app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - mainWindow = createMainWindow(isQuittingRef, performQuit); - // SEC-005: macOS activate 重新创建窗口时同步更新 sender ID - setMainWindowId(mainWindow.webContents.id); - } - }); - }); - - // 标记应用即将退出 - app.on('before-quit', () => { - isQuittingRef.value = true; - }); - - // 所有窗口关闭时退出应用 - app.on('window-all-closed', () => { - logger.info('All windows closed'); - - disposeCaptureHandlers(); - destroyAutoUpdater(); - destroyTray(); - closeDb(); - mainWindow = null; - - // 关闭 MCP Bridge 子进程(防止孤儿进程阻塞退出) - mcpManager.shutdown().catch((err) => { - logger.error('[MCP] Shutdown error during quit', err); - }).finally(() => { - app.quit(); - }); - }); -} +/** + * Electron 主进程入口 + * + * 应用生命周期管理、单实例锁、IPC handler 注册。 + * 窗口创建 → windowManager.ts + * 托盘管理 → trayManager.ts + * AI 网关代理 → ai/index.ts + ai/handlers/*.ts + * 截图/音频采集 → captureHandlers.ts + * + * @ai-context: 2026-07 拆分——环境加载在 envLoader、CSP 在 cspPolicy、 + * db:* IPC 在 db/dbIpcHandlers、storage/backup IPC 在 storageIpcHandlers; + * 本文件保留生命周期编排与窗口/更新/网关 IPC。启动顺序有严格依赖: + * loadEnvironment → CSP → loadPersistedGatewayUrl → initAIModule → + * registerAIHandlers → SQLite 初始化 → createMainWindow,调整顺序 + * 可能导致 handler 使用错误的网关 URL 或数据库未就绪。 + * @ai-context: 本文件为 AGENTS.md 标注的高风险变更区——改动可能导致 + * 应用无法启动,任何修改需完整回归启动/退出/托盘/更新流程。 + */ + +import { app, BrowserWindow, Menu } from 'electron'; +import { safeHandle, setMainWindowId } from './ipcUtils.js'; +import { logger } from './logger.js'; +import { registerAIHandlers, initAIModule } from './ai/index.js'; +import { loadPersistedGatewayUrl, setRuntimeGatewayUrl, gatewayUrl, isDevMode } from './ai/utils.js'; +import { initAutoUpdater, checkForUpdate, downloadUpdate, installUpdate, destroyAutoUpdater, setAutoCheckEnabled } from './updater.js'; +import { createMainWindow, saveCloseChoice, completeSyncBeforeQuit } from './windowManager.js'; +import { destroyTray } from './trayManager.js'; +import { registerCaptureHandlers, disposeCaptureHandlers } from './captureHandlers.js'; +import { mcpManager } from './mcpManager.js'; +import { initialize, close as closeDb } from './db/sqliteService.js'; +import { initializeSchema } from './db/schema.js'; +import { resolveDbPath } from './db/storageConfig.js'; +import { registerMigrationHandlers } from './db/migration.js'; +import { loadEnvironment } from './envLoader.js'; +import { installCspPolicy } from './cspPolicy.js'; +import { registerDbIpcHandlers } from './db/dbIpcHandlers.js'; +import { registerStorageIpcHandlers } from './storageIpcHandlers.js'; + +// ================================================================ +// 性能优化:启用 GPU 光栅化与零拷贝 +// ================================================================ +app.commandLine.appendSwitch('enable-gpu-rasterization'); +app.commandLine.appendSwitch('enable-zero-copy'); +app.commandLine.appendSwitch('enable-features', 'WebGLDraftExtensions,SharedArrayBuffer'); + +// Windows: ANGLE + Direct3D 11 +// 注意:值必须是 'd3d11',曾误写为 'gl' 导致 ANGLE 被锁定 OpenGL 后端, +// 引发 WEBGL_lose_context 缺失、上下文异常及渲染卡顿 +if (process.platform === 'win32') { + app.commandLine.appendSwitch('use-angle', 'd3d11'); +} + +// macOS: Metal +if (process.platform === 'darwin') { + app.commandLine.appendSwitch('enable-metal', '1'); +} + +// ================================================================ +// 环境变量加载(详见 envLoader.ts) +// ================================================================ +loadEnvironment(__dirname); + +// ================================================================ +// 模块级状态 +// ================================================================ + +/** 标记应用是否正在退出(区分"最小化到托盘"与"真正退出") */ +const isQuittingRef = { value: false }; + +/** 主窗口引用 */ +let mainWindow: BrowserWindow | null = null; + +// ================================================================ +// 退出辅助 +// ================================================================ + +/** 确认退出应用 */ +function performQuit(): void { + isQuittingRef.value = true; + app.quit(); +} + +// ================================================================ +// 单实例锁 — 防止重复启动导致多个后台进程 +// ================================================================ + +const gotTheLock = app.requestSingleInstanceLock(); + +if (!gotTheLock) { + app.quit(); +} else { + app.on('second-instance', () => { + const win = BrowserWindow.getAllWindows()[0]; + if (win) { + if (win.isMinimized()) win.restore(); + if (!win.isVisible()) win.show(); + win.focus(); + } + }); + + // ================================================================ + // 应用生命周期 + // ================================================================ + + process.on('uncaughtException', (error) => { + logger.crash('Uncaught Exception', error); + }); + + process.on('unhandledRejection', (reason) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + logger.crash('Unhandled Rejection', error); + }); + + app.whenReady().then(async () => { + // 异步初始化日志系统(创建日志目录和文件流) + await logger.initLogger(); + logger.info('App ready'); + + // SEC-005: CSP 安全策略注入(详见 cspPolicy.ts) + installCspPolicy(isDevMode()); + + // 加载持久化的 AI 网关地址(在注册 handler 之前,确保 handler 可用正确的 URL) + await loadPersistedGatewayUrl(); + logger.info(`[AI] Gateway URL resolved: ${gatewayUrl()}`); + // 初始化 AI 模块(加载 Ollama 配置、执行检测),须在注册 handler 之前完成 + await initAIModule(); + registerAIHandlers(); + registerCaptureHandlers(); + + // v1.0.0: 初始化 SQLite 数据库 + const defaultDbPath = await resolveDbPath(); + const sqliteDb = initialize(defaultDbPath); + initializeSchema(sqliteDb); + logger.info('[DB] SQLite initialized and schema ready'); + + // v1.0.0: 注册数据迁移 IPC handlers(IndexedDB → SQLite) + registerMigrationHandlers(safeHandle); + + // 数据访问与存储/备份 IPC(详见 db/dbIpcHandlers.ts、storageIpcHandlers.ts) + registerDbIpcHandlers(); + registerStorageIpcHandlers(); + + // 隐藏默认 Electron 菜单栏 + Menu.setApplicationMenu(null); + + // AI 网关地址同步(渲染进程 → 主进程) + safeHandle('ai:set-gateway-url', async (_event, url: string) => { + // SEC: URL 白名单验证 — 仅允许受信任的域名 + const allowedDomains = ['entropydecrease.com', 'localhost', '127.0.0.1']; + let parsedUrl: URL; + try { + parsedUrl = new URL(url); + } catch { + throw new Error('无效的网关 URL 格式'); + } + if (!allowedDomains.some(d => parsedUrl.hostname === d || parsedUrl.hostname.endsWith('.' + d))) { + throw new Error('不允许的网关域名'); + } + if (parsedUrl.protocol !== 'https:' && parsedUrl.hostname !== 'localhost' && parsedUrl.hostname !== '127.0.0.1') { + throw new Error('生产环境必须使用 HTTPS'); + } + + await setRuntimeGatewayUrl(url); + return { success: true }; + }); + + // 通用 IPC handlers + safeHandle('get-app-version', async () => { + return app.getVersion(); + }); + + // 创建主窗口(内部会创建托盘) + mainWindow = createMainWindow(isQuittingRef, performQuit); + + // SEC-005: 设置主窗口 ID 以启用 IPC sender 验证 + setMainWindowId(mainWindow.webContents.id); + + initAutoUpdater(mainWindow); + + // ---- 窗口控制 IPC handlers ---- + safeHandle('window:minimize', async () => { + if (mainWindow) mainWindow.minimize(); + return { success: true }; + }); + + safeHandle('window:maximize', async () => { + if (mainWindow) { + if (mainWindow.isMaximized()) { + mainWindow.unmaximize(); + } else { + mainWindow.maximize(); + } + } + return { success: true }; + }); + + safeHandle('window:close', async () => { + if (mainWindow) mainWindow.close(); + return { success: true }; + }); + + safeHandle('window:isMaximized', async () => { + return mainWindow ? mainWindow.isMaximized() : false; + }); + + safeHandle('window:close-action', async (_event, action: 'quit' | 'minimize' | 'cancel', remember: boolean) => { + if (!mainWindow) return; + + if (remember) { + await saveCloseChoice(action); + } + + if (action === 'quit') { + performQuit(); + } else if (action === 'minimize') { + mainWindow.hide(); + } + }); + + // 更新相关 IPC handler + safeHandle('update:check', async () => { + checkForUpdate(); + return { success: true }; + }); + + safeHandle('update:download', async () => { + downloadUpdate(); + return { success: true }; + }); + + safeHandle('update:install', async () => { + installUpdate(); + return { success: true }; + }); + + safeHandle('update:set-auto-check', async (_event, enabled: boolean) => { + setAutoCheckEnabled(enabled); + return { success: true }; + }); + + // 退出前同步完成通知(渲染进程 → 主进程) + safeHandle('sync:quit-complete', async () => { + completeSyncBeforeQuit(); + return { success: true }; + }); + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + mainWindow = createMainWindow(isQuittingRef, performQuit); + // SEC-005: macOS activate 重新创建窗口时同步更新 sender ID + setMainWindowId(mainWindow.webContents.id); + } + }); + }); + + // 标记应用即将退出 + app.on('before-quit', () => { + isQuittingRef.value = true; + }); + + // 所有窗口关闭时退出应用 + app.on('window-all-closed', () => { + logger.info('All windows closed'); + + disposeCaptureHandlers(); + destroyAutoUpdater(); + destroyTray(); + closeDb(); + mainWindow = null; + + // 关闭 MCP Bridge 子进程(防止孤儿进程阻塞退出) + mcpManager.shutdown().catch((err) => { + logger.error('[MCP] Shutdown error during quit', err); + }).finally(() => { + app.quit(); + }); + }); +} diff --git a/client/electron/mcpBridge.ts b/client/electron/mcpBridge.ts index a4c7b422..35b4bfbd 100644 --- a/client/electron/mcpBridge.ts +++ b/client/electron/mcpBridge.ts @@ -1,269 +1,269 @@ -/** - * MCP Bridge — 纯 Node.js 子进程 - * - * 由主进程的 mcpManager.ts 通过 child_process.fork() 启动, - * 在独立的 Node.js 运行环境中加载 MCP SDK 并管理 server 连接。 - * - * 为什么需要 Bridge: - * Electron 主进程是 CJS 环境,而 MCP SDK 的 StdioClientTransport - * 仅提供 ESM 导出。Electron 的模块系统不支持 new Function + import() 技巧。 - * Bridge 运行在纯 Node.js 中,原生支持 ESM dynamic import()。 - * - * 通信协议(JSON over IPC): - * 主进程 → Bridge:{ id, method, params } - * Bridge → 主进程:{ id, result?, error? } - * - * 注意:此文件不应 import 任何 Electron 模块(app, BrowserWindow 等)。 - * - * @ai-context Electron MCP 集成 — Bridge 子进程 - */ - -// ================================================================ -// IPC 消息类型 -// ================================================================ - -interface BridgeRequest { - id: string; - method: 'init' | 'listTools' | 'callTool' | 'shutdown'; - params?: Record; -} - -interface BridgeResponse { - id: string; - result?: unknown; - error?: string; -} - -// ================================================================ -// MCP SDK 类型(运行时) -// ================================================================ - -interface McpClient { - connect(transport: unknown): Promise; - listTools(): Promise<{ tools: McpToolInfo[] }>; - callTool(params: { name: string; arguments?: Record }): Promise; - close(): Promise; -} - -interface McpTransport { - close(): Promise; -} - -interface McpToolInfo { - name: string; - description?: string; - inputSchema?: Record; -} - -interface StdioServerParameters { - command: string; - args?: string[]; - env?: Record; - stderr?: 'pipe' | 'overlapped' | 'inherit' | 'ignore'; - cwd?: string; -} - -// ================================================================ -// SDK 构造器(init 时加载) -// ================================================================ - -let ClientCtor: (new (opts: { name: string; version: string }) => McpClient) | null = null; -let StdioTransportCtor: (new (params: StdioServerParameters) => McpTransport) | null = null; - -// ================================================================ -// Server 管理 -// ================================================================ - -interface ServerEntry { - name: string; - client: McpClient | null; - transport: McpTransport | null; - connected: boolean; -} - -const servers = new Map(); - -// ================================================================ -// 核心方法 -// ================================================================ - -async function handleInit(params: Record): Promise> { - // 1a. CJS 加载 Client - const clientMod = require('@modelcontextprotocol/sdk/client') as { - Client: new (opts: { name: string; version: string }) => McpClient; - }; - ClientCtor = clientMod.Client; - log('Client loaded via CJS require'); - - // 1b. 原生 import() 加载 StdioClientTransport - // 在纯 Node.js (v22+) 中,new Function 保留原生 ESM dynamic import - const nativeImport = new Function('specifier', 'return import(specifier)') as (s: string) => Promise; - const stdioMod = await nativeImport('@modelcontextprotocol/sdk/client/stdio.js') as { - StdioClientTransport: new (params: StdioServerParameters) => McpTransport; - }; - StdioTransportCtor = stdioMod.StdioClientTransport; - log('StdioClientTransport loaded via native dynamic import'); - - // 2. 启动各 server - const serverConfigs = params.servers as Array<{ - name: string; - command: string; - args: string[]; - }>; - - for (const config of serverConfigs) { - await startServer(config); - } - - // 3. 返回状态 - const status: Record = {}; - for (const [name, entry] of servers) { - status[name] = entry.connected; - } - - const connected = Object.values(status).filter(Boolean).length; - log(`Init complete: ${connected}/${serverConfigs.length} servers connected`); - return status; -} - -async function startServer(config: { name: string; command: string; args: string[] }): Promise { - if (!ClientCtor || !StdioTransportCtor) return; - - const entry: ServerEntry = { - name: config.name, - client: null, - transport: null, - connected: false, - }; - servers.set(config.name, entry); - - try { - log(`Starting server "${config.name}": ${config.command} ${config.args.join(' ')}`); - - const transport = new StdioTransportCtor({ - command: config.command, - args: config.args, - env: process.env as Record, - stderr: 'pipe', - }); - - entry.transport = transport; - - const client = new ClientCtor({ - name: `keban-${config.name}`, - version: '1.0.0', - }); - - await client.connect(transport); - entry.client = client; - entry.connected = true; - - log(`Server "${config.name}" connected successfully`); - } catch (err) { - const errMsg = err instanceof Error ? err.message : String(err); - log(`Failed to start server "${config.name}": ${errMsg}`); - if (entry.transport) { - entry.transport.close().catch(() => {}); - } - entry.transport = null; - entry.client = null; - entry.connected = false; - } -} - -async function handleListTools(params: Record): Promise { - const serverName = params.serverName as string; - const entry = servers.get(serverName); - if (!entry?.connected || !entry.client) { - throw new Error(`MCP server "${serverName}" is not connected`); - } - const result = await entry.client.listTools(); - return result.tools; -} - -async function handleCallTool(params: Record): Promise { - const serverName = params.serverName as string; - const toolName = params.toolName as string; - const args = params.args as Record | undefined; - - const entry = servers.get(serverName); - if (!entry?.connected || !entry.client) { - throw new Error(`MCP server "${serverName}" is not connected`); - } - - log(`Calling tool "${toolName}" on server "${serverName}"`); - return await entry.client.callTool({ name: toolName, arguments: args }); -} - -async function handleShutdown(): Promise { - log('Shutting down all MCP servers...'); - - const promises: Promise[] = []; - - for (const entry of servers.values()) { - if (entry.client) { - promises.push(entry.client.close().catch(() => {})); - } - if (entry.transport) { - promises.push(entry.transport.close().catch(() => {})); - } - entry.connected = false; - entry.client = null; - entry.transport = null; - } - - await Promise.allSettled(promises); - servers.clear(); - log('All MCP servers shut down'); -} - -// ================================================================ -// IPC 消息处理 -// ================================================================ - -function log(msg: string): void { - // 通过 IPC 发送日志到主进程(stderr 保留给错误) - process.stdout.write(`[MCP-Bridge] ${msg}\n`); -} - -process.on('message', async (msg: BridgeRequest) => { - const response: BridgeResponse = { id: msg.id }; - - try { - switch (msg.method) { - case 'init': - response.result = await handleInit(msg.params ?? {}); - break; - case 'listTools': - response.result = await handleListTools(msg.params ?? {}); - break; - case 'callTool': - response.result = await handleCallTool(msg.params ?? {}); - break; - case 'shutdown': - await handleShutdown(); - response.result = { ok: true }; - break; - default: - throw new Error(`Unknown method: ${msg.method}`); - } - } catch (err) { - response.error = err instanceof Error ? err.message : String(err); - } - - process.send!(response); -}); - -// 优雅退出:父进程断开时自行退出 -process.on('disconnect', () => { - log('Parent disconnected, exiting'); - handleShutdown().finally(() => process.exit(0)); -}); - -// 未捕获异常不要崩溃,发日志后继续 -process.on('uncaughtException', (err) => { - log(`Uncaught exception: ${err.message}`); -}); - -log(`Bridge process started, env keys: ${Object.keys(process.env).length}, PATH: ${(process.env.PATH || process.env.Path || '').slice(0, 80)}`); -log('Waiting for commands...'); +/** + * MCP Bridge — 纯 Node.js 子进程 + * + * 由主进程的 mcpManager.ts 通过 child_process.fork() 启动, + * 在独立的 Node.js 运行环境中加载 MCP SDK 并管理 server 连接。 + * + * 为什么需要 Bridge: + * Electron 主进程是 CJS 环境,而 MCP SDK 的 StdioClientTransport + * 仅提供 ESM 导出。Electron 的模块系统不支持 new Function + import() 技巧。 + * Bridge 运行在纯 Node.js 中,原生支持 ESM dynamic import()。 + * + * 通信协议(JSON over IPC): + * 主进程 → Bridge:{ id, method, params } + * Bridge → 主进程:{ id, result?, error? } + * + * 注意:此文件不应 import 任何 Electron 模块(app, BrowserWindow 等)。 + * + * @ai-context Electron MCP 集成 — Bridge 子进程 + */ + +// ================================================================ +// IPC 消息类型 +// ================================================================ + +interface BridgeRequest { + id: string; + method: 'init' | 'listTools' | 'callTool' | 'shutdown'; + params?: Record; +} + +interface BridgeResponse { + id: string; + result?: unknown; + error?: string; +} + +// ================================================================ +// MCP SDK 类型(运行时) +// ================================================================ + +interface McpClient { + connect(transport: unknown): Promise; + listTools(): Promise<{ tools: McpToolInfo[] }>; + callTool(params: { name: string; arguments?: Record }): Promise; + close(): Promise; +} + +interface McpTransport { + close(): Promise; +} + +interface McpToolInfo { + name: string; + description?: string; + inputSchema?: Record; +} + +interface StdioServerParameters { + command: string; + args?: string[]; + env?: Record; + stderr?: 'pipe' | 'overlapped' | 'inherit' | 'ignore'; + cwd?: string; +} + +// ================================================================ +// SDK 构造器(init 时加载) +// ================================================================ + +let ClientCtor: (new (opts: { name: string; version: string }) => McpClient) | null = null; +let StdioTransportCtor: (new (params: StdioServerParameters) => McpTransport) | null = null; + +// ================================================================ +// Server 管理 +// ================================================================ + +interface ServerEntry { + name: string; + client: McpClient | null; + transport: McpTransport | null; + connected: boolean; +} + +const servers = new Map(); + +// ================================================================ +// 核心方法 +// ================================================================ + +async function handleInit(params: Record): Promise> { + // 1a. CJS 加载 Client + const clientMod = require('@modelcontextprotocol/sdk/client') as { + Client: new (opts: { name: string; version: string }) => McpClient; + }; + ClientCtor = clientMod.Client; + log('Client loaded via CJS require'); + + // 1b. 原生 import() 加载 StdioClientTransport + // 在纯 Node.js (v22+) 中,new Function 保留原生 ESM dynamic import + const nativeImport = new Function('specifier', 'return import(specifier)') as (s: string) => Promise; + const stdioMod = await nativeImport('@modelcontextprotocol/sdk/client/stdio.js') as { + StdioClientTransport: new (params: StdioServerParameters) => McpTransport; + }; + StdioTransportCtor = stdioMod.StdioClientTransport; + log('StdioClientTransport loaded via native dynamic import'); + + // 2. 启动各 server + const serverConfigs = params.servers as Array<{ + name: string; + command: string; + args: string[]; + }>; + + for (const config of serverConfigs) { + await startServer(config); + } + + // 3. 返回状态 + const status: Record = {}; + for (const [name, entry] of servers) { + status[name] = entry.connected; + } + + const connected = Object.values(status).filter(Boolean).length; + log(`Init complete: ${connected}/${serverConfigs.length} servers connected`); + return status; +} + +async function startServer(config: { name: string; command: string; args: string[] }): Promise { + if (!ClientCtor || !StdioTransportCtor) return; + + const entry: ServerEntry = { + name: config.name, + client: null, + transport: null, + connected: false, + }; + servers.set(config.name, entry); + + try { + log(`Starting server "${config.name}": ${config.command} ${config.args.join(' ')}`); + + const transport = new StdioTransportCtor({ + command: config.command, + args: config.args, + env: process.env as Record, + stderr: 'pipe', + }); + + entry.transport = transport; + + const client = new ClientCtor({ + name: `entropydecrease-${config.name}`, + version: '1.0.0', + }); + + await client.connect(transport); + entry.client = client; + entry.connected = true; + + log(`Server "${config.name}" connected successfully`); + } catch (err) { + const errMsg = err instanceof Error ? err.message : String(err); + log(`Failed to start server "${config.name}": ${errMsg}`); + if (entry.transport) { + entry.transport.close().catch(() => {}); + } + entry.transport = null; + entry.client = null; + entry.connected = false; + } +} + +async function handleListTools(params: Record): Promise { + const serverName = params.serverName as string; + const entry = servers.get(serverName); + if (!entry?.connected || !entry.client) { + throw new Error(`MCP server "${serverName}" is not connected`); + } + const result = await entry.client.listTools(); + return result.tools; +} + +async function handleCallTool(params: Record): Promise { + const serverName = params.serverName as string; + const toolName = params.toolName as string; + const args = params.args as Record | undefined; + + const entry = servers.get(serverName); + if (!entry?.connected || !entry.client) { + throw new Error(`MCP server "${serverName}" is not connected`); + } + + log(`Calling tool "${toolName}" on server "${serverName}"`); + return await entry.client.callTool({ name: toolName, arguments: args }); +} + +async function handleShutdown(): Promise { + log('Shutting down all MCP servers...'); + + const promises: Promise[] = []; + + for (const entry of servers.values()) { + if (entry.client) { + promises.push(entry.client.close().catch(() => {})); + } + if (entry.transport) { + promises.push(entry.transport.close().catch(() => {})); + } + entry.connected = false; + entry.client = null; + entry.transport = null; + } + + await Promise.allSettled(promises); + servers.clear(); + log('All MCP servers shut down'); +} + +// ================================================================ +// IPC 消息处理 +// ================================================================ + +function log(msg: string): void { + // 通过 IPC 发送日志到主进程(stderr 保留给错误) + process.stdout.write(`[MCP-Bridge] ${msg}\n`); +} + +process.on('message', async (msg: BridgeRequest) => { + const response: BridgeResponse = { id: msg.id }; + + try { + switch (msg.method) { + case 'init': + response.result = await handleInit(msg.params ?? {}); + break; + case 'listTools': + response.result = await handleListTools(msg.params ?? {}); + break; + case 'callTool': + response.result = await handleCallTool(msg.params ?? {}); + break; + case 'shutdown': + await handleShutdown(); + response.result = { ok: true }; + break; + default: + throw new Error(`Unknown method: ${msg.method}`); + } + } catch (err) { + response.error = err instanceof Error ? err.message : String(err); + } + + process.send!(response); +}); + +// 优雅退出:父进程断开时自行退出 +process.on('disconnect', () => { + log('Parent disconnected, exiting'); + handleShutdown().finally(() => process.exit(0)); +}); + +// 未捕获异常不要崩溃,发日志后继续 +process.on('uncaughtException', (err) => { + log(`Uncaught exception: ${err.message}`); +}); + +log(`Bridge process started, env keys: ${Object.keys(process.env).length}, PATH: ${(process.env.PATH || process.env.Path || '').slice(0, 80)}`); +log('Waiting for commands...'); diff --git a/client/electron/mcpEnv.ts b/client/electron/mcpEnv.ts new file mode 100644 index 00000000..0a892670 --- /dev/null +++ b/client/electron/mcpEnv.ts @@ -0,0 +1,149 @@ +/** + * MCP Bridge 环境与配置构建 + * + * @ai-context: 从 mcpManager.ts 拆出。Electron 主进程的 process.env + * 可能几乎为空(仅含 Electron 自设变量),Windows 下经 PowerShell + * .NET API 从注册表读取 Machine+User 环境变量作为基础层、process.env + * 覆盖其上——MCP Server 子进程需要完整 PATH 才能运行。 + * @ai-context: buildServerConfigs 解析 node_modules/.bin 下的三个 + * MCP server 可执行文件(Windows 加 .cmd 后缀);新增 server 在此登记。 + * @ai-context: SEC——execSync 命令串为完全固定常量(无任何用户/外部 + * 输入拼接),无 shell 注入面;若未来需参数化必须改用 execFile。 + */ +import { execSync } from 'child_process'; +import * as path from 'path'; +import { logger } from './logger.js'; + +// ================================================================ +// IPC 消息类型 +// ================================================================ + +export interface BridgeRequest { + id: string; + method: 'init' | 'listTools' | 'callTool' | 'shutdown'; + params?: Record; +} + +export interface BridgeResponse { + id: string; + result?: unknown; + error?: string; +} + +/** 工具描述信息 */ +export interface McpToolInfo { + name: string; + description?: string; + inputSchema?: Record; +} + +export type ServerName = 'filesystem' | 'sequential-thinking' | 'memory'; + +/** MCP Server 启动配置 */ +export interface McpServerConfig { + name: string; + command: string; + args: string[]; +} + +// ================================================================ +// Windows 注册表环境变量读取 +// ================================================================ + +/** + * 从 Windows 注册表读取用户 + 系统环境变量。 + * @returns 从注册表读取的环境变量对象,失败时返回空对象 + */ +function readWindowsRegistryEnv(): Record { + const env: Record = {}; + + if (process.platform !== 'win32') return env; + + try { + // 使用 PowerShell .NET API 从注册表读取用户 + 系统环境变量 + // [Environment]::GetEnvironmentVariables() 合并 Machine + User 两层 + const output = execSync( + 'powershell -NoProfile -Command "' + + '$e = [Environment]::GetEnvironmentVariables();' + + 'foreach ($k in $e.Keys) { Write-Output \"$k=$($e[$k])\" }"', + { + encoding: 'utf-8', + timeout: 10000, + windowsHide: true, + }, + ); + + for (const line of output.split('\n')) { + const eqIdx = line.indexOf('='); + if (eqIdx > 0) { + const key = line.slice(0, eqIdx).trim(); + const value = line.slice(eqIdx + 1).trim(); + if (key) env[key] = value; + } + } + + logger.info(`[MCP] Registry env loaded: ${Object.keys(env).length} keys`); + } catch (err) { + logger.error('[MCP] Failed to read registry env via PowerShell', err); + } + + return env; +} + +/** + * 构建完整的子进程环境变量: + * 合并 Electron process.env + Windows 注册表环境变量。 + * 注册表值作为基础层,process.env 覆盖其上(保留 Electron 特有能力如 ELECTRON_RUN_AS_NODE)。 + */ +export function buildChildEnv(): Record { + const registryEnv = readWindowsRegistryEnv(); + const processEnv = process.env as Record; + + // 注册表为基础,process.env 覆盖 + const merged: Record = {}; + for (const [k, v] of Object.entries(registryEnv)) { + merged[k] = v; + } + for (const [k, v] of Object.entries(processEnv)) { + if (v !== undefined) { + merged[k] = v; + } + } + + return merged; +} + +/** + * 构建三个内置 MCP server 的启动配置 + * @param dirname 调用方 __dirname(编译后为 dist-electron/electron/) + * @param userDataDir filesystem server 的工作目录(userData) + */ +export function buildServerConfigs(dirname: string, userDataDir: string): McpServerConfig[] { + const clientRoot = path.resolve(dirname, '..', '..'); + const binDir = path.join(clientRoot, 'node_modules', '.bin'); + const isWindows = process.platform === 'win32'; + + return [ + { + name: 'filesystem', + binName: 'mcp-server-filesystem', + args: [userDataDir], + }, + { + name: 'sequential-thinking', + binName: 'mcp-server-sequential-thinking', + args: [], + }, + { + name: 'memory', + binName: 'mcp-server-memory', + args: [], + }, + ].map((cfg) => ({ + name: cfg.name, + command: isWindows + ? path.join(binDir, `${cfg.binName}.cmd`) + : path.join(binDir, cfg.binName), + args: cfg.args, + })); +} diff --git a/client/electron/mcpManager.ts b/client/electron/mcpManager.ts index 52397b1e..83352c88 100644 --- a/client/electron/mcpManager.ts +++ b/client/electron/mcpManager.ts @@ -1,373 +1,254 @@ -/** - * MCP Server 管理器(Bridge 架构) - * - * 通过 child_process.fork() 启动独立的 Node.js 子进程(mcpBridge.ts), - * 在子进程中加载 MCP SDK 并管理 server 连接。 - * - * 为什么需要 Bridge: - * Electron 主进程是 CJS 环境,MCP SDK 的 StdioClientTransport 仅 ESM 导出。 - * Electron 的模块系统不支持 new Function + import() 技巧加载 ESM 模块。 - * Bridge 运行在纯 Node.js 中,原生支持 ESM dynamic import()。 - * - * 通信协议(JSON over IPC): - * Manager → Bridge:{ id, method, params } - * Bridge → Manager:{ id, result?, error? } - * - * @ai-context Electron 主进程 MCP 集成入口 - */ - -import { fork, execSync, type ChildProcess } from 'child_process'; -import * as path from 'path'; -import { app } from 'electron'; -import { logger } from './logger.js'; - -// ================================================================ -// IPC 消息类型 -// ================================================================ - -interface BridgeRequest { - id: string; - method: 'init' | 'listTools' | 'callTool' | 'shutdown'; - params?: Record; -} - -interface BridgeResponse { - id: string; - result?: unknown; - error?: string; -} - -/** 工具描述信息 */ -interface McpToolInfo { - name: string; - description?: string; - inputSchema?: Record; -} - -// ================================================================ -// Server 名称 -// ================================================================ - -type ServerName = 'filesystem' | 'sequential-thinking' | 'memory'; - -// ================================================================ -// Windows 注册表环境变量读取 -// ================================================================ - -/** - * 从 Windows 注册表读取用户 + 系统环境变量。 - * Electron 主进程的 process.env 可能几乎为空(仅含 Electron 自设变量), - * 但 MCP Server 子进程需要完整环境(PATH, NODE_PATH 等)才能正常运行。 - * - * @returns 从注册表读取的环境变量对象,失败时返回空对象 - */ -function readWindowsRegistryEnv(): Record { - const env: Record = {}; - - if (process.platform !== 'win32') return env; - - try { - // 使用 PowerShell .NET API 从注册表读取用户 + 系统环境变量 - // [Environment]::GetEnvironmentVariables() 合并 Machine + User 两层 - const output = execSync( - 'powershell -NoProfile -Command "' + - '$e = [Environment]::GetEnvironmentVariables();' + - 'foreach ($k in $e.Keys) { Write-Output \"$k=$($e[$k])\" }"', - { - encoding: 'utf-8', - timeout: 10000, - windowsHide: true, - }, - ); - - for (const line of output.split('\n')) { - const eqIdx = line.indexOf('='); - if (eqIdx > 0) { - const key = line.slice(0, eqIdx).trim(); - const value = line.slice(eqIdx + 1).trim(); - if (key) env[key] = value; - } - } - - logger.info(`[MCP] Registry env loaded: ${Object.keys(env).length} keys`); - } catch (err) { - logger.error('[MCP] Failed to read registry env via PowerShell', err); - } - - return env; -} - -/** - * 构建完整的子进程环境变量: - * 合并 Electron process.env + Windows 注册表环境变量。 - * 注册表值作为基础层,process.env 覆盖其上(保留 Electron 特有能力如 ELECTRON_RUN_AS_NODE)。 - */ -function buildChildEnv(): Record { - const registryEnv = readWindowsRegistryEnv(); - const processEnv = process.env as Record; - - // 注册表为基础,process.env 覆盖 - const merged: Record = {}; - for (const [k, v] of Object.entries(registryEnv)) { - merged[k] = v; - } - for (const [k, v] of Object.entries(processEnv)) { - if (v !== undefined) { - merged[k] = v; - } - } - - return merged; -} - -// ================================================================ -// 管理器 -// ================================================================ - -class McpManager { - private bridge: ChildProcess | null = null; - private initialized = false; - private requestCounter = 0; - /** 待响应的请求回调 */ - private pending = new Map void; - reject: (reason: Error) => void; - }>(); - - /** - * 初始化 MCP Manager:fork Bridge 子进程并发送 init 命令 - */ - async init(): Promise { - if (this.initialized) return; - this.initialized = true; - - logger.info('[MCP] Initializing MCP Manager (bridge architecture)...'); - - // 1. Fork bridge 子进程 - // 编译后 __dirname = dist-electron/electron/ - // bridge 编译产物也在同目录:dist-electron/electron/mcpBridge.js - const bridgePath = path.join(__dirname, 'mcpBridge.js'); - - // 构建完整环境变量(Electron process.env 可能几乎为空,需从 Windows 注册表补充) - const childEnv = buildChildEnv(); - logger.info(`[MCP] Main process env keys: ${Object.keys(process.env).length}, merged child env keys: ${Object.keys(childEnv).length}, PATH: ${(childEnv.PATH || childEnv.Path || '').slice(0, 80)}`); - - try { - this.bridge = fork(bridgePath, [], { - stdio: ['pipe', 'pipe', 'pipe', 'ipc'], - env: childEnv, - }); - - if (!this.bridge.pid) { - throw new Error('Failed to fork bridge process — no PID assigned'); - } - - logger.info(`[MCP] Bridge process forked (pid: ${this.bridge.pid})`); - - // 监听 bridge 的 stdout(日志) - this.bridge.stdout?.on('data', (data: Buffer) => { - const msg = data.toString().trim(); - if (msg) logger.info(msg); - }); - - // 监听 bridge 的 stderr(错误) - this.bridge.stderr?.on('data', (data: Buffer) => { - const msg = data.toString().trim(); - if (msg) logger.error(msg); - }); - - // 监听 bridge 的 IPC 消息 - this.bridge.on('message', (msg: BridgeResponse) => { - this.handleResponse(msg); - }); - - // bridge 进程退出 - this.bridge.on('exit', (code, signal) => { - logger.warn(`[MCP] Bridge process exited: code=${code} signal=${signal}`); - this.bridge = null; - // 拒绝所有待处理的请求 - for (const [id, pending] of this.pending) { - pending.reject(new Error('Bridge process exited')); - this.pending.delete(id); - } - }); - - // bridge 进程错误 - this.bridge.on('error', (err) => { - logger.error('[MCP] Bridge process error', err); - }); - - // 2. 解析 bin 目录和 server 配置 - const clientRoot = path.resolve(__dirname, '..', '..'); - const binDir = path.join(clientRoot, 'node_modules', '.bin'); - const isWindows = process.platform === 'win32'; - const userDataDir = app.getPath('userData'); - - const serverConfigs = [ - { - name: 'filesystem', - binName: 'mcp-server-filesystem', - args: [userDataDir], - }, - { - name: 'sequential-thinking', - binName: 'mcp-server-sequential-thinking', - args: [], - }, - { - name: 'memory', - binName: 'mcp-server-memory', - args: [], - }, - ].map((cfg) => ({ - name: cfg.name, - command: isWindows - ? path.join(binDir, `${cfg.binName}.cmd`) - : path.join(binDir, cfg.binName), - args: cfg.args, - })); - - // 3. 发送 init 命令到 bridge - const result = await this.sendRequest('init', { servers: serverConfigs }); - const status = result as Record; - - const connectedCount = Object.values(status).filter(Boolean).length; - logger.info(`[MCP] Initialization complete: ${connectedCount}/${serverConfigs.length} servers connected`); - } catch (err) { - logger.error('[MCP] Manager init failed', err); - this.killBridge(); - } - } - - /** - * 列出指定 server 的所有可用工具 - */ - async listTools(serverName: ServerName): Promise { - const result = await this.sendRequest('listTools', { serverName }); - return result as McpToolInfo[]; - } - - /** - * 调用指定 server 上的工具 - */ - async callTool( - serverName: ServerName, - toolName: string, - args?: Record, - ): Promise { - return await this.sendRequest('callTool', { serverName, toolName, args }); - } - - /** - * 获取所有 server 的连接状态 - */ - async getStatus(): Promise> { - if (!this.bridge) { - return { filesystem: false, 'sequential-thinking': false, memory: false }; - } - // 通过 listTools 间接检测连接状态 - const status = {} as Record; - const names: ServerName[] = ['filesystem', 'sequential-thinking', 'memory']; - for (const name of names) { - try { - await this.sendRequest('listTools', { serverName: name }); - status[name] = true; - } catch { - status[name] = false; - } - } - return status; - } - - /** - * 关闭所有 server(发送 shutdown 命令并终止 bridge 进程) - */ - async shutdown(): Promise { - logger.info('[MCP] Shutting down MCP Manager...'); - - if (this.bridge) { - try { - // 给 bridge 1 秒时间优雅关闭(避免阻塞退出) - await Promise.race([ - this.sendRequest('shutdown', {}), - new Promise((_, reject) => - setTimeout(() => reject(new Error('Shutdown timeout')), 1000), - ), - ]); - } catch { - // 超时或失败,忽略 - } - this.killBridge(); - } - - logger.info('[MCP] MCP Manager shut down'); - } - - // ================================================================ - // 内部方法 - // ================================================================ - - /** - * 向 bridge 发送请求并等待响应 - */ - private sendRequest(method: BridgeRequest['method'], params: Record): Promise { - return new Promise((resolve, reject) => { - if (!this.bridge) { - reject(new Error('Bridge process is not running')); - return; - } - - const id = `req_${++this.requestCounter}`; - const request: BridgeRequest = { id, method, params }; - - this.pending.set(id, { resolve, reject }); - - this.bridge.send(request, (err) => { - if (err) { - this.pending.delete(id); - reject(new Error(`Failed to send request: ${err.message}`)); - } - }); - }); - } - - /** - * 处理 bridge 返回的响应 - */ - private handleResponse(msg: BridgeResponse): void { - const pending = this.pending.get(msg.id); - if (!pending) { - logger.warn(`[MCP] Received response for unknown request: ${msg.id}`); - return; - } - - this.pending.delete(msg.id); - - if (msg.error) { - pending.reject(new Error(msg.error)); - } else { - pending.resolve(msg.result); - } - } - - /** - * 强制终止 bridge 子进程 - */ - private killBridge(): void { - if (this.bridge) { - this.bridge.kill('SIGTERM'); - // 5 秒后强杀 - const bridge = this.bridge; - setTimeout(() => { - if (bridge.connected) bridge.kill('SIGKILL'); - }, 5000); - this.bridge = null; - } - } -} - -// ================================================================ -// 单例导出 -// ================================================================ - -export const mcpManager = new McpManager(); +/** + * MCP Server 管理器(Bridge 架构) + * + * 通过 child_process.fork() 启动独立的 Node.js 子进程(mcpBridge.ts), + * 在子进程中加载 MCP SDK 并管理 server 连接。 + * + * 为什么需要 Bridge: + * Electron 主进程是 CJS 环境,MCP SDK 的 StdioClientTransport 仅 ESM 导出。 + * Electron 的模块系统不支持 new Function + import() 技巧加载 ESM 模块。 + * Bridge 运行在纯 Node.js 中,原生支持 ESM dynamic import()。 + * + * 通信协议(JSON over IPC): + * Manager → Bridge:{ id, method, params } + * Bridge → Manager:{ id, result?, error? } + * + * @ai-context Electron 主进程 MCP 集成入口。2026-07 拆分——环境变量 + * 合并与 server 配置在 mcpEnv.ts;本类保留 Bridge 进程生命周期与 + * 请求-响应管线。shutdown 有 1s 优雅关闭 + SIGTERM + 5s SIGKILL + * 三级兜底,防孤儿进程阻塞应用退出。 + */ + +import { fork, type ChildProcess } from 'child_process'; +import * as path from 'path'; +import { app } from 'electron'; +import { logger } from './logger.js'; +import { + buildChildEnv, buildServerConfigs, + type BridgeRequest, type BridgeResponse, type McpToolInfo, type ServerName, +} from './mcpEnv.js'; + +// ================================================================ +// 管理器 +// ================================================================ + +class McpManager { + private bridge: ChildProcess | null = null; + private initialized = false; + private requestCounter = 0; + /** 待响应的请求回调 */ + private pending = new Map void; + reject: (reason: Error) => void; + }>(); + + /** + * 初始化 MCP Manager:fork Bridge 子进程并发送 init 命令 + */ + async init(): Promise { + if (this.initialized) return; + this.initialized = true; + + logger.info('[MCP] Initializing MCP Manager (bridge architecture)...'); + + // 1. Fork bridge 子进程 + // 编译后 __dirname = dist-electron/electron/ + // bridge 编译产物也在同目录:dist-electron/electron/mcpBridge.js + const bridgePath = path.join(__dirname, 'mcpBridge.js'); + + // 构建完整环境变量(Electron process.env 可能几乎为空,需从 Windows 注册表补充) + const childEnv = buildChildEnv(); + logger.info(`[MCP] Main process env keys: ${Object.keys(process.env).length}, merged child env keys: ${Object.keys(childEnv).length}, PATH: ${(childEnv.PATH || childEnv.Path || '').slice(0, 80)}`); + + try { + this.bridge = fork(bridgePath, [], { + stdio: ['pipe', 'pipe', 'pipe', 'ipc'], + env: childEnv, + }); + + if (!this.bridge.pid) { + throw new Error('Failed to fork bridge process — no PID assigned'); + } + + logger.info(`[MCP] Bridge process forked (pid: ${this.bridge.pid})`); + + // 监听 bridge 的 stdout(日志) + this.bridge.stdout?.on('data', (data: Buffer) => { + const msg = data.toString().trim(); + if (msg) logger.info(msg); + }); + + // 监听 bridge 的 stderr(错误) + this.bridge.stderr?.on('data', (data: Buffer) => { + const msg = data.toString().trim(); + if (msg) logger.error(msg); + }); + + // 监听 bridge 的 IPC 消息 + this.bridge.on('message', (msg: BridgeResponse) => { + this.handleResponse(msg); + }); + + // bridge 进程退出 + this.bridge.on('exit', (code, signal) => { + logger.warn(`[MCP] Bridge process exited: code=${code} signal=${signal}`); + this.bridge = null; + // 拒绝所有待处理的请求 + for (const [id, pending] of this.pending) { + pending.reject(new Error('Bridge process exited')); + this.pending.delete(id); + } + }); + + // bridge 进程错误 + this.bridge.on('error', (err) => { + logger.error('[MCP] Bridge process error', err); + }); + + // 2. 解析 bin 目录和 server 配置(详见 mcpEnv.ts) + const serverConfigs = buildServerConfigs(__dirname, app.getPath('userData')); + + // 3. 发送 init 命令到 bridge + const result = await this.sendRequest('init', { servers: serverConfigs }); + const status = result as Record; + + const connectedCount = Object.values(status).filter(Boolean).length; + logger.info(`[MCP] Initialization complete: ${connectedCount}/${serverConfigs.length} servers connected`); + } catch (err) { + logger.error('[MCP] Manager init failed', err); + this.killBridge(); + } + } + + /** + * 列出指定 server 的所有可用工具 + */ + async listTools(serverName: ServerName): Promise { + const result = await this.sendRequest('listTools', { serverName }); + return result as McpToolInfo[]; + } + + /** + * 调用指定 server 上的工具 + */ + async callTool( + serverName: ServerName, + toolName: string, + args?: Record, + ): Promise { + return await this.sendRequest('callTool', { serverName, toolName, args }); + } + + /** + * 获取所有 server 的连接状态 + */ + async getStatus(): Promise> { + if (!this.bridge) { + return { filesystem: false, 'sequential-thinking': false, memory: false }; + } + // 通过 listTools 间接检测连接状态 + const status = {} as Record; + const names: ServerName[] = ['filesystem', 'sequential-thinking', 'memory']; + for (const name of names) { + try { + await this.sendRequest('listTools', { serverName: name }); + status[name] = true; + } catch { + status[name] = false; + } + } + return status; + } + + /** + * 关闭所有 server(发送 shutdown 命令并终止 bridge 进程) + */ + async shutdown(): Promise { + logger.info('[MCP] Shutting down MCP Manager...'); + + if (this.bridge) { + try { + // 给 bridge 1 秒时间优雅关闭(避免阻塞退出) + await Promise.race([ + this.sendRequest('shutdown', {}), + new Promise((_, reject) => + setTimeout(() => reject(new Error('Shutdown timeout')), 1000), + ), + ]); + } catch { + // 超时或失败,忽略 + } + this.killBridge(); + } + + logger.info('[MCP] MCP Manager shut down'); + } + + // ================================================================ + // 内部方法 + // ================================================================ + + /** + * 向 bridge 发送请求并等待响应 + */ + private sendRequest(method: BridgeRequest['method'], params: Record): Promise { + return new Promise((resolve, reject) => { + if (!this.bridge) { + reject(new Error('Bridge process is not running')); + return; + } + + const id = `req_${++this.requestCounter}`; + const request: BridgeRequest = { id, method, params }; + + this.pending.set(id, { resolve, reject }); + + this.bridge.send(request, (err) => { + if (err) { + this.pending.delete(id); + reject(new Error(`Failed to send request: ${err.message}`)); + } + }); + }); + } + + /** + * 处理 bridge 返回的响应 + */ + private handleResponse(msg: BridgeResponse): void { + const pending = this.pending.get(msg.id); + if (!pending) { + logger.warn(`[MCP] Received response for unknown request: ${msg.id}`); + return; + } + + this.pending.delete(msg.id); + + if (msg.error) { + pending.reject(new Error(msg.error)); + } else { + pending.resolve(msg.result); + } + } + + /** + * 强制终止 bridge 子进程 + */ + private killBridge(): void { + if (this.bridge) { + this.bridge.kill('SIGTERM'); + // 5 秒后强杀 + const bridge = this.bridge; + setTimeout(() => { + if (bridge.connected) bridge.kill('SIGKILL'); + }, 5000); + this.bridge = null; + } + } +} + +// ================================================================ +// 单例导出 +// ================================================================ + +export const mcpManager = new McpManager(); diff --git a/client/electron/mediaCaptureHandlers.ts b/client/electron/mediaCaptureHandlers.ts new file mode 100644 index 00000000..1282ebe4 --- /dev/null +++ b/client/electron/mediaCaptureHandlers.ts @@ -0,0 +1,224 @@ +/** + * 系统音频捕获 & 视频录制 IPC Handler + * + * @ai-context: 从 captureHandlers.ts 拆出。音频/视频数据块均由渲染进程 + * 经 ipcMain.on 回传(audio_capture_chunk / video_record_chunk),两处 + * 都有 SEC-005 sender.id 验证——仅接受主窗口数据,防第三方窗口注入; + * 音频块另有运行时结构断言(audioBuffer/sampleRate/channels/durationMs)。 + * @ai-context: 所有 start 入口均幂等(先 dispose 旧实例再建新)。 + */ +import { BrowserWindow, ipcMain } from 'electron'; +import { AudioCapture, listAudioSources } from './audioCapture.js'; +import type { AudioCaptureOptions, AudioChunk } from './audioCapture.js'; +import { VideoRecorder } from './videoRecorder.js'; +import type { VideoRecordOptions } from './videoRecorder.js'; +import { safeHandle, getMainWindowId } from './ipcUtils.js'; +import { logger } from './logger.js'; + +// ================================================================ +// 模块级状态 +// ================================================================ + +/** 当前活跃的音频捕获实例 */ +let activeAudioCapture: AudioCapture | null = null; + +/** @ai-context Path C 全程录制:当前活跃的视频录制实例 */ +let activeVideoRecorder: VideoRecorder | null = null; + +/** SEC-005 sender 验证:非主窗口来源返回 false 并告警 */ +function verifySender(senderId: number, channel: string): boolean { + const mainId = getMainWindowId(); + if (mainId !== null && senderId !== mainId) { + logger.warn( + `[IPC] Sender verification failed for "${channel}": ` + + `expected sender.id=${mainId}, got ${senderId}` + ); + return false; + } + return true; +} + +/** + * 注册音频捕获与视频录制相关的 IPC handler + */ +export function registerMediaCaptureHandlers(): void { + // ---- 系统音频捕获 ---- + + safeHandle('audio_list_sources', async () => { + try { + return await listAudioSources(); + } catch (err) { + logger.error('[IPC] audio_list_sources failed:', err); + return []; + } + }); + + safeHandle( + 'audio_capture_start', + async (event, options?: Partial & { sourceId?: string }) => { + if (activeAudioCapture) { + activeAudioCapture.dispose(); + activeAudioCapture = null; + } + + const senderWin = BrowserWindow.fromWebContents(event.sender); + if (!senderWin || senderWin.isDestroyed()) { + return { success: false, error: 'No valid window' }; + } + + const captureOptions: Partial = { + chunkDurationMs: options?.chunkDurationMs, + sampleRate: options?.sampleRate, + channels: options?.channels, + }; + + activeAudioCapture = new AudioCapture(captureOptions, (chunk: AudioChunk) => { + if (senderWin && !senderWin.isDestroyed()) { + senderWin.webContents.send('audio_capture_chunk', chunk); + } + }); + + try { + await activeAudioCapture.start(senderWin, options?.sourceId); + logger.info('[IPC] audio_capture_start 已启动'); + return { success: true }; + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + logger.error('[IPC] audio_capture_start failed:', message); + activeAudioCapture.dispose(); + activeAudioCapture = null; + return { success: false, error: message }; + } + }, + ); + + safeHandle('audio_capture_stop', async () => { + if (activeAudioCapture) { + activeAudioCapture.dispose(); + activeAudioCapture = null; + logger.info('[IPC] audio_capture_stop 已停止'); + } + return { success: true }; + }); + + ipcMain.on( + 'audio_capture_chunk', + (_event, data: unknown) => { + // SEC-005: sender 验证,仅接受主窗口的音频数据 + if (!verifySender(_event.sender.id, 'audio_capture_chunk')) return; + + // SEC: 运行时类型断言 — 防止恶意或格式错误的数据 + if ( + !data || + typeof data !== 'object' || + !('audioBuffer' in data) || + typeof (data as Record).sampleRate !== 'number' || + typeof (data as Record).channels !== 'number' || + typeof (data as Record).durationMs !== 'number' + ) { + logger.warn('[IPC] audio_capture_chunk: invalid data format, dropping chunk'); + return; + } + + const chunk = data as { audioBuffer: ArrayBuffer; sampleRate: number; channels: number; durationMs: number }; + if (activeAudioCapture && activeAudioCapture.isCapturing) { + activeAudioCapture.handleRendererChunk(chunk); + } + }, + ); + + // ---- Path C 视频录制 ---- + + safeHandle( + 'video_record_start', + async (event, sourceId: string, options?: VideoRecordOptions) => { + // 幂等:先清理旧实例 + if (activeVideoRecorder) { + activeVideoRecorder.dispose(); + activeVideoRecorder = null; + } + + const senderWin = BrowserWindow.fromWebContents(event.sender); + if (!senderWin || senderWin.isDestroyed()) { + return { success: false, error: 'No valid window' }; + } + + activeVideoRecorder = new VideoRecorder(options); + activeVideoRecorder.bindWindow(senderWin); + + try { + activeVideoRecorder.startRecording(sourceId, options); + logger.info('[IPC] video_record_start 已启动'); + return { success: true }; + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + logger.error('[IPC] video_record_start failed:', message); + activeVideoRecorder.dispose(); + activeVideoRecorder = null; + return { success: false, error: message }; + } + }, + ); + + safeHandle('video_record_stop', async () => { + if (!activeVideoRecorder) { + return { success: false, error: 'No active recording' }; + } + try { + const filePath = await activeVideoRecorder.stopRecording(); + const finalStatus = activeVideoRecorder.status; + logger.info('[IPC] video_record_stop 已完成'); + activeVideoRecorder.dispose(); + activeVideoRecorder = null; + return { success: true, filePath, finalStatus }; + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + logger.error('[IPC] video_record_stop failed:', message); + activeVideoRecorder?.dispose(); + activeVideoRecorder = null; + return { success: false, error: message }; + } + }); + + safeHandle('video_record_pause', async () => { + activeVideoRecorder?.pauseRecording(); + return { success: true }; + }); + + safeHandle('video_record_resume', async () => { + activeVideoRecorder?.resumeRecording(); + return { success: true }; + }); + + safeHandle('video_record_status', async () => { + return activeVideoRecorder?.status ?? { + isRecording: false, isPaused: false, duration: 0, fileSizeBytes: 0, filePath: null, + }; + }); + + // 渲染进程回传视频数据块 + ipcMain.on('video_record_chunk', (_event, chunkBuffer: ArrayBuffer) => { + if (!verifySender(_event.sender.id, 'video_record_chunk')) return; + activeVideoRecorder?.handleRendererChunk(chunkBuffer); + }); + + // 渲染进程上报录制错误 + ipcMain.on('video_record_error', (_event, errorInfo: { message: string }) => { + if (!verifySender(_event.sender.id, 'video_record_error')) return; + activeVideoRecorder?.handleRendererError(errorInfo); + }); +} + +/** + * 释放音频/视频采集资源 + */ +export function disposeMediaCaptureHandlers(): void { + if (activeAudioCapture) { + activeAudioCapture.dispose(); + activeAudioCapture = null; + } + if (activeVideoRecorder) { + activeVideoRecorder.dispose(); + activeVideoRecorder = null; + } +} diff --git a/client/electron/preload.ts b/client/electron/preload.ts index cd6bc1ad..09c20909 100644 --- a/client/electron/preload.ts +++ b/client/electron/preload.ts @@ -1,241 +1,243 @@ -/** - * Electron 预加载脚本 - * - * 在渲染进程与主进程之间建立安全的通信桥梁, - * 通过 contextBridge 暴露白名单内的 IPC channel。 - */ - -import { contextBridge, ipcRenderer } from 'electron'; - -/** 允许渲染进程调用的 IPC channel 白名单 */ -const ALLOWED_CHANNELS = [ - 'ai_summarize', - 'ai_generate_cards', - 'ai_evaluate', - 'ai_recommend_duration', - 'ai_feynman_question', - 'ai_feynman_evaluate_answers', - 'ai_optimize_card', - 'ai_tag_content', - 'ai_sort_inspiration', - 'ai_anchor_point', - 'ai_socratic', - 'ai_socratic_evaluate', - 'ai_socratic_deepening', - 'ai_predict', - 'ai_rescue', - 'ai_vision_extract', - 'ai_session_analyze', - 'ai_video_analyze', - 'ai_merge_notes', - 'ai:set-gateway-url', - 'screen_list_windows', - 'screen_watch_windows_start', - 'screen_watch_windows_stop', - 'screen_capture_start', - 'screen_capture_stop', - 'audio_list_sources', - 'audio_capture_start', - 'audio_capture_stop', - 'get-app-version', - 'dialog:selectDirectory', - 'get-default-storage-path', - 'update:check', - 'update:download', - 'update:install', - 'update:set-auto-check', - 'window:close-action', - 'window:minimize', - 'window:maximize', - 'window:close', - 'window:isMaximized', - // v0.9.0: 备份相关 IPC channel - 'backup:save', - 'backup:open', - // v1.0.0: 数据访问 IPC channel - 'db:query', - 'db:insert', - 'db:update', - 'db:delete', - 'db:search', - 'db:batch', - // v1.0.0: 数据迁移 IPC channel - 'migration:check', - 'migration:import-table', - 'migration:complete', - // v1.1.0: 存储路径切换 IPC channel - 'storage:change-path', - 'storage:get-active-path', - // 退出前同步完成通知 - 'sync:quit-complete', - // 文件读取(课堂助手视频分析) - 'fs:read-file', - // Path C 视频录制 IPC channel - 'video_record_start', - 'video_record_stop', - 'video_record_pause', - 'video_record_resume', - 'video_record_status', - // Ollama 本地推理 IPC channel - 'ollama:get-status', - 'ollama:set-config', - 'ollama:pull-model', - 'ollama:delete-model', - // AI 流式输出 IPC channel - 'ai:stream:start', - 'ai:stream:cancel', -] as const; - -/** 允许渲染进程监听的事件 channel 白名单(主进程 → 渲染进程推送) */ -const ALLOWED_EVENT_CHANNELS = [ - 'screen_capture_frame', - 'screen_windows_changed', - 'audio_capture_chunk', - 'audio_capture_do_start', - 'audio_capture_do_stop', - 'update-status', - 'window:closing', - 'window:maximized-changed', - 'sync:before-quit', - // Path C 视频录制状态推送 - 'video_record_status', - 'video_record_error', - 'video_record_do_start', - 'video_record_do_stop', - // Ollama 模型拉取进度推送 - 'ollama:pull-progress', - // AI 流式输出推送 - 'ai:stream:chunk', - 'ai:stream:end', - 'ai:stream:error', -] as const; - -/** 允许渲染进程单向发送的 channel 白名单(渲染进程 → 主进程,fire-and-forget) */ -const ALLOWED_SEND_CHANNELS = [ - 'audio_capture_chunk', - // Path C 视频录制数据块回传 - 'video_record_chunk', - 'video_record_started', - 'video_record_stopped', - 'video_record_error', -] as const; - -type AllowedChannel = (typeof ALLOWED_CHANNELS)[number]; -type AllowedEventChannel = (typeof ALLOWED_EVENT_CHANNELS)[number]; -type AllowedSendChannel = (typeof ALLOWED_SEND_CHANNELS)[number]; - -/** - * 暴露 electronAPI 对象到渲染进程的 window 全局变量, - * 仅允许白名单内的 channel 通过,防止任意 IPC 调用。 - */ -contextBridge.exposeInMainWorld('electronAPI', { - invoke: (channel: AllowedChannel, ...args: unknown[]) => { - if ((ALLOWED_CHANNELS as readonly string[]).includes(channel)) { - return ipcRenderer.invoke(channel, ...args); - } - return Promise.reject(new Error(`[preload] 不允许的 IPC channel: ${channel}`)); - }, - on: (channel: AllowedEventChannel, callback: (...args: unknown[]) => void) => { - if ((ALLOWED_EVENT_CHANNELS as readonly string[]).includes(channel)) { - // 保留包装后的 handler 引用,卸载时只移除自己的监听器。 - // 注意:不能使用 removeAllListeners(channel)——多个组件会订阅同一 - // channel(如 audio_capture_chunk),removeAllListeners 会把其他 - // 组件的监听器一并清除,导致音频流静默中断。 - const handler = (_event: unknown, ...args: unknown[]) => callback(...args); - ipcRenderer.on(channel, handler); - return () => { - ipcRenderer.removeListener(channel, handler); - }; - } - console.warn(`[preload] 不允许的事件 channel: ${channel}`); - return () => {}; - }, - send: (channel: AllowedSendChannel, ...args: unknown[]) => { - if ((ALLOWED_SEND_CHANNELS as readonly string[]).includes(channel)) { - ipcRenderer.send(channel, ...args); - } else { - console.warn(`[preload] 不允许的发送 channel: ${channel}`); - } - }, - /** 监听主进程发出的窗口关闭事件 */ - onWindowClosing: (callback: () => void) => { - ipcRenderer.on('window:closing', callback); - return () => ipcRenderer.removeAllListeners('window:closing'); - }, - /** 向主进程发送关闭行为选择 */ - closeAction: (action: 'quit' | 'minimize' | 'cancel', remember: boolean) => { - return ipcRenderer.invoke('window:close-action', action, remember); - }, - // ---- 窗口控制 API ---- - windowMinimize: () => ipcRenderer.invoke('window:minimize'), - windowMaximize: () => ipcRenderer.invoke('window:maximize'), - windowClose: () => ipcRenderer.invoke('window:close'), - windowIsMaximized: () => ipcRenderer.invoke('window:isMaximized') as Promise, - onMaximizedChanged: (callback: (isMaximized: boolean) => void) => { - const handler = (_event: unknown, isMaximized: boolean) => callback(isMaximized); - ipcRenderer.on('window:maximized-changed', handler); - return () => ipcRenderer.removeListener('window:maximized-changed', handler); - }, - /** 监听退出前同步事件 */ - onSyncBeforeQuit: (callback: () => void) => { - ipcRenderer.on('sync:before-quit', callback); - return () => ipcRenderer.removeAllListeners('sync:before-quit'); - }, - /** 通知主进程同步已完成 */ - notifySyncComplete: () => { - ipcRenderer.invoke('sync:quit-complete'); - }, - // ---- 自动更新 API ---- - /** 设置是否自动检查更新 */ - setAutoUpdate: (enabled: boolean) => ipcRenderer.invoke('update:set-auto-check', enabled), - // ---- v0.9.0: 备份 API ---- - /** 保存备份文件(显示系统保存对话框) */ - backupSave: (data: string, defaultName?: string) => ipcRenderer.invoke('backup:save', data, defaultName), - /** 打开备份文件(显示系统打开对话框,返回文件内容) */ - backupOpen: () => ipcRenderer.invoke('backup:open'), - // ---- v1.0.0: 数据访问 API ---- - db: { - query: (table: string, method: string, args?: unknown[]) => - ipcRenderer.invoke('db:query', { table, method, args }), - insert: (table: string, item: unknown) => - ipcRenderer.invoke('db:insert', { table, item }), - update: (table: string, id: string, changes: unknown) => - ipcRenderer.invoke('db:update', { table, id, changes }), - delete: (table: string, id: string) => - ipcRenderer.invoke('db:delete', { table, id }), - search: (table: string, query: string) => - ipcRenderer.invoke('db:search', { table, query }), - batch: (operations: unknown[]) => - ipcRenderer.invoke('db:batch', { operations }), - }, - // ---- v1.0.0: 数据迁移 API ---- - migration: { - check: () => ipcRenderer.invoke('migration:check'), - importTable: (table: string, rows: unknown[]) => - ipcRenderer.invoke('migration:import-table', { table, rows }), - complete: () => ipcRenderer.invoke('migration:complete'), - }, - // ---- v1.1.0: 存储路径管理 API ---- - storage: { - changePath: (newPath: string) => - ipcRenderer.invoke('storage:change-path', { newPath }), - getActivePath: () => - ipcRenderer.invoke('storage:get-active-path'), - }, - // ---- Ollama 本地推理 API ---- - ollama: { - getStatus: (forceRefresh?: boolean) => - ipcRenderer.invoke('ollama:get-status', forceRefresh), - setConfig: (config: Record) => - ipcRenderer.invoke('ollama:set-config', config), - pullModel: (modelName: string) => - ipcRenderer.invoke('ollama:pull-model', modelName), - deleteModel: (modelName: string) => - ipcRenderer.invoke('ollama:delete-model', modelName), - onPullProgress: (callback: (...args: unknown[]) => void) => { - const handler = (_event: unknown, ...args: unknown[]) => callback(...args); - ipcRenderer.on('ollama:pull-progress', handler); - return () => ipcRenderer.removeListener('ollama:pull-progress', handler); - }, - }, -}); +/** + * Electron 预加载脚本 + * + * 在渲染进程与主进程之间建立安全的通信桥梁, + * 通过 contextBridge 暴露白名单内的 IPC channel。 + * + * @ai-context: IPC 桥接安全边界(contextBridge 白名单暴露)——渲染进程唯一的主进程访问面,新增通道必须显式登记,任何修改需安全审查。 + */ + +import { contextBridge, ipcRenderer } from 'electron'; + +/** 允许渲染进程调用的 IPC channel 白名单 */ +const ALLOWED_CHANNELS = [ + 'ai_summarize', + 'ai_generate_cards', + 'ai_evaluate', + 'ai_recommend_duration', + 'ai_feynman_question', + 'ai_feynman_evaluate_answers', + 'ai_optimize_card', + 'ai_tag_content', + 'ai_sort_inspiration', + 'ai_anchor_point', + 'ai_socratic', + 'ai_socratic_evaluate', + 'ai_socratic_deepening', + 'ai_predict', + 'ai_rescue', + 'ai_vision_extract', + 'ai_session_analyze', + 'ai_video_analyze', + 'ai_merge_notes', + 'ai:set-gateway-url', + 'screen_list_windows', + 'screen_watch_windows_start', + 'screen_watch_windows_stop', + 'screen_capture_start', + 'screen_capture_stop', + 'audio_list_sources', + 'audio_capture_start', + 'audio_capture_stop', + 'get-app-version', + 'dialog:selectDirectory', + 'get-default-storage-path', + 'update:check', + 'update:download', + 'update:install', + 'update:set-auto-check', + 'window:close-action', + 'window:minimize', + 'window:maximize', + 'window:close', + 'window:isMaximized', + // v0.9.0: 备份相关 IPC channel + 'backup:save', + 'backup:open', + // v1.0.0: 数据访问 IPC channel + 'db:query', + 'db:insert', + 'db:update', + 'db:delete', + 'db:search', + 'db:batch', + // v1.0.0: 数据迁移 IPC channel + 'migration:check', + 'migration:import-table', + 'migration:complete', + // v1.1.0: 存储路径切换 IPC channel + 'storage:change-path', + 'storage:get-active-path', + // 退出前同步完成通知 + 'sync:quit-complete', + // 文件读取(课堂助手视频分析) + 'fs:read-file', + // Path C 视频录制 IPC channel + 'video_record_start', + 'video_record_stop', + 'video_record_pause', + 'video_record_resume', + 'video_record_status', + // Ollama 本地推理 IPC channel + 'ollama:get-status', + 'ollama:set-config', + 'ollama:pull-model', + 'ollama:delete-model', + // AI 流式输出 IPC channel + 'ai:stream:start', + 'ai:stream:cancel', +] as const; + +/** 允许渲染进程监听的事件 channel 白名单(主进程 → 渲染进程推送) */ +const ALLOWED_EVENT_CHANNELS = [ + 'screen_capture_frame', + 'screen_windows_changed', + 'audio_capture_chunk', + 'audio_capture_do_start', + 'audio_capture_do_stop', + 'update-status', + 'window:closing', + 'window:maximized-changed', + 'sync:before-quit', + // Path C 视频录制状态推送 + 'video_record_status', + 'video_record_error', + 'video_record_do_start', + 'video_record_do_stop', + // Ollama 模型拉取进度推送 + 'ollama:pull-progress', + // AI 流式输出推送 + 'ai:stream:chunk', + 'ai:stream:end', + 'ai:stream:error', +] as const; + +/** 允许渲染进程单向发送的 channel 白名单(渲染进程 → 主进程,fire-and-forget) */ +const ALLOWED_SEND_CHANNELS = [ + 'audio_capture_chunk', + // Path C 视频录制数据块回传 + 'video_record_chunk', + 'video_record_started', + 'video_record_stopped', + 'video_record_error', +] as const; + +type AllowedChannel = (typeof ALLOWED_CHANNELS)[number]; +type AllowedEventChannel = (typeof ALLOWED_EVENT_CHANNELS)[number]; +type AllowedSendChannel = (typeof ALLOWED_SEND_CHANNELS)[number]; + +/** + * 暴露 electronAPI 对象到渲染进程的 window 全局变量, + * 仅允许白名单内的 channel 通过,防止任意 IPC 调用。 + */ +contextBridge.exposeInMainWorld('electronAPI', { + invoke: (channel: AllowedChannel, ...args: unknown[]) => { + if ((ALLOWED_CHANNELS as readonly string[]).includes(channel)) { + return ipcRenderer.invoke(channel, ...args); + } + return Promise.reject(new Error(`[preload] 不允许的 IPC channel: ${channel}`)); + }, + on: (channel: AllowedEventChannel, callback: (...args: unknown[]) => void) => { + if ((ALLOWED_EVENT_CHANNELS as readonly string[]).includes(channel)) { + // 保留包装后的 handler 引用,卸载时只移除自己的监听器。 + // 注意:不能使用 removeAllListeners(channel)——多个组件会订阅同一 + // channel(如 audio_capture_chunk),removeAllListeners 会把其他 + // 组件的监听器一并清除,导致音频流静默中断。 + const handler = (_event: unknown, ...args: unknown[]) => callback(...args); + ipcRenderer.on(channel, handler); + return () => { + ipcRenderer.removeListener(channel, handler); + }; + } + console.warn(`[preload] 不允许的事件 channel: ${channel}`); + return () => {}; + }, + send: (channel: AllowedSendChannel, ...args: unknown[]) => { + if ((ALLOWED_SEND_CHANNELS as readonly string[]).includes(channel)) { + ipcRenderer.send(channel, ...args); + } else { + console.warn(`[preload] 不允许的发送 channel: ${channel}`); + } + }, + /** 监听主进程发出的窗口关闭事件 */ + onWindowClosing: (callback: () => void) => { + ipcRenderer.on('window:closing', callback); + return () => ipcRenderer.removeAllListeners('window:closing'); + }, + /** 向主进程发送关闭行为选择 */ + closeAction: (action: 'quit' | 'minimize' | 'cancel', remember: boolean) => { + return ipcRenderer.invoke('window:close-action', action, remember); + }, + // ---- 窗口控制 API ---- + windowMinimize: () => ipcRenderer.invoke('window:minimize'), + windowMaximize: () => ipcRenderer.invoke('window:maximize'), + windowClose: () => ipcRenderer.invoke('window:close'), + windowIsMaximized: () => ipcRenderer.invoke('window:isMaximized') as Promise, + onMaximizedChanged: (callback: (isMaximized: boolean) => void) => { + const handler = (_event: unknown, isMaximized: boolean) => callback(isMaximized); + ipcRenderer.on('window:maximized-changed', handler); + return () => ipcRenderer.removeListener('window:maximized-changed', handler); + }, + /** 监听退出前同步事件 */ + onSyncBeforeQuit: (callback: () => void) => { + ipcRenderer.on('sync:before-quit', callback); + return () => ipcRenderer.removeAllListeners('sync:before-quit'); + }, + /** 通知主进程同步已完成 */ + notifySyncComplete: () => { + ipcRenderer.invoke('sync:quit-complete'); + }, + // ---- 自动更新 API ---- + /** 设置是否自动检查更新 */ + setAutoUpdate: (enabled: boolean) => ipcRenderer.invoke('update:set-auto-check', enabled), + // ---- v0.9.0: 备份 API ---- + /** 保存备份文件(显示系统保存对话框) */ + backupSave: (data: string, defaultName?: string) => ipcRenderer.invoke('backup:save', data, defaultName), + /** 打开备份文件(显示系统打开对话框,返回文件内容) */ + backupOpen: () => ipcRenderer.invoke('backup:open'), + // ---- v1.0.0: 数据访问 API ---- + db: { + query: (table: string, method: string, args?: unknown[]) => + ipcRenderer.invoke('db:query', { table, method, args }), + insert: (table: string, item: unknown) => + ipcRenderer.invoke('db:insert', { table, item }), + update: (table: string, id: string, changes: unknown) => + ipcRenderer.invoke('db:update', { table, id, changes }), + delete: (table: string, id: string) => + ipcRenderer.invoke('db:delete', { table, id }), + search: (table: string, query: string) => + ipcRenderer.invoke('db:search', { table, query }), + batch: (operations: unknown[]) => + ipcRenderer.invoke('db:batch', { operations }), + }, + // ---- v1.0.0: 数据迁移 API ---- + migration: { + check: () => ipcRenderer.invoke('migration:check'), + importTable: (table: string, rows: unknown[]) => + ipcRenderer.invoke('migration:import-table', { table, rows }), + complete: () => ipcRenderer.invoke('migration:complete'), + }, + // ---- v1.1.0: 存储路径管理 API ---- + storage: { + changePath: (newPath: string) => + ipcRenderer.invoke('storage:change-path', { newPath }), + getActivePath: () => + ipcRenderer.invoke('storage:get-active-path'), + }, + // ---- Ollama 本地推理 API ---- + ollama: { + getStatus: (forceRefresh?: boolean) => + ipcRenderer.invoke('ollama:get-status', forceRefresh), + setConfig: (config: Record) => + ipcRenderer.invoke('ollama:set-config', config), + pullModel: (modelName: string) => + ipcRenderer.invoke('ollama:pull-model', modelName), + deleteModel: (modelName: string) => + ipcRenderer.invoke('ollama:delete-model', modelName), + onPullProgress: (callback: (...args: unknown[]) => void) => { + const handler = (_event: unknown, ...args: unknown[]) => callback(...args); + ipcRenderer.on('ollama:pull-progress', handler); + return () => ipcRenderer.removeListener('ollama:pull-progress', handler); + }, + }, +}); diff --git a/client/electron/screenCapture.ts b/client/electron/screenCapture.ts index 08e6fcbf..423eb114 100644 --- a/client/electron/screenCapture.ts +++ b/client/electron/screenCapture.ts @@ -1,271 +1,273 @@ -/** - * Electron 主进程屏幕截图采集模块 - * - * 使用 desktopCapturer API 定时截取指定窗口画面, - * 通过 IPC 将 PNG 数据推送到渲染进程。 - */ - -import { desktopCapturer, DesktopCapturerSource, BrowserWindow } from 'electron'; -import { logger } from './logger'; - -// ================================================================ -// 类型定义 -// ================================================================ - -/** 可捕获窗口信息 */ -export interface WindowInfo { - id: string; - name: string; - displayId: string; -} - -/** 截图采集配置 */ -export interface ScreenCaptureOptions { - interval: number; // 截图间隔 ms,默认 5000 - windowId?: string; // 目标窗口 source ID -} - -/** 截图帧数据(通过 IPC 传输到渲染进程) */ -export interface ScreenshotFrameData { - imageBuffer: ArrayBuffer; // PNG 图片数据 - width: number; - height: number; - timestamp: number; // 单调递增时间戳 (ms) - sourceId: string; // 来源 source ID - hasChanged: boolean; // 帧变化检测结果(false 表示与上一帧相同,可跳过) -} - -// ================================================================ -// 截图采集器 -// ================================================================ - -const DEFAULT_INTERVAL = 5000; -const THUMBNAIL_SIZE = { width: 1920, height: 1080 }; - -/** 单调递增时间戳生成器 */ -let lastTimestamp = 0; -function monotonicTimestamp(): number { - const now = Date.now(); - lastTimestamp = now > lastTimestamp ? now : lastTimestamp + 1; - return lastTimestamp; -} - -export class ScreenCapture { - private timer: ReturnType | null = null; - private readonly options: Required> & - Pick; - private readonly onScreenshot: (data: ScreenshotFrameData) => void; - private disposed = false; - - /** 上一帧的分块 hash 数组,用于快速判断画面是否变化 */ - private lastFrameBlockHashes: string[] = []; - - constructor( - options: ScreenCaptureOptions, - onScreenshot: (data: ScreenshotFrameData) => void, - ) { - this.options = { - interval: options.interval || DEFAULT_INTERVAL, - windowId: options.windowId, - }; - this.onScreenshot = onScreenshot; - } - - /** - * 列出所有可捕获的窗口和屏幕源 - */ - static async listWindows(): Promise { - const sources = await desktopCapturer.getSources({ - types: ['window', 'screen'], - thumbnailSize: { width: 1, height: 1 }, // 列表不需要缩略图 - }); - - return sources.map((source) => ({ - id: source.id, - name: source.name, - displayId: source.display_id ?? '', - })); - } - - /** - * 开始定时截图采集 - */ - start(): void { - if (this.timer !== null || this.disposed) return; - - logger.info( - `[ScreenCapture] 开始采集, interval=${this.options.interval}ms, windowId=${this.options.windowId ?? 'auto'}`, - ); - - // 立即执行一次,然后定时执行 - this.captureAndEmit(); - this.timer = setInterval(() => { - this.captureAndEmit(); - }, this.options.interval); - } - - /** - * 停止截图采集 - */ - stop(): void { - if (this.timer !== null) { - clearInterval(this.timer); - this.timer = null; - logger.info('[ScreenCapture] 停止采集'); - } - } - - /** - * 单次截图(不启动定时器) - */ - async captureOnce(): Promise { - const source = await this.resolveSource(); - if (!source) { - console.warn('[ScreenCapture] captureOnce: 未找到可用的截图源'); - return null; - } - - return this.extractFrame(source); - } - - /** - * 销毁实例,释放所有资源 - */ - dispose(): void { - this.stop(); - this.disposed = true; - this.lastFrameBlockHashes = []; - logger.info('[ScreenCapture] 已销毁'); - } - - // ================================================================ - // 内部方法 - // ================================================================ - - /** 执行一次截图并通过回调发送 */ - private async captureAndEmit(): Promise { - try { - const source = await this.resolveSource(); - if (!source) { - logger.warn('[ScreenCapture] 目标窗口不可见(可能已最小化),跳过本帧'); - return; - } - - const frame = this.extractFrame(source); - if (frame) { - this.onScreenshot(frame); - } - } catch (error) { - logger.error('[ScreenCapture] 截图失败:', error); - } - } - - /** 解析目标截图源 */ - private async resolveSource(): Promise { - const sources = await desktopCapturer.getSources({ - types: ['window', 'screen'], - thumbnailSize: THUMBNAIL_SIZE, - }); - - if (sources.length === 0) return null; - - // 如果指定了 windowId,按 ID 匹配 - if (this.options.windowId) { - const matched = sources.find((s) => s.id === this.options.windowId); - if (matched) return matched; - console.warn( - `[ScreenCapture] 未找到 windowId=${this.options.windowId} 的源,回退到首个屏幕源`, - ); - } - - // 回退策略:优先选屏幕源,否则选第一个 - const screenSource = sources.find((s) => s.id.startsWith('screen:')); - return screenSource ?? sources[0]; - } - - /** 从 DesktopCapturerSource 提取帧数据(JPEG 压缩输出,降低 AI 分析传输体积) */ - private extractFrame(source: DesktopCapturerSource): ScreenshotFrameData | null { - const nativeImage = source.thumbnail; - if (!nativeImage || nativeImage.isEmpty()) { - logger.warn(`[ScreenCapture] source "${source.name}" 的缩略图为空`); - return null; - } - - // 缩放到 1280px 宽(多模态模型内部会缩到 672px,无需原尺寸) - const resized = nativeImage.resize({ width: 1280 }); - // JPEG 压缩:质量 75(板书场景可后续在渲染进程按需提高) - const jpegBuffer = resized.toJPEG(75); - const size = resized.getSize(); - - // 复制一份纯 ArrayBuffer - const arrayBuffer = new ArrayBuffer(jpegBuffer.byteLength); - new Uint8Array(arrayBuffer).set(jpegBuffer); - - const hasChanged = this.hasFrameChanged(arrayBuffer); - - return { - imageBuffer: arrayBuffer, - width: size.width, - height: size.height, - timestamp: monotonicTimestamp(), - sourceId: source.id, - hasChanged, - }; - } - - /** - * 基于分块采样 + hash 对比的帧变化检测(含 1px 容差) - * - * 将截图数据分为 8 个区域块,每块采样 ~60 字节(共约 500 字节), - * 分别计算 hash 后对比。为过滤 1px 鼠标微动导致的误判, - * 要求至少 2 个块同时发生变化才认为帧已变化。 - * 无论是否判定为“变化”,均更新基准 hash,防止亚阈值变化累积。 - */ - private hasFrameChanged(imageBuffer: ArrayBuffer): boolean { - const view = new Uint8Array(imageBuffer); - const size = view.length; - if (size === 0) return false; - - // 分为 8 个块,每块采样 ~60 字节,总采样约 500 字节 - const BLOCK_COUNT = 8; - const SAMPLES_PER_BLOCK = 60; - const blockHashes: string[] = []; - - for (let b = 0; b < BLOCK_COUNT; b++) { - const blockStart = Math.floor((size * b) / BLOCK_COUNT); - const blockEnd = Math.floor((size * (b + 1)) / BLOCK_COUNT); - const blockSize = blockEnd - blockStart; - if (blockSize <= 0) { - blockHashes.push(''); - continue; - } - - const step = Math.max(1, Math.floor(blockSize / SAMPLES_PER_BLOCK)); - let hash = blockSize.toString(36); - for (let i = blockStart; i < blockEnd; i += step) { - hash += view[i].toString(16); - } - blockHashes.push(hash); - } - - // 与上一帧的分块 hash 逐块对比,统计变化块数 - // 要求至少 2 个块变化才认为帧已变化(过滤 1px 鼠标微动误判) - const MIN_CHANGED_BLOCKS = 2; - let changedCount = 0; - if (blockHashes.length === this.lastFrameBlockHashes.length) { - for (let i = 0; i < blockHashes.length; i++) { - if (blockHashes[i] !== this.lastFrameBlockHashes[i]) { - changedCount++; - if (changedCount >= MIN_CHANGED_BLOCKS) break; // 提前退出 - } - } - } else { - // 块数不一致(首帧或尺寸变化),视为已变化 - changedCount = MIN_CHANGED_BLOCKS; - } - - // 无论是否判定为变化,均更新基准 hash,防止亚阈值变化累积 - this.lastFrameBlockHashes = blockHashes; - return changedCount >= MIN_CHANGED_BLOCKS; - } -} +/** + * Electron 主进程屏幕截图采集模块 + * + * 使用 desktopCapturer API 定时截取指定窗口画面, + * 通过 IPC 将 PNG 数据推送到渲染进程。 + * + * @ai-context: 定时截图采集器:desktopCapturer 抓帧、间隔可配(100ms-60s 边界校验)。 + */ + +import { desktopCapturer, DesktopCapturerSource, BrowserWindow } from 'electron'; +import { logger } from './logger'; + +// ================================================================ +// 类型定义 +// ================================================================ + +/** 可捕获窗口信息 */ +export interface WindowInfo { + id: string; + name: string; + displayId: string; +} + +/** 截图采集配置 */ +export interface ScreenCaptureOptions { + interval: number; // 截图间隔 ms,默认 5000 + windowId?: string; // 目标窗口 source ID +} + +/** 截图帧数据(通过 IPC 传输到渲染进程) */ +export interface ScreenshotFrameData { + imageBuffer: ArrayBuffer; // PNG 图片数据 + width: number; + height: number; + timestamp: number; // 单调递增时间戳 (ms) + sourceId: string; // 来源 source ID + hasChanged: boolean; // 帧变化检测结果(false 表示与上一帧相同,可跳过) +} + +// ================================================================ +// 截图采集器 +// ================================================================ + +const DEFAULT_INTERVAL = 5000; +const THUMBNAIL_SIZE = { width: 1920, height: 1080 }; + +/** 单调递增时间戳生成器 */ +let lastTimestamp = 0; +function monotonicTimestamp(): number { + const now = Date.now(); + lastTimestamp = now > lastTimestamp ? now : lastTimestamp + 1; + return lastTimestamp; +} + +export class ScreenCapture { + private timer: ReturnType | null = null; + private readonly options: Required> & + Pick; + private readonly onScreenshot: (data: ScreenshotFrameData) => void; + private disposed = false; + + /** 上一帧的分块 hash 数组,用于快速判断画面是否变化 */ + private lastFrameBlockHashes: string[] = []; + + constructor( + options: ScreenCaptureOptions, + onScreenshot: (data: ScreenshotFrameData) => void, + ) { + this.options = { + interval: options.interval || DEFAULT_INTERVAL, + windowId: options.windowId, + }; + this.onScreenshot = onScreenshot; + } + + /** + * 列出所有可捕获的窗口和屏幕源 + */ + static async listWindows(): Promise { + const sources = await desktopCapturer.getSources({ + types: ['window', 'screen'], + thumbnailSize: { width: 1, height: 1 }, // 列表不需要缩略图 + }); + + return sources.map((source) => ({ + id: source.id, + name: source.name, + displayId: source.display_id ?? '', + })); + } + + /** + * 开始定时截图采集 + */ + start(): void { + if (this.timer !== null || this.disposed) return; + + logger.info( + `[ScreenCapture] 开始采集, interval=${this.options.interval}ms, windowId=${this.options.windowId ?? 'auto'}`, + ); + + // 立即执行一次,然后定时执行 + this.captureAndEmit(); + this.timer = setInterval(() => { + this.captureAndEmit(); + }, this.options.interval); + } + + /** + * 停止截图采集 + */ + stop(): void { + if (this.timer !== null) { + clearInterval(this.timer); + this.timer = null; + logger.info('[ScreenCapture] 停止采集'); + } + } + + /** + * 单次截图(不启动定时器) + */ + async captureOnce(): Promise { + const source = await this.resolveSource(); + if (!source) { + console.warn('[ScreenCapture] captureOnce: 未找到可用的截图源'); + return null; + } + + return this.extractFrame(source); + } + + /** + * 销毁实例,释放所有资源 + */ + dispose(): void { + this.stop(); + this.disposed = true; + this.lastFrameBlockHashes = []; + logger.info('[ScreenCapture] 已销毁'); + } + + // ================================================================ + // 内部方法 + // ================================================================ + + /** 执行一次截图并通过回调发送 */ + private async captureAndEmit(): Promise { + try { + const source = await this.resolveSource(); + if (!source) { + logger.warn('[ScreenCapture] 目标窗口不可见(可能已最小化),跳过本帧'); + return; + } + + const frame = this.extractFrame(source); + if (frame) { + this.onScreenshot(frame); + } + } catch (error) { + logger.error('[ScreenCapture] 截图失败:', error); + } + } + + /** 解析目标截图源 */ + private async resolveSource(): Promise { + const sources = await desktopCapturer.getSources({ + types: ['window', 'screen'], + thumbnailSize: THUMBNAIL_SIZE, + }); + + if (sources.length === 0) return null; + + // 如果指定了 windowId,按 ID 匹配 + if (this.options.windowId) { + const matched = sources.find((s) => s.id === this.options.windowId); + if (matched) return matched; + console.warn( + `[ScreenCapture] 未找到 windowId=${this.options.windowId} 的源,回退到首个屏幕源`, + ); + } + + // 回退策略:优先选屏幕源,否则选第一个 + const screenSource = sources.find((s) => s.id.startsWith('screen:')); + return screenSource ?? sources[0]; + } + + /** 从 DesktopCapturerSource 提取帧数据(JPEG 压缩输出,降低 AI 分析传输体积) */ + private extractFrame(source: DesktopCapturerSource): ScreenshotFrameData | null { + const nativeImage = source.thumbnail; + if (!nativeImage || nativeImage.isEmpty()) { + logger.warn(`[ScreenCapture] source "${source.name}" 的缩略图为空`); + return null; + } + + // 缩放到 1280px 宽(多模态模型内部会缩到 672px,无需原尺寸) + const resized = nativeImage.resize({ width: 1280 }); + // JPEG 压缩:质量 75(板书场景可后续在渲染进程按需提高) + const jpegBuffer = resized.toJPEG(75); + const size = resized.getSize(); + + // 复制一份纯 ArrayBuffer + const arrayBuffer = new ArrayBuffer(jpegBuffer.byteLength); + new Uint8Array(arrayBuffer).set(jpegBuffer); + + const hasChanged = this.hasFrameChanged(arrayBuffer); + + return { + imageBuffer: arrayBuffer, + width: size.width, + height: size.height, + timestamp: monotonicTimestamp(), + sourceId: source.id, + hasChanged, + }; + } + + /** + * 基于分块采样 + hash 对比的帧变化检测(含 1px 容差) + * + * 将截图数据分为 8 个区域块,每块采样 ~60 字节(共约 500 字节), + * 分别计算 hash 后对比。为过滤 1px 鼠标微动导致的误判, + * 要求至少 2 个块同时发生变化才认为帧已变化。 + * 无论是否判定为“变化”,均更新基准 hash,防止亚阈值变化累积。 + */ + private hasFrameChanged(imageBuffer: ArrayBuffer): boolean { + const view = new Uint8Array(imageBuffer); + const size = view.length; + if (size === 0) return false; + + // 分为 8 个块,每块采样 ~60 字节,总采样约 500 字节 + const BLOCK_COUNT = 8; + const SAMPLES_PER_BLOCK = 60; + const blockHashes: string[] = []; + + for (let b = 0; b < BLOCK_COUNT; b++) { + const blockStart = Math.floor((size * b) / BLOCK_COUNT); + const blockEnd = Math.floor((size * (b + 1)) / BLOCK_COUNT); + const blockSize = blockEnd - blockStart; + if (blockSize <= 0) { + blockHashes.push(''); + continue; + } + + const step = Math.max(1, Math.floor(blockSize / SAMPLES_PER_BLOCK)); + let hash = blockSize.toString(36); + for (let i = blockStart; i < blockEnd; i += step) { + hash += view[i].toString(16); + } + blockHashes.push(hash); + } + + // 与上一帧的分块 hash 逐块对比,统计变化块数 + // 要求至少 2 个块变化才认为帧已变化(过滤 1px 鼠标微动误判) + const MIN_CHANGED_BLOCKS = 2; + let changedCount = 0; + if (blockHashes.length === this.lastFrameBlockHashes.length) { + for (let i = 0; i < blockHashes.length; i++) { + if (blockHashes[i] !== this.lastFrameBlockHashes[i]) { + changedCount++; + if (changedCount >= MIN_CHANGED_BLOCKS) break; // 提前退出 + } + } + } else { + // 块数不一致(首帧或尺寸变化),视为已变化 + changedCount = MIN_CHANGED_BLOCKS; + } + + // 无论是否判定为变化,均更新基准 hash,防止亚阈值变化累积 + this.lastFrameBlockHashes = blockHashes; + return changedCount >= MIN_CHANGED_BLOCKS; + } +} diff --git a/client/electron/screenCaptureHandlers.ts b/client/electron/screenCaptureHandlers.ts new file mode 100644 index 00000000..deb1d31e --- /dev/null +++ b/client/electron/screenCaptureHandlers.ts @@ -0,0 +1,214 @@ +/** + * 屏幕截图 & 窗口监听 IPC Handler + * + * @ai-context: 从 captureHandlers.ts 拆出。screen_capture_start 有 + * 500ms 防抖 + captureSessionToken 单调递增校验——stop 后残留的 + * debounce 回调经 token 比对失效,防止"停止后又自动重启采集"的竞态。 + * 窗口监听为 3s 轮询 diff(desktopCapturer 无变化事件可订阅)。 + * @ai-context: 帧数据经 sender 窗口 webContents.send 推回(非广播), + * 窗口销毁时静默丢帧。 + */ +import { BrowserWindow, desktopCapturer } from 'electron'; +import { ScreenCapture } from './screenCapture.js'; +import type { ScreenCaptureOptions, ScreenshotFrameData } from './screenCapture.js'; +import { safeHandle, getMainWindowId } from './ipcUtils.js'; +import { logger } from './logger.js'; +import { scoreAndFilterWindows } from './windowScorer.js'; + +// ================================================================ +// 模块级状态 +// ================================================================ + +/** 当前活跃的截图采集实例 */ +let activeCapture: ScreenCapture | null = null; + +/** screen_capture_start 防抖:500ms 内多次调用只响应最后一次 */ +let startDebounceTimer: ReturnType | null = null; +const START_DEBOUNCE_MS = 500; + +/** 单调递增会话标识,用于防止 stop 后残留的 debounce 重启采集 */ +let captureSessionToken = 0; + +/** 窗口监听轮询定时器 */ +let windowWatchTimer: ReturnType | null = null; + +/** 上一次窗口列表的 id 集合(用于 diff 检测变化) */ +let lastWindowIds: Set = new Set(); + +const WINDOW_WATCH_INTERVAL_MS = 3000; + +/** + * 注册屏幕截图与窗口监听相关的 IPC handler + */ +export function registerScreenCaptureHandlers(): void { + safeHandle( + 'screen_capture_start', + async (event, options: ScreenCaptureOptions) => { + // 防抖:500ms 内多次调用只响应最后一次 + if (startDebounceTimer) { + clearTimeout(startDebounceTimer); + startDebounceTimer = null; + } + + // 记录本次会话 token,用于 debounce 回调时校验是否仍然有效 + const token = ++captureSessionToken; + + return new Promise<{ success: boolean }>((resolve) => { + startDebounceTimer = setTimeout(() => { + startDebounceTimer = null; + + // 如果在 debounce 期间调用了 stop(token 已变),放弃本次启动 + if (token !== captureSessionToken) { + logger.info('[IPC] screen_capture_start debounce 已过期(stop 后残留),跳过'); + resolve({ success: false }); + return; + } + + // 幂等:先清理旧实例 + if (activeCapture) { + activeCapture.dispose(); + activeCapture = null; + } + + const senderWin = BrowserWindow.fromWebContents(event.sender); + + // 对采集参数做边界校验,防止非法值导致主进程异常 + const safeOptions = options || {}; + if (typeof safeOptions.interval === 'number' && (safeOptions.interval < 100 || safeOptions.interval > 60000)) { + safeOptions.interval = 5000; + } + + activeCapture = new ScreenCapture(safeOptions, (frame: ScreenshotFrameData) => { + if (senderWin && !senderWin.isDestroyed()) { + senderWin.webContents.send('screen_capture_frame', frame); + } + }); + + activeCapture.start(); + logger.info('[IPC] screen_capture_start 已启动(防抖后)'); + resolve({ success: true }); + }, START_DEBOUNCE_MS); + }); + }, + ); + + safeHandle('screen_capture_stop', async () => { + // 递增 token,使残留的 debounce 回调失效 + captureSessionToken++; + + // 清理防抖定时器 + if (startDebounceTimer) { + clearTimeout(startDebounceTimer); + startDebounceTimer = null; + } + + if (activeCapture) { + activeCapture.dispose(); + activeCapture = null; + logger.info('[IPC] screen_capture_stop 已停止'); + } + return { success: true }; + }); + + safeHandle('screen_list_windows', async () => { + try { + const sources = await desktopCapturer.getSources({ + types: ['window'], + thumbnailSize: { width: 240, height: 135 }, + }); + + const rawWindows = sources.map((src) => { + const thumb = src.thumbnail.isEmpty() ? src.thumbnail : src.thumbnail.resize({ width: 120 }); + return { + id: src.id, + title: src.name, + thumbnail: thumb.toDataURL(), + }; + }); + + // 智能评分、过滤与排序 + return scoreAndFilterWindows(rawWindows); + } catch (err) { + logger.error('[IPC] screen_list_windows failed:', err); + return []; + } + }); + + // ---- 窗口变化监听(轮询) ---- + + safeHandle('screen_watch_windows_start', async () => { + if (windowWatchTimer) return { success: true }; // 已在监听 + + logger.info('[IPC] 窗口监听已启动, interval=' + WINDOW_WATCH_INTERVAL_MS + 'ms'); + + windowWatchTimer = setInterval(async () => { + try { + const sources = await desktopCapturer.getSources({ + types: ['window'], + thumbnailSize: { width: 240, height: 135 }, + }); + + const currentIds = new Set(sources.map((s) => s.id)); + + // 检测是否有变化(新增或关闭窗口) + const hasChanged = + currentIds.size !== lastWindowIds.size || + [...currentIds].some((id) => !lastWindowIds.has(id)); + + if (hasChanged) { + lastWindowIds = currentIds; + + const rawWindows = sources.map((src) => { + const thumb = src.thumbnail.isEmpty() ? src.thumbnail : src.thumbnail.resize({ width: 120 }); + return { id: src.id, title: src.name, thumbnail: thumb.toDataURL() }; + }); + + const scored = scoreAndFilterWindows(rawWindows); + + // 推送到渲染进程 + const mainWindowId = getMainWindowId(); + if (mainWindowId) { + const win = BrowserWindow.fromId(mainWindowId); + if (win && !win.isDestroyed()) { + win.webContents.send('screen_windows_changed', scored); + } + } + } + } catch (err) { + logger.error('[IPC] window watch poll error:', err); + } + }, WINDOW_WATCH_INTERVAL_MS); + + return { success: true }; + }); + + safeHandle('screen_watch_windows_stop', async () => { + if (windowWatchTimer) { + clearInterval(windowWatchTimer); + windowWatchTimer = null; + lastWindowIds = new Set(); + logger.info('[IPC] 窗口监听已停止'); + } + return { success: true }; + }); +} + +/** + * 释放屏幕截图相关资源(含防抖定时器与轮询) + */ +export function disposeScreenCaptureHandlers(): void { + // 清理防抖定时器 + if (startDebounceTimer) { + clearTimeout(startDebounceTimer); + startDebounceTimer = null; + } + if (windowWatchTimer) { + clearInterval(windowWatchTimer); + windowWatchTimer = null; + lastWindowIds = new Set(); + } + if (activeCapture) { + activeCapture.dispose(); + activeCapture = null; + } +} diff --git a/client/electron/storageIpcHandlers.ts b/client/electron/storageIpcHandlers.ts new file mode 100644 index 00000000..5116c55a --- /dev/null +++ b/client/electron/storageIpcHandlers.ts @@ -0,0 +1,202 @@ +/** + * 存储路径与备份 IPC handlers(storage:* / backup:* / dialog / fs) + * + * @ai-context: 从 main.ts 拆出。storage:change-path 是七步事务式迁移 + * (验证→备份→checkpoint→迁移→完整性校验→重连→持久化),任一步失败 + * 回滚旧路径;isChangingPath 互斥锁防并发切换。'keban.db' 文件名为 + * 存量用户数据标识,永久豁免品牌改名。 + * @ai-context: fs:read-file 仅允许 userData/temp 目录(路径穿越防护); + * 备份文件名前缀 entropy-decrease-backup(新品牌)。 + */ +import { app, dialog } from 'electron'; +import * as path from 'path'; +import { writeFile, readFile } from 'fs/promises'; +import { safeHandle } from './ipcUtils.js'; +import { logger } from './logger.js'; +import { getConnection, checkpointAndClose, reinitialize, getDbPath } from './db/sqliteService.js'; +import { initializeSchema } from './db/schema.js'; +import { saveCustomStoragePath, resolveDbPath } from './db/storageConfig.js'; +import { migrateDatabaseFiles, verifyDatabaseIntegrity, createBackup } from './db/dbFileMigrator.js'; + +/** SQLite 主库文件名 — 存量用户数据标识,绝对不可改名 */ +const DB_FILE_NAME = 'keban.db'; + +/** v1.1.0: 存储路径切换互斥锁 */ +let isChangingPath = false; + +/** 回滚到指定目录的数据库(迁移失败/校验失败共用) */ +function rollbackToPath(dir: string, stage: string): void { + try { + reinitialize(path.join(dir, DB_FILE_NAME)); + initializeSchema(getConnection()); + logger.info(`[Storage] Rolled back to previous path (${stage})`); + } catch (rollbackErr) { + logger.error(`[Storage] Rollback after ${stage} also failed!`, rollbackErr); + } +} + +/** + * 注册存储/备份/文件对话框相关 IPC handlers(app ready 后调用一次) + */ +export function registerStorageIpcHandlers(): void { + safeHandle('get-default-storage-path', async () => { + return app.getPath('userData'); + }); + + // 文件读取 IPC handler(仅允许读取应用数据目录或临时目录下的文件) + safeHandle('fs:read-file', async (_event, filePath: string) => { + const appDataPath = app.getPath('userData'); + const tempPath = app.getPath('temp'); + const resolvedPath = path.resolve(filePath); + + if (!resolvedPath.startsWith(appDataPath) && !resolvedPath.startsWith(tempPath)) { + throw new Error('不允许读取该路径的文件'); + } + + const buffer = await readFile(resolvedPath); + return buffer.buffer; // 返回 ArrayBuffer + }); + + safeHandle('dialog:selectDirectory', async (_event, options?: { title?: string; defaultPath?: string }) => { + const result = await dialog.showOpenDialog({ + title: options?.title || '选择数据存储目录', + defaultPath: options?.defaultPath, + properties: ['openDirectory', 'createDirectory'], + }); + + if (result.canceled || result.filePaths.length === 0) { + return { canceled: true, path: null }; + } + + return { canceled: false, path: result.filePaths[0] }; + }); + + // v1.1.0: 获取当前实际使用的存储路径 + safeHandle('storage:get-active-path', async () => { + return getDbPath() ?? await resolveDbPath(); + }); + + // v1.1.0: 存储路径切换(含数据迁移) + safeHandle('storage:change-path', async (_event, args: { newPath: string }) => { + if (isChangingPath) { + return { success: false, error: '正在处理路径切换,请稍后重试' }; + } + + isChangingPath = true; + const previousPath = path.dirname(getDbPath() ?? await resolveDbPath()); + + try { + const { newPath } = args; + + // 1. 验证路径不同 + const normalizedNew = path.resolve(newPath); + const normalizedOld = path.resolve(previousPath); + if (normalizedNew === normalizedOld) { + return { success: false, error: '新路径与当前路径相同' }; + } + + logger.info(`[Storage] Switching storage path: ${normalizedOld} → ${normalizedNew}`); + + // 2. 为旧数据库创建备份 + await createBackup(normalizedOld); + + // 3. WAL checkpoint 并关闭旧连接 + checkpointAndClose(); + + // 4. 迁移数据库文件 + const migrationResult = await migrateDatabaseFiles(normalizedOld, normalizedNew); + if (!migrationResult.success) { + logger.error('[Storage] Migration failed:', migrationResult.error); + rollbackToPath(normalizedOld, 'migration failure'); + return { success: false, error: migrationResult.error }; + } + + // 5. 验证新数据库完整性 + const newDbPath = path.join(normalizedNew, DB_FILE_NAME); + if (!verifyDatabaseIntegrity(newDbPath)) { + logger.error('[Storage] Integrity check failed for new database'); + rollbackToPath(normalizedOld, 'integrity check failure'); + return { success: false, error: '新数据库完整性校验失败,已回滚到原路径' }; + } + + // 6. 重新连接到新路径 + reinitialize(newDbPath); + initializeSchema(getConnection()); + + // 7. 持久化新路径配置 + await saveCustomStoragePath(normalizedNew); + + logger.info(`[Storage] Path switch completed: ${normalizedNew}`); + return { + success: true, + previousPath: normalizedOld, + newPath: normalizedNew, + }; + } catch (err) { + const errorMsg = err instanceof Error ? err.message : String(err); + logger.error('[Storage] Path switch failed', err); + rollbackToPath(previousPath, 'unexpected error'); + return { success: false, error: '路径切换失败: ' + errorMsg }; + } finally { + isChangingPath = false; + } + }); + + // ================================================================ + // v0.9.0: 备份相关 IPC handlers + // ================================================================ + + /** + * 显示保存对话框并将备份数据写入文件 + */ + safeHandle('backup:save', async (_event, data: string, defaultName?: string) => { + const filename = defaultName || `entropy-decrease-backup-${new Date().toISOString().slice(0, 10)}.json`; + + const result = await dialog.showSaveDialog({ + title: '保存备份文件', + defaultPath: filename, + filters: [ + { name: '熵减备份文件', extensions: ['json'] }, + { name: '所有文件', extensions: ['*'] }, + ], + }); + + if (result.canceled || !result.filePath) { + return { success: false, canceled: true, path: null }; + } + + try { + await writeFile(result.filePath, data, 'utf-8'); + return { success: true, canceled: false, path: result.filePath }; + } catch (err) { + const msg = err instanceof Error ? err.message : '写入失败'; + return { success: false, canceled: false, path: null, error: msg }; + } + }); + + /** + * 显示打开对话框,选择备份文件并读取内容 + */ + safeHandle('backup:open', async () => { + const result = await dialog.showOpenDialog({ + title: '选择备份文件', + filters: [ + { name: '熵减备份文件', extensions: ['json'] }, + { name: '所有文件', extensions: ['*'] }, + ], + properties: ['openFile'], + }); + + if (result.canceled || result.filePaths.length === 0) { + return { success: false, canceled: true, content: null }; + } + + try { + const content = await readFile(result.filePaths[0], 'utf-8'); + return { success: true, canceled: false, content, path: result.filePaths[0] }; + } catch (err) { + const msg = err instanceof Error ? err.message : '读取失败'; + return { success: false, canceled: false, content: null, error: msg }; + } + }); +} diff --git a/client/electron/trayManager.ts b/client/electron/trayManager.ts index c33a9080..66169898 100644 --- a/client/electron/trayManager.ts +++ b/client/electron/trayManager.ts @@ -1,99 +1,101 @@ -/** - * 系统托盘管理器 - * - * 从 main.ts 拆分而来,负责创建系统托盘图标及右键菜单。 - */ - -import { Tray, Menu, nativeImage, app } from 'electron'; -import type { BrowserWindow } from 'electron'; -import * as path from 'path'; -import { logger } from './logger.js'; - -// ================================================================ -// 模块级状态 -// ================================================================ - -/** 系统托盘实例 */ -let tray: Tray | null = null; - -/** 应用是否正在退出(由外部 setter 控制) */ -let isQuittingRef: { value: boolean } = { value: false }; - -// ================================================================ -// 公共 API -// ================================================================ - -/** - * 设置 isQuitting 标志的引用,与 main.ts 共享状态 - */ -export function setQuittingRef(ref: { value: boolean }): void { - isQuittingRef = ref; -} - -/** - * 创建系统托盘图标及右键菜单 - * - * @param win - 主窗口实例,用于显示/聚焦操作 - * @param onQuit - 用户点击"退出"时的回调 - * @returns 创建的 Tray 实例 - */ -export function createTray(win: BrowserWindow, onQuit: () => void): Tray { - const iconPath = path.join(app.getAppPath(), 'app-icon.png'); - let trayIcon = nativeImage.createFromPath(iconPath); - - // 如果图标加载失败则创建 16x16 空白图标作为 fallback - if (trayIcon.isEmpty()) { - trayIcon = nativeImage.createEmpty(); - } else { - trayIcon = trayIcon.resize({ width: 16, height: 16 }); - } - - tray = new Tray(trayIcon); - tray.setToolTip('熵减'); - - const contextMenu = Menu.buildFromTemplate([ - { - label: '显示窗口', - click: () => { - win.show(); - win.focus(); - }, - }, - { type: 'separator' }, - { - label: '退出', - click: () => { - onQuit(); - }, - }, - ]); - - tray.setContextMenu(contextMenu); - - // 双击托盘图标恢复窗口 - tray.on('double-click', () => { - if (win.isMinimized()) win.restore(); - if (!win.isVisible()) win.show(); - win.focus(); - }); - - logger.info('[Tray] System tray created'); - return tray; -} - -/** - * 销毁系统托盘实例 - */ -export function destroyTray(): void { - if (tray) { - tray.destroy(); - tray = null; - } -} - -/** - * 获取当前托盘实例 - */ -export function getTray(): Tray | null { - return tray; -} +/** + * 系统托盘管理器 + * + * 从 main.ts 拆分而来,负责创建系统托盘图标及右键菜单。 + * + * @ai-context: 系统托盘:最小化到托盘/恢复/退出菜单。 + */ + +import { Tray, Menu, nativeImage, app } from 'electron'; +import type { BrowserWindow } from 'electron'; +import * as path from 'path'; +import { logger } from './logger.js'; + +// ================================================================ +// 模块级状态 +// ================================================================ + +/** 系统托盘实例 */ +let tray: Tray | null = null; + +/** 应用是否正在退出(由外部 setter 控制) */ +let isQuittingRef: { value: boolean } = { value: false }; + +// ================================================================ +// 公共 API +// ================================================================ + +/** + * 设置 isQuitting 标志的引用,与 main.ts 共享状态 + */ +export function setQuittingRef(ref: { value: boolean }): void { + isQuittingRef = ref; +} + +/** + * 创建系统托盘图标及右键菜单 + * + * @param win - 主窗口实例,用于显示/聚焦操作 + * @param onQuit - 用户点击"退出"时的回调 + * @returns 创建的 Tray 实例 + */ +export function createTray(win: BrowserWindow, onQuit: () => void): Tray { + const iconPath = path.join(app.getAppPath(), 'app-icon.png'); + let trayIcon = nativeImage.createFromPath(iconPath); + + // 如果图标加载失败则创建 16x16 空白图标作为 fallback + if (trayIcon.isEmpty()) { + trayIcon = nativeImage.createEmpty(); + } else { + trayIcon = trayIcon.resize({ width: 16, height: 16 }); + } + + tray = new Tray(trayIcon); + tray.setToolTip('熵减'); + + const contextMenu = Menu.buildFromTemplate([ + { + label: '显示窗口', + click: () => { + win.show(); + win.focus(); + }, + }, + { type: 'separator' }, + { + label: '退出', + click: () => { + onQuit(); + }, + }, + ]); + + tray.setContextMenu(contextMenu); + + // 双击托盘图标恢复窗口 + tray.on('double-click', () => { + if (win.isMinimized()) win.restore(); + if (!win.isVisible()) win.show(); + win.focus(); + }); + + logger.info('[Tray] System tray created'); + return tray; +} + +/** + * 销毁系统托盘实例 + */ +export function destroyTray(): void { + if (tray) { + tray.destroy(); + tray = null; + } +} + +/** + * 获取当前托盘实例 + */ +export function getTray(): Tray | null { + return tray; +} diff --git a/client/electron/tsconfig.json b/client/electron/tsconfig.json index d0083732..cc86beb8 100644 --- a/client/electron/tsconfig.json +++ b/client/electron/tsconfig.json @@ -1,24 +1,24 @@ -{ - "compilerOptions": { - "ignoreDeprecations": "6.0", - "target": "ES2022", - "module": "CommonJS", - "moduleResolution": "node", - "strict": true, - "esModuleInterop": true, - "outDir": "../dist-electron", - "rootDir": "..", - "baseUrl": "..", - "paths": { - "@/*": ["src/*"] - }, - "typeRoots": ["../node_modules/@types"], - "skipLibCheck": true, - "resolveJsonModule": true - }, - "include": [ - "./**/*.ts", - "../src/lib/storage/interfaces.ts", - "../src/types/models.ts" - ] -} +{ + "compilerOptions": { + "ignoreDeprecations": "6.0", + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "node", + "strict": true, + "esModuleInterop": true, + "outDir": "../dist-electron", + "rootDir": "..", + "baseUrl": "..", + "paths": { + "@/*": ["src/*"] + }, + "typeRoots": ["../node_modules/@types"], + "skipLibCheck": true, + "resolveJsonModule": true + }, + "include": [ + "./**/*.ts", + "../src/lib/storage/interfaces.ts", + "../src/types/models.ts" + ] +} diff --git a/client/electron/updater.ts b/client/electron/updater.ts index d2af4b29..3364f958 100644 --- a/client/electron/updater.ts +++ b/client/electron/updater.ts @@ -1,259 +1,261 @@ -/** - * 自动更新模块 - * - * 封装 electron-updater 的 autoUpdater, - * 处理更新检查、下载、安装等事件, - * 通过 IPC 将状态推送到渲染进程。 - */ -import * as electronUpdater from 'electron-updater'; -const { autoUpdater } = electronUpdater; -import type { UpdateInfo, ProgressInfo } from 'electron-updater'; -import { BrowserWindow, app, net } from 'electron'; -import { readFile, writeFile } from 'fs/promises'; -import * as path from 'path'; -import { logger } from './logger.js'; - -/** 自动检查开关(由渲染进程通过 IPC 设置,默认开启) */ -let autoCheckEnabled = true; - -/** 自动检查最小间隔(24 小时,毫秒) */ -const AUTO_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; - -/** 上次检查更新的时间戳(持久化到 userData/update-check.json) */ -let lastCheckTimestamp = 0; - -/** - * 读取持久化的上次检查时间戳 - */ -async function loadLastCheckTimestamp(): Promise { - try { - const filePath = path.join(app.getPath('userData'), 'update-check.json'); - const data = JSON.parse(await readFile(filePath, 'utf-8')); - return typeof data.lastCheck === 'number' ? data.lastCheck : 0; - } catch { - return 0; - } -} - -/** - * 将当前时间戳持久化到文件 - */ -async function saveLastCheckTimestamp(): Promise { - try { - const filePath = path.join(app.getPath('userData'), 'update-check.json'); - await writeFile(filePath, JSON.stringify({ lastCheck: Date.now() }), 'utf-8'); - lastCheckTimestamp = Date.now(); - } catch (err) { - logger.warn(`[AutoUpdater] Failed to save last check timestamp: ${err instanceof Error ? err.message : String(err)}`); - } -} - -/** - * 判断距上次检查是否已满 24 小时 - */ -function shouldAutoCheck(): boolean { - return Date.now() - lastCheckTimestamp >= AUTO_CHECK_INTERVAL_MS; -} - -/** 检查更新超时时间(毫秒) */ -const CHECK_UPDATE_TIMEOUT = 10_000; - -/** 下载重试状态 */ -let downloadRetryCount = 0; -const MAX_DOWNLOAD_RETRIES = 3; -const DOWNLOAD_RETRY_DELAYS = [30_000, 60_000, 120_000]; // 30s, 60s, 120s -/** 标记当前是否正在下载(用于区分 error 事件来源) */ -let isDownloading = false; - -/** - * 设置自动检查开关 - * 由 main.ts 的 IPC handler 调用 - */ -export function setAutoCheckEnabled(enabled: boolean): void { - autoCheckEnabled = enabled; - logger.info(`[AutoUpdater] Auto check ${enabled ? 'enabled' : 'disabled'}`); -} - -/** - * 带超时保护的 checkForUpdates 封装 - * 超过 CHECK_UPDATE_TIMEOUT 未响应则视为失败 - */ -function checkForUpdatesWithTimeout(): Promise { - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - reject(new Error('未成功取得资源,请检查网络连接后重试')); - }, CHECK_UPDATE_TIMEOUT); - - autoUpdater.checkForUpdates() - .then((result) => { - clearTimeout(timer); - resolve(result); - }) - .catch((err: unknown) => { - clearTimeout(timer); - reject(err); - }); - }); -} - -export function initAutoUpdater(mainWindow: BrowserWindow | null): void { - // 开发模式下禁用自动更新 - if (!app.isPackaged) { - logger.info('[AutoUpdater] Skipped in development mode'); - return; - } - - autoUpdater.autoDownload = false; - autoUpdater.autoInstallOnAppQuit = true; - - autoUpdater.on('checking-for-update', () => { - logger.info('[AutoUpdater] Checking for update...'); - sendToRenderer(mainWindow, 'update-status', { status: 'checking' }); - }); - - autoUpdater.on('update-available', (info: UpdateInfo) => { - logger.info(`[AutoUpdater] Update available: v${info.version}`); - sendToRenderer(mainWindow, 'update-status', { - status: 'available', - version: info.version, - releaseNotes: info.releaseNotes ?? null, - }); - }); - - autoUpdater.on('update-not-available', () => { - logger.info('[AutoUpdater] No update available'); - sendToRenderer(mainWindow, 'update-status', { status: 'not-available' }); - }); - - autoUpdater.on('download-progress', (progress: ProgressInfo) => { - sendToRenderer(mainWindow, 'update-status', { - status: 'downloading', - percent: Math.round(progress.percent), - bytesPerSecond: progress.bytesPerSecond, - }); - }); - - autoUpdater.on('update-downloaded', (info: UpdateInfo) => { - logger.info(`[AutoUpdater] Update downloaded: v${info.version}`); - // 下载成功,重置重试计数 - downloadRetryCount = 0; - isDownloading = false; - sendToRenderer(mainWindow, 'update-status', { - status: 'downloaded', - version: info.version, - }); - }); - - autoUpdater.on('error', (error: Error) => { - logger.error('[AutoUpdater] Error', error); - - // 下载失败时执行带退避的重试 - if (isDownloading && downloadRetryCount < MAX_DOWNLOAD_RETRIES) { - const delay = DOWNLOAD_RETRY_DELAYS[downloadRetryCount] ?? DOWNLOAD_RETRY_DELAYS[DOWNLOAD_RETRY_DELAYS.length - 1]; - downloadRetryCount++; - logger.warn( - `[AutoUpdater] Download failed, retrying in ${delay / 1000}s (attempt ${downloadRetryCount}/${MAX_DOWNLOAD_RETRIES})`, - ); - sendToRenderer(mainWindow, 'update-status', { - status: 'downloading', - percent: 0, - retryIn: delay, - retryCount: downloadRetryCount, - maxRetries: MAX_DOWNLOAD_RETRIES, - }); - setTimeout(() => { - autoUpdater.downloadUpdate().catch((err) => { - logger.error('[AutoUpdater] Retry download failed', err); - }); - }, delay); - return; - } - - // 重试耗尽或非下载阶段的错误 - downloadRetryCount = 0; - isDownloading = false; - - // 断网时静默忽略,不弹窗打扰用户 - if (!net.isOnline()) { - logger.info('[AutoUpdater] Offline, skipping error notification'); - return; - } - - sendToRenderer(mainWindow, 'update-status', { - status: 'error', - message: error.message, - }); - }); - - // 启动时检查更新(延迟 10 秒,等窗口加载完) - // 加载持久化的上次检查时间戳,判断是否已满 24 小时 - loadLastCheckTimestamp().then((ts) => { - lastCheckTimestamp = ts; - }).finally(() => { - setTimeout(() => { - if (!autoCheckEnabled) return; - // 断网时跳过检查,静默等待下次启动 - if (!net.isOnline()) { - logger.info('[AutoUpdater] Offline, skipping auto check'); - return; - } - // 距上次检查不足 24 小时,跳过本次自动检查 - if (!shouldAutoCheck()) { - const hoursLeft = Math.ceil((AUTO_CHECK_INTERVAL_MS - (Date.now() - lastCheckTimestamp)) / (60 * 60 * 1000)); - logger.info(`[AutoUpdater] Auto check skipped, next check in ~${hoursLeft} hour(s)`); - return; - } - logger.info('[AutoUpdater] 24-hour interval elapsed, performing auto check'); - checkForUpdatesWithTimeout() - .then(() => { saveLastCheckTimestamp(); }) - .catch((err: unknown) => { - logger.error('[AutoUpdater] Initial check failed', err); - // 断网导致的失败不通知前端 - if (!net.isOnline()) return; - sendToRenderer(mainWindow, 'update-status', { - status: 'error', - message: err instanceof Error ? err.message : String(err), - }); - }); - }, 10_000); - }); -} - -/** - * 手动检查更新(不受 7 天频率限制,始终执行) - */ -export function checkForUpdate(): void { - checkForUpdatesWithTimeout() - .then(() => { saveLastCheckTimestamp(); }) - .catch((err: unknown) => { - logger.error('[AutoUpdater] Manual check failed', err); - // 手动检查时也将超时错误通知到渲染进程 - sendToRenderer( - BrowserWindow.getAllWindows().find((w) => !w.isDestroyed()) ?? null, - 'update-status', - { status: 'error', message: err instanceof Error ? err.message : String(err) }, - ); - }); -} - -export function downloadUpdate(): void { - isDownloading = true; - downloadRetryCount = 0; - autoUpdater.downloadUpdate().catch((err) => { - logger.error('[AutoUpdater] Download failed', err); - }); -} - -export function installUpdate(): void { - autoUpdater.quitAndInstall(); -} - -export function destroyAutoUpdater(): void { - // 清理由(当前无定时任务,保留以便未来扩展) -} - -function sendToRenderer(win: BrowserWindow | null, channel: string, data: unknown): void { - if (win && !win.isDestroyed()) { - win.webContents.send(channel, data); - } -} +/** + * 自动更新模块 + * + * 封装 electron-updater 的 autoUpdater, + * 处理更新检查、下载、安装等事件, + * 通过 IPC 将状态推送到渲染进程。 + * + * @ai-context: electron-updater 自动更新:24h 节流检查(产品规范),下载/安装经 IPC 由用户确认。 + */ +import * as electronUpdater from 'electron-updater'; +const { autoUpdater } = electronUpdater; +import type { UpdateInfo, ProgressInfo } from 'electron-updater'; +import { BrowserWindow, app, net } from 'electron'; +import { readFile, writeFile } from 'fs/promises'; +import * as path from 'path'; +import { logger } from './logger.js'; + +/** 自动检查开关(由渲染进程通过 IPC 设置,默认开启) */ +let autoCheckEnabled = true; + +/** 自动检查最小间隔(24 小时,毫秒) */ +const AUTO_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; + +/** 上次检查更新的时间戳(持久化到 userData/update-check.json) */ +let lastCheckTimestamp = 0; + +/** + * 读取持久化的上次检查时间戳 + */ +async function loadLastCheckTimestamp(): Promise { + try { + const filePath = path.join(app.getPath('userData'), 'update-check.json'); + const data = JSON.parse(await readFile(filePath, 'utf-8')); + return typeof data.lastCheck === 'number' ? data.lastCheck : 0; + } catch { + return 0; + } +} + +/** + * 将当前时间戳持久化到文件 + */ +async function saveLastCheckTimestamp(): Promise { + try { + const filePath = path.join(app.getPath('userData'), 'update-check.json'); + await writeFile(filePath, JSON.stringify({ lastCheck: Date.now() }), 'utf-8'); + lastCheckTimestamp = Date.now(); + } catch (err) { + logger.warn(`[AutoUpdater] Failed to save last check timestamp: ${err instanceof Error ? err.message : String(err)}`); + } +} + +/** + * 判断距上次检查是否已满 24 小时 + */ +function shouldAutoCheck(): boolean { + return Date.now() - lastCheckTimestamp >= AUTO_CHECK_INTERVAL_MS; +} + +/** 检查更新超时时间(毫秒) */ +const CHECK_UPDATE_TIMEOUT = 10_000; + +/** 下载重试状态 */ +let downloadRetryCount = 0; +const MAX_DOWNLOAD_RETRIES = 3; +const DOWNLOAD_RETRY_DELAYS = [30_000, 60_000, 120_000]; // 30s, 60s, 120s +/** 标记当前是否正在下载(用于区分 error 事件来源) */ +let isDownloading = false; + +/** + * 设置自动检查开关 + * 由 main.ts 的 IPC handler 调用 + */ +export function setAutoCheckEnabled(enabled: boolean): void { + autoCheckEnabled = enabled; + logger.info(`[AutoUpdater] Auto check ${enabled ? 'enabled' : 'disabled'}`); +} + +/** + * 带超时保护的 checkForUpdates 封装 + * 超过 CHECK_UPDATE_TIMEOUT 未响应则视为失败 + */ +function checkForUpdatesWithTimeout(): Promise { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject(new Error('未成功取得资源,请检查网络连接后重试')); + }, CHECK_UPDATE_TIMEOUT); + + autoUpdater.checkForUpdates() + .then((result) => { + clearTimeout(timer); + resolve(result); + }) + .catch((err: unknown) => { + clearTimeout(timer); + reject(err); + }); + }); +} + +export function initAutoUpdater(mainWindow: BrowserWindow | null): void { + // 开发模式下禁用自动更新 + if (!app.isPackaged) { + logger.info('[AutoUpdater] Skipped in development mode'); + return; + } + + autoUpdater.autoDownload = false; + autoUpdater.autoInstallOnAppQuit = true; + + autoUpdater.on('checking-for-update', () => { + logger.info('[AutoUpdater] Checking for update...'); + sendToRenderer(mainWindow, 'update-status', { status: 'checking' }); + }); + + autoUpdater.on('update-available', (info: UpdateInfo) => { + logger.info(`[AutoUpdater] Update available: v${info.version}`); + sendToRenderer(mainWindow, 'update-status', { + status: 'available', + version: info.version, + releaseNotes: info.releaseNotes ?? null, + }); + }); + + autoUpdater.on('update-not-available', () => { + logger.info('[AutoUpdater] No update available'); + sendToRenderer(mainWindow, 'update-status', { status: 'not-available' }); + }); + + autoUpdater.on('download-progress', (progress: ProgressInfo) => { + sendToRenderer(mainWindow, 'update-status', { + status: 'downloading', + percent: Math.round(progress.percent), + bytesPerSecond: progress.bytesPerSecond, + }); + }); + + autoUpdater.on('update-downloaded', (info: UpdateInfo) => { + logger.info(`[AutoUpdater] Update downloaded: v${info.version}`); + // 下载成功,重置重试计数 + downloadRetryCount = 0; + isDownloading = false; + sendToRenderer(mainWindow, 'update-status', { + status: 'downloaded', + version: info.version, + }); + }); + + autoUpdater.on('error', (error: Error) => { + logger.error('[AutoUpdater] Error', error); + + // 下载失败时执行带退避的重试 + if (isDownloading && downloadRetryCount < MAX_DOWNLOAD_RETRIES) { + const delay = DOWNLOAD_RETRY_DELAYS[downloadRetryCount] ?? DOWNLOAD_RETRY_DELAYS[DOWNLOAD_RETRY_DELAYS.length - 1]; + downloadRetryCount++; + logger.warn( + `[AutoUpdater] Download failed, retrying in ${delay / 1000}s (attempt ${downloadRetryCount}/${MAX_DOWNLOAD_RETRIES})`, + ); + sendToRenderer(mainWindow, 'update-status', { + status: 'downloading', + percent: 0, + retryIn: delay, + retryCount: downloadRetryCount, + maxRetries: MAX_DOWNLOAD_RETRIES, + }); + setTimeout(() => { + autoUpdater.downloadUpdate().catch((err) => { + logger.error('[AutoUpdater] Retry download failed', err); + }); + }, delay); + return; + } + + // 重试耗尽或非下载阶段的错误 + downloadRetryCount = 0; + isDownloading = false; + + // 断网时静默忽略,不弹窗打扰用户 + if (!net.isOnline()) { + logger.info('[AutoUpdater] Offline, skipping error notification'); + return; + } + + sendToRenderer(mainWindow, 'update-status', { + status: 'error', + message: error.message, + }); + }); + + // 启动时检查更新(延迟 10 秒,等窗口加载完) + // 加载持久化的上次检查时间戳,判断是否已满 24 小时 + loadLastCheckTimestamp().then((ts) => { + lastCheckTimestamp = ts; + }).finally(() => { + setTimeout(() => { + if (!autoCheckEnabled) return; + // 断网时跳过检查,静默等待下次启动 + if (!net.isOnline()) { + logger.info('[AutoUpdater] Offline, skipping auto check'); + return; + } + // 距上次检查不足 24 小时,跳过本次自动检查 + if (!shouldAutoCheck()) { + const hoursLeft = Math.ceil((AUTO_CHECK_INTERVAL_MS - (Date.now() - lastCheckTimestamp)) / (60 * 60 * 1000)); + logger.info(`[AutoUpdater] Auto check skipped, next check in ~${hoursLeft} hour(s)`); + return; + } + logger.info('[AutoUpdater] 24-hour interval elapsed, performing auto check'); + checkForUpdatesWithTimeout() + .then(() => { saveLastCheckTimestamp(); }) + .catch((err: unknown) => { + logger.error('[AutoUpdater] Initial check failed', err); + // 断网导致的失败不通知前端 + if (!net.isOnline()) return; + sendToRenderer(mainWindow, 'update-status', { + status: 'error', + message: err instanceof Error ? err.message : String(err), + }); + }); + }, 10_000); + }); +} + +/** + * 手动检查更新(不受 7 天频率限制,始终执行) + */ +export function checkForUpdate(): void { + checkForUpdatesWithTimeout() + .then(() => { saveLastCheckTimestamp(); }) + .catch((err: unknown) => { + logger.error('[AutoUpdater] Manual check failed', err); + // 手动检查时也将超时错误通知到渲染进程 + sendToRenderer( + BrowserWindow.getAllWindows().find((w) => !w.isDestroyed()) ?? null, + 'update-status', + { status: 'error', message: err instanceof Error ? err.message : String(err) }, + ); + }); +} + +export function downloadUpdate(): void { + isDownloading = true; + downloadRetryCount = 0; + autoUpdater.downloadUpdate().catch((err) => { + logger.error('[AutoUpdater] Download failed', err); + }); +} + +export function installUpdate(): void { + autoUpdater.quitAndInstall(); +} + +export function destroyAutoUpdater(): void { + // 清理由(当前无定时任务,保留以便未来扩展) +} + +function sendToRenderer(win: BrowserWindow | null, channel: string, data: unknown): void { + if (win && !win.isDestroyed()) { + win.webContents.send(channel, data); + } +} diff --git a/client/electron/videoRecorder.ts b/client/electron/videoRecorder.ts index 946b6663..1fa8b05f 100644 --- a/client/electron/videoRecorder.ts +++ b/client/electron/videoRecorder.ts @@ -1,269 +1,269 @@ -/** - * Electron 主进程视频录制管理器 - * - * @ai-context Path C 全程录制模式的核心引擎 - * 架构复用 AudioCapture 的"主进程调度 + 渲染进程执行 + IPC 回传"模式: - * 1. 主进程管理录制生命周期、写入 WebM 文件到磁盘 - * 2. 渲染进程通过 MediaRecorder 采集桌面视频流 - * 3. 视频数据块通过 IPC video_record_chunk 回传主进程并追加写入文件 - */ - -import { app, BrowserWindow } from 'electron'; -import * as fs from 'node:fs'; -import * as path from 'node:path'; -import { logger } from './logger.js'; - -// ================================================================ -// 类型定义 -// ================================================================ - -/** 视频录制选项 */ -export interface VideoRecordOptions { - videoBitsPerSecond?: number; - frameRate?: number; -} - -/** 录制状态(主进程 → 渲染进程) */ -export interface RecordingStatus { - isRecording: boolean; - isPaused: boolean; - duration: number; - fileSizeBytes: number; - filePath: string | null; -} - -// ================================================================ -// 默认配置 -// ================================================================ - -/** @ai-context 500kbps 低码率 + 5s 分片,平衡文件体积与录制流畅度 */ -const DEFAULT_OPTIONS: Required = { - videoBitsPerSecond: 500_000, - frameRate: 15, -}; - -const RECORDINGS_DIR_NAME = 'keban-recordings'; - -// ================================================================ -// 视频录制管理器 -// ================================================================ - -export class VideoRecorder { - private readonly options: Required; - private recording = false; - private paused = false; - private disposed = false; - private boundWin: BrowserWindow | null = null; - - /** 当前录制输出文件路径 */ - private filePath: string | null = null; - /** 文件写入流(追加模式) */ - private writeStream: fs.WriteStream | null = null; - /** 录制开始时间戳 */ - private startTime = 0; - /** 暂停期间累计的暂停时长 */ - private pausedDurationMs = 0; - /** 暂停开始时间 */ - private pauseStartedAt = 0; - /** 已写入字节数 */ - private fileSizeBytes = 0; - /** 状态推送定时器 */ - private statusTimer: ReturnType | null = null; - - constructor(options?: VideoRecordOptions) { - this.options = { ...DEFAULT_OPTIONS, ...options }; - } - - /** 是否正在录制 */ - get isRecording(): boolean { - return this.recording; - } - - /** 当前录制状态快照 */ - get status(): RecordingStatus { - return { - isRecording: this.recording, - isPaused: this.paused, - duration: this.getDurationMs(), - fileSizeBytes: this.fileSizeBytes, - filePath: this.filePath, - }; - } - - /** - * 开始视频录制 - * 通知渲染进程启动 MediaRecorder,主进程准备文件写入流 - */ - startRecording(sourceId: string, options?: VideoRecordOptions): void { - if (this.recording || this.disposed) return; - - const mergedOpts = { ...this.options, ...options }; - - // 准备录制目录和文件 - const dir = path.join(app.getPath('temp'), RECORDINGS_DIR_NAME); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); - this.filePath = path.join(dir, `recording-${timestamp}.webm`); - this.writeStream = fs.createWriteStream(this.filePath, { flags: 'a' }); - this.fileSizeBytes = 0; - this.startTime = Date.now(); - this.pausedDurationMs = 0; - this.recording = true; - this.paused = false; - - logger.info( - `[VideoRecorder] 开始录制, sourceId=${sourceId}, ` + - `bitsPerSecond=${mergedOpts.videoBitsPerSecond}, frameRate=${mergedOpts.frameRate}, ` + - `output=${this.filePath}`, - ); - - // 启动状态推送定时器(每秒一次) - this.statusTimer = setInterval(() => this.pushStatus(), 1000); - - // 通知渲染进程开始录制 - if (this.boundWin && !this.boundWin.isDestroyed()) { - this.boundWin.webContents.send('video_record_do_start', { - sourceId, - options: mergedOpts, - }); - } - } - - /** - * 停止录制,返回视频文件路径 - */ - async stopRecording(): Promise { - if (!this.recording) { - throw new Error('[VideoRecorder] 当前未在录制'); - } - - this.recording = false; - this.paused = false; - this.stopStatusTimer(); - - // 通知渲染进程停止 MediaRecorder - if (this.boundWin && !this.boundWin.isDestroyed()) { - this.boundWin.webContents.send('video_record_do_stop'); - } - - // 等待最后一批 chunk 写入完成(给渲染进程 500ms 缓冲) - await new Promise((resolve) => setTimeout(resolve, 500)); - - // 关闭文件流 - const finalPath = this.filePath; - await new Promise((resolve) => { - if (this.writeStream) { - this.writeStream.end(() => resolve()); - } else { - resolve(); - } - }); - this.writeStream = null; - - logger.info( - `[VideoRecorder] 停止录制, duration=${this.getDurationMs()}ms, ` + - `size=${this.fileSizeBytes} bytes, file=${finalPath}`, - ); - - return finalPath ?? ''; - } - - /** 暂停录制 */ - pauseRecording(): void { - if (!this.recording || this.paused) return; - this.paused = true; - this.pauseStartedAt = Date.now(); - logger.info('[VideoRecorder] 暂停录制'); - } - - /** 恢复录制 */ - resumeRecording(): void { - if (!this.recording || !this.paused) return; - this.pausedDurationMs += Date.now() - this.pauseStartedAt; - this.paused = false; - logger.info('[VideoRecorder] 恢复录制'); - } - - /** - * 接收渲染进程回传的视频数据块,追加写入文件 - * 由 IPC handler 调用 - */ - handleRendererChunk(chunkBuffer: ArrayBuffer): void { - if (!this.recording || this.paused || !this.writeStream) return; - const buf = Buffer.from(chunkBuffer); - this.writeStream.write(buf); - this.fileSizeBytes += buf.byteLength; - } - - /** - * 处理渲染进程上报的录制错误 - * 停止录制并向渲染进程广播错误通知 - */ - handleRendererError(errorInfo: { message: string }): void { - logger.error('[VideoRecorder] 渲染进程录制错误:', errorInfo.message); - // 标记录制停止,避免后续操作 - this.recording = false; - this.paused = false; - this.stopStatusTimer(); - // 关闭文件流 - if (this.writeStream) { - this.writeStream.end(); - this.writeStream = null; - } - // 向渲染进程广播错误事件 - if (this.boundWin && !this.boundWin.isDestroyed()) { - this.boundWin.webContents.send('video_record_error', { - message: errorInfo.message, - filePath: this.filePath, - }); - } - } - - /** 绑定主窗口(用于 IPC 通信) */ - bindWindow(win: BrowserWindow): void { - this.boundWin = win; - } - - /** 销毁实例,释放资源 */ - dispose(): void { - if (this.recording) { - this.stopRecording().catch((err) => { - logger.error('[VideoRecorder] dispose 时停止录制失败:', err); - }); - } - this.stopStatusTimer(); - this.disposed = true; - this.boundWin = null; - logger.info('[VideoRecorder] 已销毁'); - } - - // ================================================================ - // 私有方法 - // ================================================================ - - /** 计算有效录制时长(扣除暂停时间) */ - private getDurationMs(): number { - if (!this.startTime) return 0; - const elapsed = Date.now() - this.startTime; - const pauseOffset = this.paused - ? this.pausedDurationMs + (Date.now() - this.pauseStartedAt) - : this.pausedDurationMs; - return Math.max(0, elapsed - pauseOffset); - } - - /** 向渲染进程推送录制状态 */ - private pushStatus(): void { - if (!this.boundWin || this.boundWin.isDestroyed()) return; - this.boundWin.webContents.send('video_record_status', this.status); - } - - /** 停止状态推送定时器 */ - private stopStatusTimer(): void { - if (this.statusTimer !== null) { - clearInterval(this.statusTimer); - this.statusTimer = null; - } - } -} +/** + * Electron 主进程视频录制管理器 + * + * @ai-context Path C 全程录制模式的核心引擎 + * 架构复用 AudioCapture 的"主进程调度 + 渲染进程执行 + IPC 回传"模式: + * 1. 主进程管理录制生命周期、写入 WebM 文件到磁盘 + * 2. 渲染进程通过 MediaRecorder 采集桌面视频流 + * 3. 视频数据块通过 IPC video_record_chunk 回传主进程并追加写入文件 + */ + +import { app, BrowserWindow } from 'electron'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { logger } from './logger.js'; + +// ================================================================ +// 类型定义 +// ================================================================ + +/** 视频录制选项 */ +export interface VideoRecordOptions { + videoBitsPerSecond?: number; + frameRate?: number; +} + +/** 录制状态(主进程 → 渲染进程) */ +export interface RecordingStatus { + isRecording: boolean; + isPaused: boolean; + duration: number; + fileSizeBytes: number; + filePath: string | null; +} + +// ================================================================ +// 默认配置 +// ================================================================ + +/** @ai-context 500kbps 低码率 + 5s 分片,平衡文件体积与录制流畅度 */ +const DEFAULT_OPTIONS: Required = { + videoBitsPerSecond: 500_000, + frameRate: 15, +}; + +const RECORDINGS_DIR_NAME = 'keban-recordings'; + +// ================================================================ +// 视频录制管理器 +// ================================================================ + +export class VideoRecorder { + private readonly options: Required; + private recording = false; + private paused = false; + private disposed = false; + private boundWin: BrowserWindow | null = null; + + /** 当前录制输出文件路径 */ + private filePath: string | null = null; + /** 文件写入流(追加模式) */ + private writeStream: fs.WriteStream | null = null; + /** 录制开始时间戳 */ + private startTime = 0; + /** 暂停期间累计的暂停时长 */ + private pausedDurationMs = 0; + /** 暂停开始时间 */ + private pauseStartedAt = 0; + /** 已写入字节数 */ + private fileSizeBytes = 0; + /** 状态推送定时器 */ + private statusTimer: ReturnType | null = null; + + constructor(options?: VideoRecordOptions) { + this.options = { ...DEFAULT_OPTIONS, ...options }; + } + + /** 是否正在录制 */ + get isRecording(): boolean { + return this.recording; + } + + /** 当前录制状态快照 */ + get status(): RecordingStatus { + return { + isRecording: this.recording, + isPaused: this.paused, + duration: this.getDurationMs(), + fileSizeBytes: this.fileSizeBytes, + filePath: this.filePath, + }; + } + + /** + * 开始视频录制 + * 通知渲染进程启动 MediaRecorder,主进程准备文件写入流 + */ + startRecording(sourceId: string, options?: VideoRecordOptions): void { + if (this.recording || this.disposed) return; + + const mergedOpts = { ...this.options, ...options }; + + // 准备录制目录和文件 + const dir = path.join(app.getPath('temp'), RECORDINGS_DIR_NAME); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); + this.filePath = path.join(dir, `recording-${timestamp}.webm`); + this.writeStream = fs.createWriteStream(this.filePath, { flags: 'a' }); + this.fileSizeBytes = 0; + this.startTime = Date.now(); + this.pausedDurationMs = 0; + this.recording = true; + this.paused = false; + + logger.info( + `[VideoRecorder] 开始录制, sourceId=${sourceId}, ` + + `bitsPerSecond=${mergedOpts.videoBitsPerSecond}, frameRate=${mergedOpts.frameRate}, ` + + `output=${this.filePath}`, + ); + + // 启动状态推送定时器(每秒一次) + this.statusTimer = setInterval(() => this.pushStatus(), 1000); + + // 通知渲染进程开始录制 + if (this.boundWin && !this.boundWin.isDestroyed()) { + this.boundWin.webContents.send('video_record_do_start', { + sourceId, + options: mergedOpts, + }); + } + } + + /** + * 停止录制,返回视频文件路径 + */ + async stopRecording(): Promise { + if (!this.recording) { + throw new Error('[VideoRecorder] 当前未在录制'); + } + + this.recording = false; + this.paused = false; + this.stopStatusTimer(); + + // 通知渲染进程停止 MediaRecorder + if (this.boundWin && !this.boundWin.isDestroyed()) { + this.boundWin.webContents.send('video_record_do_stop'); + } + + // 等待最后一批 chunk 写入完成(给渲染进程 500ms 缓冲) + await new Promise((resolve) => setTimeout(resolve, 500)); + + // 关闭文件流 + const finalPath = this.filePath; + await new Promise((resolve) => { + if (this.writeStream) { + this.writeStream.end(() => resolve()); + } else { + resolve(); + } + }); + this.writeStream = null; + + logger.info( + `[VideoRecorder] 停止录制, duration=${this.getDurationMs()}ms, ` + + `size=${this.fileSizeBytes} bytes, file=${finalPath}`, + ); + + return finalPath ?? ''; + } + + /** 暂停录制 */ + pauseRecording(): void { + if (!this.recording || this.paused) return; + this.paused = true; + this.pauseStartedAt = Date.now(); + logger.info('[VideoRecorder] 暂停录制'); + } + + /** 恢复录制 */ + resumeRecording(): void { + if (!this.recording || !this.paused) return; + this.pausedDurationMs += Date.now() - this.pauseStartedAt; + this.paused = false; + logger.info('[VideoRecorder] 恢复录制'); + } + + /** + * 接收渲染进程回传的视频数据块,追加写入文件 + * 由 IPC handler 调用 + */ + handleRendererChunk(chunkBuffer: ArrayBuffer): void { + if (!this.recording || this.paused || !this.writeStream) return; + const buf = Buffer.from(chunkBuffer); + this.writeStream.write(buf); + this.fileSizeBytes += buf.byteLength; + } + + /** + * 处理渲染进程上报的录制错误 + * 停止录制并向渲染进程广播错误通知 + */ + handleRendererError(errorInfo: { message: string }): void { + logger.error('[VideoRecorder] 渲染进程录制错误:', errorInfo.message); + // 标记录制停止,避免后续操作 + this.recording = false; + this.paused = false; + this.stopStatusTimer(); + // 关闭文件流 + if (this.writeStream) { + this.writeStream.end(); + this.writeStream = null; + } + // 向渲染进程广播错误事件 + if (this.boundWin && !this.boundWin.isDestroyed()) { + this.boundWin.webContents.send('video_record_error', { + message: errorInfo.message, + filePath: this.filePath, + }); + } + } + + /** 绑定主窗口(用于 IPC 通信) */ + bindWindow(win: BrowserWindow): void { + this.boundWin = win; + } + + /** 销毁实例,释放资源 */ + dispose(): void { + if (this.recording) { + this.stopRecording().catch((err) => { + logger.error('[VideoRecorder] dispose 时停止录制失败:', err); + }); + } + this.stopStatusTimer(); + this.disposed = true; + this.boundWin = null; + logger.info('[VideoRecorder] 已销毁'); + } + + // ================================================================ + // 私有方法 + // ================================================================ + + /** 计算有效录制时长(扣除暂停时间) */ + private getDurationMs(): number { + if (!this.startTime) return 0; + const elapsed = Date.now() - this.startTime; + const pauseOffset = this.paused + ? this.pausedDurationMs + (Date.now() - this.pauseStartedAt) + : this.pausedDurationMs; + return Math.max(0, elapsed - pauseOffset); + } + + /** 向渲染进程推送录制状态 */ + private pushStatus(): void { + if (!this.boundWin || this.boundWin.isDestroyed()) return; + this.boundWin.webContents.send('video_record_status', this.status); + } + + /** 停止状态推送定时器 */ + private stopStatusTimer(): void { + if (this.statusTimer !== null) { + clearInterval(this.statusTimer); + this.statusTimer = null; + } + } +} diff --git a/client/electron/windowManager.ts b/client/electron/windowManager.ts index eb647b27..150333e1 100644 --- a/client/electron/windowManager.ts +++ b/client/electron/windowManager.ts @@ -1,245 +1,247 @@ -/** - * 主窗口管理器 - * - * 从 main.ts 拆分而来,负责 BrowserWindow 创建配置 - * 及关闭行为偏好持久化。 - */ - -import { BrowserWindow, app, shell } from 'electron'; -import * as path from 'path'; -import { access, readFile, writeFile } from 'fs/promises'; -import { logger } from './logger.js'; -import { createTray } from './trayManager.js'; - -// ================================================================ -// 常量 -// ================================================================ - -const WINDOW_DEFAULT_WIDTH = 1200; -const WINDOW_DEFAULT_HEIGHT = 800; -const WINDOW_MIN_WIDTH = 600; - -// ================================================================ -// 关闭偏好持久化 -// ================================================================ - -/** 缓存的关闭选择,避免在同步事件处理器中执行异步 I/O */ -let cachedCloseChoice: string | null = null; - -/** 退出前同步状态 */ -let syncBeforeQuitRequested = false; -let syncBeforeQuitCompleted = false; - -/** 同步超时保护定时器(防止渲染进程无响应导致退出卡死) */ -let syncTimeoutTimer: ReturnType | null = null; - -/** 同步超时时间(毫秒):渲染进程未响应则强制继续退出 */ -const SYNC_BEFORE_QUIT_TIMEOUT_MS = 1500; - -/** 读取保存的关闭选择 */ -export async function getCloseChoice(): Promise { - try { - const configPath = path.join(app.getPath('userData'), 'close-preference.json'); - try { - await access(configPath); - } catch { - return null; - } - const data = JSON.parse(await readFile(configPath, 'utf-8')); - cachedCloseChoice = data.choice || null; - return cachedCloseChoice; - } catch { /* ignore */ } - return null; -} - -/** 保存关闭选择到配置文件 */ -export async function saveCloseChoice(choice: string): Promise { - try { - const configPath = path.join(app.getPath('userData'), 'close-preference.json'); - await writeFile(configPath, JSON.stringify({ choice }), 'utf-8'); - cachedCloseChoice = choice; - } catch { /* ignore */ } -} - -// ================================================================ -// 创建主窗口 -// ================================================================ - -/** - * 创建并返回主窗口 - * - * @param isQuittingRef - 退出标志引用,用于区分“最小化到托盘”与“真正退出” - * @param onQuit - 确认退出时的回调 - * @returns 创建的 BrowserWindow 实例 - */ -export function createMainWindow( - isQuittingRef: { value: boolean }, - onQuit: () => void, -): BrowserWindow { - const win = new BrowserWindow({ - width: WINDOW_DEFAULT_WIDTH, - height: WINDOW_DEFAULT_HEIGHT, - minWidth: 800, - minHeight: WINDOW_MIN_WIDTH, - title: '熵减', - frame: false, - show: false, // 启动缓冲带:等待渲染就绪后再显示 - backgroundColor: '#0C1524', // 深海底色,防止白闪 - icon: path.join(app.getAppPath(), 'app-icon.png'), - webPreferences: { - contextIsolation: true, - nodeIntegration: false, - sandbox: true, - backgroundThrottling: false, // 保证后台计时器精度 - preload: path.join(__dirname, 'preload.js'), - }, - }); - - // 启动缓冲带:渲染进程首次绘制完成后显示窗口 - win.once('ready-to-show', () => { - win.show(); - win.focus(); - logger.info('[Window] Window shown (ready-to-show)'); - }); - - // 拦截外部链接:target="_blank" 或 window.open() 统一用系统默认浏览器打开 - win.webContents.setWindowOpenHandler(({ url }) => { - if (url.startsWith('https://') || url.startsWith('http://')) { - shell.openExternal(url); - } - return { action: 'deny' }; - }); - - // 窗口最大化状态变化时通知前端 - win.on('maximize', () => { - win.webContents.send('window:maximized-changed', true); - }); - win.on('unmaximize', () => { - win.webContents.send('window:maximized-changed', false); - }); - - // 判断开发/生产模式 - const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged; - - if (isDev) { - // 开发模式:连接 Vite 开发服务器 - win.loadURL('http://localhost:5173'); - // 等待页面加载完成后再打开 DevTools,避免 "Runtime agent is not enabled" 错误 - win.webContents.once('did-finish-load', () => { - win.webContents.openDevTools({ mode: 'right' }); - }); - } else { - // 生产模式:加载打包后的 index.html - win.loadFile(path.join(app.getAppPath(), 'dist', 'index.html')); - - // 生产环境禁用 DevTools(防止用户打开开发人员工具) - win.webContents.on('devtools-opened', () => { - win.webContents.closeDevTools(); - }); - // 拦截 DevTools 快捷键 - win.webContents.on('before-input-event', (event, input) => { - if ( - (input.control && input.shift && input.key.toLowerCase() === 'i') || - (input.control && input.shift && input.key.toLowerCase() === 'j') || - (input.key === 'F12') - ) { - event.preventDefault(); - } - }); - } - - // 预加载关闭偏好(异步加载,同步事件处理器使用缓存值) - getCloseChoice(); // fire-and-forget:加载结果写入 cachedCloseChoice - - // 关闭窗口时根据用户偏好决定行为 - win.on('close', (event) => { - if (!isQuittingRef.value) { - event.preventDefault(); - const savedChoice = cachedCloseChoice; - if (savedChoice === 'quit') { - syncAndQuit(win, isQuittingRef, onQuit); - } else if (savedChoice === 'minimize') { - win.hide(); - } else { - // 无记忆选择,通知前端弹出确认对话框 - win.webContents.send('window:closing'); - } - } else if (!syncBeforeQuitCompleted) { - // 用户确认退出,先触发数据同步 - if (!syncBeforeQuitRequested) { - event.preventDefault(); - syncBeforeQuitRequested = true; - logger.info('[Window] Sync before quit: requesting renderer sync'); - win.webContents.send('sync:before-quit'); - } else { - // 同步尚未完成,继续等待 - event.preventDefault(); - } - } - // syncBeforeQuitCompleted === true 时允许窗口正常关闭 - }); - - // 创建系统托盘 - createTray(win, syncAndQuit.bind(null, win, isQuittingRef, onQuit)); - - logger.info('[Window] Main window created'); - return win; -} - -/** - * 退出前同步流程入口 - * 立即隐藏窗口(感知零延迟),后台执行同步再真正关闭 - * 附带超时保护:若渲染进程在 SYNC_BEFORE_QUIT_TIMEOUT_MS 内未响应,强制继续退出 - */ -function syncAndQuit( - win: BrowserWindow, - isQuittingRef: { value: boolean }, - onQuit: () => void, -): void { - if (syncBeforeQuitRequested && !syncBeforeQuitCompleted) { - // 同步已在进行中,等待完成(超时保护已启动) - return; - } - if (syncBeforeQuitCompleted) { - // 同步已完成,直接退出 - isQuittingRef.value = true; - onQuit(); - return; - } - - // ✨ 立即隐藏窗口,用户感知零延迟退出 - win.hide(); - - // 后台触发同步 - syncBeforeQuitRequested = true; - logger.info('[Window] Sync before quit: window hidden, requesting renderer sync'); - win.webContents.send('sync:before-quit'); - - // 超时保护:渲染进程未响应时强制完成同步流程 - syncTimeoutTimer = setTimeout(() => { - syncTimeoutTimer = null; - if (!syncBeforeQuitCompleted) { - logger.warn('[Window] Sync before quit: timeout reached, forcing quit'); - completeSyncBeforeQuit(); - } - }, SYNC_BEFORE_QUIT_TIMEOUT_MS); -} - -/** - * 渲染进程同步完成后调用,允许窗口关闭 - * 也可由超时保护触发(渲染进程无响应时强制继续) - */ -export function completeSyncBeforeQuit(): void { - if (syncBeforeQuitCompleted) return; // 幂等保护 - syncBeforeQuitCompleted = true; - - // 清除超时定时器(若由渲染进程正常完成) - if (syncTimeoutTimer) { - clearTimeout(syncTimeoutTimer); - syncTimeoutTimer = null; - } - - logger.info('[Window] Sync before quit: completed, proceeding with quit'); - // 直接调用 app.quit(),避免再次触发 win.close() 的 close 事件循环 - app.quit(); -} +/** + * 主窗口管理器 + * + * 从 main.ts 拆分而来,负责 BrowserWindow 创建配置 + * 及关闭行为偏好持久化。 + * + * @ai-context: 主窗口创建与关闭策略(退出确认/最小化到托盘/退出前同步等待)。 + */ + +import { BrowserWindow, app, shell } from 'electron'; +import * as path from 'path'; +import { access, readFile, writeFile } from 'fs/promises'; +import { logger } from './logger.js'; +import { createTray } from './trayManager.js'; + +// ================================================================ +// 常量 +// ================================================================ + +const WINDOW_DEFAULT_WIDTH = 1200; +const WINDOW_DEFAULT_HEIGHT = 800; +const WINDOW_MIN_WIDTH = 600; + +// ================================================================ +// 关闭偏好持久化 +// ================================================================ + +/** 缓存的关闭选择,避免在同步事件处理器中执行异步 I/O */ +let cachedCloseChoice: string | null = null; + +/** 退出前同步状态 */ +let syncBeforeQuitRequested = false; +let syncBeforeQuitCompleted = false; + +/** 同步超时保护定时器(防止渲染进程无响应导致退出卡死) */ +let syncTimeoutTimer: ReturnType | null = null; + +/** 同步超时时间(毫秒):渲染进程未响应则强制继续退出 */ +const SYNC_BEFORE_QUIT_TIMEOUT_MS = 1500; + +/** 读取保存的关闭选择 */ +export async function getCloseChoice(): Promise { + try { + const configPath = path.join(app.getPath('userData'), 'close-preference.json'); + try { + await access(configPath); + } catch { + return null; + } + const data = JSON.parse(await readFile(configPath, 'utf-8')); + cachedCloseChoice = data.choice || null; + return cachedCloseChoice; + } catch { /* ignore */ } + return null; +} + +/** 保存关闭选择到配置文件 */ +export async function saveCloseChoice(choice: string): Promise { + try { + const configPath = path.join(app.getPath('userData'), 'close-preference.json'); + await writeFile(configPath, JSON.stringify({ choice }), 'utf-8'); + cachedCloseChoice = choice; + } catch { /* ignore */ } +} + +// ================================================================ +// 创建主窗口 +// ================================================================ + +/** + * 创建并返回主窗口 + * + * @param isQuittingRef - 退出标志引用,用于区分“最小化到托盘”与“真正退出” + * @param onQuit - 确认退出时的回调 + * @returns 创建的 BrowserWindow 实例 + */ +export function createMainWindow( + isQuittingRef: { value: boolean }, + onQuit: () => void, +): BrowserWindow { + const win = new BrowserWindow({ + width: WINDOW_DEFAULT_WIDTH, + height: WINDOW_DEFAULT_HEIGHT, + minWidth: 800, + minHeight: WINDOW_MIN_WIDTH, + title: '熵减', + frame: false, + show: false, // 启动缓冲带:等待渲染就绪后再显示 + backgroundColor: '#0C1524', // 深海底色,防止白闪 + icon: path.join(app.getAppPath(), 'app-icon.png'), + webPreferences: { + contextIsolation: true, + nodeIntegration: false, + sandbox: true, + backgroundThrottling: false, // 保证后台计时器精度 + preload: path.join(__dirname, 'preload.js'), + }, + }); + + // 启动缓冲带:渲染进程首次绘制完成后显示窗口 + win.once('ready-to-show', () => { + win.show(); + win.focus(); + logger.info('[Window] Window shown (ready-to-show)'); + }); + + // 拦截外部链接:target="_blank" 或 window.open() 统一用系统默认浏览器打开 + win.webContents.setWindowOpenHandler(({ url }) => { + if (url.startsWith('https://') || url.startsWith('http://')) { + shell.openExternal(url); + } + return { action: 'deny' }; + }); + + // 窗口最大化状态变化时通知前端 + win.on('maximize', () => { + win.webContents.send('window:maximized-changed', true); + }); + win.on('unmaximize', () => { + win.webContents.send('window:maximized-changed', false); + }); + + // 判断开发/生产模式 + const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged; + + if (isDev) { + // 开发模式:连接 Vite 开发服务器 + win.loadURL('http://localhost:5173'); + // 等待页面加载完成后再打开 DevTools,避免 "Runtime agent is not enabled" 错误 + win.webContents.once('did-finish-load', () => { + win.webContents.openDevTools({ mode: 'right' }); + }); + } else { + // 生产模式:加载打包后的 index.html + win.loadFile(path.join(app.getAppPath(), 'dist', 'index.html')); + + // 生产环境禁用 DevTools(防止用户打开开发人员工具) + win.webContents.on('devtools-opened', () => { + win.webContents.closeDevTools(); + }); + // 拦截 DevTools 快捷键 + win.webContents.on('before-input-event', (event, input) => { + if ( + (input.control && input.shift && input.key.toLowerCase() === 'i') || + (input.control && input.shift && input.key.toLowerCase() === 'j') || + (input.key === 'F12') + ) { + event.preventDefault(); + } + }); + } + + // 预加载关闭偏好(异步加载,同步事件处理器使用缓存值) + getCloseChoice(); // fire-and-forget:加载结果写入 cachedCloseChoice + + // 关闭窗口时根据用户偏好决定行为 + win.on('close', (event) => { + if (!isQuittingRef.value) { + event.preventDefault(); + const savedChoice = cachedCloseChoice; + if (savedChoice === 'quit') { + syncAndQuit(win, isQuittingRef, onQuit); + } else if (savedChoice === 'minimize') { + win.hide(); + } else { + // 无记忆选择,通知前端弹出确认对话框 + win.webContents.send('window:closing'); + } + } else if (!syncBeforeQuitCompleted) { + // 用户确认退出,先触发数据同步 + if (!syncBeforeQuitRequested) { + event.preventDefault(); + syncBeforeQuitRequested = true; + logger.info('[Window] Sync before quit: requesting renderer sync'); + win.webContents.send('sync:before-quit'); + } else { + // 同步尚未完成,继续等待 + event.preventDefault(); + } + } + // syncBeforeQuitCompleted === true 时允许窗口正常关闭 + }); + + // 创建系统托盘 + createTray(win, syncAndQuit.bind(null, win, isQuittingRef, onQuit)); + + logger.info('[Window] Main window created'); + return win; +} + +/** + * 退出前同步流程入口 + * 立即隐藏窗口(感知零延迟),后台执行同步再真正关闭 + * 附带超时保护:若渲染进程在 SYNC_BEFORE_QUIT_TIMEOUT_MS 内未响应,强制继续退出 + */ +function syncAndQuit( + win: BrowserWindow, + isQuittingRef: { value: boolean }, + onQuit: () => void, +): void { + if (syncBeforeQuitRequested && !syncBeforeQuitCompleted) { + // 同步已在进行中,等待完成(超时保护已启动) + return; + } + if (syncBeforeQuitCompleted) { + // 同步已完成,直接退出 + isQuittingRef.value = true; + onQuit(); + return; + } + + // ✨ 立即隐藏窗口,用户感知零延迟退出 + win.hide(); + + // 后台触发同步 + syncBeforeQuitRequested = true; + logger.info('[Window] Sync before quit: window hidden, requesting renderer sync'); + win.webContents.send('sync:before-quit'); + + // 超时保护:渲染进程未响应时强制完成同步流程 + syncTimeoutTimer = setTimeout(() => { + syncTimeoutTimer = null; + if (!syncBeforeQuitCompleted) { + logger.warn('[Window] Sync before quit: timeout reached, forcing quit'); + completeSyncBeforeQuit(); + } + }, SYNC_BEFORE_QUIT_TIMEOUT_MS); +} + +/** + * 渲染进程同步完成后调用,允许窗口关闭 + * 也可由超时保护触发(渲染进程无响应时强制继续) + */ +export function completeSyncBeforeQuit(): void { + if (syncBeforeQuitCompleted) return; // 幂等保护 + syncBeforeQuitCompleted = true; + + // 清除超时定时器(若由渲染进程正常完成) + if (syncTimeoutTimer) { + clearTimeout(syncTimeoutTimer); + syncTimeoutTimer = null; + } + + logger.info('[Window] Sync before quit: completed, proceeding with quit'); + // 直接调用 app.quit(),避免再次触发 win.close() 的 close 事件循环 + app.quit(); +} diff --git a/client/electron/windowScorer.ts b/client/electron/windowScorer.ts index 698113cd..c44ea0a3 100644 --- a/client/electron/windowScorer.ts +++ b/client/electron/windowScorer.ts @@ -1,128 +1,130 @@ -/** - * 窗口智能评分与过滤模块 - * - * 基于关键词匹配对 desktopCapturer 返回的窗口列表进行评分和排序, - * 过滤系统/不可见窗口,将最可能是网课/直播/会议的窗口排在前面。 - * 仅针对 Windows 平台优化关键词列表。 - */ - -// ================================================================ -// 类型定义 -// ================================================================ - -export interface ScoredWindow { - id: string; - title: string; - thumbnail: string; - score: number; - matched?: string; // 命中的关键词(用于前端显示推荐理由) -} - -// ================================================================ -// 关键词评分规则 -// ================================================================ - -const SCORE_RULES = { - /** 高优先级:网课/直播/会议关键词 (+100) */ - highPriority: [ - '网课', '直播', '课程', '课堂', '学习', '讲座', '培训', - '腾讯会议', '钉钉', 'Zoom', 'Teams', 'Meet', 'Webex', - '中国大学MOOC', '学堂在线', '智慧树', '学习通', '雨课堂', - 'Bilibili', '哔哩哔哩', 'YouTube', '网易公开课', - 'Coursera', 'edX', 'Udemy', - ], - /** 中优先级:浏览器/视频播放器 (+50) */ - mediumPriority: [ - 'Chrome', 'Edge', 'Firefox', 'Brave', 'Opera', - 'PotPlayer', 'VLC', 'mpv', 'Windows Media', - 'EV录屏', 'OBS', 'MPC-HC', - ], - /** 黑名单:系统/工具窗口(直接过滤) */ - blacklist: [ - 'Program Manager', - 'Taskbar', - 'Settings', - '设置', - 'Windows Input Experience', - 'MSCTFIME', - 'Default IME', - 'Electron', - 'Entropy decrease', - '课伴', - '熵减', - ], -} as const; - -const HIGH_SCORE = 100; -const MEDIUM_SCORE = 50; - -// ================================================================ -// 评分逻辑 -// ================================================================ - -/** - * 对窗口标题进行关键词匹配评分 - * @returns score 和 matched 关键词,若命中黑名单返回 null - */ -function scoreTitle(title: string): { score: number; matched?: string } | null { - const lowerTitle = title.toLowerCase(); - - // 黑名单检测 - for (const keyword of SCORE_RULES.blacklist) { - if (lowerTitle.includes(keyword.toLowerCase())) { - return null; // 过滤 - } - } - - // 高优先级匹配 - for (const keyword of SCORE_RULES.highPriority) { - if (lowerTitle.includes(keyword.toLowerCase())) { - return { score: HIGH_SCORE, matched: keyword }; - } - } - - // 中优先级匹配 - for (const keyword of SCORE_RULES.mediumPriority) { - if (lowerTitle.includes(keyword.toLowerCase())) { - return { score: MEDIUM_SCORE, matched: keyword }; - } - } - - // 无匹配,基础分 0 - return { score: 0 }; -} - -/** - * 对窗口列表进行评分、过滤和排序 - * @param windows 原始窗口列表(来自 desktopCapturer) - * @returns 过滤并排序后的窗口列表(降序) - */ -export function scoreAndFilterWindows( - windows: { id: string; title: string; thumbnail: string }[], -): ScoredWindow[] { - const scored: ScoredWindow[] = []; - - for (const win of windows) { - // 过滤空标题窗口 - if (!win.title || win.title.trim() === '') continue; - - const result = scoreTitle(win.title); - if (result === null) continue; // 命中黑名单 - - scored.push({ - id: win.id, - title: win.title, - thumbnail: win.thumbnail, - score: result.score, - matched: result.matched, - }); - } - - // 按 score 降序排列,同分按 id 稳定排序 - scored.sort((a, b) => { - if (b.score !== a.score) return b.score - a.score; - return a.id.localeCompare(b.id); - }); - - return scored; -} +/** + * 窗口智能评分与过滤模块 + * + * 基于关键词匹配对 desktopCapturer 返回的窗口列表进行评分和排序, + * 过滤系统/不可见窗口,将最可能是网课/直播/会议的窗口排在前面。 + * 仅针对 Windows 平台优化关键词列表。 + * + * @ai-context: 采集窗口智能评分过滤:排除自身窗口(含旧品牌'课伴'关键词——防旧版本窗口被采集,为兼容保留勿删)与系统窗口。 + */ + +// ================================================================ +// 类型定义 +// ================================================================ + +export interface ScoredWindow { + id: string; + title: string; + thumbnail: string; + score: number; + matched?: string; // 命中的关键词(用于前端显示推荐理由) +} + +// ================================================================ +// 关键词评分规则 +// ================================================================ + +const SCORE_RULES = { + /** 高优先级:网课/直播/会议关键词 (+100) */ + highPriority: [ + '网课', '直播', '课程', '课堂', '学习', '讲座', '培训', + '腾讯会议', '钉钉', 'Zoom', 'Teams', 'Meet', 'Webex', + '中国大学MOOC', '学堂在线', '智慧树', '学习通', '雨课堂', + 'Bilibili', '哔哩哔哩', 'YouTube', '网易公开课', + 'Coursera', 'edX', 'Udemy', + ], + /** 中优先级:浏览器/视频播放器 (+50) */ + mediumPriority: [ + 'Chrome', 'Edge', 'Firefox', 'Brave', 'Opera', + 'PotPlayer', 'VLC', 'mpv', 'Windows Media', + 'EV录屏', 'OBS', 'MPC-HC', + ], + /** 黑名单:系统/工具窗口(直接过滤) */ + blacklist: [ + 'Program Manager', + 'Taskbar', + 'Settings', + '设置', + 'Windows Input Experience', + 'MSCTFIME', + 'Default IME', + 'Electron', + 'Entropy decrease', + '课伴', + '熵减', + ], +} as const; + +const HIGH_SCORE = 100; +const MEDIUM_SCORE = 50; + +// ================================================================ +// 评分逻辑 +// ================================================================ + +/** + * 对窗口标题进行关键词匹配评分 + * @returns score 和 matched 关键词,若命中黑名单返回 null + */ +function scoreTitle(title: string): { score: number; matched?: string } | null { + const lowerTitle = title.toLowerCase(); + + // 黑名单检测 + for (const keyword of SCORE_RULES.blacklist) { + if (lowerTitle.includes(keyword.toLowerCase())) { + return null; // 过滤 + } + } + + // 高优先级匹配 + for (const keyword of SCORE_RULES.highPriority) { + if (lowerTitle.includes(keyword.toLowerCase())) { + return { score: HIGH_SCORE, matched: keyword }; + } + } + + // 中优先级匹配 + for (const keyword of SCORE_RULES.mediumPriority) { + if (lowerTitle.includes(keyword.toLowerCase())) { + return { score: MEDIUM_SCORE, matched: keyword }; + } + } + + // 无匹配,基础分 0 + return { score: 0 }; +} + +/** + * 对窗口列表进行评分、过滤和排序 + * @param windows 原始窗口列表(来自 desktopCapturer) + * @returns 过滤并排序后的窗口列表(降序) + */ +export function scoreAndFilterWindows( + windows: { id: string; title: string; thumbnail: string }[], +): ScoredWindow[] { + const scored: ScoredWindow[] = []; + + for (const win of windows) { + // 过滤空标题窗口 + if (!win.title || win.title.trim() === '') continue; + + const result = scoreTitle(win.title); + if (result === null) continue; // 命中黑名单 + + scored.push({ + id: win.id, + title: win.title, + thumbnail: win.thumbnail, + score: result.score, + matched: result.matched, + }); + } + + // 按 score 降序排列,同分按 id 稳定排序 + scored.sort((a, b) => { + if (b.score !== a.score) return b.score - a.score; + return a.id.localeCompare(b.id); + }); + + return scored; +} diff --git a/client/index.html b/client/index.html index 91c60670..d8bbb7b0 100644 --- a/client/index.html +++ b/client/index.html @@ -1,19 +1,19 @@ - - - - - - - 熵减 - - - -

-
- 熵减 -
- -
- - - + + + + + + + 熵减 + + + +
+
+ 熵减 +
+ +
+ + + diff --git a/client/package-lock.json b/client/package-lock.json index f49c5739..4f93e0fe 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,18287 +1,18287 @@ -{ - "name": "entropy-decrease", - "version": "0.24.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "entropy-decrease", - "version": "0.24.0", - "hasInstallScript": true, - "dependencies": { - "@automerge/automerge": "^3.3.2", - "@modelcontextprotocol/sdk": "^1.29.0", - "@modelcontextprotocol/server-filesystem": "^2026.7.10", - "@modelcontextprotocol/server-memory": "^2026.7.4", - "@modelcontextprotocol/server-sequential-thinking": "^2026.7.4", - "@radix-ui/react-context-menu": "^2.3.3", - "@radix-ui/react-dialog": "^1.1.19", - "@radix-ui/react-slot": "^1.3.0", - "@radix-ui/react-toast": "^1.2.19", - "@react-three/drei": "^9.122.0", - "@react-three/fiber": "^8.18.0", - "@react-three/postprocessing": "^2.19.1", - "@supabase/supabase-js": "^2.110.1", - "@tanstack/react-query": "^5.101.2", - "@tanstack/react-virtual": "^3.14.5", - "@tiptap/extension-color": "^3.27.3", - "@tiptap/extension-highlight": "^3.27.3", - "@tiptap/extension-image": "^3.27.3", - "@tiptap/extension-placeholder": "^3.27.3", - "@tiptap/extension-table": "^3.27.3", - "@tiptap/extension-table-cell": "^3.27.3", - "@tiptap/extension-table-header": "^3.27.3", - "@tiptap/extension-table-row": "^3.27.3", - "@tiptap/extension-task-item": "^3.27.3", - "@tiptap/extension-task-list": "^3.27.3", - "@tiptap/extension-text-align": "^3.27.3", - "@tiptap/extension-text-style": "^3.27.3", - "@tiptap/extension-underline": "^3.27.3", - "@tiptap/pm": "^3.27.3", - "@tiptap/react": "^3.27.3", - "@tiptap/starter-kit": "^3.27.3", - "better-sqlite3": "^11.0.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "dexie": "^4.4.4", - "dompurify": "^3.4.12", - "electron-updater": "^6.3.9", - "framer-motion": "^12.42.2", - "lucide-react": "^1.23.0", - "lxgw-wenkai-lite-webfont": "^1.7.0", - "pixelmatch": "^7.2.0", - "pngjs": "^7.0.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^7.18.1", - "recharts": "^3.9.2", - "tailwind-merge": "^3.6.0", - "tailwindcss-animate": "^1.0.7", - "three": "^0.185.1", - "uuid": "^14.0.1", - "zustand": "^5.0.14" - }, - "devDependencies": { - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@types/better-sqlite3": "^7.6.0", - "@types/dompurify": "^3.0.5", - "@types/node": "^24.13.2", - "@types/pngjs": "^6.0.5", - "@types/react": "^18.3.18", - "@types/react-dom": "^18.3.5", - "@types/three": "^0.185.1", - "@types/uuid": "^10.0.0", - "@vitejs/plugin-react": "^6.0.3", - "autoprefixer": "^10.5.2", - "concurrently": "^10.0.3", - "cross-env": "^10.1.0", - "electron": "^35.7.5", - "electron-builder": "^25.1.8", - "electron-rebuild": "^3.2.9", - "jsdom": "^29.1.1", - "oxlint": "^1.71.0", - "postcss": "^8.5.16", - "tailwindcss": "^3.4.19", - "typescript": "~6.0.2", - "vite": "^8.1.1", - "vite-plugin-pwa": "^1.3.0", - "vitest": "^4.1.10", - "wait-on": "^9.0.10", - "workbox-window": "^7.4.1" - } - }, - "node_modules/@adobe/css-tools": { - "version": "4.5.0", - "resolved": "https://registry.npmmirror.com/@adobe/css-tools/-/css-tools-4.5.0.tgz", - "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@apideck/better-ajv-errors": { - "version": "0.3.7", - "resolved": "https://registry.npmmirror.com/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.7.tgz", - "integrity": "sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsonpointer": "^5.0.1", - "leven": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, - "node_modules/@asamuzakjp/css-color": { - "version": "5.1.11", - "resolved": "https://registry.npmmirror.com/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", - "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/generational-cache": "^1.0.1", - "@csstools/css-calc": "^3.2.0", - "@csstools/css-color-parser": "^4.1.0", - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/@asamuzakjp/dom-selector": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", - "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/generational-cache": "^1.0.1", - "@asamuzakjp/nwsapi": "^2.3.9", - "bidi-js": "^1.0.3", - "css-tree": "^3.2.1", - "is-potential-custom-element-name": "^1.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/@asamuzakjp/generational-cache": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", - "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/@asamuzakjp/nwsapi": { - "version": "2.3.9", - "resolved": "https://registry.npmmirror.com/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", - "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@automerge/automerge": { - "version": "3.3.2", - "resolved": "https://registry.npmmirror.com/@automerge/automerge/-/automerge-3.3.2.tgz", - "integrity": "sha512-9vCdCL7pdQwUra66SBxPVHr+/t9epXKni9KDeak2rNBFMzABVh2u6gSpcwxi3jkR5qr047jVqZv9DlrOfVxLFw==", - "license": "MIT" - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", - "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", - "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-member-expression-to-functions": "^7.29.7", - "@babel/helper-optimise-call-expression": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/traverse": "^7.29.7", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", - "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.8", - "resolved": "https://registry.npmmirror.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", - "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "debug": "^4.4.3", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.11" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", - "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", - "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", - "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-wrap-function": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", - "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.29.7", - "@babel/helper-optimise-call-expression": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", - "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", - "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", - "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", - "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", - "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", - "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", - "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/plugin-transform-optional-chaining": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", - "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", - "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", - "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", - "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", - "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-remap-async-to-generator": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", - "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-remap-async-to-generator": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", - "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", - "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", - "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", - "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", - "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", - "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/template": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", - "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", - "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", - "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", - "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", - "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", - "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", - "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", - "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", - "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", - "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", - "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", - "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", - "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", - "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", - "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", - "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", - "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", - "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", - "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", - "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", - "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", - "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", - "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7", - "@babel/plugin-transform-parameters": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", - "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", - "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", - "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", - "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", - "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", - "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", - "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", - "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", - "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", - "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", - "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", - "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", - "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", - "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", - "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", - "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", - "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", - "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", - "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.29.7.tgz", - "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", - "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.29.7", - "@babel/plugin-syntax-import-attributes": "^7.29.7", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.29.7", - "@babel/plugin-transform-async-generator-functions": "^7.29.7", - "@babel/plugin-transform-async-to-generator": "^7.29.7", - "@babel/plugin-transform-block-scoped-functions": "^7.29.7", - "@babel/plugin-transform-block-scoping": "^7.29.7", - "@babel/plugin-transform-class-properties": "^7.29.7", - "@babel/plugin-transform-class-static-block": "^7.29.7", - "@babel/plugin-transform-classes": "^7.29.7", - "@babel/plugin-transform-computed-properties": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7", - "@babel/plugin-transform-dotall-regex": "^7.29.7", - "@babel/plugin-transform-duplicate-keys": "^7.29.7", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", - "@babel/plugin-transform-dynamic-import": "^7.29.7", - "@babel/plugin-transform-explicit-resource-management": "^7.29.7", - "@babel/plugin-transform-exponentiation-operator": "^7.29.7", - "@babel/plugin-transform-export-namespace-from": "^7.29.7", - "@babel/plugin-transform-for-of": "^7.29.7", - "@babel/plugin-transform-function-name": "^7.29.7", - "@babel/plugin-transform-json-strings": "^7.29.7", - "@babel/plugin-transform-literals": "^7.29.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", - "@babel/plugin-transform-member-expression-literals": "^7.29.7", - "@babel/plugin-transform-modules-amd": "^7.29.7", - "@babel/plugin-transform-modules-commonjs": "^7.29.7", - "@babel/plugin-transform-modules-systemjs": "^7.29.7", - "@babel/plugin-transform-modules-umd": "^7.29.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", - "@babel/plugin-transform-new-target": "^7.29.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", - "@babel/plugin-transform-numeric-separator": "^7.29.7", - "@babel/plugin-transform-object-rest-spread": "^7.29.7", - "@babel/plugin-transform-object-super": "^7.29.7", - "@babel/plugin-transform-optional-catch-binding": "^7.29.7", - "@babel/plugin-transform-optional-chaining": "^7.29.7", - "@babel/plugin-transform-parameters": "^7.29.7", - "@babel/plugin-transform-private-methods": "^7.29.7", - "@babel/plugin-transform-private-property-in-object": "^7.29.7", - "@babel/plugin-transform-property-literals": "^7.29.7", - "@babel/plugin-transform-regenerator": "^7.29.7", - "@babel/plugin-transform-regexp-modifiers": "^7.29.7", - "@babel/plugin-transform-reserved-words": "^7.29.7", - "@babel/plugin-transform-shorthand-properties": "^7.29.7", - "@babel/plugin-transform-spread": "^7.29.7", - "@babel/plugin-transform-sticky-regex": "^7.29.7", - "@babel/plugin-transform-template-literals": "^7.29.7", - "@babel/plugin-transform-typeof-symbol": "^7.29.7", - "@babel/plugin-transform-unicode-escapes": "^7.29.7", - "@babel/plugin-transform-unicode-property-regex": "^7.29.7", - "@babel/plugin-transform-unicode-regex": "^7.29.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.15", - "babel-plugin-polyfill-corejs3": "^0.14.0", - "babel-plugin-polyfill-regenerator": "^0.6.6", - "core-js-compat": "^3.48.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmmirror.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bramus/specificity": { - "version": "2.4.2", - "resolved": "https://registry.npmmirror.com/@bramus/specificity/-/specificity-2.4.2.tgz", - "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "css-tree": "^3.0.0" - }, - "bin": { - "specificity": "bin/cli.js" - } - }, - "node_modules/@csstools/color-helpers": { - "version": "6.1.0", - "resolved": "https://registry.npmmirror.com/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", - "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@csstools/css-calc": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/@csstools/css-calc/-/css-calc-3.2.1.tgz", - "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "4.1.9", - "resolved": "https://registry.npmmirror.com/@csstools/css-color-parser/-/css-color-parser-4.1.9.tgz", - "integrity": "sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^6.1.0", - "@csstools/css-calc": "^3.2.1" - }, - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", - "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.6", - "resolved": "https://registry.npmmirror.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.6.tgz", - "integrity": "sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "peerDependencies": { - "css-tree": "^3.2.1" - }, - "peerDependenciesMeta": { - "css-tree": { - "optional": true - } - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", - "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@develar/schema-utils": { - "version": "2.6.5", - "resolved": "https://registry.npmmirror.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz", - "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.0", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/@develar/schema-utils/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@develar/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/@develar/schema-utils/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@dimforge/rapier3d-compat": { - "version": "0.12.0", - "resolved": "https://registry.npmmirror.com/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", - "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", - "license": "Apache-2.0" - }, - "node_modules/@electron/asar": { - "version": "3.4.1", - "resolved": "https://registry.npmmirror.com/@electron/asar/-/asar-3.4.1.tgz", - "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^5.0.0", - "glob": "^7.1.6", - "minimatch": "^3.0.4" - }, - "bin": { - "asar": "bin/asar.js" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/@electron/asar/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@electron/asar/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@electron/asar/node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmmirror.com/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@electron/asar/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@electron/asar/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@electron/get": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/@electron/get/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@electron/get/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/get/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/@electron/notarize": { - "version": "2.5.0", - "resolved": "https://registry.npmmirror.com/@electron/notarize/-/notarize-2.5.0.tgz", - "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.1", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@electron/osx-sign": { - "version": "1.3.1", - "resolved": "https://registry.npmmirror.com/@electron/osx-sign/-/osx-sign-1.3.1.tgz", - "integrity": "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "compare-version": "^0.1.2", - "debug": "^4.3.4", - "fs-extra": "^10.0.0", - "isbinaryfile": "^4.0.8", - "minimist": "^1.2.6", - "plist": "^3.0.5" - }, - "bin": { - "electron-osx-flat": "bin/electron-osx-flat.js", - "electron-osx-sign": "bin/electron-osx-sign.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@electron/osx-sign/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/@electron/rebuild": { - "version": "3.6.1", - "resolved": "https://registry.npmmirror.com/@electron/rebuild/-/rebuild-3.6.1.tgz", - "integrity": "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", - "debug": "^4.1.1", - "detect-libc": "^2.0.1", - "fs-extra": "^10.0.0", - "got": "^11.7.0", - "node-abi": "^3.45.0", - "node-api-version": "^0.2.0", - "node-gyp": "^9.0.0", - "ora": "^5.1.0", - "read-binary-file-arch": "^1.0.6", - "semver": "^7.3.5", - "tar": "^6.0.5", - "yargs": "^17.0.1" - }, - "bin": { - "electron-rebuild": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/@electron/rebuild/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/rebuild/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/universal": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/@electron/universal/-/universal-2.0.1.tgz", - "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@electron/asar": "^3.2.7", - "@malept/cross-spawn-promise": "^2.0.0", - "debug": "^4.3.1", - "dir-compare": "^4.2.0", - "fs-extra": "^11.1.1", - "minimatch": "^9.0.3", - "plist": "^3.1.0" - }, - "engines": { - "node": ">=16.4" - } - }, - "node_modules/@electron/universal/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@electron/universal/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "11.3.6", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.6.tgz", - "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@electron/universal/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmmirror.com/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@epic-web/invariant": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/@epic-web/invariant/-/invariant-1.0.0.tgz", - "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@exodus/bytes": { - "version": "1.15.1", - "resolved": "https://registry.npmmirror.com/@exodus/bytes/-/bytes-1.15.1.tgz", - "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@noble/hashes": "^1.8.0 || ^2.0.0" - }, - "peerDependenciesMeta": { - "@noble/hashes": { - "optional": true - } - } - }, - "node_modules/@floating-ui/core": { - "version": "1.8.0", - "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.8.0.tgz", - "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.12" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.8.0", - "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.8.0.tgz", - "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.8.0", - "@floating-ui/utils": "^0.2.12" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.9", - "resolved": "https://registry.npmmirror.com/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", - "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", - "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.8.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.12", - "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.12.tgz", - "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", - "license": "MIT" - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@hapi/address": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/@hapi/address/-/address-5.1.1.tgz", - "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/formula": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/@hapi/formula/-/formula-3.0.2.tgz", - "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/hoek": { - "version": "11.0.7", - "resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-11.0.7.tgz", - "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/pinpoint": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", - "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/tlds": { - "version": "1.1.7", - "resolved": "https://registry.npmmirror.com/@hapi/tlds/-/tlds-1.1.7.tgz", - "integrity": "sha512-MgNjRwy9Ti92yVAixLmDc8dd1bJIKwO9qlWCfFQRwRmUEDPQHYn4G6hwPFvFGUTzAa0FsS+inMjLin7GnyBRhA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/topo": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/@hapi/topo/-/topo-6.0.2.tgz", - "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hono/node-server": { - "version": "1.19.14", - "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.14.tgz", - "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@isaacs/cliui": { - "version": "9.0.0", - "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-9.0.0.tgz", - "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmmirror.com/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@malept/cross-spawn-promise": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", - "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" - } - ], - "license": "Apache-2.0", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/@malept/flatpak-bundler": { - "version": "0.4.0", - "resolved": "https://registry.npmmirror.com/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", - "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.0", - "lodash": "^4.17.15", - "tmp-promise": "^3.0.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@mediapipe/tasks-vision": { - "version": "0.10.17", - "resolved": "https://registry.npmmirror.com/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", - "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", - "license": "Apache-2.0" - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.29.0", - "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", - "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@modelcontextprotocol/server-filesystem": { - "version": "2026.7.10", - "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/server-filesystem/-/server-filesystem-2026.7.10.tgz", - "integrity": "sha512-Mmjg4anFBD5OzbPnGJOA0jPPN8645ERhQk38HQLpSenx1ox9bfdPkmAzUnNjeQtqQGFLtKe13J20RtLBmUKMZA==", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", - "diff": "^8.0.3", - "glob": "^10.5.0", - "minimatch": "^10.0.1" - }, - "bin": { - "mcp-server-filesystem": "dist/index.js" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmmirror.com/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/glob/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@modelcontextprotocol/server-filesystem/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@modelcontextprotocol/server-memory": { - "version": "2026.7.4", - "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/server-memory/-/server-memory-2026.7.4.tgz", - "integrity": "sha512-D+NNzChsOHN72y58ngDmO+TzjJijGi/sSY/gBydhB3TJCcm1XQEozVWwEpruHeXt/HSkMV3Z/BpHDhdt1MLD5w==", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0" - }, - "bin": { - "mcp-server-memory": "dist/index.js" - } - }, - "node_modules/@modelcontextprotocol/server-sequential-thinking": { - "version": "2026.7.4", - "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/server-sequential-thinking/-/server-sequential-thinking-2026.7.4.tgz", - "integrity": "sha512-tmR/ieGaeweffLNBrDp1H1w4sn4M6TN5yWSbMS+YMfS+0GDyPjnNKzqCl2uqfdRiX3D44PJUhwiDGqtJp6tFhw==", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", - "chalk": "^5.3.0", - "yargs": "^17.7.2" - }, - "bin": { - "mcp-server-sequential-thinking": "dist/index.js" - } - }, - "node_modules/@modelcontextprotocol/server-sequential-thinking/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@monogrid/gainmap-js": { - "version": "3.4.0", - "resolved": "https://registry.npmmirror.com/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", - "integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==", - "license": "MIT", - "dependencies": { - "promise-worker-transferable": "^1.0.4" - }, - "peerDependencies": { - "three": ">= 0.159.0" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmmirror.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.139.0", - "resolved": "https://registry.npmmirror.com/@oxc-project/types/-/types-0.139.0.tgz", - "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@oxlint/binding-android-arm-eabi": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.73.0.tgz", - "integrity": "sha512-HZQRN/UMBu+Ut+/9MiAChkbP4qZqrNOWBcNI45vOT40GVhbGR0JgHB87L48D4iAqFQIdVmeQYtV9RF89AjTKkg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-android-arm64": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-android-arm64/-/binding-android-arm64-1.73.0.tgz", - "integrity": "sha512-Gp+KJRylv2aW7thRpG5p1KTxZq4ZJFbWowrKzufNq9d3ssl3r3JviYV45/+p+7CN1Nv0zDd1e8Ex0b/HUDq4TQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-darwin-arm64": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.73.0.tgz", - "integrity": "sha512-3de96NdtXhxERMjIz7wsp2HYMY6pMQycGxFWac2mFecAx6VeARF/IqFb1QIaqiCRIdfzBwzTed+pCTCoiS+CYA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-darwin-x64": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.73.0.tgz", - "integrity": "sha512-5zx/uPW32TiaOeVY1dQ/H5iOf0K1HOdFKOJhLqGl4o63+i1fpzoqqu/mKtd7OFgFjNCdhlyTGgjVkQTZm1ELcg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-freebsd-x64": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.73.0.tgz", - "integrity": "sha512-qNe4gKHaGnLuZJ8toUg90JAa0S2vTVvDw+0bRi3q1avXZXDT4u5mMeECf3nD4HYrbdn1O7dXqWut4onY/yx/Xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-arm-gnueabihf": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.73.0.tgz", - "integrity": "sha512-cCehYh5hTbfShm/fxTD6wwrGUWIpvX+N5OxmAMhFhDeTGXvw+BeNj889tpxsFQ9ZLatQ6wImuY8tsKLZ+FMz7w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-arm-musleabihf": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.73.0.tgz", - "integrity": "sha512-d5j5GDU/2dMgjVhw7TQT9ITrsIr1Y02KEXKyVGIXUkD+KiaxE9TP65FS2ZdgTBemQvoRL+gSBdbrIm3cQIeacg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-arm64-gnu": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.73.0.tgz", - "integrity": "sha512-Eyf1SrP3+yR1DI3OJgOY2Pvrr9dWP9TK37xPaDYycwTtlGlI45erJAVIfH5/m/xosDt6BupJYEFi47bvbTuuyw==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-arm64-musl": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.73.0.tgz", - "integrity": "sha512-IlT/OJApEDKaMmCooHuncgJZbbCe7T5QIWmTZBEtYscWvzPQuuEinVcid6kwQRVQOUdb7PUCz4jQHnaYXdfJXw==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-ppc64-gnu": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.73.0.tgz", - "integrity": "sha512-L+JYcb/vdg5fmcH08V6o0YYLU28cTH1SPNulwJdvK9NK49aXSkYy6oNpKBmddArVOXYqNepriDGiZ04G54kh1Q==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-riscv64-gnu": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.73.0.tgz", - "integrity": "sha512-Qtk0g3bKV6OwWjIm7R8kQN1uOZRKQt/MODK2a8QfkwhTpXBD53ozx5XLVWLGDQAVyp2otLW4D2wB98XfAfMPGA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-riscv64-musl": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.73.0.tgz", - "integrity": "sha512-wX0NQKZVxltkAOVmzFcpOaMpdaUvsq1Eqpx9tkAfl71UdkTlSo1R4AdAnGccR1Fm2+TzFgZ22CyyGuZ41RDr/A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-s390x-gnu": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.73.0.tgz", - "integrity": "sha512-vPe7UGBMWyiLTtnqS4xxgMQFSFGmtQwhwCxuiw6lXygaO6bVt0D8dFVg8Xv05eaiN3ybC0HXXHUAohFMFvqoCQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-x64-gnu": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.73.0.tgz", - "integrity": "sha512-2CwIWr9cemFC/CbRBWZvuk5mffz6ObmfFkfcC/9rTQ7f+icNhYr2kOjf9Rt8lLvugvkdGDOmkoVoFFHh6ClCTw==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-x64-musl": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.73.0.tgz", - "integrity": "sha512-nDadfJgg7NBBxG0N560wOe7LLX5QiYp6qBaI7viuk5EUORFBktU/NfV0MbTqU3gTqQDCh4VyxKdo5VADxk9w8Q==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-openharmony-arm64": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.73.0.tgz", - "integrity": "sha512-wGjJC+NLH9xP+IKGn9RDW94ojJR/wPbg5WCnQjj/oReaOtCQthr8ws1zICe77JFmo4ouUdeTHHZL/ESGiF6Pmw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-win32-arm64-msvc": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.73.0.tgz", - "integrity": "sha512-I7X47GPGljw225YUQ5SbC/rb1Kkdrd0yQf0x+hYxeKS6DpfjMbo9ccQPQ6LNY6BoJQ1sHhgDUGuMn5Vg5gHT6w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-win32-ia32-msvc": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.73.0.tgz", - "integrity": "sha512-5lWj+3h+74Fm1jYOO9qkJA4xkAlZA099DkXppuXsk7UpnpZLttsefrZU469vChGaG6hcSqrkKXQOvMTZtbjeNg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-win32-x64-msvc": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.73.0.tgz", - "integrity": "sha512-WaNRvh4f6zY9CvUQk2YoA1O90ieWrIklI84+HXFr9Isjz9CSESrdqo/RtIYt4Dll/cAchqGDMehfaZd0vqEFZw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-1.1.5.tgz", - "integrity": "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.11", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-arrow/-/react-arrow-1.1.11.tgz", - "integrity": "sha512-Kdil9BB1rIFC/khmf4hC35bn8701AJcizTU7G7cUbEbk5XqqbjDuHW60uUfKqO5WojjZcbAW51Q7P0hRmMLw8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.7" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.12", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-1.1.12.tgz", - "integrity": "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-slot": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz", - "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.2.0.tgz", - "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context-menu": { - "version": "2.3.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-context-menu/-/react-context-menu-2.3.3.tgz", - "integrity": "sha512-PS+gKE0z2prJ74Y0sM+brAGK4mYOHIR7TlcV5EJgUQ6E0xMvyswkK2X4yRqyganrzsRL+WCSKAPu0NQITICRWg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-menu": "2.1.20", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-controllable-state": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.19", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-dialog/-/react-dialog-1.1.19.tgz", - "integrity": "sha512-+HhbN2+YtkRgVirjZ2afMeutQRuGOrdkWR5+EFC58SJojGmtyNQwYzgi6tHBpOxvFHefMtPeHdgtjz0BOGxFQg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-dismissable-layer": "1.1.15", - "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.12", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.7", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-slot": "1.3.0", - "@radix-ui/react-use-controllable-state": "1.2.3", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.7.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-direction/-/react-direction-1.1.2.tgz", - "integrity": "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.15", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.15.tgz", - "integrity": "sha512-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-effect-event": "0.0.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz", - "integrity": "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.12", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.12.tgz", - "integrity": "sha512-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-id/-/react-id-1.1.2.tgz", - "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.20", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-menu/-/react-menu-2.1.20.tgz", - "integrity": "sha512-VsUrXxFe9d2ScbZF0fR/oPR1+qjyeLs5p0jzG8h90puMoA9bq4SirYlXbE+USRg9Q2qTeJSFNqjw2nts8jJe4w==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-collection": "1.1.12", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.15", - "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.12", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-popper": "1.3.3", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.7", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-roving-focus": "1.1.15", - "@radix-ui/react-slot": "1.3.0", - "@radix-ui/react-use-callback-ref": "1.1.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.7.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-popper/-/react-popper-1.3.3.tgz", - "integrity": "sha512-mS7dGpyjv6b+gsDjLF7e0ia1W4Im1B1hSCy2yuXlHuvnZxHKagfDaobt/KAKt27EpZMit2pss8eJBVyVjEWM+g==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.11", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.2", - "@radix-ui/react-use-rect": "1.1.2", - "@radix-ui/react-use-size": "1.1.2", - "@radix-ui/rect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.13", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-portal/-/react-portal-1.1.13.tgz", - "integrity": "sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.7", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.1.7.tgz", - "integrity": "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.7", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.7.tgz", - "integrity": "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.15", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.15.tgz", - "integrity": "sha512-40svmmugfM3mUN7VUDGVE1tQGOhyi8enlGD0CNJEcMM36C1f71PKM21DFgNHUfem0XnA+d8H8oN3Z9ZpJjSslg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-collection": "1.1.12", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-controllable-state": "1.2.3", - "@radix-ui/react-use-is-hydrated": "0.1.1", - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", - "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast": { - "version": "1.2.19", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-toast/-/react-toast-1.2.19.tgz", - "integrity": "sha512-SxfVZfVOibWKWdkf0Xx1awW2d09fQu4V4PXDY1j5hi4MVf7MWdJZqTBJMa1KWtOr1S6GGtCk02nniZ0Iia+dHw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-collection": "1.1.12", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-dismissable-layer": "1.1.15", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.7", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-controllable-state": "1.2.3", - "@radix-ui/react-use-layout-effect": "1.1.2", - "@radix-ui/react-visually-hidden": "1.2.7" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz", - "integrity": "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", - "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.3", - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz", - "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-is-hydrated": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.1.tgz", - "integrity": "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz", - "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.2.tgz", - "integrity": "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==", - "license": "MIT", - "dependencies": { - "@radix-ui/rect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-size/-/react-use-size-1.1.2.tgz", - "integrity": "sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.7", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.7.tgz", - "integrity": "sha512-1wNZBggTDK3GRuuQ6nP4k2yi7a6l7I5qbMPbZcRsrGsGVead/f/d5FhEzUvqFs0bcrDLx7n1zKQ3JvLR6whaaw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.7" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/rect": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/rect/-/rect-1.1.2.tgz", - "integrity": "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==", - "license": "MIT" - }, - "node_modules/@react-spring/animated": { - "version": "9.7.5", - "resolved": "https://registry.npmmirror.com/@react-spring/animated/-/animated-9.7.5.tgz", - "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", - "license": "MIT", - "dependencies": { - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-spring/core": { - "version": "9.7.5", - "resolved": "https://registry.npmmirror.com/@react-spring/core/-/core-9.7.5.tgz", - "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~9.7.5", - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-spring/donate" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-spring/rafz": { - "version": "9.7.5", - "resolved": "https://registry.npmmirror.com/@react-spring/rafz/-/rafz-9.7.5.tgz", - "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", - "license": "MIT" - }, - "node_modules/@react-spring/shared": { - "version": "9.7.5", - "resolved": "https://registry.npmmirror.com/@react-spring/shared/-/shared-9.7.5.tgz", - "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", - "license": "MIT", - "dependencies": { - "@react-spring/rafz": "~9.7.5", - "@react-spring/types": "~9.7.5" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-spring/three": { - "version": "9.7.5", - "resolved": "https://registry.npmmirror.com/@react-spring/three/-/three-9.7.5.tgz", - "integrity": "sha512-RxIsCoQfUqOS3POmhVHa1wdWS0wyHAUway73uRLp3GAL5U2iYVNdnzQsep6M2NZ994BlW8TcKuMtQHUqOsy6WA==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~9.7.5", - "@react-spring/core": "~9.7.5", - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" - }, - "peerDependencies": { - "@react-three/fiber": ">=6.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "three": ">=0.126" - } - }, - "node_modules/@react-spring/types": { - "version": "9.7.5", - "resolved": "https://registry.npmmirror.com/@react-spring/types/-/types-9.7.5.tgz", - "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", - "license": "MIT" - }, - "node_modules/@react-three/drei": { - "version": "9.122.0", - "resolved": "https://registry.npmmirror.com/@react-three/drei/-/drei-9.122.0.tgz", - "integrity": "sha512-SEO/F/rBCTjlLez7WAlpys+iGe9hty4rNgjZvgkQeXFSiwqD4Hbk/wNHMAbdd8vprO2Aj81mihv4dF5bC7D0CA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.26.0", - "@mediapipe/tasks-vision": "0.10.17", - "@monogrid/gainmap-js": "^3.0.6", - "@react-spring/three": "~9.7.5", - "@use-gesture/react": "^10.3.1", - "camera-controls": "^2.9.0", - "cross-env": "^7.0.3", - "detect-gpu": "^5.0.56", - "glsl-noise": "^0.0.0", - "hls.js": "^1.5.17", - "maath": "^0.10.8", - "meshline": "^3.3.1", - "react-composer": "^5.0.3", - "stats-gl": "^2.2.8", - "stats.js": "^0.17.0", - "suspend-react": "^0.1.3", - "three-mesh-bvh": "^0.7.8", - "three-stdlib": "^2.35.6", - "troika-three-text": "^0.52.0", - "tunnel-rat": "^0.1.2", - "utility-types": "^3.11.0", - "zustand": "^5.0.1" - }, - "peerDependencies": { - "@react-three/fiber": "^8", - "react": "^18", - "react-dom": "^18", - "three": ">=0.137" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/@react-three/drei/node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@react-three/fiber": { - "version": "8.18.0", - "resolved": "https://registry.npmmirror.com/@react-three/fiber/-/fiber-8.18.0.tgz", - "integrity": "sha512-FYZZqD0UUHUswKz3LQl2Z7H24AhD14XGTsIRw3SJaXUxyfVMi+1yiZGmqTcPt/CkPpdU7rrxqcyQ1zJE5DjvIQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.17.8", - "@types/react-reconciler": "^0.26.7", - "@types/webxr": "*", - "base64-js": "^1.5.1", - "buffer": "^6.0.3", - "its-fine": "^1.0.6", - "react-reconciler": "^0.27.0", - "react-use-measure": "^2.1.7", - "scheduler": "^0.21.0", - "suspend-react": "^0.1.3", - "zustand": "^3.7.1" - }, - "peerDependencies": { - "expo": ">=43.0", - "expo-asset": ">=8.4", - "expo-file-system": ">=11.0", - "expo-gl": ">=11.0", - "react": ">=18 <19", - "react-dom": ">=18 <19", - "react-native": ">=0.64", - "three": ">=0.133" - }, - "peerDependenciesMeta": { - "expo": { - "optional": true - }, - "expo-asset": { - "optional": true - }, - "expo-file-system": { - "optional": true - }, - "expo-gl": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/@react-three/fiber/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/@react-three/fiber/node_modules/scheduler": { - "version": "0.21.0", - "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.21.0.tgz", - "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/@react-three/fiber/node_modules/zustand": { - "version": "3.7.2", - "resolved": "https://registry.npmmirror.com/zustand/-/zustand-3.7.2.tgz", - "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", - "license": "MIT", - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, - "node_modules/@react-three/postprocessing": { - "version": "2.19.1", - "resolved": "https://registry.npmmirror.com/@react-three/postprocessing/-/postprocessing-2.19.1.tgz", - "integrity": "sha512-7P25LOSToH/I6b3UipNK17IIFlX4FDUmWcaomfwu82+CzhXTOz8Fcc1ZXEZ7vFA/5Fr/2peNlXgXZJvoa+aCdA==", - "license": "MIT", - "dependencies": { - "buffer": "^6.0.3", - "maath": "^0.6.0", - "n8ao": "^1.6.6", - "postprocessing": "^6.32.1", - "three-stdlib": "^2.23.4" - }, - "peerDependencies": { - "@react-three/fiber": "^8.0", - "react": "^18.0", - "three": ">= 0.138.0" - } - }, - "node_modules/@react-three/postprocessing/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/@react-three/postprocessing/node_modules/maath": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/maath/-/maath-0.6.0.tgz", - "integrity": "sha512-dSb2xQuP7vDnaYqfoKzlApeRcR2xtN8/f7WV/TMAkBC8552TwTLtOO0JTcSygkYMjNDPoo6V01jTw/aPi4JrMw==", - "license": "MIT", - "peerDependencies": { - "@types/three": ">=0.144.0", - "three": ">=0.144.0" - } - }, - "node_modules/@reduxjs/toolkit": { - "version": "2.12.0", - "resolved": "https://registry.npmmirror.com/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", - "integrity": "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@standard-schema/utils": "^0.3.0", - "immer": "^11.0.0", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", - "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", - "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", - "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", - "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", - "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", - "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", - "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", - "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", - "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", - "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", - "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", - "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", - "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", - "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.11.1", - "@emnapi/runtime": "1.11.1", - "@napi-rs/wasm-runtime": "^1.1.6" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", - "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", - "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/plugin-babel": { - "version": "6.1.0", - "resolved": "https://registry.npmmirror.com/@rollup/plugin-babel/-/plugin-babel-6.1.0.tgz", - "integrity": "sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@rollup/pluginutils": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - }, - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "16.0.3", - "resolved": "https://registry.npmmirror.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", - "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-replace": { - "version": "6.0.3", - "resolved": "https://registry.npmmirror.com/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", - "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.30.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-terser": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", - "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "serialize-javascript": "^7.0.3", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.4.0", - "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", - "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", - "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", - "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", - "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", - "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", - "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", - "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", - "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", - "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", - "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", - "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", - "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", - "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", - "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", - "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", - "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", - "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", - "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", - "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", - "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", - "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", - "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", - "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", - "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", - "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", - "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@standard-schema/utils": { - "version": "0.3.0", - "resolved": "https://registry.npmmirror.com/@standard-schema/utils/-/utils-0.3.0.tgz", - "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", - "license": "MIT" - }, - "node_modules/@supabase/auth-js": { - "version": "2.110.1", - "resolved": "https://registry.npmmirror.com/@supabase/auth-js/-/auth-js-2.110.1.tgz", - "integrity": "sha512-8EJUoRoqzAYWkieHrLCrGrxs3cBbRB94xK8GzHe0aSLlSa4mt1enYLCiMgLiKJOF8GNYeX6PLTBNef0XAhILgw==", - "license": "MIT", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@supabase/functions-js": { - "version": "2.110.1", - "resolved": "https://registry.npmmirror.com/@supabase/functions-js/-/functions-js-2.110.1.tgz", - "integrity": "sha512-Pm9HD9Qth6zQO0aOGZ3DxYb6QlCzrkTkP6eUEOvhTlbvcvYRDSCZXIJ5dkDLpqxD+gdrXfWDFOpU9BpRKYjsIQ==", - "license": "MIT", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@supabase/phoenix": { - "version": "0.4.4", - "resolved": "https://registry.npmmirror.com/@supabase/phoenix/-/phoenix-0.4.4.tgz", - "integrity": "sha512-Gt0pqoXuIqX/8dvG0OKp/wMCobXNH3klNbUPBNyOfN0YA1IswrM3HyWFMOPk1Jy+BRaIyDPcFx4jLBwHNmlyfQ==", - "license": "MIT" - }, - "node_modules/@supabase/postgrest-js": { - "version": "2.110.1", - "resolved": "https://registry.npmmirror.com/@supabase/postgrest-js/-/postgrest-js-2.110.1.tgz", - "integrity": "sha512-BILNhS40oGlP2bn/VJjh/1hCyrWNMmpGZGcCrPvqd5R3s8gf8Bd5qyKoHZdMwTKynGCuJGjagRXa069abhibMw==", - "license": "MIT", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@supabase/realtime-js": { - "version": "2.110.1", - "resolved": "https://registry.npmmirror.com/@supabase/realtime-js/-/realtime-js-2.110.1.tgz", - "integrity": "sha512-JmWCpMoe2iJPNrXIdHqIvf2Mie6NfSuWHS9Ve6YCmLkn1mNl3vrK3a67IukJ5lPjgmAzB+jFagyMz2oSIX+Xnw==", - "license": "MIT", - "dependencies": { - "@supabase/phoenix": "0.4.4", - "tslib": "2.8.1" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@supabase/storage-js": { - "version": "2.110.1", - "resolved": "https://registry.npmmirror.com/@supabase/storage-js/-/storage-js-2.110.1.tgz", - "integrity": "sha512-UqJGzhFMiIRBe8vT7a6ZtrN2U5YufH4Tk9nyc9KKfa2TUtV11BkSg/v3lyy/c4A8SbekVH3UywTF0s42zpF4zw==", - "license": "MIT", - "dependencies": { - "iceberg-js": "^0.8.1", - "tslib": "2.8.1" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@supabase/supabase-js": { - "version": "2.110.1", - "resolved": "https://registry.npmmirror.com/@supabase/supabase-js/-/supabase-js-2.110.1.tgz", - "integrity": "sha512-MiJh0THZgyAvTWm91FOLknjH5dYjXRKOdxpuUsyTVZVXIf7FxCShzevIm4KGCubHRU2n25Gyt8PhTXIFzcD9FA==", - "license": "MIT", - "dependencies": { - "@supabase/auth-js": "2.110.1", - "@supabase/functions-js": "2.110.1", - "@supabase/postgrest-js": "2.110.1", - "@supabase/realtime-js": "2.110.1", - "@supabase/storage-js": "2.110.1" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tanstack/query-core": { - "version": "5.101.2", - "resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.101.2.tgz", - "integrity": "sha512-hH5MLoJhF7KaIGd7q3xTXGXvslI+GYlM1Z/35aSHHWaCJWB7XvTSHYuV3eM7tw+aE0mT/xMro4M4Q9rCGHT0lw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "5.101.2", - "resolved": "https://registry.npmmirror.com/@tanstack/react-query/-/react-query-5.101.2.tgz", - "integrity": "sha512-seDkr6kzGzX1okaaTtZPtgA688CDPlXUz1C6xSg0ESqn04Vuc8tlrYms1s3de+znBqhPVxFRfpAfUf+6XvfPWg==", - "license": "MIT", - "dependencies": { - "@tanstack/query-core": "5.101.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^18 || ^19" - } - }, - "node_modules/@tanstack/react-virtual": { - "version": "3.14.5", - "resolved": "https://registry.npmmirror.com/@tanstack/react-virtual/-/react-virtual-3.14.5.tgz", - "integrity": "sha512-4EKRXh7zBLkbKbFmG3AUVkircuHd+7OdT1pocJSepxtfBd3qnrJgJ5rtPkRYyo9fmyVb2+pI2xPy5oYvMLQy6A==", - "license": "MIT", - "dependencies": { - "@tanstack/virtual-core": "3.17.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@tanstack/virtual-core": { - "version": "3.17.3", - "resolved": "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.17.3.tgz", - "integrity": "sha512-8Np/TFELpI0ySuJoVmjvOrQYXH/8sTX0Biv9szhFhY39xOdAAY+smrMxjxOum/ux3eM8MUJQsEJ0/R0UpvC8dw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmmirror.com/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "6.9.1", - "resolved": "https://registry.npmmirror.com/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", - "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "picocolors": "^1.1.1", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmmirror.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@testing-library/react": { - "version": "16.3.2", - "resolved": "https://registry.npmmirror.com/@testing-library/react/-/react-16.3.2.tgz", - "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0 || ^19.0.0", - "@types/react-dom": "^18.0.0 || ^19.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@tiptap/core": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/core/-/core-3.27.3.tgz", - "integrity": "sha512-TJj5929M96C1KlH796wS8MywfHDh49RhmakOyzyMMc9pFmRj9UXi1gj0TCXgsZtjEOG7B+m/DRvNOvnuvR9kmg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/extension-blockquote": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-blockquote/-/extension-blockquote-3.27.3.tgz", - "integrity": "sha512-VGoVMcqcGkkoduzEqQ70ZK5OOHBDn5iYeHJSgkvNoSHzYHl0CaKoWxoDKJjSWC5DAM4mBU+tXTlsiUp3evRMfA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-bold": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-bold/-/extension-bold-3.27.3.tgz", - "integrity": "sha512-pchbycFppBqBmvk+OxrQLIPZLNd3rNbcm7zOa+OTjluphpAcsJ6AmHBmiRhJUYWitV6/SA+0nujcaWxBp5hNcQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-bubble-menu": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.27.3.tgz", - "integrity": "sha512-PKSM9g8BXzO0Lxm2gOin7FAFvxO6T0QvlXTXVke/GJn/sR1tEz7w5ybsvweytUPmSliUc601pfIUOHKEhIVC2Q==", - "license": "MIT", - "optional": true, - "dependencies": { - "@floating-ui/dom": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/extension-bullet-list": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-bullet-list/-/extension-bullet-list-3.27.3.tgz", - "integrity": "sha512-owQW6mcgnYgQU1z5BqmslcjZFBUm1SGM/Ax++4R6XelIt/7ol6uSTjzjAzum+ASW7UlBbuJHuSgRjl8cA+RGkg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-list": "3.27.3" - } - }, - "node_modules/@tiptap/extension-code": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-code/-/extension-code-3.27.3.tgz", - "integrity": "sha512-T7JF10Y3k7fyVujXXLVubdUh7fctgBUoiuxbvjotpltg1U/mPbOcT0UW/uif9j3H8TFvAwNApVw3x8bwwFUakA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-code-block": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-code-block/-/extension-code-block-3.27.3.tgz", - "integrity": "sha512-3CVnzkpGoqqI5KaXI9l9PMwLkx34SYY63tpeo0I0QjDk4LU+JTAQDTPJFSwB4zTsHZ7ZFMU0jjasFOZ1kZRVgw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/extension-color": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-color/-/extension-color-3.27.3.tgz", - "integrity": "sha512-tNXyK3VXPGygJP+vq1+YyPmrxLabx4vs+rYiVhGtmhIapTQeMVYcHbFH4s4v3h5m8JGVlTWnpI8n7cb5ExIhSQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-text-style": "3.27.3" - } - }, - "node_modules/@tiptap/extension-document": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-document/-/extension-document-3.27.3.tgz", - "integrity": "sha512-PR25MRv56Nm4ETVLwA8nAh/0RrVdvD4D2nxnAC8kUkxz1WOYDaqTfPqqEeSWDoUUTUp1I1xzDkD4x0gEnAlmZA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-dropcursor": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.27.3.tgz", - "integrity": "sha512-XsL0Ziual+ynXyx5JgLb0KIOShlMN3MW7+GQvf9PGRb1vOB7IOTRFDxMPrxDWcFIZ6WWMWSrbkCLOKHStt1BWg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extensions": "3.27.3" - } - }, - "node_modules/@tiptap/extension-floating-menu": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.27.3.tgz", - "integrity": "sha512-qL+g1Z6MqZvYG4mHTPwub9II2fWZY+2I5VFfV8fzqy1HchBOyY6Df0mRKDNb0bmjBdFabIXnswz3iqLx3mDTbw==", - "license": "MIT", - "optional": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@floating-ui/dom": "^1.0.0", - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/extension-gapcursor": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-gapcursor/-/extension-gapcursor-3.27.3.tgz", - "integrity": "sha512-MVBqzwYrDOttkn2GOrvvKTDCymfSS2VGSKpahcKKhge5mweSDiqko2X1vBDnMF8aVW3WxIFfDMmO4VMmh8HDZA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extensions": "3.27.3" - } - }, - "node_modules/@tiptap/extension-hard-break": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-hard-break/-/extension-hard-break-3.27.3.tgz", - "integrity": "sha512-cySObJITR2CRrWII87mI2LJ12wEETTnxt2p1vvC6ZtUmKnB50fOu+ux8ZEt6KYNocIOtrEZthNFzTOx7R7UtrQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-heading": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-heading/-/extension-heading-3.27.3.tgz", - "integrity": "sha512-QHXnsNic6iId8pnsFZ8z4PkX5L+HCHa/D7rAi3nNWtPlSIAOxo4nKrALcB5/tHmY+XL8kEXKH3nsNLNEDLCYPg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-highlight": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-highlight/-/extension-highlight-3.27.3.tgz", - "integrity": "sha512-99QYxMx8F/NhdvznM8/Zhm4XiCdMU0OEiLwPvLNObJiKV8UBqjdA68cJLX6FRuOi2nqD7xfJq2KuSsFKBldi2A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-horizontal-rule": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.27.3.tgz", - "integrity": "sha512-sNCuo0+Q001B5XTVWY+ULpWXQqtBNRmAqXxAexZl44bx3rDqHG8OzjwT4EM0LIj2+BYVbdqwaJ1vfQbZVEEbig==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/extension-image": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-image/-/extension-image-3.27.3.tgz", - "integrity": "sha512-3OVLRH54Xkh9yrI5oGIempuqZkhLG1plyJBRnapx0N8j9IjEImOLF78kPYoAZzaBuU78M3Zk/E7HQZgmnaNRBg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-italic": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-italic/-/extension-italic-3.27.3.tgz", - "integrity": "sha512-7VpVi2vn8kGFAc/HLrt96J/E6+LXOGKn8xLhJS863t150yLIG3EPQLA1h+G5O6eo+/w+9YokvJAAJoeDihj1Jg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-link": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-link/-/extension-link-3.27.3.tgz", - "integrity": "sha512-iXmu1tJ/3vP60c9d+zfO3+X64vod2EyBrM1qeufecAtWA6t0bT9tYeka0Zq6qDRGsZK5zViO9F2lsY7eHXiYuA==", - "license": "MIT", - "dependencies": { - "linkifyjs": "^4.3.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/extension-list": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-list/-/extension-list-3.27.3.tgz", - "integrity": "sha512-52rcaSzYjtVGUrNkdB8k1Bw/rId2lBirrWMvmnBLsieoeFd8zo8ow5zkwV057BYSgWXfnMAV7GOpDyq2IoSD9A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/extension-list-item": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-list-item/-/extension-list-item-3.27.3.tgz", - "integrity": "sha512-UddhVaQ7+V9IfQVVE8AJLNzSmyaaNpZPQsoPQxFNlJyOFxD6RwSTT8L4rb/TwbUctxSFWpyd1J7exzf33Ony/g==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-list": "3.27.3" - } - }, - "node_modules/@tiptap/extension-list-keymap": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-list-keymap/-/extension-list-keymap-3.27.3.tgz", - "integrity": "sha512-GZPVg4QCFm41yTMPEPeTlH2odNeQwRuWHY/pt3pI5LsfipQ4kDBv6h9we928vJQUnU2Gg9Y3cL5iRbmXIWWTUA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-list": "3.27.3" - } - }, - "node_modules/@tiptap/extension-ordered-list": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-ordered-list/-/extension-ordered-list-3.27.3.tgz", - "integrity": "sha512-oHYoE65WfRSM5tCcXi8MtQmzPxz83E2qw0pa2yHBKwr9xCCQUu8vJHJE+EJGduWdaNImv43+6/6kVMeYYbXRKg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-list": "3.27.3" - } - }, - "node_modules/@tiptap/extension-paragraph": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-paragraph/-/extension-paragraph-3.27.3.tgz", - "integrity": "sha512-G5XPCN7lm0nULYPelJC2eUbKbt1q97j67e/HSWxwMYEXhceec5eNAtVfpDCRyXNO9osyBi2kXqLv/IQtxbch9A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-placeholder": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-placeholder/-/extension-placeholder-3.27.3.tgz", - "integrity": "sha512-Y43dGaN3rA0oU4CWmXkZ2idjZjrxPX9oy0zZL92EgXOguhAUToBs0dIxRG5ZanYX9A8kKKWPlfeRFlBMtRhKvg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extensions": "3.27.3" - } - }, - "node_modules/@tiptap/extension-strike": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-strike/-/extension-strike-3.27.3.tgz", - "integrity": "sha512-dp6Rs3I4zLVJPvAw2Q9yrNuYKcX5LTONH3/oyULvGsrqq5DKz7pqscfwhwnDSzrgm/3aCz6B9r1BVHlYI/DXlA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-table": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-table/-/extension-table-3.27.3.tgz", - "integrity": "sha512-P7iQ0SkkDWZwnXzQDOVFLXktXlX67VQ3s2YxoJYKTHlc8rPZ4UCaSogFq0G2APyBlizlY3LbMNrDeZAVFOD8wQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/extension-table-cell": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-table-cell/-/extension-table-cell-3.27.3.tgz", - "integrity": "sha512-W8onBLgjge3D2PlYetbPC/BvwH5jgYfL9PLqMurfCPD7t8fyU4s+4E3SwbZkuf6eCH0twBjqyapH7+sOW/sPhA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-table": "3.27.3" - } - }, - "node_modules/@tiptap/extension-table-header": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-table-header/-/extension-table-header-3.27.3.tgz", - "integrity": "sha512-8iBOxh0S1Wh5VC1rmVTZVJKanGhJpZd5E5O7Pycf+KKUu+BcWQZ17ewj3+VVSdU76sDCUWIjQE0qJ/EyI1vZeg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-table": "3.27.3" - } - }, - "node_modules/@tiptap/extension-table-row": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-table-row/-/extension-table-row-3.27.3.tgz", - "integrity": "sha512-AFMVQI+1kRh97++g+NA6MjATpwQPvjar4JUyaGlnSBIt+b5sYLTW3qQS8EzpMbKPqUp7uZOX9EkLgpvepWYSow==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-table": "3.27.3" - } - }, - "node_modules/@tiptap/extension-task-item": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-task-item/-/extension-task-item-3.27.3.tgz", - "integrity": "sha512-CajIPpHTsuE1l+bM3xKgpZ/3PTvRuFb+ZEyC+yxI/cY2pZd4EJ7iXHT5Fl3ITwdDq8/syVev1BBZ/QDZTOA3rw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-list": "3.27.3" - } - }, - "node_modules/@tiptap/extension-task-list": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-task-list/-/extension-task-list-3.27.3.tgz", - "integrity": "sha512-g1zp2SnR+3DbsXbK1GbAucrj0lh1WnTarp1YPY4beFENzjAPklyVIpF22IjFZD/08QWN1j1fRN3zVzTGHuFXFA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extension-list": "3.27.3" - } - }, - "node_modules/@tiptap/extension-text": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-text/-/extension-text-3.27.3.tgz", - "integrity": "sha512-wSatZ/bop0pleeC18nF90zvWWEoRe/ewZncvm8LjcMrXwq41kTEs3j7nZflMYAh7X8fZvu00UIMeEyCNJl+5Yg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-text-align": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-text-align/-/extension-text-align-3.27.3.tgz", - "integrity": "sha512-yyhlwRz0Eh6xQCn+GtTDWUGqxGajT02Qf8zBN/3eZQtl3EZ2xrI8lvfLmcV9SAW0srgMd+5hX0CVV+zKeXuxeg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-text-style": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-text-style/-/extension-text-style-3.27.3.tgz", - "integrity": "sha512-oim4RqFtMBCA4N+J8f8dTFFYZrwyfmXLxLL5SvQkn+kkpfGLv8PqJCnJ4uHxsnHXDNsWHBtVVhfTGUABZsTEHg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extension-underline": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extension-underline/-/extension-underline-3.27.3.tgz", - "integrity": "sha512-YH7ka/Rp7ZwlzTuQCcs0OZ4CMSx/P/MzbseQKxKebEIZreWaKMZAaED97Fnu0dA66VlreD4/1C7xHJy84ovamg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3" - } - }, - "node_modules/@tiptap/extensions": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/extensions/-/extensions-3.27.3.tgz", - "integrity": "sha512-IA2QKUVJgzUPEhhkUfr6P5u5GFVfhiApiEaaHXBz07saL2c4HNoVs2RC18QlZDCtLNKrPR1mUScr72u7uYs+YQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3" - } - }, - "node_modules/@tiptap/pm": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/pm/-/pm-3.27.3.tgz", - "integrity": "sha512-ppiG57RxM3HSHHgcHT0hP6Ib4P56Sd5itxdV4w0hIGHKPGyLLKiAkYp+htIHa9T7IvjMdaqxIlsfyV3ZKsS1sw==", - "license": "MIT", - "dependencies": { - "prosemirror-changeset": "^2.4.1", - "prosemirror-commands": "^1.7.1", - "prosemirror-dropcursor": "^1.8.2", - "prosemirror-gapcursor": "^1.4.1", - "prosemirror-history": "^1.5.0", - "prosemirror-inputrules": "^1.5.1", - "prosemirror-keymap": "^1.2.3", - "prosemirror-model": "^1.25.9", - "prosemirror-schema-list": "^1.5.1", - "prosemirror-state": "^1.4.4", - "prosemirror-tables": "^1.8.5", - "prosemirror-transform": "^1.12.0", - "prosemirror-view": "^1.41.9" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - } - }, - "node_modules/@tiptap/react": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/react/-/react-3.27.3.tgz", - "integrity": "sha512-lanXxMScw/LevbRFuFw5MoQJ1grmHUDszwph2VIk4l2U5e/EDIw3rr4CeDME6Z4isVReD6zccMFVShkHqsv+jg==", - "license": "MIT", - "dependencies": { - "@types/use-sync-external-store": "^0.0.6", - "fast-equals": "^5.3.3", - "use-sync-external-store": "^1.4.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "optionalDependencies": { - "@tiptap/extension-bubble-menu": "^3.27.3", - "@tiptap/extension-floating-menu": "^3.27.3" - }, - "peerDependencies": { - "@tiptap/core": "3.27.3", - "@tiptap/pm": "3.27.3", - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@tiptap/starter-kit": { - "version": "3.27.3", - "resolved": "https://registry.npmmirror.com/@tiptap/starter-kit/-/starter-kit-3.27.3.tgz", - "integrity": "sha512-xX3baFqiC30skntdhxUUvyJo755ON9c1pE83+2Wiq2g+Qnffg9knUuLCZStHoZZ318yB0aBsKAMvHWLtYDo8AA==", - "license": "MIT", - "dependencies": { - "@tiptap/core": "^3.27.3", - "@tiptap/extension-blockquote": "^3.27.3", - "@tiptap/extension-bold": "^3.27.3", - "@tiptap/extension-bullet-list": "^3.27.3", - "@tiptap/extension-code": "^3.27.3", - "@tiptap/extension-code-block": "^3.27.3", - "@tiptap/extension-document": "^3.27.3", - "@tiptap/extension-dropcursor": "^3.27.3", - "@tiptap/extension-gapcursor": "^3.27.3", - "@tiptap/extension-hard-break": "^3.27.3", - "@tiptap/extension-heading": "^3.27.3", - "@tiptap/extension-horizontal-rule": "^3.27.3", - "@tiptap/extension-italic": "^3.27.3", - "@tiptap/extension-link": "^3.27.3", - "@tiptap/extension-list": "^3.27.3", - "@tiptap/extension-list-item": "^3.27.3", - "@tiptap/extension-list-keymap": "^3.27.3", - "@tiptap/extension-ordered-list": "^3.27.3", - "@tiptap/extension-paragraph": "^3.27.3", - "@tiptap/extension-strike": "^3.27.3", - "@tiptap/extension-text": "^3.27.3", - "@tiptap/extension-underline": "^3.27.3", - "@tiptap/extensions": "^3.27.3", - "@tiptap/pm": "^3.27.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/@tootallnate/once/-/once-2.0.1.tgz", - "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/@trickfilm400/rollup-plugin-off-main-thread": { - "version": "3.0.0-pre1", - "resolved": "https://registry.npmmirror.com/@trickfilm400/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-3.0.0-pre1.tgz", - "integrity": "sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "ejs": "^3.1.10", - "json5": "^2.2.3", - "magic-string": "^0.30.21", - "string.prototype.matchall": "^4.0.12" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@tweenjs/tween.js": { - "version": "23.1.3", - "resolved": "https://registry.npmmirror.com/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", - "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", - "license": "MIT" - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmmirror.com/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/better-sqlite3": { - "version": "7.6.13", - "resolved": "https://registry.npmmirror.com/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", - "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmmirror.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmmirror.com/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmmirror.com/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "license": "MIT" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "license": "MIT" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", - "license": "MIT", - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmmirror.com/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", - "license": "MIT", - "dependencies": { - "@types/d3-time": "*" - } - }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmmirror.com/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", - "license": "MIT", - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmmirror.com/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" - }, - "node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmmirror.com/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/dompurify": { - "version": "3.0.5", - "resolved": "https://registry.npmmirror.com/@types/dompurify/-/dompurify-3.0.5.tgz", - "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/trusted-types": "*" - } - }, - "node_modules/@types/draco3d": { - "version": "1.4.10", - "resolved": "https://registry.npmmirror.com/@types/draco3d/-/draco3d-1.4.10.tgz", - "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/fs-extra": { - "version": "9.0.13", - "resolved": "https://registry.npmmirror.com/@types/fs-extra/-/fs-extra-9.0.13.tgz", - "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmmirror.com/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.13.3", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-24.13.3.tgz", - "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/offscreencanvas": { - "version": "2019.7.3", - "resolved": "https://registry.npmmirror.com/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", - "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", - "license": "MIT" - }, - "node_modules/@types/plist": { - "version": "3.0.5", - "resolved": "https://registry.npmmirror.com/@types/plist/-/plist-3.0.5.tgz", - "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, - "node_modules/@types/pngjs": { - "version": "6.0.5", - "resolved": "https://registry.npmmirror.com/@types/pngjs/-/pngjs-6.0.5.tgz", - "integrity": "sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.31", - "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.31.tgz", - "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@types/react-reconciler": { - "version": "0.26.7", - "resolved": "https://registry.npmmirror.com/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", - "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmmirror.com/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/stats.js": { - "version": "0.17.4", - "resolved": "https://registry.npmmirror.com/@types/stats.js/-/stats.js-0.17.4.tgz", - "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", - "license": "MIT" - }, - "node_modules/@types/three": { - "version": "0.185.1", - "resolved": "https://registry.npmmirror.com/@types/three/-/three-0.185.1.tgz", - "integrity": "sha512-db1xTb+EgYF2didW+eudSvVPtn75zo+fGsY8ShQrJY/B5ZBmC2Fiaykv3aImHAlCNEGuMPkPGXBJGLwzu5mC7A==", - "license": "MIT", - "dependencies": { - "@dimforge/rapier3d-compat": "~0.12.0", - "@tweenjs/tween.js": "~23.1.3", - "@types/stats.js": "*", - "@types/webxr": ">=0.5.17", - "fflate": "~0.8.2", - "meshoptimizer": "~1.1.1" - } - }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.6", - "resolved": "https://registry.npmmirror.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", - "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", - "license": "MIT" - }, - "node_modules/@types/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmmirror.com/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/verror": { - "version": "1.10.11", - "resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.11.tgz", - "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/@types/webxr": { - "version": "0.5.24", - "resolved": "https://registry.npmmirror.com/@types/webxr/-/webxr-0.5.24.tgz", - "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", - "license": "MIT" - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmmirror.com/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@use-gesture/core": { - "version": "10.3.1", - "resolved": "https://registry.npmmirror.com/@use-gesture/core/-/core-10.3.1.tgz", - "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", - "license": "MIT" - }, - "node_modules/@use-gesture/react": { - "version": "10.3.1", - "resolved": "https://registry.npmmirror.com/@use-gesture/react/-/react-10.3.1.tgz", - "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", - "license": "MIT", - "dependencies": { - "@use-gesture/core": "10.3.1" - }, - "peerDependencies": { - "react": ">= 16.8.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "6.0.3", - "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz", - "integrity": "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rolldown/pluginutils": "^1.0.1" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@rolldown/plugin-babel": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.10", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.10", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@xmldom/xmldom": { - "version": "0.9.10", - "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.9.10.tgz", - "integrity": "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.6" - } - }, - "node_modules/7zip-bin": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/7zip-bin/-/7zip-bin-5.2.0.tgz", - "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "license": "ISC" - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/accepts/node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmmirror.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/app-builder-bin": { - "version": "5.0.0-alpha.10", - "resolved": "https://registry.npmmirror.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.10.tgz", - "integrity": "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==", - "dev": true, - "license": "MIT" - }, - "node_modules/app-builder-lib": { - "version": "25.1.8", - "resolved": "https://registry.npmmirror.com/app-builder-lib/-/app-builder-lib-25.1.8.tgz", - "integrity": "sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@develar/schema-utils": "~2.6.5", - "@electron/notarize": "2.5.0", - "@electron/osx-sign": "1.3.1", - "@electron/rebuild": "3.6.1", - "@electron/universal": "2.0.1", - "@malept/flatpak-bundler": "^0.4.0", - "@types/fs-extra": "9.0.13", - "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.9", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chromium-pickle-js": "^0.2.0", - "config-file-ts": "0.2.8-rc1", - "debug": "^4.3.4", - "dotenv": "^16.4.5", - "dotenv-expand": "^11.0.6", - "ejs": "^3.1.8", - "electron-publish": "25.1.7", - "form-data": "^4.0.0", - "fs-extra": "^10.1.0", - "hosted-git-info": "^4.1.0", - "is-ci": "^3.0.0", - "isbinaryfile": "^5.0.0", - "js-yaml": "^4.1.0", - "json5": "^2.2.3", - "lazy-val": "^1.0.5", - "minimatch": "^10.0.0", - "resedit": "^1.7.0", - "sanitize-filename": "^1.6.3", - "semver": "^7.3.8", - "tar": "^6.1.12", - "temp-file": "^3.4.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "dmg-builder": "25.1.8", - "electron-builder-squirrel-windows": "25.1.8" - } - }, - "node_modules/app-builder-lib/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/app-builder-lib/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/aproba": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/aproba/-/aproba-2.1.0.tgz", - "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", - "dev": true, - "license": "ISC" - }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmmirror.com/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/archiver-utils/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/archiver-utils/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/archiver-utils/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/archiver-utils/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/aria-hidden": { - "version": "1.2.6", - "resolved": "https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.6.tgz", - "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmmirror.com/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmmirror.com/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, - "license": "MIT" - }, - "node_modules/async-exit-hook": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz", - "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/autoprefixer": { - "version": "10.5.2", - "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.5.2.tgz", - "integrity": "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.4", - "caniuse-lite": "^1.0.30001799", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axios": { - "version": "1.18.1", - "resolved": "https://registry.npmmirror.com/axios/-/axios-1.18.1.tgz", - "integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/axios/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/axios/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.17", - "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", - "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.8", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.14.2", - "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", - "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8", - "core-js-compat": "^3.48.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.8", - "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", - "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.42", - "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz", - "integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/better-sqlite3": { - "version": "11.10.0", - "resolved": "https://registry.npmmirror.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz", - "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "bindings": "^1.5.0", - "prebuild-install": "^7.1.1" - } - }, - "node_modules/bidi-js": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/bidi-js/-/bidi-js-1.0.3.tgz", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", - "license": "MIT", - "dependencies": { - "require-from-string": "^2.0.2" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/bluebird-lst": { - "version": "1.0.9", - "resolved": "https://registry.npmmirror.com/bluebird-lst/-/bluebird-lst-1.0.9.tgz", - "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bluebird": "^3.5.5" - } - }, - "node_modules/body-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-2.3.0.tgz", - "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^2.0.0", - "debug": "^4.4.3", - "http-errors": "^2.0.1", - "iconv-lite": "^0.7.2", - "on-finished": "^2.4.1", - "qs": "^6.15.2", - "raw-body": "^3.0.2", - "type-is": "^2.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/body-parser/node_modules/content-type": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.7.3", - "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.3.tgz", - "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.5", - "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.5.tgz", - "integrity": "sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.10.42", - "caniuse-lite": "^1.0.30001800", - "electron-to-chromium": "^1.5.387", - "node-releases": "^2.0.50", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmmirror.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/builder-util": { - "version": "25.1.7", - "resolved": "https://registry.npmmirror.com/builder-util/-/builder-util-25.1.7.tgz", - "integrity": "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/debug": "^4.1.6", - "7zip-bin": "~5.2.0", - "app-builder-bin": "5.0.0-alpha.10", - "bluebird-lst": "^1.0.9", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "debug": "^4.3.4", - "fs-extra": "^10.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "is-ci": "^3.0.0", - "js-yaml": "^4.1.0", - "source-map-support": "^0.5.19", - "stat-mode": "^1.0.0", - "temp-file": "^3.4.0" - } - }, - "node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmmirror.com/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/builder-util/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmmirror.com/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/cacache/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.9", - "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.9.tgz", - "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", - "dev": true, - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/camera-controls": { - "version": "2.10.1", - "resolved": "https://registry.npmmirror.com/camera-controls/-/camera-controls-2.10.1.tgz", - "integrity": "sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==", - "license": "MIT", - "peerDependencies": { - "three": ">=0.126.1" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001803", - "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001803.tgz", - "integrity": "sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmmirror.com/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/chromium-pickle-js": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", - "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/class-variance-authority": { - "version": "0.7.1", - "resolved": "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz", - "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", - "license": "Apache-2.0", - "dependencies": { - "clsx": "^2.1.1" - }, - "funding": { - "url": "https://polar.sh/cva" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmmirror.com/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmmirror.com/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/compare-version": { - "version": "0.1.2", - "resolved": "https://registry.npmmirror.com/compare-version/-/compare-version-0.1.2.tgz", - "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concurrently": { - "version": "10.0.3", - "resolved": "https://registry.npmmirror.com/concurrently/-/concurrently-10.0.3.tgz", - "integrity": "sha512-hc3LH4UaKWd/bbyDK/IGVa4RB6PtQ3CUYwtrkzqHn+wIG3Hr5fhpRlk0L/gCa8ZE1L/Ufj50Zho69cI5w8SQBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "5.6.2", - "rxjs": "7.8.2", - "shell-quote": "1.8.4", - "supports-color": "10.2.2", - "tree-kill": "1.2.2", - "yargs": "18.0.0" - }, - "bin": { - "conc": "dist/bin/index.js", - "concurrently": "dist/bin/index.js" - }, - "engines": { - "node": ">=22" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmmirror.com/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/concurrently/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/concurrently/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/concurrently/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "10.2.2", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-10.2.2.tgz", - "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmmirror.com/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/concurrently/node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/config-file-ts": { - "version": "0.2.8-rc1", - "resolved": "https://registry.npmmirror.com/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz", - "integrity": "sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "glob": "^10.3.12", - "typescript": "^5.4.3" - } - }, - "node_modules/config-file-ts/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/config-file-ts/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/config-file-ts/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/config-file-ts/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/config-file-ts/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/config-file-ts/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/config-file-ts/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmmirror.com/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/config-file-ts/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/config-file-ts/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/config-file-ts/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/config-file-ts/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/config-file-ts/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/core-js-compat": { - "version": "3.49.0", - "resolved": "https://registry.npmmirror.com/core-js-compat/-/core-js-compat-3.49.0.tgz", - "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/crc": { - "version": "3.8.0", - "resolved": "https://registry.npmmirror.com/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.1.0" - } - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cross-env": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-10.1.0.tgz", - "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@epic-web/invariant": "^1.0.0", - "cross-spawn": "^7.0.6" - }, - "bin": { - "cross-env": "dist/bin/cross-env.js", - "cross-env-shell": "dist/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/css-tree": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-3.2.1.tgz", - "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdn-data": "2.27.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/d3-format/-/d3-format-3.1.2.tgz", - "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmmirror.com/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/data-urls": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/data-urls/-/data-urls-7.0.0.tgz", - "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, - "license": "MIT" - }, - "node_modules/decimal.js-light": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz", - "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", - "license": "MIT" - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-gpu": { - "version": "5.0.70", - "resolved": "https://registry.npmmirror.com/detect-gpu/-/detect-gpu-5.0.70.tgz", - "integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==", - "license": "MIT", - "dependencies": { - "webgl-constants": "^1.1.1" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "license": "MIT" - }, - "node_modules/dexie": { - "version": "4.4.4", - "resolved": "https://registry.npmmirror.com/dexie/-/dexie-4.4.4.tgz", - "integrity": "sha512-jIwsYI8Os2hgnqc6O49YwFDKGc5v5QjGx0wPVp543ip1F53VFAKMLthV2pQosQcVTv3eAskTWYspOx195PM0FQ==", - "license": "Apache-2.0" - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "license": "Apache-2.0" - }, - "node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmmirror.com/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-compare": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/dir-compare/-/dir-compare-4.2.0.tgz", - "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimatch": "^3.0.5", - "p-limit": "^3.1.0 " - } - }, - "node_modules/dir-compare/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/dir-compare/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/dir-compare/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "license": "MIT" - }, - "node_modules/dmg-builder": { - "version": "25.1.8", - "resolved": "https://registry.npmmirror.com/dmg-builder/-/dmg-builder-25.1.8.tgz", - "integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "fs-extra": "^10.1.0", - "iconv-lite": "^0.6.2", - "js-yaml": "^4.1.0" - }, - "optionalDependencies": { - "dmg-license": "^1.0.11" - } - }, - "node_modules/dmg-builder/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dmg-license": { - "version": "1.0.11", - "resolved": "https://registry.npmmirror.com/dmg-license/-/dmg-license-1.0.11.tgz", - "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - }, - "bin": { - "dmg-license": "bin/dmg-license.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dmg-license/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/dmg-license/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmmirror.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/dompurify": { - "version": "3.4.12", - "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.4.12.tgz", - "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-expand": { - "version": "11.0.7", - "resolved": "https://registry.npmmirror.com/dotenv-expand/-/dotenv-expand-11.0.7.tgz", - "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^16.4.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/draco3d": { - "version": "1.5.7", - "resolved": "https://registry.npmmirror.com/draco3d/-/draco3d-1.5.7.tgz", - "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", - "license": "Apache-2.0" - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmmirror.com/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron": { - "version": "35.7.5", - "resolved": "https://registry.npmmirror.com/electron/-/electron-35.7.5.tgz", - "integrity": "sha512-dnL+JvLraKZl7iusXTVTGYs10TKfzUi30uEDTqsmTm0guN9V2tbOjTzyIZbh9n3ygUjgEYyo+igAwMRXIi3IPw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^22.7.7", - "extract-zip": "^2.0.1" - }, - "bin": { - "electron": "cli.js" - }, - "engines": { - "node": ">= 12.20.55" - } - }, - "node_modules/electron-builder": { - "version": "25.1.8", - "resolved": "https://registry.npmmirror.com/electron-builder/-/electron-builder-25.1.8.tgz", - "integrity": "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig==", - "dev": true, - "license": "MIT", - "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "dmg-builder": "25.1.8", - "fs-extra": "^10.1.0", - "is-ci": "^3.0.0", - "lazy-val": "^1.0.5", - "simple-update-notifier": "2.0.0", - "yargs": "^17.6.2" - }, - "bin": { - "electron-builder": "cli.js", - "install-app-deps": "install-app-deps.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/electron-builder-squirrel-windows": { - "version": "25.1.8", - "resolved": "https://registry.npmmirror.com/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-25.1.8.tgz", - "integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "app-builder-lib": "25.1.8", - "archiver": "^5.3.1", - "builder-util": "25.1.7", - "fs-extra": "^10.1.0" - } - }, - "node_modules/electron-builder-squirrel-windows/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-builder/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-publish": { - "version": "25.1.7", - "resolved": "https://registry.npmmirror.com/electron-publish/-/electron-publish-25.1.7.tgz", - "integrity": "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^9.0.11", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "fs-extra": "^10.1.0", - "lazy-val": "^1.0.5", - "mime": "^2.5.2" - } - }, - "node_modules/electron-publish/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-rebuild": { - "version": "3.2.9", - "resolved": "https://registry.npmmirror.com/electron-rebuild/-/electron-rebuild-3.2.9.tgz", - "integrity": "sha512-FkEZNFViUem3P0RLYbZkUjC8LUFIK+wKq09GHoOITSJjfDAVQv964hwaNseTTWt58sITQX3/5fHNYcTefqaCWw==", - "deprecated": "Please use @electron/rebuild moving forward. There is no API change, just a package name change", - "dev": true, - "license": "MIT", - "dependencies": { - "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", - "debug": "^4.1.1", - "detect-libc": "^2.0.1", - "fs-extra": "^10.0.0", - "got": "^11.7.0", - "lzma-native": "^8.0.5", - "node-abi": "^3.0.0", - "node-api-version": "^0.1.4", - "node-gyp": "^9.0.0", - "ora": "^5.1.0", - "semver": "^7.3.5", - "tar": "^6.0.5", - "yargs": "^17.0.1" - }, - "bin": { - "electron-rebuild": "lib/src/cli.js" - }, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/electron-rebuild/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-rebuild/node_modules/node-api-version": { - "version": "0.1.4", - "resolved": "https://registry.npmmirror.com/node-api-version/-/node-api-version-0.1.4.tgz", - "integrity": "sha512-KGXihXdUChwJAOHO53bv9/vXcLmdUsZ6jIptbvYvkpKfth+r7jw44JkVxQFA3kX5nQjzjmGu1uAu/xNNLNlI5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - } - }, - "node_modules/electron-rebuild/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.389", - "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.389.tgz", - "integrity": "sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==", - "dev": true, - "license": "ISC" - }, - "node_modules/electron-updater": { - "version": "6.8.9", - "resolved": "https://registry.npmmirror.com/electron-updater/-/electron-updater-6.8.9.tgz", - "integrity": "sha512-ZhVxM9iGONUpZGI1FxdMRgJjUFXi7AYGVa5PwKlO1tV1/4zDxQmfKpXOHVztKrd6L9rLcFjERvi1Mf2vxyTkig==", - "license": "MIT", - "dependencies": { - "builder-util-runtime": "9.7.0", - "fs-extra": "^10.1.0", - "js-yaml": "^4.1.0", - "lazy-val": "^1.0.5", - "lodash.escaperegexp": "^4.1.2", - "lodash.isequal": "^4.5.0", - "semver": "~7.7.3", - "tiny-typed-emitter": "^2.1.0" - } - }, - "node_modules/electron-updater/node_modules/builder-util-runtime": { - "version": "9.7.0", - "resolved": "https://registry.npmmirror.com/builder-util-runtime/-/builder-util-runtime-9.7.0.tgz", - "integrity": "sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/electron-updater/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-updater/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron/node_modules/@types/node": { - "version": "22.20.1", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.20.1.tgz", - "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/electron/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/entities/-/entities-8.0.0.tgz", - "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-abstract": { - "version": "1.24.2", - "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.24.2.tgz", - "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract-get": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/es-abstract-get/-/es-abstract-get-1.0.0.tgz", - "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.2", - "is-callable": "^1.2.7", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-2.3.0.tgz", - "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.4", - "resolved": "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.3.4.tgz", - "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-abstract-get": "^1.0.0", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "is-callable": "^1.2.7", - "is-date-object": "^1.1.0", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-toolkit": { - "version": "1.49.0", - "resolved": "https://registry.npmmirror.com/es-toolkit/-/es-toolkit-1.49.0.tgz", - "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eta": { - "version": "4.6.0", - "resolved": "https://registry.npmmirror.com/eta/-/eta-4.6.0.tgz", - "integrity": "sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/bgub/eta?sponsor=1" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "license": "MIT" - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.1.0.tgz", - "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/expect-type": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/expect-type/-/expect-type-1.4.0.tgz", - "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz", - "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.5.2", - "resolved": "https://registry.npmmirror.com/express-rate-limit/-/express-rate-limit-8.5.2.tgz", - "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", - "license": "MIT", - "dependencies": { - "ip-address": "^10.2.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/express/node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.4.1", - "resolved": "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.4.1.tgz", - "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT", - "optional": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-equals": { - "version": "5.4.0", - "resolved": "https://registry.npmmirror.com/fast-equals/-/fast-equals-5.4.0.tgz", - "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fflate": { - "version": "0.8.3", - "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.3.tgz", - "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", - "license": "MIT" - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" - }, - "node_modules/filelist": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/filelist/-/filelist-1.0.6.tgz", - "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.6", - "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.6.tgz", - "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.4", - "mime-types": "^2.1.35" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/framer-motion": { - "version": "12.42.2", - "resolved": "https://registry.npmmirror.com/framer-motion/-/framer-motion-12.42.2.tgz", - "integrity": "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw==", - "license": "MIT", - "dependencies": { - "motion-dom": "^12.42.2", - "motion-utils": "^12.39.0", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.2.0.tgz", - "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2", - "hasown": "^2.0.4", - "is-callable": "^1.2.7", - "is-document.all": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmmirror.com/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gauge/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", - "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true, - "license": "ISC" - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmmirror.com/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT" - }, - "node_modules/glob": { - "version": "11.1.0", - "resolved": "https://registry.npmmirror.com/glob/-/glob-11.1.0.tgz", - "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/global-agent": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/global-agent/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glsl-noise": { - "version": "0.0.0", - "resolved": "https://registry.npmmirror.com/glsl-noise/-/glsl-noise-0.0.0.tgz", - "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==", - "license": "MIT" - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmmirror.com/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hls.js": { - "version": "1.6.16", - "resolved": "https://registry.npmmirror.com/hls.js/-/hls.js-1.6.16.tgz", - "integrity": "sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==", - "license": "Apache-2.0" - }, - "node_modules/hono": { - "version": "4.12.30", - "resolved": "https://registry.npmmirror.com/hono/-/hono-4.12.30.tgz", - "integrity": "sha512-emn+JoJjrN9YTpRDS5it/UI2SO9BAE37T6I3d963RxcZ81G9A4pr2SZTEiiaiKbzx+NKRg5BZ89fCL7gCJCUog==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/html-encoding-sniffer": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", - "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.6.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iceberg-js": { - "version": "0.8.1", - "resolved": "https://registry.npmmirror.com/iceberg-js/-/iceberg-js-0.8.1.tgz", - "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/iconv-corefoundation": { - "version": "1.1.7", - "resolved": "https://registry.npmmirror.com/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", - "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - }, - "engines": { - "node": "^8.11.2 || >=10" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, - "node_modules/immer": { - "version": "11.1.11", - "resolved": "https://registry.npmmirror.com/immer/-/immer-11.1.11.tgz", - "integrity": "sha512-qzXuyXAkPySAGYkfsAwodDPWT8Zm7/Uo5BNt4BjhMhG5WlWyZZ4wQqnWwdS8kjlQ1Cwu6gjw3A6+0gTQwlyYtw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true, - "license": "ISC" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/ip-address": { - "version": "10.2.0", - "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.2.0.tgz", - "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-document.all": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-document.all/-/is-document.all-1.0.0.tgz", - "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isbinaryfile": { - "version": "5.0.7", - "resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-5.0.7.tgz", - "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/its-fine": { - "version": "1.2.5", - "resolved": "https://registry.npmmirror.com/its-fine/-/its-fine-1.2.5.tgz", - "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", - "license": "MIT", - "dependencies": { - "@types/react-reconciler": "^0.28.0" - }, - "peerDependencies": { - "react": ">=18.0" - } - }, - "node_modules/its-fine/node_modules/@types/react-reconciler": { - "version": "0.28.9", - "resolved": "https://registry.npmmirror.com/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", - "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*" - } - }, - "node_modules/jackspeak": { - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-4.2.3.tgz", - "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^9.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmmirror.com/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmmirror.com/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/joi": { - "version": "18.2.3", - "resolved": "https://registry.npmmirror.com/joi/-/joi-18.2.3.tgz", - "integrity": "sha512-N5A3KTWQpPWT4ExxxPlUx7WmykGXRzhNidWhV41d6Abu9YfI2NyWCJuxdPnslJCPWtbRpSVOWSnSS6GakLM/Rg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/address": "^5.1.1", - "@hapi/formula": "^3.0.2", - "@hapi/hoek": "^11.0.7", - "@hapi/pinpoint": "^2.0.1", - "@hapi/tlds": "^1.1.1", - "@hapi/topo": "^6.0.2", - "@standard-schema/spec": "^1.1.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/jose": { - "version": "6.2.3", - "resolved": "https://registry.npmmirror.com/jose/-/jose-6.2.3.tgz", - "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "29.1.1", - "resolved": "https://registry.npmmirror.com/jsdom/-/jsdom-29.1.1.tgz", - "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^5.1.11", - "@asamuzakjp/dom-selector": "^7.1.1", - "@bramus/specificity": "^2.4.2", - "@csstools/css-syntax-patches-for-csstree": "^1.1.3", - "@exodus/bytes": "^1.15.0", - "css-tree": "^3.2.1", - "data-urls": "^7.0.0", - "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^6.0.0", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.3.5", - "parse5": "^8.0.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.1", - "undici": "^7.25.0", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.1", - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.1", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24.0.0" - }, - "peerDependencies": { - "canvas": "^3.0.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/lazy-val": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/lazy-val/-/lazy-val-1.0.5.tgz", - "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", - "license": "MIT" - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, - "node_modules/linkifyjs": { - "version": "4.3.3", - "resolved": "https://registry.npmmirror.com/linkifyjs/-/linkifyjs-4.3.3.tgz", - "integrity": "sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==", - "license": "MIT" - }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmmirror.com/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", - "license": "MIT" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmmirror.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmmirror.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmmirror.com/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/lucide-react": { - "version": "1.23.0", - "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-1.23.0.tgz", - "integrity": "sha512-38BpJcD0JhFosxHApP/BYsBetLpQFRoTRzEzstM/XCc3jsAG7wqaY1lgVwxiUe3xqYE+lNxo2PkCmYwXWrwwIw==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/lxgw-wenkai-lite-webfont": { - "version": "1.7.0", - "resolved": "https://registry.npmmirror.com/lxgw-wenkai-lite-webfont/-/lxgw-wenkai-lite-webfont-1.7.0.tgz", - "integrity": "sha512-VcQYNRpdXAxaZsJ18rfT1mmAreGqkIFNZ/9pdVLbT2Tkb+2lLWJDXq4zYxMEk9AcecSnxO31R2LHh5ieLlxjRg==", - "license": "MIT" - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/lzma-native": { - "version": "8.0.6", - "resolved": "https://registry.npmmirror.com/lzma-native/-/lzma-native-8.0.6.tgz", - "integrity": "sha512-09xfg67mkL2Lz20PrrDeNYZxzeW7ADtpYFbwSQh9U8+76RIzx5QsJBMy8qikv3hbUPfpy6hqwxt6FcGK81g9AA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^3.1.0", - "node-gyp-build": "^4.2.1", - "readable-stream": "^3.6.0" - }, - "bin": { - "lzmajs": "bin/lzmajs" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/lzma-native/node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/maath": { - "version": "0.10.8", - "resolved": "https://registry.npmmirror.com/maath/-/maath-0.10.8.tgz", - "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", - "license": "MIT", - "peerDependencies": { - "@types/three": ">=0.134.0", - "three": ">=0.134.0" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmmirror.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/make-fetch-happen/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdn-data": { - "version": "2.27.1", - "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.27.1.tgz", - "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/meshline": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/meshline/-/meshline-3.3.1.tgz", - "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==", - "license": "MIT", - "peerDependencies": { - "three": ">=0.137" - } - }, - "node_modules/meshoptimizer": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/meshoptimizer/-/meshoptimizer-1.1.1.tgz", - "integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==", - "license": "MIT" - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmmirror.com/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-fetch/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-fetch/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-flush": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/minipass-flush/-/minipass-flush-1.0.7.tgz", - "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmmirror.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" - }, - "node_modules/motion-dom": { - "version": "12.42.2", - "resolved": "https://registry.npmmirror.com/motion-dom/-/motion-dom-12.42.2.tgz", - "integrity": "sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA==", - "license": "MIT", - "dependencies": { - "motion-utils": "^12.39.0" - } - }, - "node_modules/motion-utils": { - "version": "12.39.0", - "resolved": "https://registry.npmmirror.com/motion-utils/-/motion-utils-12.39.0.tgz", - "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/n8ao": { - "version": "1.10.3", - "resolved": "https://registry.npmmirror.com/n8ao/-/n8ao-1.10.3.tgz", - "integrity": "sha512-JFRk4WgUAUWO2KdJTqmBT02dP9kG7rE2oQbBy64E9+YwQ3d96KB9QBanqNy/NnYUfUTYU6Z/5OS5t/yLey7+6Q==", - "license": "ISC", - "peerDependencies": { - "postprocessing": ">=6.30.0", - "three": ">=0.137" - } - }, - "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-abi": { - "version": "3.94.0", - "resolved": "https://registry.npmmirror.com/node-abi/-/node-abi-3.94.0.tgz", - "integrity": "sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/node-api-version": { - "version": "0.2.1", - "resolved": "https://registry.npmmirror.com/node-api-version/-/node-api-version-0.2.1.tgz", - "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - } - }, - "node_modules/node-api-version/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmmirror.com/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmmirror.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "dev": true, - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-gyp/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-releases": { - "version": "2.0.50", - "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.50.tgz", - "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obug": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/obug/-/obug-2.1.3.tgz", - "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT", - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/orderedmap": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/orderedmap/-/orderedmap-2.1.1.tgz", - "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", - "license": "MIT" - }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/oxlint": { - "version": "1.73.0", - "resolved": "https://registry.npmmirror.com/oxlint/-/oxlint-1.73.0.tgz", - "integrity": "sha512-u91G9TJzU6yqKWNZUYprQB07W7YvntZXaRxQ6CkoytepYhLWUXWsr1M8zUJ34VatNPuUAr3Z8GH+O2A331CluQ==", - "dev": true, - "license": "MIT", - "bin": { - "oxlint": "bin/oxlint" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/Boshen" - }, - "optionalDependencies": { - "@oxlint/binding-android-arm-eabi": "1.73.0", - "@oxlint/binding-android-arm64": "1.73.0", - "@oxlint/binding-darwin-arm64": "1.73.0", - "@oxlint/binding-darwin-x64": "1.73.0", - "@oxlint/binding-freebsd-x64": "1.73.0", - "@oxlint/binding-linux-arm-gnueabihf": "1.73.0", - "@oxlint/binding-linux-arm-musleabihf": "1.73.0", - "@oxlint/binding-linux-arm64-gnu": "1.73.0", - "@oxlint/binding-linux-arm64-musl": "1.73.0", - "@oxlint/binding-linux-ppc64-gnu": "1.73.0", - "@oxlint/binding-linux-riscv64-gnu": "1.73.0", - "@oxlint/binding-linux-riscv64-musl": "1.73.0", - "@oxlint/binding-linux-s390x-gnu": "1.73.0", - "@oxlint/binding-linux-x64-gnu": "1.73.0", - "@oxlint/binding-linux-x64-musl": "1.73.0", - "@oxlint/binding-openharmony-arm64": "1.73.0", - "@oxlint/binding-win32-arm64-msvc": "1.73.0", - "@oxlint/binding-win32-ia32-msvc": "1.73.0", - "@oxlint/binding-win32-x64-msvc": "1.73.0" - }, - "peerDependencies": { - "oxlint-tsgolint": ">=0.24.0", - "vite-plus": "*" - }, - "peerDependenciesMeta": { - "oxlint-tsgolint": { - "optional": true - }, - "vite-plus": { - "optional": true - } - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmmirror.com/parse5/-/parse5-8.0.1.tgz", - "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^8.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-to-regexp": { - "version": "8.4.2", - "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/pe-library": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/pe-library/-/pe-library-0.4.1.tgz", - "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmmirror.com/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pixelmatch": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/pixelmatch/-/pixelmatch-7.2.0.tgz", - "integrity": "sha512-xhcb4yHu9sM/G7foGzoLtXYcC0zHEaOXXjRKhGup0fw78Nf2Tkiapv4EQyMzrbcmQPsllAI7DbFY2UT7PlI9Pg==", - "license": "ISC", - "dependencies": { - "pngjs": "^7.0.0" - }, - "bin": { - "pixelmatch": "bin/pixelmatch" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/plist": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/plist/-/plist-3.1.1.tgz", - "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.9.10", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/pngjs": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-7.0.0.tgz", - "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", - "license": "MIT", - "engines": { - "node": ">=14.19.0" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.16", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.16.tgz", - "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmmirror.com/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "license": "MIT" - }, - "node_modules/postprocessing": { - "version": "6.39.2", - "resolved": "https://registry.npmmirror.com/postprocessing/-/postprocessing-6.39.2.tgz", - "integrity": "sha512-AxPY+xFyVOsz+8bbHSyQBoOK4AUqSQspTXXIsNcKhmGJRm/afHRAwZ8bKC02AeSPII0PW6lbCN84SgAoWFsKKA==", - "license": "Zlib", - "peerDependencies": { - "three": ">= 0.168.0 < 0.186.0" - } - }, - "node_modules/potpack": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "license": "ISC" - }, - "node_modules/prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pretty-bytes": { - "version": "6.1.1", - "resolved": "https://registry.npmmirror.com/pretty-bytes/-/pretty-bytes-6.1.1.tgz", - "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/promise-worker-transferable": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", - "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", - "license": "Apache-2.0", - "dependencies": { - "is-promise": "^2.1.0", - "lie": "^3.0.2" - } - }, - "node_modules/promise-worker-transferable/node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmmirror.com/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "license": "MIT" - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/prosemirror-changeset": { - "version": "2.4.1", - "resolved": "https://registry.npmmirror.com/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", - "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", - "license": "MIT", - "dependencies": { - "prosemirror-transform": "^1.0.0" - } - }, - "node_modules/prosemirror-commands": { - "version": "1.7.1", - "resolved": "https://registry.npmmirror.com/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", - "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", - "license": "MIT", - "dependencies": { - "prosemirror-model": "^1.0.0", - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.10.2" - } - }, - "node_modules/prosemirror-dropcursor": { - "version": "1.8.3", - "resolved": "https://registry.npmmirror.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.3.tgz", - "integrity": "sha512-FoYbsJR8gK+DGlqhNoE29Loa38eIZPzQRIb1VMaDNBoo4OLP6vVof/jR8qFY/6XvUd6Dhug8MDCHl2a/h8RTfQ==", - "license": "MIT", - "dependencies": { - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.1.0", - "prosemirror-view": "^1.1.0" - } - }, - "node_modules/prosemirror-gapcursor": { - "version": "1.4.1", - "resolved": "https://registry.npmmirror.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", - "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", - "license": "MIT", - "dependencies": { - "prosemirror-keymap": "^1.0.0", - "prosemirror-model": "^1.0.0", - "prosemirror-state": "^1.0.0", - "prosemirror-view": "^1.0.0" - } - }, - "node_modules/prosemirror-history": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/prosemirror-history/-/prosemirror-history-1.5.0.tgz", - "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", - "license": "MIT", - "dependencies": { - "prosemirror-state": "^1.2.2", - "prosemirror-transform": "^1.0.0", - "prosemirror-view": "^1.31.0", - "rope-sequence": "^1.3.0" - } - }, - "node_modules/prosemirror-inputrules": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz", - "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==", - "license": "MIT", - "dependencies": { - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "node_modules/prosemirror-keymap": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", - "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", - "license": "MIT", - "dependencies": { - "prosemirror-state": "^1.0.0", - "w3c-keyname": "^2.2.0" - } - }, - "node_modules/prosemirror-model": { - "version": "1.25.10", - "resolved": "https://registry.npmmirror.com/prosemirror-model/-/prosemirror-model-1.25.10.tgz", - "integrity": "sha512-9n6rH4DbJU1eH4SxLt6Y0HhJIo6cZsb7DJ/30uob1hOKPeO6TAaMWI2tc7kwR92BjfPOU2fFHWbZLovLi3XQfA==", - "license": "MIT", - "dependencies": { - "orderedmap": "^2.0.0" - } - }, - "node_modules/prosemirror-schema-list": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", - "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", - "license": "MIT", - "dependencies": { - "prosemirror-model": "^1.0.0", - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.7.3" - } - }, - "node_modules/prosemirror-state": { - "version": "1.4.4", - "resolved": "https://registry.npmmirror.com/prosemirror-state/-/prosemirror-state-1.4.4.tgz", - "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", - "license": "MIT", - "dependencies": { - "prosemirror-model": "^1.0.0", - "prosemirror-transform": "^1.0.0", - "prosemirror-view": "^1.27.0" - } - }, - "node_modules/prosemirror-tables": { - "version": "1.8.5", - "resolved": "https://registry.npmmirror.com/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", - "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", - "license": "MIT", - "dependencies": { - "prosemirror-keymap": "^1.2.3", - "prosemirror-model": "^1.25.4", - "prosemirror-state": "^1.4.4", - "prosemirror-transform": "^1.10.5", - "prosemirror-view": "^1.41.4" - } - }, - "node_modules/prosemirror-transform": { - "version": "1.12.0", - "resolved": "https://registry.npmmirror.com/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", - "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", - "license": "MIT", - "dependencies": { - "prosemirror-model": "^1.21.0" - } - }, - "node_modules/prosemirror-view": { - "version": "1.42.0", - "resolved": "https://registry.npmmirror.com/prosemirror-view/-/prosemirror-view-1.42.0.tgz", - "integrity": "sha512-N54DF3OXNWDuP81G1kbfCys8ZzIjuL1VnvJ2mk5STSu/fNxWIcX/EutQLA3s9KR/2wVhgDi4hzBB/1fINVxk0A==", - "license": "MIT", - "dependencies": { - "prosemirror-model": "^1.25.8", - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.1.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmmirror.com/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", - "license": "BSD-3-Clause", - "dependencies": { - "es-define-property": "^1.0.1", - "side-channel": "^1.1.1" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/range-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.3.0.tgz", - "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.3", - "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.3.tgz", - "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-composer": { - "version": "5.0.3", - "resolved": "https://registry.npmmirror.com/react-composer/-/react-composer-5.0.3.tgz", - "integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==", - "license": "MIT", - "dependencies": { - "prop-types": "^15.6.0" - }, - "peerDependencies": { - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "license": "MIT", - "peer": true - }, - "node_modules/react-reconciler": { - "version": "0.27.0", - "resolved": "https://registry.npmmirror.com/react-reconciler/-/react-reconciler-0.27.0.tgz", - "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.21.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/react-reconciler/node_modules/scheduler": { - "version": "0.21.0", - "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.21.0.tgz", - "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/react-redux": { - "version": "9.3.0", - "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-9.3.0.tgz", - "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", - "license": "MIT", - "dependencies": { - "@types/use-sync-external-store": "^0.0.6", - "use-sync-external-store": "^1.4.0" - }, - "peerDependencies": { - "@types/react": "^18.2.25 || ^19", - "react": "^18.0 || ^19", - "redux": "^5.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, - "node_modules/react-remove-scroll": { - "version": "2.7.2", - "resolved": "https://registry.npmmirror.com/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", - "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", - "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.3", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.3" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-remove-scroll-bar": { - "version": "2.3.8", - "resolved": "https://registry.npmmirror.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", - "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", - "license": "MIT", - "dependencies": { - "react-style-singleton": "^2.2.2", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-router": { - "version": "7.18.1", - "resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.18.1.tgz", - "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==", - "license": "MIT", - "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/react-router-dom": { - "version": "7.18.1", - "resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.18.1.tgz", - "integrity": "sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==", - "license": "MIT", - "dependencies": { - "react-router": "7.18.1" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - } - }, - "node_modules/react-style-singleton": { - "version": "2.2.3", - "resolved": "https://registry.npmmirror.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz", - "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", - "license": "MIT", - "dependencies": { - "get-nonce": "^1.0.0", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-use-measure": { - "version": "2.1.7", - "resolved": "https://registry.npmmirror.com/react-use-measure/-/react-use-measure-2.1.7.tgz", - "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", - "license": "MIT", - "peerDependencies": { - "react": ">=16.13", - "react-dom": ">=16.13" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/read-binary-file-arch": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", - "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "bin": { - "read-binary-file-arch": "cli.js" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/recharts": { - "version": "3.9.2", - "resolved": "https://registry.npmmirror.com/recharts/-/recharts-3.9.2.tgz", - "integrity": "sha512-G4fy+Pk46RaXgwWMh+Nzhyo/lbFAVqXo9gtetlyehe6Ehge9CsgDuOTwQDD+i1+llaLktNBiNq4bhnGlDRXFtw==", - "license": "MIT", - "workspaces": [ - "www" - ], - "dependencies": { - "@reduxjs/toolkit": "^1.9.0 || 2.x.x", - "clsx": "^2.1.1", - "decimal.js-light": "^2.5.1", - "es-toolkit": "^1.39.3", - "eventemitter3": "^5.0.1", - "immer": "^11.1.8", - "react-redux": "8.x.x || 9.x.x", - "reselect": "5.2.0", - "tiny-invariant": "^1.3.3", - "use-sync-external-store": "^1.2.2", - "victory-vendor": "^37.0.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/redux": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" - }, - "node_modules/redux-thunk": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/redux-thunk/-/redux-thunk-3.1.0.tgz", - "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", - "license": "MIT", - "peerDependencies": { - "redux": "^5.0.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmmirror.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmmirror.com/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmmirror.com/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/regjsparser": { - "version": "0.13.2", - "resolved": "https://registry.npmmirror.com/regjsparser/-/regjsparser-0.13.2.tgz", - "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resedit": { - "version": "1.7.2", - "resolved": "https://registry.npmmirror.com/resedit/-/resedit-1.7.2.tgz", - "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pe-library": "^0.4.1" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, - "node_modules/reselect": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/reselect/-/reselect-5.2.0.tgz", - "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==", - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmmirror.com/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmmirror.com/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/rolldown": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/rolldown/-/rolldown-1.1.5.tgz", - "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.139.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.1.5", - "@rolldown/binding-darwin-arm64": "1.1.5", - "@rolldown/binding-darwin-x64": "1.1.5", - "@rolldown/binding-freebsd-x64": "1.1.5", - "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", - "@rolldown/binding-linux-arm64-gnu": "1.1.5", - "@rolldown/binding-linux-arm64-musl": "1.1.5", - "@rolldown/binding-linux-ppc64-gnu": "1.1.5", - "@rolldown/binding-linux-s390x-gnu": "1.1.5", - "@rolldown/binding-linux-x64-gnu": "1.1.5", - "@rolldown/binding-linux-x64-musl": "1.1.5", - "@rolldown/binding-openharmony-arm64": "1.1.5", - "@rolldown/binding-wasm32-wasi": "1.1.5", - "@rolldown/binding-win32-arm64-msvc": "1.1.5", - "@rolldown/binding-win32-x64-msvc": "1.1.5" - } - }, - "node_modules/rollup": { - "version": "4.62.2", - "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.62.2.tgz", - "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.9" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.62.2", - "@rollup/rollup-android-arm64": "4.62.2", - "@rollup/rollup-darwin-arm64": "4.62.2", - "@rollup/rollup-darwin-x64": "4.62.2", - "@rollup/rollup-freebsd-arm64": "4.62.2", - "@rollup/rollup-freebsd-x64": "4.62.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", - "@rollup/rollup-linux-arm-musleabihf": "4.62.2", - "@rollup/rollup-linux-arm64-gnu": "4.62.2", - "@rollup/rollup-linux-arm64-musl": "4.62.2", - "@rollup/rollup-linux-loong64-gnu": "4.62.2", - "@rollup/rollup-linux-loong64-musl": "4.62.2", - "@rollup/rollup-linux-ppc64-gnu": "4.62.2", - "@rollup/rollup-linux-ppc64-musl": "4.62.2", - "@rollup/rollup-linux-riscv64-gnu": "4.62.2", - "@rollup/rollup-linux-riscv64-musl": "4.62.2", - "@rollup/rollup-linux-s390x-gnu": "4.62.2", - "@rollup/rollup-linux-x64-gnu": "4.62.2", - "@rollup/rollup-linux-x64-musl": "4.62.2", - "@rollup/rollup-openbsd-x64": "4.62.2", - "@rollup/rollup-openharmony-arm64": "4.62.2", - "@rollup/rollup-win32-arm64-msvc": "4.62.2", - "@rollup/rollup-win32-ia32-msvc": "4.62.2", - "@rollup/rollup-win32-x64-gnu": "4.62.2", - "@rollup/rollup-win32-x64-msvc": "4.62.2", - "fsevents": "~2.3.2" - } - }, - "node_modules/rope-sequence": { - "version": "1.3.4", - "resolved": "https://registry.npmmirror.com/rope-sequence/-/rope-sequence-1.3.4.tgz", - "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", - "license": "MIT" - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.1.4.tgz", - "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "get-intrinsic": "^1.3.0", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/sanitize-filename": { - "version": "1.6.4", - "resolved": "https://registry.npmmirror.com/sanitize-filename/-/sanitize-filename-1.6.4.tgz", - "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", - "dev": true, - "license": "WTFPL OR ISC", - "dependencies": { - "truncate-utf8-bytes": "^1.0.0" - } - }, - "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=11.0.0" - } - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/send/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmmirror.com/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/serialize-error/node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/serialize-javascript": { - "version": "7.0.7", - "resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-7.0.7.tgz", - "integrity": "sha512-YAy8Od6KV+uuwUuU50np8fGB/Aues6Y0nAhA9y/hId74PlKUcme4pXcBD46NWKr1Q4osN/iseZ17YqO1XfmI8g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC" - }, - "node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", - "license": "MIT" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.4", - "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.4.tgz", - "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.1.tgz", - "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4", - "side-channel-list": "^1.0.1", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/smob": { - "version": "1.6.2", - "resolved": "https://registry.npmmirror.com/smob/-/smob-1.6.2.tgz", - "integrity": "sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.9", - "resolved": "https://registry.npmmirror.com/socks/-/socks-2.8.9.tgz", - "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^10.1.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "deprecated": "The work that was done in this beta branch won't be included in future versions", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/source-map/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/source-map/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmmirror.com/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ssri/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ssri/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/stat-mode": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/stat-mode/-/stat-mode-1.0.0.tgz", - "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/stats-gl": { - "version": "2.4.2", - "resolved": "https://registry.npmmirror.com/stats-gl/-/stats-gl-2.4.2.tgz", - "integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==", - "license": "MIT", - "dependencies": { - "@types/three": "*", - "three": "^0.170.0" - }, - "peerDependencies": { - "@types/three": "*", - "three": "*" - } - }, - "node_modules/stats-gl/node_modules/three": { - "version": "0.170.0", - "resolved": "https://registry.npmmirror.com/three/-/three-0.170.0.tgz", - "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==", - "license": "MIT" - }, - "node_modules/stats.js": { - "version": "0.17.0", - "resolved": "https://registry.npmmirror.com/stats.js/-/stats.js-0.17.0.tgz", - "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", - "license": "MIT" - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", - "dev": true, - "license": "MIT" - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.12", - "resolved": "https://registry.npmmirror.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", - "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.11", - "resolved": "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", - "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.2", - "es-object-atoms": "^1.1.2", - "has-property-descriptors": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.10", - "resolved": "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", - "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmmirror.com/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmmirror.com/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sumchecker": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/sumchecker/-/sumchecker-3.0.1.tgz", - "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "debug": "^4.1.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/suspend-react": { - "version": "0.1.3", - "resolved": "https://registry.npmmirror.com/suspend-react/-/suspend-react-0.1.3.tgz", - "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", - "license": "MIT", - "peerDependencies": { - "react": ">=17.0" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tailwind-merge": { - "version": "3.6.0", - "resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.6.0.tgz", - "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss-animate": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", - "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", - "license": "MIT", - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar-fs": { - "version": "2.1.5", - "resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.5.tgz", - "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==", - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/temp-file": { - "version": "3.4.0", - "resolved": "https://registry.npmmirror.com/temp-file/-/temp-file-3.4.0.tgz", - "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-exit-hook": "^2.0.1", - "fs-extra": "^10.0.0" - } - }, - "node_modules/temp-file/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/tempy": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/tempy/-/tempy-0.6.0.tgz", - "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.49.0", - "resolved": "https://registry.npmmirror.com/terser/-/terser-5.49.0.tgz", - "integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/three": { - "version": "0.185.1", - "resolved": "https://registry.npmmirror.com/three/-/three-0.185.1.tgz", - "integrity": "sha512-5aojFCXKwnjBRZvUnt3WFfEcvUJgkN5LlijRFN95hMy8WVkG4I0QNcJE+OuWvuJ0bOdStrbfXn0pkd6/QyiAlg==", - "license": "MIT" - }, - "node_modules/three-mesh-bvh": { - "version": "0.7.8", - "resolved": "https://registry.npmmirror.com/three-mesh-bvh/-/three-mesh-bvh-0.7.8.tgz", - "integrity": "sha512-BGEZTOIC14U0XIRw3tO4jY7IjP7n7v24nv9JXS1CyeVRWOCkcOMhRnmENUjuV39gktAw4Ofhr0OvIAiTspQrrw==", - "deprecated": "Deprecated due to three.js version incompatibility. Please use v0.8.0, instead.", - "license": "MIT", - "peerDependencies": { - "three": ">= 0.151.0" - } - }, - "node_modules/three-stdlib": { - "version": "2.36.1", - "resolved": "https://registry.npmmirror.com/three-stdlib/-/three-stdlib-2.36.1.tgz", - "integrity": "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==", - "license": "MIT", - "dependencies": { - "@types/draco3d": "^1.4.0", - "@types/offscreencanvas": "^2019.6.4", - "@types/webxr": "^0.5.2", - "draco3d": "^1.4.1", - "fflate": "^0.6.9", - "potpack": "^1.0.1" - }, - "peerDependencies": { - "three": ">=0.128.0" - } - }, - "node_modules/three-stdlib/node_modules/fflate": { - "version": "0.6.10", - "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.6.10.tgz", - "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", - "license": "MIT" - }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "license": "MIT" - }, - "node_modules/tiny-typed-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", - "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==", - "license": "MIT" - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tldts": { - "version": "7.4.7", - "resolved": "https://registry.npmmirror.com/tldts/-/tldts-7.4.7.tgz", - "integrity": "sha512-56L0/9HELHSsG1bFCzay8UoLxzRL7kpFf7Wl5q/kSYwiSJGACvro61xnKzPNM+SadxllzdtXsKDSXE7HPeqIAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^7.4.7" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "7.4.7", - "resolved": "https://registry.npmmirror.com/tldts-core/-/tldts-core-7.4.7.tgz", - "integrity": "sha512-rNlAI8fKn/JckBMUSbNL/ES2kmDiurWaE49l+ikwEc9A6lFR7gMx9AhgQMQKBK4H5w4pKLH64JzZfB99uRsGNQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/tmp": { - "version": "0.2.7", - "resolved": "https://registry.npmmirror.com/tmp/-/tmp-0.2.7.tgz", - "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/tmp-promise/-/tmp-promise-3.0.3.tgz", - "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tmp": "^0.2.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-6.0.2.tgz", - "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^7.0.5" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/tr46": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/tr46/-/tr46-6.0.0.tgz", - "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/troika-three-text": { - "version": "0.52.4", - "resolved": "https://registry.npmmirror.com/troika-three-text/-/troika-three-text-0.52.4.tgz", - "integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==", - "license": "MIT", - "dependencies": { - "bidi-js": "^1.0.2", - "troika-three-utils": "^0.52.4", - "troika-worker-utils": "^0.52.0", - "webgl-sdf-generator": "1.1.1" - }, - "peerDependencies": { - "three": ">=0.125.0" - } - }, - "node_modules/troika-three-utils": { - "version": "0.52.4", - "resolved": "https://registry.npmmirror.com/troika-three-utils/-/troika-three-utils-0.52.4.tgz", - "integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==", - "license": "MIT", - "peerDependencies": { - "three": ">=0.125.0" - } - }, - "node_modules/troika-worker-utils": { - "version": "0.52.0", - "resolved": "https://registry.npmmirror.com/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", - "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==", - "license": "MIT" - }, - "node_modules/truncate-utf8-bytes": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", - "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", - "dev": true, - "license": "WTFPL", - "dependencies": { - "utf8-byte-length": "^1.0.1" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmmirror.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "license": "Apache-2.0" - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tunnel-rat": { - "version": "0.1.2", - "resolved": "https://registry.npmmirror.com/tunnel-rat/-/tunnel-rat-0.1.2.tgz", - "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", - "license": "MIT", - "dependencies": { - "zustand": "^4.3.2" - } - }, - "node_modules/tunnel-rat/node_modules/zustand": { - "version": "4.5.7", - "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.7.tgz", - "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "^1.2.2" - }, - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "immer": ">=9.0.6", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - } - } - }, - "node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/type-is/-/type-is-2.1.0.tgz", - "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", - "license": "MIT", - "dependencies": { - "content-type": "^2.0.0", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/type-is/node_modules/content-type": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/type-is/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/type-is/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.8.tgz", - "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "for-each": "^0.3.5", - "gopd": "^1.2.0", - "is-typed-array": "^1.1.15", - "possible-typed-array-names": "^1.1.0", - "reflect.getprototypeof": "^1.0.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmmirror.com/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/use-callback-ref": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz", - "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-sidecar": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/use-sidecar/-/use-sidecar-1.1.3.tgz", - "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", - "license": "MIT", - "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/utf8-byte-length": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", - "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", - "dev": true, - "license": "(WTFPL OR MIT)" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/utility-types": { - "version": "3.11.0", - "resolved": "https://registry.npmmirror.com/utility-types/-/utility-types-3.11.0.tgz", - "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/uuid": { - "version": "14.0.1", - "resolved": "https://registry.npmmirror.com/uuid/-/uuid-14.0.1.tgz", - "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/verror": { - "version": "1.10.1", - "resolved": "https://registry.npmmirror.com/verror/-/verror-1.10.1.tgz", - "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/victory-vendor": { - "version": "37.3.6", - "resolved": "https://registry.npmmirror.com/victory-vendor/-/victory-vendor-37.3.6.tgz", - "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", - "license": "MIT AND ISC", - "dependencies": { - "@types/d3-array": "^3.0.3", - "@types/d3-ease": "^3.0.0", - "@types/d3-interpolate": "^3.0.1", - "@types/d3-scale": "^4.0.2", - "@types/d3-shape": "^3.1.0", - "@types/d3-time": "^3.0.0", - "@types/d3-timer": "^3.0.0", - "d3-array": "^3.1.6", - "d3-ease": "^3.0.1", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-shape": "^3.1.0", - "d3-time": "^3.0.0", - "d3-timer": "^3.0.1" - } - }, - "node_modules/vite": { - "version": "8.1.3", - "resolved": "https://registry.npmmirror.com/vite/-/vite-8.1.3.tgz", - "integrity": "sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.16", - "rolldown": "~1.1.3", - "tinyglobby": "^0.2.17" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.3.0", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite-plugin-pwa": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/vite-plugin-pwa/-/vite-plugin-pwa-1.3.0.tgz", - "integrity": "sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.6", - "pretty-bytes": "^6.1.1", - "tinyglobby": "^0.2.10", - "workbox-build": "^7.4.1", - "workbox-window": "^7.4.1" - }, - "engines": { - "node": ">=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vite-pwa/assets-generator": "^1.0.0", - "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", - "workbox-build": "^7.4.1", - "workbox-window": "^7.4.1" - }, - "peerDependenciesMeta": { - "@vite-pwa/assets-generator": { - "optional": true - } - } - }, - "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmmirror.com/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - } - }, - "node_modules/w3c-keyname": { - "version": "2.2.8", - "resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz", - "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "license": "MIT" - }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/wait-on": { - "version": "9.0.10", - "resolved": "https://registry.npmmirror.com/wait-on/-/wait-on-9.0.10.tgz", - "integrity": "sha512-rCoJEhvMr0X6alHmwc9abbrA5ZrLZFKpFQVKPNFwl2h7DapXOGdmimIHDtLOWhT4PjhZhxFEtZoQgEXbkDWdZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "axios": "^1.16.0", - "joi": "^18.2.1", - "lodash": "^4.18.1", - "minimist": "^1.2.8", - "rxjs": "^7.8.2" - }, - "bin": { - "wait-on": "bin/wait-on" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webgl-constants": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/webgl-constants/-/webgl-constants-1.1.1.tgz", - "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" - }, - "node_modules/webgl-sdf-generator": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", - "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==", - "license": "MIT" - }, - "node_modules/webidl-conversions": { - "version": "8.0.1", - "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-8.0.1.tgz", - "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20" - } - }, - "node_modules/whatwg-mimetype": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", - "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/whatwg-url": { - "version": "16.0.1", - "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-16.0.1.tgz", - "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.11.0", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.22", - "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.22.tgz", - "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", - "dev": true, - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/workbox-background-sync": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-background-sync/-/workbox-background-sync-7.4.1.tgz", - "integrity": "sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==", - "dev": true, - "license": "MIT", - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "7.4.1" - } - }, - "node_modules/workbox-broadcast-update": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-broadcast-update/-/workbox-broadcast-update-7.4.1.tgz", - "integrity": "sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-core": "7.4.1" - } - }, - "node_modules/workbox-build": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-build/-/workbox-build-7.4.1.tgz", - "integrity": "sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.24.4", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-replace": "^6.0.3", - "@rollup/plugin-terser": "^1.0.0", - "@trickfilm400/rollup-plugin-off-main-thread": "^3.0.0-pre1", - "ajv": "^8.6.0", - "common-tags": "^1.8.0", - "eta": "^4.5.1", - "fast-json-stable-stringify": "^2.1.0", - "fs-extra": "^9.0.1", - "glob": "^11.0.1", - "pretty-bytes": "^5.3.0", - "rollup": "^4.53.3", - "source-map": "^0.8.0-beta.0", - "stringify-object": "^3.3.0", - "strip-comments": "^2.0.1", - "tempy": "^0.6.0", - "upath": "^1.2.0", - "workbox-background-sync": "7.4.1", - "workbox-broadcast-update": "7.4.1", - "workbox-cacheable-response": "7.4.1", - "workbox-core": "7.4.1", - "workbox-expiration": "7.4.1", - "workbox-google-analytics": "7.4.1", - "workbox-navigation-preload": "7.4.1", - "workbox-precaching": "7.4.1", - "workbox-range-requests": "7.4.1", - "workbox-recipes": "7.4.1", - "workbox-routing": "7.4.1", - "workbox-strategies": "7.4.1", - "workbox-streams": "7.4.1", - "workbox-sw": "7.4.1", - "workbox-window": "7.4.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/workbox-build/node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmmirror.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/workbox-cacheable-response": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-cacheable-response/-/workbox-cacheable-response-7.4.1.tgz", - "integrity": "sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-core": "7.4.1" - } - }, - "node_modules/workbox-core": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-core/-/workbox-core-7.4.1.tgz", - "integrity": "sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/workbox-expiration": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-expiration/-/workbox-expiration-7.4.1.tgz", - "integrity": "sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "7.4.1" - } - }, - "node_modules/workbox-google-analytics": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-google-analytics/-/workbox-google-analytics-7.4.1.tgz", - "integrity": "sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-background-sync": "7.4.1", - "workbox-core": "7.4.1", - "workbox-routing": "7.4.1", - "workbox-strategies": "7.4.1" - } - }, - "node_modules/workbox-navigation-preload": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-navigation-preload/-/workbox-navigation-preload-7.4.1.tgz", - "integrity": "sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-core": "7.4.1" - } - }, - "node_modules/workbox-precaching": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-precaching/-/workbox-precaching-7.4.1.tgz", - "integrity": "sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-core": "7.4.1", - "workbox-routing": "7.4.1", - "workbox-strategies": "7.4.1" - } - }, - "node_modules/workbox-range-requests": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-range-requests/-/workbox-range-requests-7.4.1.tgz", - "integrity": "sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-core": "7.4.1" - } - }, - "node_modules/workbox-recipes": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-recipes/-/workbox-recipes-7.4.1.tgz", - "integrity": "sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-cacheable-response": "7.4.1", - "workbox-core": "7.4.1", - "workbox-expiration": "7.4.1", - "workbox-precaching": "7.4.1", - "workbox-routing": "7.4.1", - "workbox-strategies": "7.4.1" - } - }, - "node_modules/workbox-routing": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-routing/-/workbox-routing-7.4.1.tgz", - "integrity": "sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-core": "7.4.1" - } - }, - "node_modules/workbox-strategies": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-strategies/-/workbox-strategies-7.4.1.tgz", - "integrity": "sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-core": "7.4.1" - } - }, - "node_modules/workbox-streams": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-streams/-/workbox-streams-7.4.1.tgz", - "integrity": "sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "workbox-core": "7.4.1", - "workbox-routing": "7.4.1" - } - }, - "node_modules/workbox-sw": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-sw/-/workbox-sw-7.4.1.tgz", - "integrity": "sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==", - "dev": true, - "license": "MIT" - }, - "node_modules/workbox-window": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/workbox-window/-/workbox-window-7.4.1.tgz", - "integrity": "sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "7.4.1" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "license": "MIT" - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.3", - "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.3.tgz", - "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmmirror.com/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmmirror.com/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/zip-stream/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/zip-stream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/zip-stream/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.2", - "resolved": "https://registry.npmmirror.com/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", - "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25.28 || ^4" - } - }, - "node_modules/zustand": { - "version": "5.0.14", - "resolved": "https://registry.npmmirror.com/zustand/-/zustand-5.0.14.tgz", - "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==", - "license": "MIT", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=18.0.0", - "immer": ">=9.0.6", - "react": ">=18.0.0", - "use-sync-external-store": ">=1.2.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - }, - "use-sync-external-store": { - "optional": true - } - } - } - } -} +{ + "name": "entropy-decrease", + "version": "0.23.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "entropy-decrease", + "version": "0.23.0", + "hasInstallScript": true, + "dependencies": { + "@automerge/automerge": "^3.3.2", + "@modelcontextprotocol/sdk": "^1.29.0", + "@modelcontextprotocol/server-filesystem": "^2026.7.10", + "@modelcontextprotocol/server-memory": "^2026.7.4", + "@modelcontextprotocol/server-sequential-thinking": "^2026.7.4", + "@radix-ui/react-context-menu": "^2.3.3", + "@radix-ui/react-dialog": "^1.1.19", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-toast": "^1.2.19", + "@react-three/drei": "^9.122.0", + "@react-three/fiber": "^8.18.0", + "@react-three/postprocessing": "^2.19.1", + "@supabase/supabase-js": "^2.110.1", + "@tanstack/react-query": "^5.101.2", + "@tanstack/react-virtual": "^3.14.5", + "@tiptap/extension-color": "^3.27.3", + "@tiptap/extension-highlight": "^3.27.3", + "@tiptap/extension-image": "^3.27.3", + "@tiptap/extension-placeholder": "^3.27.3", + "@tiptap/extension-table": "^3.27.3", + "@tiptap/extension-table-cell": "^3.27.3", + "@tiptap/extension-table-header": "^3.27.3", + "@tiptap/extension-table-row": "^3.27.3", + "@tiptap/extension-task-item": "^3.27.3", + "@tiptap/extension-task-list": "^3.27.3", + "@tiptap/extension-text-align": "^3.27.3", + "@tiptap/extension-text-style": "^3.27.3", + "@tiptap/extension-underline": "^3.27.3", + "@tiptap/pm": "^3.27.3", + "@tiptap/react": "^3.27.3", + "@tiptap/starter-kit": "^3.27.3", + "better-sqlite3": "^11.0.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "dexie": "^4.4.4", + "dompurify": "^3.4.12", + "electron-updater": "^6.3.9", + "framer-motion": "^12.42.2", + "lucide-react": "^1.23.0", + "lxgw-wenkai-lite-webfont": "^1.7.0", + "pixelmatch": "^7.2.0", + "pngjs": "^7.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^7.18.1", + "recharts": "^3.9.2", + "tailwind-merge": "^3.6.0", + "tailwindcss-animate": "^1.0.7", + "three": "^0.185.1", + "uuid": "^14.0.1", + "zustand": "^5.0.14" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/better-sqlite3": "^7.6.0", + "@types/dompurify": "^3.0.5", + "@types/node": "^24.13.2", + "@types/pngjs": "^6.0.5", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@types/three": "^0.185.1", + "@types/uuid": "^10.0.0", + "@vitejs/plugin-react": "^6.0.3", + "autoprefixer": "^10.5.2", + "concurrently": "^10.0.3", + "cross-env": "^10.1.0", + "electron": "^35.7.5", + "electron-builder": "^25.1.8", + "electron-rebuild": "^3.2.9", + "jsdom": "^29.1.1", + "oxlint": "^1.71.0", + "postcss": "^8.5.16", + "tailwindcss": "^3.4.19", + "typescript": "~6.0.2", + "vite": "^8.1.1", + "vite-plugin-pwa": "^1.3.0", + "vitest": "^4.1.10", + "wait-on": "^9.0.10", + "workbox-window": "^7.4.1" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@apideck/better-ajv-errors": { + "version": "0.3.7", + "resolved": "https://registry.npmmirror.com/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.7.tgz", + "integrity": "sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonpointer": "^5.0.1", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmmirror.com/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmmirror.com/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@automerge/automerge": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/@automerge/automerge/-/automerge-3.3.2.tgz", + "integrity": "sha512-9vCdCL7pdQwUra66SBxPVHr+/t9epXKni9KDeak2rNBFMzABVh2u6gSpcwxi3jkR5qr047jVqZv9DlrOfVxLFw==", + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmmirror.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", + "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", + "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmmirror.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@csstools/css-color-parser/-/css-color-parser-4.1.9.tgz", + "integrity": "sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.2.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.6", + "resolved": "https://registry.npmmirror.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.6.tgz", + "integrity": "sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmmirror.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@develar/schema-utils/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@develar/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/@develar/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "license": "Apache-2.0" + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmmirror.com/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@electron/asar/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/get": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@electron/get/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/get/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/@electron/osx-sign/-/osx-sign-1.3.1.tgz", + "integrity": "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/rebuild": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/@electron/rebuild/-/rebuild-3.6.1.tgz", + "integrity": "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "fs-extra": "^10.0.0", + "got": "^11.7.0", + "node-abi": "^3.45.0", + "node-api-version": "^0.2.0", + "node-gyp": "^9.0.0", + "ora": "^5.1.0", + "read-binary-file-arch": "^1.0.6", + "semver": "^7.3.5", + "tar": "^6.0.5", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@electron/rebuild/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/rebuild/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/universal": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/@electron/universal/-/universal-2.0.1.tgz", + "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.2.7", + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.3.1", + "dir-compare": "^4.2.0", + "fs-extra": "^11.1.1", + "minimatch": "^9.0.3", + "plist": "^3.1.0" + }, + "engines": { + "node": ">=16.4" + } + }, + "node_modules/@electron/universal/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmmirror.com/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@epic-web/invariant": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/@epic-web/invariant/-/invariant-1.0.0.tgz", + "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmmirror.com/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmmirror.com/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@hapi/address": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/@hapi/address/-/address-5.1.1.tgz", + "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^11.0.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@hapi/formula": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@hapi/formula/-/formula-3.0.2.tgz", + "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/hoek": { + "version": "11.0.7", + "resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-11.0.7.tgz", + "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/pinpoint": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", + "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/tlds": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/@hapi/tlds/-/tlds-1.1.7.tgz", + "integrity": "sha512-MgNjRwy9Ti92yVAixLmDc8dd1bJIKwO9qlWCfFQRwRmUEDPQHYn4G6hwPFvFGUTzAa0FsS+inMjLin7GnyBRhA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@hapi/topo": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/@hapi/topo/-/topo-6.0.2.tgz", + "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^11.0.2" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmmirror.com/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@mediapipe/tasks-vision": { + "version": "0.10.17", + "resolved": "https://registry.npmmirror.com/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", + "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", + "license": "Apache-2.0" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/server-filesystem": { + "version": "2026.7.10", + "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/server-filesystem/-/server-filesystem-2026.7.10.tgz", + "integrity": "sha512-Mmjg4anFBD5OzbPnGJOA0jPPN8645ERhQk38HQLpSenx1ox9bfdPkmAzUnNjeQtqQGFLtKe13J20RtLBmUKMZA==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "diff": "^8.0.3", + "glob": "^10.5.0", + "minimatch": "^10.0.1" + }, + "bin": { + "mcp-server-filesystem": "dist/index.js" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmmirror.com/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@modelcontextprotocol/server-filesystem/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@modelcontextprotocol/server-memory": { + "version": "2026.7.4", + "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/server-memory/-/server-memory-2026.7.4.tgz", + "integrity": "sha512-D+NNzChsOHN72y58ngDmO+TzjJijGi/sSY/gBydhB3TJCcm1XQEozVWwEpruHeXt/HSkMV3Z/BpHDhdt1MLD5w==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0" + }, + "bin": { + "mcp-server-memory": "dist/index.js" + } + }, + "node_modules/@modelcontextprotocol/server-sequential-thinking": { + "version": "2026.7.4", + "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/server-sequential-thinking/-/server-sequential-thinking-2026.7.4.tgz", + "integrity": "sha512-tmR/ieGaeweffLNBrDp1H1w4sn4M6TN5yWSbMS+YMfS+0GDyPjnNKzqCl2uqfdRiX3D44PJUhwiDGqtJp6tFhw==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "chalk": "^5.3.0", + "yargs": "^17.7.2" + }, + "bin": { + "mcp-server-sequential-thinking": "dist/index.js" + } + }, + "node_modules/@modelcontextprotocol/server-sequential-thinking/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@monogrid/gainmap-js": { + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", + "integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==", + "license": "MIT", + "dependencies": { + "promise-worker-transferable": "^1.0.4" + }, + "peerDependencies": { + "three": ">= 0.159.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmmirror.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.139.0", + "resolved": "https://registry.npmmirror.com/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.73.0.tgz", + "integrity": "sha512-HZQRN/UMBu+Ut+/9MiAChkbP4qZqrNOWBcNI45vOT40GVhbGR0JgHB87L48D4iAqFQIdVmeQYtV9RF89AjTKkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-android-arm64/-/binding-android-arm64-1.73.0.tgz", + "integrity": "sha512-Gp+KJRylv2aW7thRpG5p1KTxZq4ZJFbWowrKzufNq9d3ssl3r3JviYV45/+p+7CN1Nv0zDd1e8Ex0b/HUDq4TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.73.0.tgz", + "integrity": "sha512-3de96NdtXhxERMjIz7wsp2HYMY6pMQycGxFWac2mFecAx6VeARF/IqFb1QIaqiCRIdfzBwzTed+pCTCoiS+CYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.73.0.tgz", + "integrity": "sha512-5zx/uPW32TiaOeVY1dQ/H5iOf0K1HOdFKOJhLqGl4o63+i1fpzoqqu/mKtd7OFgFjNCdhlyTGgjVkQTZm1ELcg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.73.0.tgz", + "integrity": "sha512-qNe4gKHaGnLuZJ8toUg90JAa0S2vTVvDw+0bRi3q1avXZXDT4u5mMeECf3nD4HYrbdn1O7dXqWut4onY/yx/Xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.73.0.tgz", + "integrity": "sha512-cCehYh5hTbfShm/fxTD6wwrGUWIpvX+N5OxmAMhFhDeTGXvw+BeNj889tpxsFQ9ZLatQ6wImuY8tsKLZ+FMz7w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.73.0.tgz", + "integrity": "sha512-d5j5GDU/2dMgjVhw7TQT9ITrsIr1Y02KEXKyVGIXUkD+KiaxE9TP65FS2ZdgTBemQvoRL+gSBdbrIm3cQIeacg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.73.0.tgz", + "integrity": "sha512-Eyf1SrP3+yR1DI3OJgOY2Pvrr9dWP9TK37xPaDYycwTtlGlI45erJAVIfH5/m/xosDt6BupJYEFi47bvbTuuyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.73.0.tgz", + "integrity": "sha512-IlT/OJApEDKaMmCooHuncgJZbbCe7T5QIWmTZBEtYscWvzPQuuEinVcid6kwQRVQOUdb7PUCz4jQHnaYXdfJXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.73.0.tgz", + "integrity": "sha512-L+JYcb/vdg5fmcH08V6o0YYLU28cTH1SPNulwJdvK9NK49aXSkYy6oNpKBmddArVOXYqNepriDGiZ04G54kh1Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.73.0.tgz", + "integrity": "sha512-Qtk0g3bKV6OwWjIm7R8kQN1uOZRKQt/MODK2a8QfkwhTpXBD53ozx5XLVWLGDQAVyp2otLW4D2wB98XfAfMPGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.73.0.tgz", + "integrity": "sha512-wX0NQKZVxltkAOVmzFcpOaMpdaUvsq1Eqpx9tkAfl71UdkTlSo1R4AdAnGccR1Fm2+TzFgZ22CyyGuZ41RDr/A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.73.0.tgz", + "integrity": "sha512-vPe7UGBMWyiLTtnqS4xxgMQFSFGmtQwhwCxuiw6lXygaO6bVt0D8dFVg8Xv05eaiN3ybC0HXXHUAohFMFvqoCQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.73.0.tgz", + "integrity": "sha512-2CwIWr9cemFC/CbRBWZvuk5mffz6ObmfFkfcC/9rTQ7f+icNhYr2kOjf9Rt8lLvugvkdGDOmkoVoFFHh6ClCTw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.73.0.tgz", + "integrity": "sha512-nDadfJgg7NBBxG0N560wOe7LLX5QiYp6qBaI7viuk5EUORFBktU/NfV0MbTqU3gTqQDCh4VyxKdo5VADxk9w8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.73.0.tgz", + "integrity": "sha512-wGjJC+NLH9xP+IKGn9RDW94ojJR/wPbg5WCnQjj/oReaOtCQthr8ws1zICe77JFmo4ouUdeTHHZL/ESGiF6Pmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.73.0.tgz", + "integrity": "sha512-I7X47GPGljw225YUQ5SbC/rb1Kkdrd0yQf0x+hYxeKS6DpfjMbo9ccQPQ6LNY6BoJQ1sHhgDUGuMn5Vg5gHT6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.73.0.tgz", + "integrity": "sha512-5lWj+3h+74Fm1jYOO9qkJA4xkAlZA099DkXppuXsk7UpnpZLttsefrZU469vChGaG6hcSqrkKXQOvMTZtbjeNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.73.0.tgz", + "integrity": "sha512-WaNRvh4f6zY9CvUQk2YoA1O90ieWrIklI84+HXFr9Isjz9CSESrdqo/RtIYt4Dll/cAchqGDMehfaZd0vqEFZw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-1.1.5.tgz", + "integrity": "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-arrow/-/react-arrow-1.1.11.tgz", + "integrity": "sha512-Kdil9BB1rIFC/khmf4hC35bn8701AJcizTU7G7cUbEbk5XqqbjDuHW60uUfKqO5WojjZcbAW51Q7P0hRmMLw8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.12", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-1.1.12.tgz", + "integrity": "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz", + "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.2.0.tgz", + "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-context-menu/-/react-context-menu-2.3.3.tgz", + "integrity": "sha512-PS+gKE0z2prJ74Y0sM+brAGK4mYOHIR7TlcV5EJgUQ6E0xMvyswkK2X4yRqyganrzsRL+WCSKAPu0NQITICRWg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-menu": "2.1.20", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.19", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-dialog/-/react-dialog-1.1.19.tgz", + "integrity": "sha512-+HhbN2+YtkRgVirjZ2afMeutQRuGOrdkWR5+EFC58SJojGmtyNQwYzgi6tHBpOxvFHefMtPeHdgtjz0BOGxFQg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.12", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-direction/-/react-direction-1.1.2.tgz", + "integrity": "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.15.tgz", + "integrity": "sha512-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-effect-event": "0.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz", + "integrity": "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.12", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.12.tgz", + "integrity": "sha512-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-id/-/react-id-1.1.2.tgz", + "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.20", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-menu/-/react-menu-2.1.20.tgz", + "integrity": "sha512-VsUrXxFe9d2ScbZF0fR/oPR1+qjyeLs5p0jzG8h90puMoA9bq4SirYlXbE+USRg9Q2qTeJSFNqjw2nts8jJe4w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.12", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.3", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-roving-focus": "1.1.15", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-popper/-/react-popper-1.3.3.tgz", + "integrity": "sha512-mS7dGpyjv6b+gsDjLF7e0ia1W4Im1B1hSCy2yuXlHuvnZxHKagfDaobt/KAKt27EpZMit2pss8eJBVyVjEWM+g==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.11", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-rect": "1.1.2", + "@radix-ui/react-use-size": "1.1.2", + "@radix-ui/rect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.13", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-portal/-/react-portal-1.1.13.tgz", + "integrity": "sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.1.7.tgz", + "integrity": "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.7", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.7.tgz", + "integrity": "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.3.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.15.tgz", + "integrity": "sha512-40svmmugfM3mUN7VUDGVE1tQGOhyi8enlGD0CNJEcMM36C1f71PKM21DFgNHUfem0XnA+d8H8oN3Z9ZpJjSslg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", + "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.19", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-toast/-/react-toast-1.2.19.tgz", + "integrity": "sha512-SxfVZfVOibWKWdkf0Xx1awW2d09fQu4V4PXDY1j5hi4MVf7MWdJZqTBJMa1KWtOr1S6GGtCk02nniZ0Iia+dHw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz", + "integrity": "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", + "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz", + "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.1.tgz", + "integrity": "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz", + "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.2.tgz", + "integrity": "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-size/-/react-use-size-1.1.2.tgz", + "integrity": "sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.7.tgz", + "integrity": "sha512-1wNZBggTDK3GRuuQ6nP4k2yi7a6l7I5qbMPbZcRsrGsGVead/f/d5FhEzUvqFs0bcrDLx7n1zKQ3JvLR6whaaw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/rect/-/rect-1.1.2.tgz", + "integrity": "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==", + "license": "MIT" + }, + "node_modules/@react-spring/animated": { + "version": "9.7.5", + "resolved": "https://registry.npmmirror.com/@react-spring/animated/-/animated-9.7.5.tgz", + "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", + "license": "MIT", + "dependencies": { + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.5", + "resolved": "https://registry.npmmirror.com/@react-spring/core/-/core-9.7.5.tgz", + "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.5", + "resolved": "https://registry.npmmirror.com/@react-spring/rafz/-/rafz-9.7.5.tgz", + "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", + "license": "MIT" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.5", + "resolved": "https://registry.npmmirror.com/@react-spring/shared/-/shared-9.7.5.tgz", + "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", + "license": "MIT", + "dependencies": { + "@react-spring/rafz": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/three": { + "version": "9.7.5", + "resolved": "https://registry.npmmirror.com/@react-spring/three/-/three-9.7.5.tgz", + "integrity": "sha512-RxIsCoQfUqOS3POmhVHa1wdWS0wyHAUway73uRLp3GAL5U2iYVNdnzQsep6M2NZ994BlW8TcKuMtQHUqOsy6WA==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "@react-three/fiber": ">=6.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "three": ">=0.126" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.5", + "resolved": "https://registry.npmmirror.com/@react-spring/types/-/types-9.7.5.tgz", + "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", + "license": "MIT" + }, + "node_modules/@react-three/drei": { + "version": "9.122.0", + "resolved": "https://registry.npmmirror.com/@react-three/drei/-/drei-9.122.0.tgz", + "integrity": "sha512-SEO/F/rBCTjlLez7WAlpys+iGe9hty4rNgjZvgkQeXFSiwqD4Hbk/wNHMAbdd8vprO2Aj81mihv4dF5bC7D0CA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mediapipe/tasks-vision": "0.10.17", + "@monogrid/gainmap-js": "^3.0.6", + "@react-spring/three": "~9.7.5", + "@use-gesture/react": "^10.3.1", + "camera-controls": "^2.9.0", + "cross-env": "^7.0.3", + "detect-gpu": "^5.0.56", + "glsl-noise": "^0.0.0", + "hls.js": "^1.5.17", + "maath": "^0.10.8", + "meshline": "^3.3.1", + "react-composer": "^5.0.3", + "stats-gl": "^2.2.8", + "stats.js": "^0.17.0", + "suspend-react": "^0.1.3", + "three-mesh-bvh": "^0.7.8", + "three-stdlib": "^2.35.6", + "troika-three-text": "^0.52.0", + "tunnel-rat": "^0.1.2", + "utility-types": "^3.11.0", + "zustand": "^5.0.1" + }, + "peerDependencies": { + "@react-three/fiber": "^8", + "react": "^18", + "react-dom": "^18", + "three": ">=0.137" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/@react-three/drei/node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@react-three/fiber": { + "version": "8.18.0", + "resolved": "https://registry.npmmirror.com/@react-three/fiber/-/fiber-8.18.0.tgz", + "integrity": "sha512-FYZZqD0UUHUswKz3LQl2Z7H24AhD14XGTsIRw3SJaXUxyfVMi+1yiZGmqTcPt/CkPpdU7rrxqcyQ1zJE5DjvIQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8", + "@types/react-reconciler": "^0.26.7", + "@types/webxr": "*", + "base64-js": "^1.5.1", + "buffer": "^6.0.3", + "its-fine": "^1.0.6", + "react-reconciler": "^0.27.0", + "react-use-measure": "^2.1.7", + "scheduler": "^0.21.0", + "suspend-react": "^0.1.3", + "zustand": "^3.7.1" + }, + "peerDependencies": { + "expo": ">=43.0", + "expo-asset": ">=8.4", + "expo-file-system": ">=11.0", + "expo-gl": ">=11.0", + "react": ">=18 <19", + "react-dom": ">=18 <19", + "react-native": ">=0.64", + "three": ">=0.133" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "expo-asset": { + "optional": true + }, + "expo-file-system": { + "optional": true + }, + "expo-gl": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/@react-three/fiber/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@react-three/fiber/node_modules/zustand": { + "version": "3.7.2", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-3.7.2.tgz", + "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", + "license": "MIT", + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/@react-three/postprocessing": { + "version": "2.19.1", + "resolved": "https://registry.npmmirror.com/@react-three/postprocessing/-/postprocessing-2.19.1.tgz", + "integrity": "sha512-7P25LOSToH/I6b3UipNK17IIFlX4FDUmWcaomfwu82+CzhXTOz8Fcc1ZXEZ7vFA/5Fr/2peNlXgXZJvoa+aCdA==", + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "maath": "^0.6.0", + "n8ao": "^1.6.6", + "postprocessing": "^6.32.1", + "three-stdlib": "^2.23.4" + }, + "peerDependencies": { + "@react-three/fiber": "^8.0", + "react": "^18.0", + "three": ">= 0.138.0" + } + }, + "node_modules/@react-three/postprocessing/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/@react-three/postprocessing/node_modules/maath": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/maath/-/maath-0.6.0.tgz", + "integrity": "sha512-dSb2xQuP7vDnaYqfoKzlApeRcR2xtN8/f7WV/TMAkBC8552TwTLtOO0JTcSygkYMjNDPoo6V01jTw/aPi4JrMw==", + "license": "MIT", + "peerDependencies": { + "@types/three": ">=0.144.0", + "three": ">=0.144.0" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.12.0", + "resolved": "https://registry.npmmirror.com/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", + "integrity": "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-babel": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-babel/-/plugin-babel-6.1.0.tgz", + "integrity": "sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", + "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^7.0.3", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@supabase/auth-js": { + "version": "2.110.1", + "resolved": "https://registry.npmmirror.com/@supabase/auth-js/-/auth-js-2.110.1.tgz", + "integrity": "sha512-8EJUoRoqzAYWkieHrLCrGrxs3cBbRB94xK8GzHe0aSLlSa4mt1enYLCiMgLiKJOF8GNYeX6PLTBNef0XAhILgw==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.110.1", + "resolved": "https://registry.npmmirror.com/@supabase/functions-js/-/functions-js-2.110.1.tgz", + "integrity": "sha512-Pm9HD9Qth6zQO0aOGZ3DxYb6QlCzrkTkP6eUEOvhTlbvcvYRDSCZXIJ5dkDLpqxD+gdrXfWDFOpU9BpRKYjsIQ==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@supabase/phoenix": { + "version": "0.4.4", + "resolved": "https://registry.npmmirror.com/@supabase/phoenix/-/phoenix-0.4.4.tgz", + "integrity": "sha512-Gt0pqoXuIqX/8dvG0OKp/wMCobXNH3klNbUPBNyOfN0YA1IswrM3HyWFMOPk1Jy+BRaIyDPcFx4jLBwHNmlyfQ==", + "license": "MIT" + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.110.1", + "resolved": "https://registry.npmmirror.com/@supabase/postgrest-js/-/postgrest-js-2.110.1.tgz", + "integrity": "sha512-BILNhS40oGlP2bn/VJjh/1hCyrWNMmpGZGcCrPvqd5R3s8gf8Bd5qyKoHZdMwTKynGCuJGjagRXa069abhibMw==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.110.1", + "resolved": "https://registry.npmmirror.com/@supabase/realtime-js/-/realtime-js-2.110.1.tgz", + "integrity": "sha512-JmWCpMoe2iJPNrXIdHqIvf2Mie6NfSuWHS9Ve6YCmLkn1mNl3vrK3a67IukJ5lPjgmAzB+jFagyMz2oSIX+Xnw==", + "license": "MIT", + "dependencies": { + "@supabase/phoenix": "0.4.4", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.110.1", + "resolved": "https://registry.npmmirror.com/@supabase/storage-js/-/storage-js-2.110.1.tgz", + "integrity": "sha512-UqJGzhFMiIRBe8vT7a6ZtrN2U5YufH4Tk9nyc9KKfa2TUtV11BkSg/v3lyy/c4A8SbekVH3UywTF0s42zpF4zw==", + "license": "MIT", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.110.1", + "resolved": "https://registry.npmmirror.com/@supabase/supabase-js/-/supabase-js-2.110.1.tgz", + "integrity": "sha512-MiJh0THZgyAvTWm91FOLknjH5dYjXRKOdxpuUsyTVZVXIf7FxCShzevIm4KGCubHRU2n25Gyt8PhTXIFzcD9FA==", + "license": "MIT", + "dependencies": { + "@supabase/auth-js": "2.110.1", + "@supabase/functions-js": "2.110.1", + "@supabase/postgrest-js": "2.110.1", + "@supabase/realtime-js": "2.110.1", + "@supabase/storage-js": "2.110.1" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.101.2", + "resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.101.2.tgz", + "integrity": "sha512-hH5MLoJhF7KaIGd7q3xTXGXvslI+GYlM1Z/35aSHHWaCJWB7XvTSHYuV3eM7tw+aE0mT/xMro4M4Q9rCGHT0lw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.101.2", + "resolved": "https://registry.npmmirror.com/@tanstack/react-query/-/react-query-5.101.2.tgz", + "integrity": "sha512-seDkr6kzGzX1okaaTtZPtgA688CDPlXUz1C6xSg0ESqn04Vuc8tlrYms1s3de+znBqhPVxFRfpAfUf+6XvfPWg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.101.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.14.5", + "resolved": "https://registry.npmmirror.com/@tanstack/react-virtual/-/react-virtual-3.14.5.tgz", + "integrity": "sha512-4EKRXh7zBLkbKbFmG3AUVkircuHd+7OdT1pocJSepxtfBd3qnrJgJ5rtPkRYyo9fmyVb2+pI2xPy5oYvMLQy6A==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.17.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.17.3", + "resolved": "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.17.3.tgz", + "integrity": "sha512-8Np/TFELpI0ySuJoVmjvOrQYXH/8sTX0Biv9szhFhY39xOdAAY+smrMxjxOum/ux3eM8MUJQsEJ0/R0UpvC8dw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmmirror.com/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmmirror.com/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmmirror.com/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@tiptap/core": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/core/-/core-3.27.3.tgz", + "integrity": "sha512-TJj5929M96C1KlH796wS8MywfHDh49RhmakOyzyMMc9pFmRj9UXi1gj0TCXgsZtjEOG7B+m/DRvNOvnuvR9kmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-blockquote/-/extension-blockquote-3.27.3.tgz", + "integrity": "sha512-VGoVMcqcGkkoduzEqQ70ZK5OOHBDn5iYeHJSgkvNoSHzYHl0CaKoWxoDKJjSWC5DAM4mBU+tXTlsiUp3evRMfA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-bold/-/extension-bold-3.27.3.tgz", + "integrity": "sha512-pchbycFppBqBmvk+OxrQLIPZLNd3rNbcm7zOa+OTjluphpAcsJ6AmHBmiRhJUYWitV6/SA+0nujcaWxBp5hNcQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.27.3.tgz", + "integrity": "sha512-PKSM9g8BXzO0Lxm2gOin7FAFvxO6T0QvlXTXVke/GJn/sR1tEz7w5ybsvweytUPmSliUc601pfIUOHKEhIVC2Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-bullet-list/-/extension-bullet-list-3.27.3.tgz", + "integrity": "sha512-owQW6mcgnYgQU1z5BqmslcjZFBUm1SGM/Ax++4R6XelIt/7ol6uSTjzjAzum+ASW7UlBbuJHuSgRjl8cA+RGkg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.27.3" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-code/-/extension-code-3.27.3.tgz", + "integrity": "sha512-T7JF10Y3k7fyVujXXLVubdUh7fctgBUoiuxbvjotpltg1U/mPbOcT0UW/uif9j3H8TFvAwNApVw3x8bwwFUakA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-code-block/-/extension-code-block-3.27.3.tgz", + "integrity": "sha512-3CVnzkpGoqqI5KaXI9l9PMwLkx34SYY63tpeo0I0QjDk4LU+JTAQDTPJFSwB4zTsHZ7ZFMU0jjasFOZ1kZRVgw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/extension-color": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-color/-/extension-color-3.27.3.tgz", + "integrity": "sha512-tNXyK3VXPGygJP+vq1+YyPmrxLabx4vs+rYiVhGtmhIapTQeMVYcHbFH4s4v3h5m8JGVlTWnpI8n7cb5ExIhSQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-text-style": "3.27.3" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-document/-/extension-document-3.27.3.tgz", + "integrity": "sha512-PR25MRv56Nm4ETVLwA8nAh/0RrVdvD4D2nxnAC8kUkxz1WOYDaqTfPqqEeSWDoUUTUp1I1xzDkD4x0gEnAlmZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.27.3.tgz", + "integrity": "sha512-XsL0Ziual+ynXyx5JgLb0KIOShlMN3MW7+GQvf9PGRb1vOB7IOTRFDxMPrxDWcFIZ6WWMWSrbkCLOKHStt1BWg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.27.3" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.27.3.tgz", + "integrity": "sha512-qL+g1Z6MqZvYG4mHTPwub9II2fWZY+2I5VFfV8fzqy1HchBOyY6Df0mRKDNb0bmjBdFabIXnswz3iqLx3mDTbw==", + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-gapcursor/-/extension-gapcursor-3.27.3.tgz", + "integrity": "sha512-MVBqzwYrDOttkn2GOrvvKTDCymfSS2VGSKpahcKKhge5mweSDiqko2X1vBDnMF8aVW3WxIFfDMmO4VMmh8HDZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.27.3" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-hard-break/-/extension-hard-break-3.27.3.tgz", + "integrity": "sha512-cySObJITR2CRrWII87mI2LJ12wEETTnxt2p1vvC6ZtUmKnB50fOu+ux8ZEt6KYNocIOtrEZthNFzTOx7R7UtrQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-heading/-/extension-heading-3.27.3.tgz", + "integrity": "sha512-QHXnsNic6iId8pnsFZ8z4PkX5L+HCHa/D7rAi3nNWtPlSIAOxo4nKrALcB5/tHmY+XL8kEXKH3nsNLNEDLCYPg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-highlight": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-highlight/-/extension-highlight-3.27.3.tgz", + "integrity": "sha512-99QYxMx8F/NhdvznM8/Zhm4XiCdMU0OEiLwPvLNObJiKV8UBqjdA68cJLX6FRuOi2nqD7xfJq2KuSsFKBldi2A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.27.3.tgz", + "integrity": "sha512-sNCuo0+Q001B5XTVWY+ULpWXQqtBNRmAqXxAexZl44bx3rDqHG8OzjwT4EM0LIj2+BYVbdqwaJ1vfQbZVEEbig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/extension-image": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-image/-/extension-image-3.27.3.tgz", + "integrity": "sha512-3OVLRH54Xkh9yrI5oGIempuqZkhLG1plyJBRnapx0N8j9IjEImOLF78kPYoAZzaBuU78M3Zk/E7HQZgmnaNRBg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-italic/-/extension-italic-3.27.3.tgz", + "integrity": "sha512-7VpVi2vn8kGFAc/HLrt96J/E6+LXOGKn8xLhJS863t150yLIG3EPQLA1h+G5O6eo+/w+9YokvJAAJoeDihj1Jg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-link/-/extension-link-3.27.3.tgz", + "integrity": "sha512-iXmu1tJ/3vP60c9d+zfO3+X64vod2EyBrM1qeufecAtWA6t0bT9tYeka0Zq6qDRGsZK5zViO9F2lsY7eHXiYuA==", + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.3.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-list/-/extension-list-3.27.3.tgz", + "integrity": "sha512-52rcaSzYjtVGUrNkdB8k1Bw/rId2lBirrWMvmnBLsieoeFd8zo8ow5zkwV057BYSgWXfnMAV7GOpDyq2IoSD9A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-list-item/-/extension-list-item-3.27.3.tgz", + "integrity": "sha512-UddhVaQ7+V9IfQVVE8AJLNzSmyaaNpZPQsoPQxFNlJyOFxD6RwSTT8L4rb/TwbUctxSFWpyd1J7exzf33Ony/g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.27.3" + } + }, + "node_modules/@tiptap/extension-list-keymap": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-list-keymap/-/extension-list-keymap-3.27.3.tgz", + "integrity": "sha512-GZPVg4QCFm41yTMPEPeTlH2odNeQwRuWHY/pt3pI5LsfipQ4kDBv6h9we928vJQUnU2Gg9Y3cL5iRbmXIWWTUA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.27.3" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-ordered-list/-/extension-ordered-list-3.27.3.tgz", + "integrity": "sha512-oHYoE65WfRSM5tCcXi8MtQmzPxz83E2qw0pa2yHBKwr9xCCQUu8vJHJE+EJGduWdaNImv43+6/6kVMeYYbXRKg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.27.3" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-paragraph/-/extension-paragraph-3.27.3.tgz", + "integrity": "sha512-G5XPCN7lm0nULYPelJC2eUbKbt1q97j67e/HSWxwMYEXhceec5eNAtVfpDCRyXNO9osyBi2kXqLv/IQtxbch9A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-placeholder": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-placeholder/-/extension-placeholder-3.27.3.tgz", + "integrity": "sha512-Y43dGaN3rA0oU4CWmXkZ2idjZjrxPX9oy0zZL92EgXOguhAUToBs0dIxRG5ZanYX9A8kKKWPlfeRFlBMtRhKvg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.27.3" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-strike/-/extension-strike-3.27.3.tgz", + "integrity": "sha512-dp6Rs3I4zLVJPvAw2Q9yrNuYKcX5LTONH3/oyULvGsrqq5DKz7pqscfwhwnDSzrgm/3aCz6B9r1BVHlYI/DXlA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-table": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-table/-/extension-table-3.27.3.tgz", + "integrity": "sha512-P7iQ0SkkDWZwnXzQDOVFLXktXlX67VQ3s2YxoJYKTHlc8rPZ4UCaSogFq0G2APyBlizlY3LbMNrDeZAVFOD8wQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/extension-table-cell": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-table-cell/-/extension-table-cell-3.27.3.tgz", + "integrity": "sha512-W8onBLgjge3D2PlYetbPC/BvwH5jgYfL9PLqMurfCPD7t8fyU4s+4E3SwbZkuf6eCH0twBjqyapH7+sOW/sPhA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-table": "3.27.3" + } + }, + "node_modules/@tiptap/extension-table-header": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-table-header/-/extension-table-header-3.27.3.tgz", + "integrity": "sha512-8iBOxh0S1Wh5VC1rmVTZVJKanGhJpZd5E5O7Pycf+KKUu+BcWQZ17ewj3+VVSdU76sDCUWIjQE0qJ/EyI1vZeg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-table": "3.27.3" + } + }, + "node_modules/@tiptap/extension-table-row": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-table-row/-/extension-table-row-3.27.3.tgz", + "integrity": "sha512-AFMVQI+1kRh97++g+NA6MjATpwQPvjar4JUyaGlnSBIt+b5sYLTW3qQS8EzpMbKPqUp7uZOX9EkLgpvepWYSow==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-table": "3.27.3" + } + }, + "node_modules/@tiptap/extension-task-item": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-task-item/-/extension-task-item-3.27.3.tgz", + "integrity": "sha512-CajIPpHTsuE1l+bM3xKgpZ/3PTvRuFb+ZEyC+yxI/cY2pZd4EJ7iXHT5Fl3ITwdDq8/syVev1BBZ/QDZTOA3rw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.27.3" + } + }, + "node_modules/@tiptap/extension-task-list": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-task-list/-/extension-task-list-3.27.3.tgz", + "integrity": "sha512-g1zp2SnR+3DbsXbK1GbAucrj0lh1WnTarp1YPY4beFENzjAPklyVIpF22IjFZD/08QWN1j1fRN3zVzTGHuFXFA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.27.3" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-text/-/extension-text-3.27.3.tgz", + "integrity": "sha512-wSatZ/bop0pleeC18nF90zvWWEoRe/ewZncvm8LjcMrXwq41kTEs3j7nZflMYAh7X8fZvu00UIMeEyCNJl+5Yg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-text-align": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-text-align/-/extension-text-align-3.27.3.tgz", + "integrity": "sha512-yyhlwRz0Eh6xQCn+GtTDWUGqxGajT02Qf8zBN/3eZQtl3EZ2xrI8lvfLmcV9SAW0srgMd+5hX0CVV+zKeXuxeg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-text-style": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-text-style/-/extension-text-style-3.27.3.tgz", + "integrity": "sha512-oim4RqFtMBCA4N+J8f8dTFFYZrwyfmXLxLL5SvQkn+kkpfGLv8PqJCnJ4uHxsnHXDNsWHBtVVhfTGUABZsTEHg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extension-underline/-/extension-underline-3.27.3.tgz", + "integrity": "sha512-YH7ka/Rp7ZwlzTuQCcs0OZ4CMSx/P/MzbseQKxKebEIZreWaKMZAaED97Fnu0dA66VlreD4/1C7xHJy84ovamg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/extensions/-/extensions-3.27.3.tgz", + "integrity": "sha512-IA2QKUVJgzUPEhhkUfr6P5u5GFVfhiApiEaaHXBz07saL2c4HNoVs2RC18QlZDCtLNKrPR1mUScr72u7uYs+YQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3" + } + }, + "node_modules/@tiptap/pm": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/pm/-/pm-3.27.3.tgz", + "integrity": "sha512-ppiG57RxM3HSHHgcHT0hP6Ib4P56Sd5itxdV4w0hIGHKPGyLLKiAkYp+htIHa9T7IvjMdaqxIlsfyV3ZKsS1sw==", + "license": "MIT", + "dependencies": { + "prosemirror-changeset": "^2.4.1", + "prosemirror-commands": "^1.7.1", + "prosemirror-dropcursor": "^1.8.2", + "prosemirror-gapcursor": "^1.4.1", + "prosemirror-history": "^1.5.0", + "prosemirror-inputrules": "^1.5.1", + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.9", + "prosemirror-schema-list": "^1.5.1", + "prosemirror-state": "^1.4.4", + "prosemirror-tables": "^1.8.5", + "prosemirror-transform": "^1.12.0", + "prosemirror-view": "^1.41.9" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/react": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/react/-/react-3.27.3.tgz", + "integrity": "sha512-lanXxMScw/LevbRFuFw5MoQJ1grmHUDszwph2VIk4l2U5e/EDIw3rr4CeDME6Z4isVReD6zccMFVShkHqsv+jg==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "fast-equals": "^5.3.3", + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.27.3", + "@tiptap/extension-floating-menu": "^3.27.3" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3", + "@tiptap/pm": "3.27.3", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "3.27.3", + "resolved": "https://registry.npmmirror.com/@tiptap/starter-kit/-/starter-kit-3.27.3.tgz", + "integrity": "sha512-xX3baFqiC30skntdhxUUvyJo755ON9c1pE83+2Wiq2g+Qnffg9knUuLCZStHoZZ318yB0aBsKAMvHWLtYDo8AA==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^3.27.3", + "@tiptap/extension-blockquote": "^3.27.3", + "@tiptap/extension-bold": "^3.27.3", + "@tiptap/extension-bullet-list": "^3.27.3", + "@tiptap/extension-code": "^3.27.3", + "@tiptap/extension-code-block": "^3.27.3", + "@tiptap/extension-document": "^3.27.3", + "@tiptap/extension-dropcursor": "^3.27.3", + "@tiptap/extension-gapcursor": "^3.27.3", + "@tiptap/extension-hard-break": "^3.27.3", + "@tiptap/extension-heading": "^3.27.3", + "@tiptap/extension-horizontal-rule": "^3.27.3", + "@tiptap/extension-italic": "^3.27.3", + "@tiptap/extension-link": "^3.27.3", + "@tiptap/extension-list": "^3.27.3", + "@tiptap/extension-list-item": "^3.27.3", + "@tiptap/extension-list-keymap": "^3.27.3", + "@tiptap/extension-ordered-list": "^3.27.3", + "@tiptap/extension-paragraph": "^3.27.3", + "@tiptap/extension-strike": "^3.27.3", + "@tiptap/extension-text": "^3.27.3", + "@tiptap/extension-underline": "^3.27.3", + "@tiptap/extensions": "^3.27.3", + "@tiptap/pm": "^3.27.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/@tootallnate/once/-/once-2.0.1.tgz", + "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@trickfilm400/rollup-plugin-off-main-thread": { + "version": "3.0.0-pre1", + "resolved": "https://registry.npmmirror.com/@trickfilm400/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-3.0.0-pre1.tgz", + "integrity": "sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.10", + "json5": "^2.2.3", + "magic-string": "^0.30.21", + "string.prototype.matchall": "^4.0.12" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmmirror.com/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/better-sqlite3": { + "version": "7.6.13", + "resolved": "https://registry.npmmirror.com/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", + "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmmirror.com/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmmirror.com/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmmirror.com/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, + "node_modules/@types/draco3d": { + "version": "1.4.10", + "resolved": "https://registry.npmmirror.com/@types/draco3d/-/draco3d-1.4.10.tgz", + "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmmirror.com/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmmirror.com/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.13.3", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-24.13.3.tgz", + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmmirror.com/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" + }, + "node_modules/@types/plist": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/@types/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/pngjs": { + "version": "6.0.5", + "resolved": "https://registry.npmmirror.com/@types/pngjs/-/pngjs-6.0.5.tgz", + "integrity": "sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/react-reconciler": { + "version": "0.26.7", + "resolved": "https://registry.npmmirror.com/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", + "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmmirror.com/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmmirror.com/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.185.1", + "resolved": "https://registry.npmmirror.com/@types/three/-/three-0.185.1.tgz", + "integrity": "sha512-db1xTb+EgYF2didW+eudSvVPtn75zo+fGsY8ShQrJY/B5ZBmC2Fiaykv3aImHAlCNEGuMPkPGXBJGLwzu5mC7A==", + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": ">=0.5.17", + "fflate": "~0.8.2", + "meshoptimizer": "~1.1.1" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmmirror.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmmirror.com/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/verror": { + "version": "1.10.11", + "resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.11.tgz", + "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmmirror.com/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmmirror.com/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmmirror.com/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "license": "MIT" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmmirror.com/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz", + "integrity": "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.9.10", + "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.9.10.tgz", + "integrity": "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.6" + } + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/app-builder-bin": { + "version": "5.0.0-alpha.10", + "resolved": "https://registry.npmmirror.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.10.tgz", + "integrity": "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==", + "dev": true, + "license": "MIT" + }, + "node_modules/app-builder-lib": { + "version": "25.1.8", + "resolved": "https://registry.npmmirror.com/app-builder-lib/-/app-builder-lib-25.1.8.tgz", + "integrity": "sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/notarize": "2.5.0", + "@electron/osx-sign": "1.3.1", + "@electron/rebuild": "3.6.1", + "@electron/universal": "2.0.1", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "async-exit-hook": "^2.0.1", + "bluebird-lst": "^1.0.9", + "builder-util": "25.1.7", + "builder-util-runtime": "9.2.10", + "chromium-pickle-js": "^0.2.0", + "config-file-ts": "0.2.8-rc1", + "debug": "^4.3.4", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "ejs": "^3.1.8", + "electron-publish": "25.1.7", + "form-data": "^4.0.0", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "is-ci": "^3.0.0", + "isbinaryfile": "^5.0.0", + "js-yaml": "^4.1.0", + "json5": "^2.2.3", + "lazy-val": "^1.0.5", + "minimatch": "^10.0.0", + "resedit": "^1.7.0", + "sanitize-filename": "^1.6.3", + "semver": "^7.3.8", + "tar": "^6.1.12", + "temp-file": "^3.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "25.1.8", + "electron-builder-squirrel-windows": "25.1.8" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "dev": true, + "license": "ISC" + }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmmirror.com/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.2", + "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.5.2.tgz", + "integrity": "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.4", + "caniuse-lite": "^1.0.30001799", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.18.1", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.18.1.tgz", + "integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.42", + "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz", + "integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/better-sqlite3": { + "version": "11.10.0", + "resolved": "https://registry.npmmirror.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz", + "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + } + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/bluebird-lst": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/bluebird-lst/-/bluebird-lst-1.0.9.tgz", + "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.5.5" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.5", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.5.tgz", + "integrity": "sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.42", + "caniuse-lite": "^1.0.30001800", + "electron-to-chromium": "^1.5.387", + "node-releases": "^2.0.50", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmmirror.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "25.1.7", + "resolved": "https://registry.npmmirror.com/builder-util/-/builder-util-25.1.7.tgz", + "integrity": "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.2.0", + "app-builder-bin": "5.0.0-alpha.10", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "9.2.10", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "is-ci": "^3.0.0", + "js-yaml": "^4.1.0", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.2.10", + "resolved": "https://registry.npmmirror.com/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", + "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmmirror.com/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/camera-controls": { + "version": "2.10.1", + "resolved": "https://registry.npmmirror.com/camera-controls/-/camera-controls-2.10.1.tgz", + "integrity": "sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.126.1" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001803", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001803.tgz", + "integrity": "sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmmirror.com/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmmirror.com/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "10.0.3", + "resolved": "https://registry.npmmirror.com/concurrently/-/concurrently-10.0.3.tgz", + "integrity": "sha512-hc3LH4UaKWd/bbyDK/IGVa4RB6PtQ3CUYwtrkzqHn+wIG3Hr5fhpRlk0L/gCa8ZE1L/Ufj50Zho69cI5w8SQBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "5.6.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.4", + "supports-color": "10.2.2", + "tree-kill": "1.2.2", + "yargs": "18.0.0" + }, + "bin": { + "conc": "dist/bin/index.js", + "concurrently": "dist/bin/index.js" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/concurrently/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concurrently/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/concurrently/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/config-file-ts": { + "version": "0.2.8-rc1", + "resolved": "https://registry.npmmirror.com/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz", + "integrity": "sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.3.12", + "typescript": "^5.4.3" + } + }, + "node_modules/config-file-ts/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/config-file-ts/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/config-file-ts/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/config-file-ts/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-file-ts/node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/config-file-ts/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-file-ts/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmmirror.com/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/config-file-ts/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/config-file-ts/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/config-file-ts/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/config-file-ts/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/config-file-ts/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmmirror.com/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmmirror.com/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cross-env": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-10.1.0.tgz", + "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@epic-web/invariant": "^1.0.0", + "cross-spawn": "^7.0.6" + }, + "bin": { + "cross-env": "dist/bin/cross-env.js", + "cross-env-shell": "dist/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-gpu": { + "version": "5.0.70", + "resolved": "https://registry.npmmirror.com/detect-gpu/-/detect-gpu-5.0.70.tgz", + "integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==", + "license": "MIT", + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/dexie": { + "version": "4.4.4", + "resolved": "https://registry.npmmirror.com/dexie/-/dexie-4.4.4.tgz", + "integrity": "sha512-jIwsYI8Os2hgnqc6O49YwFDKGc5v5QjGx0wPVp543ip1F53VFAKMLthV2pQosQcVTv3eAskTWYspOx195PM0FQ==", + "license": "Apache-2.0" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmmirror.com/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-compare": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/dir-compare/-/dir-compare-4.2.0.tgz", + "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5", + "p-limit": "^3.1.0 " + } + }, + "node_modules/dir-compare/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dmg-builder": { + "version": "25.1.8", + "resolved": "https://registry.npmmirror.com/dmg-builder/-/dmg-builder-25.1.8.tgz", + "integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "25.1.8", + "builder-util": "25.1.7", + "builder-util-runtime": "9.2.10", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/dmg-license/-/dmg-license-1.0.11.tgz", + "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dmg-license/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/dmg-license/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmmirror.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/dompurify": { + "version": "3.4.12", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.4.12.tgz", + "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmmirror.com/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/draco3d": { + "version": "1.5.7", + "resolved": "https://registry.npmmirror.com/draco3d/-/draco3d-1.5.7.tgz", + "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", + "license": "Apache-2.0" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmmirror.com/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "35.7.5", + "resolved": "https://registry.npmmirror.com/electron/-/electron-35.7.5.tgz", + "integrity": "sha512-dnL+JvLraKZl7iusXTVTGYs10TKfzUi30uEDTqsmTm0guN9V2tbOjTzyIZbh9n3ygUjgEYyo+igAwMRXIi3IPw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/get": "^2.0.0", + "@types/node": "^22.7.7", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 12.20.55" + } + }, + "node_modules/electron-builder": { + "version": "25.1.8", + "resolved": "https://registry.npmmirror.com/electron-builder/-/electron-builder-25.1.8.tgz", + "integrity": "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "25.1.8", + "builder-util": "25.1.7", + "builder-util-runtime": "9.2.10", + "chalk": "^4.1.2", + "dmg-builder": "25.1.8", + "fs-extra": "^10.1.0", + "is-ci": "^3.0.0", + "lazy-val": "^1.0.5", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder-squirrel-windows": { + "version": "25.1.8", + "resolved": "https://registry.npmmirror.com/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-25.1.8.tgz", + "integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "25.1.8", + "archiver": "^5.3.1", + "builder-util": "25.1.7", + "fs-extra": "^10.1.0" + } + }, + "node_modules/electron-builder-squirrel-windows/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-publish": { + "version": "25.1.7", + "resolved": "https://registry.npmmirror.com/electron-publish/-/electron-publish-25.1.7.tgz", + "integrity": "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "25.1.7", + "builder-util-runtime": "9.2.10", + "chalk": "^4.1.2", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-rebuild": { + "version": "3.2.9", + "resolved": "https://registry.npmmirror.com/electron-rebuild/-/electron-rebuild-3.2.9.tgz", + "integrity": "sha512-FkEZNFViUem3P0RLYbZkUjC8LUFIK+wKq09GHoOITSJjfDAVQv964hwaNseTTWt58sITQX3/5fHNYcTefqaCWw==", + "deprecated": "Please use @electron/rebuild moving forward. There is no API change, just a package name change", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "fs-extra": "^10.0.0", + "got": "^11.7.0", + "lzma-native": "^8.0.5", + "node-abi": "^3.0.0", + "node-api-version": "^0.1.4", + "node-gyp": "^9.0.0", + "ora": "^5.1.0", + "semver": "^7.3.5", + "tar": "^6.0.5", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/src/cli.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/electron-rebuild/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-rebuild/node_modules/node-api-version": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/node-api-version/-/node-api-version-0.1.4.tgz", + "integrity": "sha512-KGXihXdUChwJAOHO53bv9/vXcLmdUsZ6jIptbvYvkpKfth+r7jw44JkVxQFA3kX5nQjzjmGu1uAu/xNNLNlI5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/electron-rebuild/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.389", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.389.tgz", + "integrity": "sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==", + "dev": true, + "license": "ISC" + }, + "node_modules/electron-updater": { + "version": "6.8.9", + "resolved": "https://registry.npmmirror.com/electron-updater/-/electron-updater-6.8.9.tgz", + "integrity": "sha512-ZhVxM9iGONUpZGI1FxdMRgJjUFXi7AYGVa5PwKlO1tV1/4zDxQmfKpXOHVztKrd6L9rLcFjERvi1Mf2vxyTkig==", + "license": "MIT", + "dependencies": { + "builder-util-runtime": "9.7.0", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "~7.7.3", + "tiny-typed-emitter": "^2.1.0" + } + }, + "node_modules/electron-updater/node_modules/builder-util-runtime": { + "version": "9.7.0", + "resolved": "https://registry.npmmirror.com/builder-util-runtime/-/builder-util-runtime-9.7.0.tgz", + "integrity": "sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/electron-updater/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-updater/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron/node_modules/@types/node": { + "version": "22.20.1", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.20.1.tgz", + "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/electron/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-2.3.0.tgz", + "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-toolkit": { + "version": "1.49.0", + "resolved": "https://registry.npmmirror.com/es-toolkit/-/es-toolkit-1.49.0.tgz", + "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/eta/-/eta-4.6.0.tgz", + "integrity": "sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/bgub/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://registry.npmmirror.com/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmmirror.com/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.3.tgz", + "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "license": "MIT" + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "12.42.2", + "resolved": "https://registry.npmmirror.com/framer-motion/-/framer-motion-12.42.2.tgz", + "integrity": "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.42.2", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmmirror.com/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmmirror.com/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmmirror.com/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==", + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmmirror.com/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hls.js": { + "version": "1.6.16", + "resolved": "https://registry.npmmirror.com/hls.js/-/hls.js-1.6.16.tgz", + "integrity": "sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==", + "license": "Apache-2.0" + }, + "node_modules/hono": { + "version": "4.12.30", + "resolved": "https://registry.npmmirror.com/hono/-/hono-4.12.30.tgz", + "integrity": "sha512-emn+JoJjrN9YTpRDS5it/UI2SO9BAE37T6I3d963RxcZ81G9A4pr2SZTEiiaiKbzx+NKRg5BZ89fCL7gCJCUog==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/immer": { + "version": "11.1.11", + "resolved": "https://registry.npmmirror.com/immer/-/immer-11.1.11.tgz", + "integrity": "sha512-qzXuyXAkPySAGYkfsAwodDPWT8Zm7/Uo5BNt4BjhMhG5WlWyZZ4wQqnWwdS8kjlQ1Cwu6gjw3A6+0gTQwlyYtw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true, + "license": "ISC" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isbinaryfile": { + "version": "5.0.7", + "resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-5.0.7.tgz", + "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/its-fine": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/its-fine/-/its-fine-1.2.5.tgz", + "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", + "license": "MIT", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, + "node_modules/its-fine/node_modules/@types/react-reconciler": { + "version": "0.28.9", + "resolved": "https://registry.npmmirror.com/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", + "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^9.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmmirror.com/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmmirror.com/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "18.2.3", + "resolved": "https://registry.npmmirror.com/joi/-/joi-18.2.3.tgz", + "integrity": "sha512-N5A3KTWQpPWT4ExxxPlUx7WmykGXRzhNidWhV41d6Abu9YfI2NyWCJuxdPnslJCPWtbRpSVOWSnSS6GakLM/Rg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/address": "^5.1.1", + "@hapi/formula": "^3.0.2", + "@hapi/hoek": "^11.0.7", + "@hapi/pinpoint": "^2.0.1", + "@hapi/tlds": "^1.1.1", + "@hapi/topo": "^6.0.2", + "@standard-schema/spec": "^1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmmirror.com/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "license": "MIT" + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/linkifyjs": { + "version": "4.3.3", + "resolved": "https://registry.npmmirror.com/linkifyjs/-/linkifyjs-4.3.3.tgz", + "integrity": "sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==", + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmmirror.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/lucide-react": { + "version": "1.23.0", + "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-1.23.0.tgz", + "integrity": "sha512-38BpJcD0JhFosxHApP/BYsBetLpQFRoTRzEzstM/XCc3jsAG7wqaY1lgVwxiUe3xqYE+lNxo2PkCmYwXWrwwIw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lxgw-wenkai-lite-webfont": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/lxgw-wenkai-lite-webfont/-/lxgw-wenkai-lite-webfont-1.7.0.tgz", + "integrity": "sha512-VcQYNRpdXAxaZsJ18rfT1mmAreGqkIFNZ/9pdVLbT2Tkb+2lLWJDXq4zYxMEk9AcecSnxO31R2LHh5ieLlxjRg==", + "license": "MIT" + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/lzma-native": { + "version": "8.0.6", + "resolved": "https://registry.npmmirror.com/lzma-native/-/lzma-native-8.0.6.tgz", + "integrity": "sha512-09xfg67mkL2Lz20PrrDeNYZxzeW7ADtpYFbwSQh9U8+76RIzx5QsJBMy8qikv3hbUPfpy6hqwxt6FcGK81g9AA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^3.1.0", + "node-gyp-build": "^4.2.1", + "readable-stream": "^3.6.0" + }, + "bin": { + "lzmajs": "bin/lzmajs" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/lzma-native/node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/maath": { + "version": "0.10.8", + "resolved": "https://registry.npmmirror.com/maath/-/maath-0.10.8.tgz", + "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", + "license": "MIT", + "peerDependencies": { + "@types/three": ">=0.134.0", + "three": ">=0.134.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmmirror.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-fetch-happen/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/meshline": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/meshline/-/meshline-3.3.1.tgz", + "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.137" + } + }, + "node_modules/meshoptimizer": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/meshoptimizer/-/meshoptimizer-1.1.1.tgz", + "integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==", + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmmirror.com/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-flush": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmmirror.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/motion-dom": { + "version": "12.42.2", + "resolved": "https://registry.npmmirror.com/motion-dom/-/motion-dom-12.42.2.tgz", + "integrity": "sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmmirror.com/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/n8ao": { + "version": "1.10.3", + "resolved": "https://registry.npmmirror.com/n8ao/-/n8ao-1.10.3.tgz", + "integrity": "sha512-JFRk4WgUAUWO2KdJTqmBT02dP9kG7rE2oQbBy64E9+YwQ3d96KB9QBanqNy/NnYUfUTYU6Z/5OS5t/yLey7+6Q==", + "license": "ISC", + "peerDependencies": { + "postprocessing": ">=6.30.0", + "three": ">=0.137" + } + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.94.0", + "resolved": "https://registry.npmmirror.com/node-abi/-/node-abi-3.94.0.tgz", + "integrity": "sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-api-version": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/node-api-version/-/node-api-version-0.2.1.tgz", + "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-api-version/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmmirror.com/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmmirror.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "dev": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-releases": { + "version": "2.0.50", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/obug/-/obug-2.1.3.tgz", + "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "license": "MIT" + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oxlint": { + "version": "1.73.0", + "resolved": "https://registry.npmmirror.com/oxlint/-/oxlint-1.73.0.tgz", + "integrity": "sha512-u91G9TJzU6yqKWNZUYprQB07W7YvntZXaRxQ6CkoytepYhLWUXWsr1M8zUJ34VatNPuUAr3Z8GH+O2A331CluQ==", + "dev": true, + "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.73.0", + "@oxlint/binding-android-arm64": "1.73.0", + "@oxlint/binding-darwin-arm64": "1.73.0", + "@oxlint/binding-darwin-x64": "1.73.0", + "@oxlint/binding-freebsd-x64": "1.73.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.73.0", + "@oxlint/binding-linux-arm-musleabihf": "1.73.0", + "@oxlint/binding-linux-arm64-gnu": "1.73.0", + "@oxlint/binding-linux-arm64-musl": "1.73.0", + "@oxlint/binding-linux-ppc64-gnu": "1.73.0", + "@oxlint/binding-linux-riscv64-gnu": "1.73.0", + "@oxlint/binding-linux-riscv64-musl": "1.73.0", + "@oxlint/binding-linux-s390x-gnu": "1.73.0", + "@oxlint/binding-linux-x64-gnu": "1.73.0", + "@oxlint/binding-linux-x64-musl": "1.73.0", + "@oxlint/binding-openharmony-arm64": "1.73.0", + "@oxlint/binding-win32-arm64-msvc": "1.73.0", + "@oxlint/binding-win32-ia32-msvc": "1.73.0", + "@oxlint/binding-win32-x64-msvc": "1.73.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=0.24.0", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pe-library": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/pe-library/-/pe-library-0.4.1.tgz", + "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pixelmatch": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/pixelmatch/-/pixelmatch-7.2.0.tgz", + "integrity": "sha512-xhcb4yHu9sM/G7foGzoLtXYcC0zHEaOXXjRKhGup0fw78Nf2Tkiapv4EQyMzrbcmQPsllAI7DbFY2UT7PlI9Pg==", + "license": "ISC", + "dependencies": { + "pngjs": "^7.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/plist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/plist/-/plist-3.1.1.tgz", + "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.9.10", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.16", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.16.tgz", + "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmmirror.com/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.4", + "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postprocessing": { + "version": "6.39.2", + "resolved": "https://registry.npmmirror.com/postprocessing/-/postprocessing-6.39.2.tgz", + "integrity": "sha512-AxPY+xFyVOsz+8bbHSyQBoOK4AUqSQspTXXIsNcKhmGJRm/afHRAwZ8bKC02AeSPII0PW6lbCN84SgAoWFsKKA==", + "license": "Zlib", + "peerDependencies": { + "three": ">= 0.168.0 < 0.186.0" + } + }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", + "license": "ISC" + }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pretty-bytes": { + "version": "6.1.1", + "resolved": "https://registry.npmmirror.com/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-worker-transferable": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", + "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", + "license": "Apache-2.0", + "dependencies": { + "is-promise": "^2.1.0", + "lie": "^3.0.2" + } + }, + "node_modules/promise-worker-transferable/node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmmirror.com/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/prosemirror-changeset": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmmirror.com/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.3", + "resolved": "https://registry.npmmirror.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.3.tgz", + "integrity": "sha512-FoYbsJR8gK+DGlqhNoE29Loa38eIZPzQRIb1VMaDNBoo4OLP6vVof/jR8qFY/6XvUd6Dhug8MDCHl2a/h8RTfQ==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/prosemirror-history/-/prosemirror-history-1.5.0.tgz", + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz", + "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.10", + "resolved": "https://registry.npmmirror.com/prosemirror-model/-/prosemirror-model-1.25.10.tgz", + "integrity": "sha512-9n6rH4DbJU1eH4SxLt6Y0HhJIo6cZsb7DJ/30uob1hOKPeO6TAaMWI2tc7kwR92BjfPOU2fFHWbZLovLi3XQfA==", + "license": "MIT", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmmirror.com/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.8.5", + "resolved": "https://registry.npmmirror.com/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.12.0", + "resolved": "https://registry.npmmirror.com/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.42.0", + "resolved": "https://registry.npmmirror.com/prosemirror-view/-/prosemirror-view-1.42.0.tgz", + "integrity": "sha512-N54DF3OXNWDuP81G1kbfCys8ZzIjuL1VnvJ2mk5STSu/fNxWIcX/EutQLA3s9KR/2wVhgDi4hzBB/1fINVxk0A==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.25.8", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-composer": { + "version": "5.0.3", + "resolved": "https://registry.npmmirror.com/react-composer/-/react-composer-5.0.3.tgz", + "integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.6.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT", + "peer": true + }, + "node_modules/react-reconciler": { + "version": "0.27.0", + "resolved": "https://registry.npmmirror.com/react-reconciler/-/react-reconciler-0.27.0.tgz", + "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.21.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/react-reconciler/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/react-redux": { + "version": "9.3.0", + "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-9.3.0.tgz", + "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmmirror.com/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "7.18.1", + "resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.18.1.tgz", + "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.18.1", + "resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.18.1.tgz", + "integrity": "sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==", + "license": "MIT", + "dependencies": { + "react-router": "7.18.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-use-measure": { + "version": "2.1.7", + "resolved": "https://registry.npmmirror.com/react-use-measure/-/react-use-measure-2.1.7.tgz", + "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/recharts": { + "version": "3.9.2", + "resolved": "https://registry.npmmirror.com/recharts/-/recharts-3.9.2.tgz", + "integrity": "sha512-G4fy+Pk46RaXgwWMh+Nzhyo/lbFAVqXo9gtetlyehe6Ehge9CsgDuOTwQDD+i1+llaLktNBiNq4bhnGlDRXFtw==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "^1.9.0 || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^11.1.8", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.2.0", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmmirror.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmmirror.com/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmmirror.com/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.2", + "resolved": "https://registry.npmmirror.com/regjsparser/-/regjsparser-0.13.2.tgz", + "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resedit": { + "version": "1.7.2", + "resolved": "https://registry.npmmirror.com/resedit/-/resedit-1.7.2.tgz", + "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pe-library": "^0.4.1" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/reselect": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/reselect/-/reselect-5.2.0.tgz", + "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmmirror.com/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/rolldown": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.139.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmmirror.com/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "license": "MIT" + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.4", + "resolved": "https://registry.npmmirror.com/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-javascript": { + "version": "7.0.7", + "resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-7.0.7.tgz", + "integrity": "sha512-YAy8Od6KV+uuwUuU50np8fGB/Aues6Y0nAhA9y/hId74PlKUcme4pXcBD46NWKr1Q4osN/iseZ17YqO1XfmI8g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.4", + "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/smob": { + "version": "1.6.2", + "resolved": "https://registry.npmmirror.com/smob/-/smob-1.6.2.tgz", + "integrity": "sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmmirror.com/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "deprecated": "The work that was done in this beta branch won't be included in future versions", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/source-map/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/source-map/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ssri/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/stats-gl": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/stats-gl/-/stats-gl-2.4.2.tgz", + "integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==", + "license": "MIT", + "dependencies": { + "@types/three": "*", + "three": "^0.170.0" + }, + "peerDependencies": { + "@types/three": "*", + "three": "*" + } + }, + "node_modules/stats-gl/node_modules/three": { + "version": "0.170.0", + "resolved": "https://registry.npmmirror.com/three/-/three-0.170.0.tgz", + "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==", + "license": "MIT" + }, + "node_modules/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmmirror.com/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmmirror.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmmirror.com/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/suspend-react": { + "version": "0.1.3", + "resolved": "https://registry.npmmirror.com/suspend-react/-/suspend-react-0.1.3.tgz", + "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=17.0" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwind-merge": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.5.tgz", + "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.49.0", + "resolved": "https://registry.npmmirror.com/terser/-/terser-5.49.0.tgz", + "integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/three": { + "version": "0.185.1", + "resolved": "https://registry.npmmirror.com/three/-/three-0.185.1.tgz", + "integrity": "sha512-5aojFCXKwnjBRZvUnt3WFfEcvUJgkN5LlijRFN95hMy8WVkG4I0QNcJE+OuWvuJ0bOdStrbfXn0pkd6/QyiAlg==", + "license": "MIT" + }, + "node_modules/three-mesh-bvh": { + "version": "0.7.8", + "resolved": "https://registry.npmmirror.com/three-mesh-bvh/-/three-mesh-bvh-0.7.8.tgz", + "integrity": "sha512-BGEZTOIC14U0XIRw3tO4jY7IjP7n7v24nv9JXS1CyeVRWOCkcOMhRnmENUjuV39gktAw4Ofhr0OvIAiTspQrrw==", + "deprecated": "Deprecated due to three.js version incompatibility. Please use v0.8.0, instead.", + "license": "MIT", + "peerDependencies": { + "three": ">= 0.151.0" + } + }, + "node_modules/three-stdlib": { + "version": "2.36.1", + "resolved": "https://registry.npmmirror.com/three-stdlib/-/three-stdlib-2.36.1.tgz", + "integrity": "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==", + "license": "MIT", + "dependencies": { + "@types/draco3d": "^1.4.0", + "@types/offscreencanvas": "^2019.6.4", + "@types/webxr": "^0.5.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "potpack": "^1.0.1" + }, + "peerDependencies": { + "three": ">=0.128.0" + } + }, + "node_modules/three-stdlib/node_modules/fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==", + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.4.7", + "resolved": "https://registry.npmmirror.com/tldts/-/tldts-7.4.7.tgz", + "integrity": "sha512-56L0/9HELHSsG1bFCzay8UoLxzRL7kpFf7Wl5q/kSYwiSJGACvro61xnKzPNM+SadxllzdtXsKDSXE7HPeqIAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.7" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.7", + "resolved": "https://registry.npmmirror.com/tldts-core/-/tldts-core-7.4.7.tgz", + "integrity": "sha512-rNlAI8fKn/JckBMUSbNL/ES2kmDiurWaE49l+ikwEc9A6lFR7gMx9AhgQMQKBK4H5w4pKLH64JzZfB99uRsGNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmmirror.com/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/troika-three-text": { + "version": "0.52.4", + "resolved": "https://registry.npmmirror.com/troika-three-text/-/troika-three-text-0.52.4.tgz", + "integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==", + "license": "MIT", + "dependencies": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.52.4", + "troika-worker-utils": "^0.52.0", + "webgl-sdf-generator": "1.1.1" + }, + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-three-utils": { + "version": "0.52.4", + "resolved": "https://registry.npmmirror.com/troika-three-utils/-/troika-three-utils-0.52.4.tgz", + "integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-worker-utils": { + "version": "0.52.0", + "resolved": "https://registry.npmmirror.com/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", + "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==", + "license": "MIT" + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmmirror.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tunnel-rat": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/tunnel-rat/-/tunnel-rat-0.1.2.tgz", + "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", + "license": "MIT", + "dependencies": { + "zustand": "^4.3.2" + } + }, + "node_modules/tunnel-rat/node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "7.28.0", + "resolved": "https://registry.npmmirror.com/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmmirror.com/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/uuid": { + "version": "14.0.1", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-14.0.1.tgz", + "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.1", + "resolved": "https://registry.npmmirror.com/verror/-/verror-1.10.1.tgz", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmmirror.com/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "8.1.3", + "resolved": "https://registry.npmmirror.com/vite/-/vite-8.1.3.tgz", + "integrity": "sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.16", + "rolldown": "~1.1.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-pwa": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/vite-plugin-pwa/-/vite-plugin-pwa-1.3.0.tgz", + "integrity": "sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.6", + "pretty-bytes": "^6.1.1", + "tinyglobby": "^0.2.10", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^1.0.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.10", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/wait-on": { + "version": "9.0.10", + "resolved": "https://registry.npmmirror.com/wait-on/-/wait-on-9.0.10.tgz", + "integrity": "sha512-rCoJEhvMr0X6alHmwc9abbrA5ZrLZFKpFQVKPNFwl2h7DapXOGdmimIHDtLOWhT4PjhZhxFEtZoQgEXbkDWdZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "axios": "^1.16.0", + "joi": "^18.2.1", + "lodash": "^4.18.1", + "minimist": "^1.2.8", + "rxjs": "^7.8.2" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, + "node_modules/webgl-sdf-generator": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==", + "license": "MIT" + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/workbox-background-sync": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-background-sync/-/workbox-background-sync-7.4.1.tgz", + "integrity": "sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-broadcast-update/-/workbox-broadcast-update-7.4.1.tgz", + "integrity": "sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-build": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-build/-/workbox-build-7.4.1.tgz", + "integrity": "sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", + "@trickfilm400/rollup-plugin-off-main-thread": "^3.0.0-pre1", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "eta": "^4.5.1", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^11.0.1", + "pretty-bytes": "^5.3.0", + "rollup": "^4.53.3", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "7.4.1", + "workbox-broadcast-update": "7.4.1", + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-google-analytics": "7.4.1", + "workbox-navigation-preload": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-range-requests": "7.4.1", + "workbox-recipes": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1", + "workbox-streams": "7.4.1", + "workbox-sw": "7.4.1", + "workbox-window": "7.4.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/workbox-build/node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmmirror.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-cacheable-response/-/workbox-cacheable-response-7.4.1.tgz", + "integrity": "sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-core": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-core/-/workbox-core-7.4.1.tgz", + "integrity": "sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-expiration": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-expiration/-/workbox-expiration-7.4.1.tgz", + "integrity": "sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-google-analytics": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-google-analytics/-/workbox-google-analytics-7.4.1.tgz", + "integrity": "sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-background-sync": "7.4.1", + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-navigation-preload/-/workbox-navigation-preload-7.4.1.tgz", + "integrity": "sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-precaching": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-precaching/-/workbox-precaching-7.4.1.tgz", + "integrity": "sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-range-requests": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-range-requests/-/workbox-range-requests-7.4.1.tgz", + "integrity": "sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-recipes": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-recipes/-/workbox-recipes-7.4.1.tgz", + "integrity": "sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-routing": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-routing/-/workbox-routing-7.4.1.tgz", + "integrity": "sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-strategies": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-strategies/-/workbox-strategies-7.4.1.tgz", + "integrity": "sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-streams": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-streams/-/workbox-streams-7.4.1.tgz", + "integrity": "sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1" + } + }, + "node_modules/workbox-sw": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-sw/-/workbox-sw-7.4.1.tgz", + "integrity": "sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-window": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-window/-/workbox-window-7.4.1.tgz", + "integrity": "sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "7.4.1" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmmirror.com/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/zip-stream/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/zip-stream/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmmirror.com/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, + "node_modules/zustand": { + "version": "5.0.14", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-5.0.14.tgz", + "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/client/package.json b/client/package.json index b11f0e30..2c4fbe41 100644 --- a/client/package.json +++ b/client/package.json @@ -1,107 +1,107 @@ -{ - "name": "entropy-decrease", - "productName": "Entropy decrease", - "private": true, - "license": "BUSL-1.1", - "version": "0.24.0", - "description": "熵减 - 跨端学习平台", - "author": "Entropy Decrease Team", - "main": "dist-electron/electron/main.js", - "scripts": { - "dev": "vite --mode test", - "build": "tsc -b && vite build", - "lint": "oxlint", - "preview": "vite preview", - "electron:dev": "concurrently -k -n vite,electron \"cross-env ELECTRON_BUILD=1 vite --mode test\" \"wait-on http://localhost:5173 && tsc -p electron/tsconfig.json && cross-env ELECTRON_BUILD=1 NODE_ENV=development VITE_AI_GATEWAY_URL=http://101.37.70.235:8000 electron .\"", - "electron:build": "cross-env ELECTRON_BUILD=1 vite build && tsc -p electron/tsconfig.json && electron-builder", - "test": "vitest run", - "test:watch": "vitest", - "postinstall": "electron-rebuild -f -w better-sqlite3", - "modelcontextprotocol": "mcp-server-sdk", - "fs": "mcp-server-filesystem", - "seq": "mcp-server-sequential-thinking", - "memory": "mcp-server-memory" - }, - "dependencies": { - "@automerge/automerge": "^3.3.2", - "@modelcontextprotocol/sdk": "^1.29.0", - "@modelcontextprotocol/server-filesystem": "^2026.7.10", - "@modelcontextprotocol/server-memory": "^2026.7.4", - "@modelcontextprotocol/server-sequential-thinking": "^2026.7.4", - "@radix-ui/react-context-menu": "^2.3.3", - "@radix-ui/react-dialog": "^1.1.19", - "@radix-ui/react-slot": "^1.3.0", - "@radix-ui/react-toast": "^1.2.19", - "@react-three/drei": "^9.122.0", - "@react-three/fiber": "^8.18.0", - "@react-three/postprocessing": "^2.19.1", - "@supabase/supabase-js": "^2.110.1", - "@tanstack/react-query": "^5.101.2", - "@tanstack/react-virtual": "^3.14.5", - "@tiptap/extension-color": "^3.27.3", - "@tiptap/extension-highlight": "^3.27.3", - "@tiptap/extension-image": "^3.27.3", - "@tiptap/extension-placeholder": "^3.27.3", - "@tiptap/extension-table": "^3.27.3", - "@tiptap/extension-table-cell": "^3.27.3", - "@tiptap/extension-table-header": "^3.27.3", - "@tiptap/extension-table-row": "^3.27.3", - "@tiptap/extension-task-item": "^3.27.3", - "@tiptap/extension-task-list": "^3.27.3", - "@tiptap/extension-text-align": "^3.27.3", - "@tiptap/extension-text-style": "^3.27.3", - "@tiptap/extension-underline": "^3.27.3", - "@tiptap/pm": "^3.27.3", - "@tiptap/react": "^3.27.3", - "@tiptap/starter-kit": "^3.27.3", - "better-sqlite3": "^11.0.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "dexie": "^4.4.4", - "dompurify": "^3.4.12", - "electron-updater": "^6.3.9", - "framer-motion": "^12.42.2", - "lucide-react": "^1.23.0", - "lxgw-wenkai-lite-webfont": "^1.7.0", - "pixelmatch": "^7.2.0", - "pngjs": "^7.0.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^7.18.1", - "recharts": "^3.9.2", - "tailwind-merge": "^3.6.0", - "tailwindcss-animate": "^1.0.7", - "three": "^0.185.1", - "uuid": "^14.0.1", - "zustand": "^5.0.14" - }, - "devDependencies": { - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@types/better-sqlite3": "^7.6.0", - "@types/dompurify": "^3.0.5", - "@types/node": "^24.13.2", - "@types/pngjs": "^6.0.5", - "@types/react": "^18.3.18", - "@types/react-dom": "^18.3.5", - "@types/three": "^0.185.1", - "@types/uuid": "^10.0.0", - "@vitejs/plugin-react": "^6.0.3", - "autoprefixer": "^10.5.2", - "concurrently": "^10.0.3", - "cross-env": "^10.1.0", - "electron": "^35.7.5", - "electron-builder": "^25.1.8", - "electron-rebuild": "^3.2.9", - "jsdom": "^29.1.1", - "oxlint": "^1.71.0", - "postcss": "^8.5.16", - "tailwindcss": "^3.4.19", - "typescript": "~6.0.2", - "vite": "^8.1.1", - "vite-plugin-pwa": "^1.3.0", - "vitest": "^4.1.10", - "wait-on": "^9.0.10", - "workbox-window": "^7.4.1" - } -} +{ + "name": "entropy-decrease", + "productName": "Entropy decrease", + "private": true, + "license": "BUSL-1.1", + "version": "0.23.0", + "description": "熵减 - 跨端学习平台", + "author": "Entropy Decrease Team", + "main": "dist-electron/electron/main.js", + "scripts": { + "dev": "vite --mode test", + "build": "tsc -b && vite build", + "lint": "oxlint", + "preview": "vite preview", + "electron:dev": "concurrently -k -n vite,electron \"cross-env ELECTRON_BUILD=1 vite --mode test\" \"wait-on http://localhost:5173 && tsc -p electron/tsconfig.json && cross-env ELECTRON_BUILD=1 NODE_ENV=development VITE_AI_GATEWAY_URL=http://101.37.70.235:8000 electron .\"", + "electron:build": "cross-env ELECTRON_BUILD=1 vite build && tsc -p electron/tsconfig.json && electron-builder", + "test": "vitest run", + "test:watch": "vitest", + "postinstall": "electron-rebuild -f -w better-sqlite3", + "modelcontextprotocol": "mcp-server-sdk", + "fs": "mcp-server-filesystem", + "seq": "mcp-server-sequential-thinking", + "memory": "mcp-server-memory" + }, + "dependencies": { + "@automerge/automerge": "^3.3.2", + "@modelcontextprotocol/sdk": "^1.29.0", + "@modelcontextprotocol/server-filesystem": "^2026.7.10", + "@modelcontextprotocol/server-memory": "^2026.7.4", + "@modelcontextprotocol/server-sequential-thinking": "^2026.7.4", + "@radix-ui/react-context-menu": "^2.3.3", + "@radix-ui/react-dialog": "^1.1.19", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-toast": "^1.2.19", + "@react-three/drei": "^9.122.0", + "@react-three/fiber": "^8.18.0", + "@react-three/postprocessing": "^2.19.1", + "@supabase/supabase-js": "^2.110.1", + "@tanstack/react-query": "^5.101.2", + "@tanstack/react-virtual": "^3.14.5", + "@tiptap/extension-color": "^3.27.3", + "@tiptap/extension-highlight": "^3.27.3", + "@tiptap/extension-image": "^3.27.3", + "@tiptap/extension-placeholder": "^3.27.3", + "@tiptap/extension-table": "^3.27.3", + "@tiptap/extension-table-cell": "^3.27.3", + "@tiptap/extension-table-header": "^3.27.3", + "@tiptap/extension-table-row": "^3.27.3", + "@tiptap/extension-task-item": "^3.27.3", + "@tiptap/extension-task-list": "^3.27.3", + "@tiptap/extension-text-align": "^3.27.3", + "@tiptap/extension-text-style": "^3.27.3", + "@tiptap/extension-underline": "^3.27.3", + "@tiptap/pm": "^3.27.3", + "@tiptap/react": "^3.27.3", + "@tiptap/starter-kit": "^3.27.3", + "better-sqlite3": "^11.0.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "dexie": "^4.4.4", + "dompurify": "^3.4.12", + "electron-updater": "^6.3.9", + "framer-motion": "^12.42.2", + "lucide-react": "^1.23.0", + "lxgw-wenkai-lite-webfont": "^1.7.0", + "pixelmatch": "^7.2.0", + "pngjs": "^7.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^7.18.1", + "recharts": "^3.9.2", + "tailwind-merge": "^3.6.0", + "tailwindcss-animate": "^1.0.7", + "three": "^0.185.1", + "uuid": "^14.0.1", + "zustand": "^5.0.14" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/better-sqlite3": "^7.6.0", + "@types/dompurify": "^3.0.5", + "@types/node": "^24.13.2", + "@types/pngjs": "^6.0.5", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@types/three": "^0.185.1", + "@types/uuid": "^10.0.0", + "@vitejs/plugin-react": "^6.0.3", + "autoprefixer": "^10.5.2", + "concurrently": "^10.0.3", + "cross-env": "^10.1.0", + "electron": "^35.7.5", + "electron-builder": "^25.1.8", + "electron-rebuild": "^3.2.9", + "jsdom": "^29.1.1", + "oxlint": "^1.71.0", + "postcss": "^8.5.16", + "tailwindcss": "^3.4.19", + "typescript": "~6.0.2", + "vite": "^8.1.1", + "vite-plugin-pwa": "^1.3.0", + "vitest": "^4.1.10", + "wait-on": "^9.0.10", + "workbox-window": "^7.4.1" + } +} diff --git a/client/postcss.config.js b/client/postcss.config.js index 2e7af2b7..5eec88dd 100644 --- a/client/postcss.config.js +++ b/client/postcss.config.js @@ -1,6 +1,6 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/client/public/favicon.svg b/client/public/favicon.svg index e2d058ca..c44c7ccf 100644 --- a/client/public/favicon.svg +++ b/client/public/favicon.svg @@ -1,11 +1,11 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/client/public/offline.html b/client/public/offline.html index b89f2501..471ed94f 100644 --- a/client/public/offline.html +++ b/client/public/offline.html @@ -1,152 +1,152 @@ - - - - - - - 熵减 — 您已离线 - - - -
- - - - - - - - - -
- -

您已离线

- -

-    - 请检查网络连接后刷新页面。
- 已缓存在本地的数据仍然可以正常使用。 -

- - - - - - - 重新连接 - - -

检测到网络连接已恢复,正在跳转…

- - - - + + + + + + + 熵减 — 您已离线 + + + +
+ + + + + + + + + +
+ +

您已离线

+ +

+    + 请检查网络连接后刷新页面。
+ 已缓存在本地的数据仍然可以正常使用。 +

+ + + + + + + 重新连接 + + +

检测到网络连接已恢复,正在跳转…

+ + + + diff --git a/client/src/AGENTS.md b/client/src/AGENTS.md index adc159bb..e1ec55ae 100644 --- a/client/src/AGENTS.md +++ b/client/src/AGENTS.md @@ -1,54 +1,54 @@ -# AGENTS.md — client/src 渲染进程子系统 - -## 入口 - -- `main.tsx` — React 应用挂载点 -- `App.tsx` — 路由定义、全局布局、3D 场景容器 - -## 目录结构 - -``` -src/ -├── components/ # 共享 UI 组件(layout/ ui/ onboarding/ overlay/ sync/) -├── features/ # 功能模块(按业务域划分) -│ ├── classroom/ # 网课笔记提取(多模态捕获) -│ ├── dashboard/ # 学习仪表盘 + 深海/穹顶双世界主题 -│ ├── flashcard/ # 闪卡(间隔重复) -│ ├── feynman/ # 费曼学习法 -│ ├── notes/ # 智能笔记(TipTap 富文本) -│ ├── pomodoro/ # 番茄钟 -│ └── inspiration/ # 灵感空间 -├── hooks/ # 全局自定义 Hooks -├── lib/ # 工具库与适配层(AI 客户端、存储、同步) -├── pages/ # 页面级组件(设置、登录等) -├── routes/ # 路由配置 -├── stores/ # Zustand 全局状态 -├── types/ # TypeScript 类型定义 -├── styles/ # 全局样式与主题变量 -└── workers/ # Web Worker -``` - -## 约束 - -- 所有 AI 调用必须经 `lib/ai/` 适配层,不得在组件中直接 fetch AI 网关 -- 本地数据操作通过 `lib/db/` 或 `lib/storage/`,禁止组件内直接操作 IndexedDB -- 新增功能模块必须在 `features/` 下创建独立目录,包含 `components/`、`hooks/`、`pages/` -- 3D 场景实体配置集中在空间导航配置中,双世界主题(深海/穹顶)必须同步适配 -- 状态管理使用 Zustand,服务端缓存使用 TanStack Query,不混用 - -## 验证路由 - -```bash -# 在 client/ 目录下执行 -npm run lint # Oxlint 静态检查 -npm run test # Vitest 单元测试 -npm run build # tsc -b && vite build — 必须零错误 -``` - -## 高影响文件 - -- `App.tsx` — 路由与全局布局变更影响所有页面 -- `stores/` — 全局状态变更需验证所有消费组件 -- `lib/ai/` — AI 调度变更影响全部 AI 功能 -- `components/layout/Sidebar.tsx` — 导航结构变更影响用户流转 -- `styles/` — 主题变量变更影响双世界全局视觉 +# AGENTS.md — client/src 渲染进程子系统 + +## 入口 + +- `main.tsx` — React 应用挂载点 +- `App.tsx` — 路由定义、全局布局、3D 场景容器 + +## 目录结构 + +``` +src/ +├── components/ # 共享 UI 组件(layout/ ui/ onboarding/ overlay/ sync/) +├── features/ # 功能模块(按业务域划分) +│ ├── classroom/ # 网课笔记提取(多模态捕获) +│ ├── dashboard/ # 学习仪表盘 + 深海/穹顶双世界主题 +│ ├── flashcard/ # 闪卡(间隔重复) +│ ├── feynman/ # 费曼学习法 +│ ├── notes/ # 智能笔记(TipTap 富文本) +│ ├── pomodoro/ # 番茄钟 +│ └── inspiration/ # 灵感空间 +├── hooks/ # 全局自定义 Hooks +├── lib/ # 工具库与适配层(AI 客户端、存储、同步) +├── pages/ # 页面级组件(设置、登录等) +├── routes/ # 路由配置 +├── stores/ # Zustand 全局状态 +├── types/ # TypeScript 类型定义 +├── styles/ # 全局样式与主题变量 +└── workers/ # Web Worker +``` + +## 约束 + +- 所有 AI 调用必须经 `lib/ai/` 适配层,不得在组件中直接 fetch AI 网关 +- 本地数据操作通过 `lib/db/` 或 `lib/storage/`,禁止组件内直接操作 IndexedDB +- 新增功能模块必须在 `features/` 下创建独立目录,包含 `components/`、`hooks/`、`pages/` +- 3D 场景实体配置集中在空间导航配置中,双世界主题(深海/穹顶)必须同步适配 +- 状态管理使用 Zustand,服务端缓存使用 TanStack Query,不混用 + +## 验证路由 + +```bash +# 在 client/ 目录下执行 +npm run lint # Oxlint 静态检查 +npm run test # Vitest 单元测试 +npm run build # tsc -b && vite build — 必须零错误 +``` + +## 高影响文件 + +- `App.tsx` — 路由与全局布局变更影响所有页面 +- `stores/` — 全局状态变更需验证所有消费组件 +- `lib/ai/` — AI 调度变更影响全部 AI 功能 +- `components/layout/Sidebar.tsx` — 导航结构变更影响用户流转 +- `styles/` — 主题变量变更影响双世界全局视觉 diff --git a/client/src/App.tsx b/client/src/App.tsx index 61a19f2e..14a3789a 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,118 +1,125 @@ -import { useState, useEffect, useLayoutEffect } from 'react'; -import { RouterProvider } from 'react-router-dom'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { ToastProvider } from '@/components/ui/Toast'; -import AchievementToast from '@/components/ui/AchievementToast'; -import UpdateNotification from '@/components/ui/UpdateNotification'; -import ConsentModal, { CURRENT_CONSENT_VERSION } from '@/components/ui/ConsentModal'; -import { AuthProvider } from '@/lib/auth/AuthContext'; -import { SyncProvider } from '@/lib/sync/SyncContext'; -import { ErrorBoundary } from '@/components/ui/ErrorBoundary'; -import { router } from '@/routes'; -import { useTheme } from '@/hooks/useTheme'; -import { db } from '@/lib/storage/database'; -import { soundPlayer } from '@/lib/audio/SoundPlayer'; -import { getAIConfig } from '@/lib/ai/config'; -import '@/stores/useSettingsStore'; // 导入以触发音效设置初始化 - -// 启动时预加载所有音效(不阻塞渲染) -soundPlayer.preloadAll(); - -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - staleTime: 5 * 60 * 1000, - retry: 1, - }, - }, -}); - -function App() { - // Initialize theme on app mount - useTheme(); - - // ── 启动缓冲带:接管 HTML 内联 splash,首次渲染完成后淡出 ── - useLayoutEffect(() => { - const splash = document.getElementById('app-splash'); - if (!splash) return; - - const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; - - if (prefersReduced) { - splash.remove(); - return; - } - - // 触发淡出过渡(CSS transition: opacity 0.5s ease) - requestAnimationFrame(() => { - splash.style.pointerEvents = 'none'; - splash.style.opacity = '0'; - const onEnd = () => { - splash.remove(); - splash.removeEventListener('transitionend', onEnd); - }; - splash.addEventListener('transitionend', onEnd); - // 安全兑底:transitionend 未触发时强制移除 - setTimeout(() => { if (splash.parentNode) splash.remove(); }, 800); - }); - - // 应用空闲时预检测 AI 网关健康状态(不阻塞首屏) - const idle = window.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1500)); - idle(() => { - // 同步网关地址到主进程(主进程无法访问 localStorage,需显式传递) - const aiConfig = getAIConfig(); - if (aiConfig.gatewayUrl && window.electronAPI) { - window.electronAPI.invoke('ai:set-gateway-url', aiConfig.gatewayUrl).catch(() => {}); - } - import('./hooks/useAIGatewayHealth').then(({ precheckGatewayHealth }) => { - precheckGatewayHealth(); - }); - }); - }, []); - - const [consentGiven, setConsentGiven] = useState(null); - - useEffect(() => { - // 检查是否已同意隐私政策 - db.consent - .where('type') - .equals('privacy') - .first() - .then((record) => { - setConsentGiven(!!record); - }) - .catch(() => { - setConsentGiven(false); - }); - }, []); - - const handleAcceptConsent = async () => { - const now = new Date(); - await db.consent.bulkPut([ - { id: crypto.randomUUID(), type: 'privacy' as const, version: CURRENT_CONSENT_VERSION, acceptedAt: now }, - { id: crypto.randomUUID(), type: 'terms' as const, version: CURRENT_CONSENT_VERSION, acceptedAt: now }, - ]); - setConsentGiven(true); - }; - - return ( - - - - - {consentGiven === false && ( - - )} - - - - - - - - - - ); -} - -export default App; +/** + * 应用根组件:全局 Provider 编排与路由挂载 + * + * @ai-context: Provider 顺序即依赖顺序——Query/Toast 在外,Auth/Sync 依赖其后, + * 路由最内层。此处仅做编排,不写业务逻辑。 + * @ai-context: 首屏用 useLayoutEffect 处理主题以避免闪白(在绘制前同步应用)。 + */ +import { useState, useEffect, useLayoutEffect } from 'react'; +import { RouterProvider } from 'react-router-dom'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ToastProvider } from '@/components/ui/Toast'; +import AchievementToast from '@/components/ui/AchievementToast'; +import UpdateNotification from '@/components/ui/UpdateNotification'; +import ConsentModal, { CURRENT_CONSENT_VERSION } from '@/components/ui/ConsentModal'; +import { AuthProvider } from '@/lib/auth/AuthContext'; +import { SyncProvider } from '@/lib/sync/SyncContext'; +import { ErrorBoundary } from '@/components/ui/ErrorBoundary'; +import { router } from '@/routes'; +import { useTheme } from '@/hooks/useTheme'; +import { db } from '@/lib/storage/database'; +import { soundPlayer } from '@/lib/audio/SoundPlayer'; +import { getAIConfig } from '@/lib/ai/config'; +import '@/stores/useSettingsStore'; // 导入以触发音效设置初始化 + +// 启动时预加载所有音效(不阻塞渲染) +soundPlayer.preloadAll(); + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60 * 1000, + retry: 1, + }, + }, +}); + +function App() { + // Initialize theme on app mount + useTheme(); + + // ── 启动缓冲带:接管 HTML 内联 splash,首次渲染完成后淡出 ── + useLayoutEffect(() => { + const splash = document.getElementById('app-splash'); + if (!splash) return; + + const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + + if (prefersReduced) { + splash.remove(); + return; + } + + // 触发淡出过渡(CSS transition: opacity 0.5s ease) + requestAnimationFrame(() => { + splash.style.pointerEvents = 'none'; + splash.style.opacity = '0'; + const onEnd = () => { + splash.remove(); + splash.removeEventListener('transitionend', onEnd); + }; + splash.addEventListener('transitionend', onEnd); + // 安全兑底:transitionend 未触发时强制移除 + setTimeout(() => { if (splash.parentNode) splash.remove(); }, 800); + }); + + // 应用空闲时预检测 AI 网关健康状态(不阻塞首屏) + const idle = window.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1500)); + idle(() => { + // 同步网关地址到主进程(主进程无法访问 localStorage,需显式传递) + const aiConfig = getAIConfig(); + if (aiConfig.gatewayUrl && window.electronAPI) { + window.electronAPI.invoke('ai:set-gateway-url', aiConfig.gatewayUrl).catch(() => {}); + } + import('./hooks/useAIGatewayHealth').then(({ precheckGatewayHealth }) => { + precheckGatewayHealth(); + }); + }); + }, []); + + const [consentGiven, setConsentGiven] = useState(null); + + useEffect(() => { + // 检查是否已同意隐私政策 + db.consent + .where('type') + .equals('privacy') + .first() + .then((record) => { + setConsentGiven(!!record); + }) + .catch(() => { + setConsentGiven(false); + }); + }, []); + + const handleAcceptConsent = async () => { + const now = new Date(); + await db.consent.bulkPut([ + { id: crypto.randomUUID(), type: 'privacy' as const, version: CURRENT_CONSENT_VERSION, acceptedAt: now }, + { id: crypto.randomUUID(), type: 'terms' as const, version: CURRENT_CONSENT_VERSION, acceptedAt: now }, + ]); + setConsentGiven(true); + }; + + return ( + + + + + {consentGiven === false && ( + + )} + + + + + + + + + + ); +} + +export default App; diff --git a/client/src/components/MigrationProgress.tsx b/client/src/components/MigrationProgress.tsx index d1eda58c..9a75f6cb 100644 --- a/client/src/components/MigrationProgress.tsx +++ b/client/src/components/MigrationProgress.tsx @@ -1,89 +1,91 @@ -/** 迁移进度 UI — 全屏遮罩 + 玻璃拟态卡片,展示 IndexedDB → SQLite 迁移进度 */ -import { useState, useEffect, useCallback } from 'react'; - -interface MigrationStatus { completed: boolean; currentTable: string; tablesTotal: number; tablesCompleted: number; rowsMigrated: number; error?: string } -interface Props { onComplete: () => void } - -const INIT: MigrationStatus = { completed: false, currentTable: '', tablesTotal: 0, tablesCompleted: 0, rowsMigrated: 0 }; -const LABELS: Record = { - notes: '结礁', noteFolders: '文件夹', flashcardDecks: '卡组', flashcards: '反衰减呼吸', - flashcardReviews: '复习记录', feynmanNotes: '浮出水面笔记', feynmanSummaries: '浮出水面总结', - feynmanWeakPoints: '薄弱点', pomodoroSessions: '深潜', pomodoroSettings: '深潜设置', - appSettings: '设置', operationLog: '操作日志', syncConflicts: '同步冲突', - offlineQueue: '离线队列', studyCheckIns: '打卡', achievements: '成就', - pomodoroGoals: '番茄目标', windowCaptures: '窗口采集', consent: '协议', - userProfile: '用户', inspirations: '萤火海沟', -}; - -export default function MigrationProgress({ onComplete }: Props) { - const [s, setS] = useState(INIT); - const [err, setErr] = useState(null); - - const run = useCallback(async () => { - const api = window.electronAPI; - if (!api) { setErr('electronAPI 不可用'); return; } - try { - const { needed, tableMapping } = await api.migration.check(); - if (!needed) { onComplete(); return; } - setS((p) => ({ ...p, tablesTotal: tableMapping.length })); - const { db: dexieDb } = await import('@/lib/storage/database'); - let rows = 0; - for (let i = 0; i < tableMapping.length; i++) { - const { dexie, sqlite } = tableMapping[i]; - setS((p) => ({ ...p, currentTable: LABELS[dexie] ?? dexie })); - const data = await dexieDb.table(dexie).toArray(); - if (data.length > 0) { - const res = await api.migration.importTable(sqlite, data); - if (!res.success) throw new Error(res.error ?? `导入 ${dexie} 失败`); - rows += res.rowsImported ?? data.length; - } - setS((p) => ({ ...p, tablesCompleted: i + 1, rowsMigrated: rows })); - } - const fin = await api.migration.complete(); - if (!fin.success) throw new Error(fin.error); - setS((p) => ({ ...p, completed: true, currentTable: '完成' })); - setTimeout(onComplete, 800); - } catch (e) { setErr(e instanceof Error ? e.message : String(e)); } - }, [onComplete]); - - useEffect(() => { run(); }, [run]); - const pct = s.tablesTotal > 0 ? Math.round((s.tablesCompleted / s.tablesTotal) * 100) : 0; - - return ( -
-
-
-
- - {s.completed ? : } - -
-
-

{s.completed ? '迁移完成' : err ? '迁移出错' : '正在迁移数据…'}

- {!s.completed && !err &&

正在迁移 {s.currentTable}

} -
-
-
-
-
-
-
- {s.tablesCompleted} / {s.tablesTotal} 张表 - {s.rowsMigrated.toLocaleString()} 行 -
-
- {err && ( - <> -
-

{err}

-
- - - )} -
-
- ); -} +/** 迁移进度 UI — 全屏遮罩 + 玻璃拟态卡片,展示 IndexedDB → SQLite 迁移进度 * + * @ai-context: 通用组件:MigrationProgress。 + */ +import { useState, useEffect, useCallback } from 'react'; + +interface MigrationStatus { completed: boolean; currentTable: string; tablesTotal: number; tablesCompleted: number; rowsMigrated: number; error?: string } +interface Props { onComplete: () => void } + +const INIT: MigrationStatus = { completed: false, currentTable: '', tablesTotal: 0, tablesCompleted: 0, rowsMigrated: 0 }; +const LABELS: Record = { + notes: '结礁', noteFolders: '文件夹', flashcardDecks: '卡组', flashcards: '反衰减呼吸', + flashcardReviews: '复习记录', feynmanNotes: '浮出水面笔记', feynmanSummaries: '浮出水面总结', + feynmanWeakPoints: '薄弱点', pomodoroSessions: '深潜', pomodoroSettings: '深潜设置', + appSettings: '设置', operationLog: '操作日志', syncConflicts: '同步冲突', + offlineQueue: '离线队列', studyCheckIns: '打卡', achievements: '成就', + pomodoroGoals: '番茄目标', windowCaptures: '窗口采集', consent: '协议', + userProfile: '用户', inspirations: '萤火海沟', +}; + +export default function MigrationProgress({ onComplete }: Props) { + const [s, setS] = useState(INIT); + const [err, setErr] = useState(null); + + const run = useCallback(async () => { + const api = window.electronAPI; + if (!api) { setErr('electronAPI 不可用'); return; } + try { + const { needed, tableMapping } = await api.migration.check(); + if (!needed) { onComplete(); return; } + setS((p) => ({ ...p, tablesTotal: tableMapping.length })); + const { db: dexieDb } = await import('@/lib/storage/database'); + let rows = 0; + for (let i = 0; i < tableMapping.length; i++) { + const { dexie, sqlite } = tableMapping[i]; + setS((p) => ({ ...p, currentTable: LABELS[dexie] ?? dexie })); + const data = await dexieDb.table(dexie).toArray(); + if (data.length > 0) { + const res = await api.migration.importTable(sqlite, data); + if (!res.success) throw new Error(res.error ?? `导入 ${dexie} 失败`); + rows += res.rowsImported ?? data.length; + } + setS((p) => ({ ...p, tablesCompleted: i + 1, rowsMigrated: rows })); + } + const fin = await api.migration.complete(); + if (!fin.success) throw new Error(fin.error); + setS((p) => ({ ...p, completed: true, currentTable: '完成' })); + setTimeout(onComplete, 800); + } catch (e) { setErr(e instanceof Error ? e.message : String(e)); } + }, [onComplete]); + + useEffect(() => { run(); }, [run]); + const pct = s.tablesTotal > 0 ? Math.round((s.tablesCompleted / s.tablesTotal) * 100) : 0; + + return ( +
+
+
+
+ + {s.completed ? : } + +
+
+

{s.completed ? '迁移完成' : err ? '迁移出错' : '正在迁移数据…'}

+ {!s.completed && !err &&

正在迁移 {s.currentTable}

} +
+
+
+
+
+
+
+ {s.tablesCompleted} / {s.tablesTotal} 张表 + {s.rowsMigrated.toLocaleString()} 行 +
+
+ {err && ( + <> +
+

{err}

+
+ + + )} +
+
+ ); +} diff --git a/client/src/components/PWAInstallPrompt.tsx b/client/src/components/PWAInstallPrompt.tsx index 21f356d3..77f2ff39 100644 --- a/client/src/components/PWAInstallPrompt.tsx +++ b/client/src/components/PWAInstallPrompt.tsx @@ -1,108 +1,111 @@ -import { useState, useEffect, useCallback } from 'react'; -import { Download, X } from 'lucide-react'; -import { Button } from '@/components/ui/Button'; -import { cn } from '@/lib/utils'; - -interface BeforeInstallPromptEvent extends Event { - prompt(): Promise; - userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>; -} - -/** - * PWA 安装提示组件 - * - * 监听浏览器 beforeinstallprompt 事件,在合适时机显示安装提示。 - * 用户可以选择安装或关闭提示。 - */ -export function PWAInstallPrompt() { - const [deferredPrompt, setDeferredPrompt] = - useState(null); - const [showPrompt, setShowPrompt] = useState(false); - const [dismissed, setDismissed] = useState(false); - - useEffect(() => { - // 如果用户之前关闭过提示,不再显示 - const wasDismissed = sessionStorage.getItem('pwa-install-dismissed'); - if (wasDismissed) { - setDismissed(true); - return; - } - - const handler = (e: Event) => { - e.preventDefault(); - setDeferredPrompt(e as BeforeInstallPromptEvent); - // 延迟显示,避免打断用户操作 - setTimeout(() => setShowPrompt(true), 3000); - }; - - window.addEventListener('beforeinstallprompt', handler); - return () => { - window.removeEventListener('beforeinstallprompt', handler); - }; - }, []); - - const handleInstall = useCallback(async () => { - if (!deferredPrompt) return; - - await deferredPrompt.prompt(); - const { outcome } = await deferredPrompt.userChoice; - - if (outcome === 'accepted') { - setShowPrompt(false); - } - - setDeferredPrompt(null); - }, [deferredPrompt]); - - const handleDismiss = useCallback(() => { - setShowPrompt(false); - setDismissed(true); - sessionStorage.setItem('pwa-install-dismissed', 'true'); - }, []); - - if (!showPrompt || dismissed || !deferredPrompt) return null; - - return ( -
-
-
- -
-
-

- 安装熵减 -

-

- 添加到桌面,随时离线使用 -

-
-
- -
- - -
-
- ); -} +/** + * @ai-context: 通用组件:PWAInstallPrompt。 + */ +import { useState, useEffect, useCallback } from 'react'; +import { Download, X } from 'lucide-react'; +import { Button } from '@/components/ui/Button'; +import { cn } from '@/lib/utils'; + +interface BeforeInstallPromptEvent extends Event { + prompt(): Promise; + userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>; +} + +/** + * PWA 安装提示组件 + * + * 监听浏览器 beforeinstallprompt 事件,在合适时机显示安装提示。 + * 用户可以选择安装或关闭提示。 + */ +export function PWAInstallPrompt() { + const [deferredPrompt, setDeferredPrompt] = + useState(null); + const [showPrompt, setShowPrompt] = useState(false); + const [dismissed, setDismissed] = useState(false); + + useEffect(() => { + // 如果用户之前关闭过提示,不再显示 + const wasDismissed = sessionStorage.getItem('pwa-install-dismissed'); + if (wasDismissed) { + setDismissed(true); + return; + } + + const handler = (e: Event) => { + e.preventDefault(); + setDeferredPrompt(e as BeforeInstallPromptEvent); + // 延迟显示,避免打断用户操作 + setTimeout(() => setShowPrompt(true), 3000); + }; + + window.addEventListener('beforeinstallprompt', handler); + return () => { + window.removeEventListener('beforeinstallprompt', handler); + }; + }, []); + + const handleInstall = useCallback(async () => { + if (!deferredPrompt) return; + + await deferredPrompt.prompt(); + const { outcome } = await deferredPrompt.userChoice; + + if (outcome === 'accepted') { + setShowPrompt(false); + } + + setDeferredPrompt(null); + }, [deferredPrompt]); + + const handleDismiss = useCallback(() => { + setShowPrompt(false); + setDismissed(true); + sessionStorage.setItem('pwa-install-dismissed', 'true'); + }, []); + + if (!showPrompt || dismissed || !deferredPrompt) return null; + + return ( +
+
+
+ +
+
+

+ 安装熵减 +

+

+ 添加到桌面,随时离线使用 +

+
+
+ +
+ + +
+
+ ); +} diff --git a/client/src/components/RescuePanel.tsx b/client/src/components/RescuePanel.tsx index 5c361437..e3f697f1 100644 --- a/client/src/components/RescuePanel.tsx +++ b/client/src/components/RescuePanel.tsx @@ -1,294 +1,297 @@ -import { useState, useCallback, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { motion, AnimatePresence } from 'framer-motion'; -import { - X, HelpCircle, Lightbulb, Layers, BookOpen, - Coffee, RotateCcw, ArrowRight, Sparkles, -} from 'lucide-react'; -import { AIThinkingIndicator } from '@/components/ui/AIThinkingIndicator'; -import { cn } from '@/lib/utils'; -import { useAIRescue } from '@/lib/ai/useAI'; -import type { RescueContext } from '@/lib/ai/types'; - -type RescueLevel = 1 | 2 | 3; - -interface RescuePanelProps { - isOpen: boolean; - onClose: () => void; - context: { - topic: string; - relatedContent?: string; - mode?: string; - }; - /** 孵化建议回调 */ - onSuggestion?: (action: string) => void; -} - -const LEVEL_CONFIG: Record & { strokeWidth?: number | string }>; desc: string }> = { - 1: { label: '简化解释', icon: Lightbulb, desc: '换个方式重新理解' }, - 2: { label: '拆解子概念', icon: Layers, desc: '分解复杂概念' }, - 3: { label: '前置知识', icon: BookOpen, desc: '补充基础知识' }, -}; - -const SUGGESTIONS = [ - { key: 'pomodoro', label: '开始深潜休息', icon: Coffee, desc: '休息5分钟再继续' }, - { key: 'flashcard', label: '切换反衰减呼吸复习', icon: RotateCcw, desc: '换个学习方式' }, - { key: 'switch', label: '换个科目', icon: ArrowRight, desc: '转换思路' }, -]; - -export function RescuePanel({ isOpen, onClose, context, onSuggestion }: RescuePanelProps) { - const [activeLevel, setActiveLevel] = useState(1); - const [showIncubation, setShowIncubation] = useState(false); - const { loading, data, error, needsConfig, rescue } = useAIRescue(); - const navigate = useNavigate(); - - // 面板打开时触发救援请求 - useEffect(() => { - if (isOpen && context.topic) { - const rescueCtx: RescueContext = { - topic: context.topic, - relatedContent: context.relatedContent, - mode: (context.mode as RescueContext['mode']) ?? 'general', - }; - rescue(rescueCtx); - } - }, [isOpen, context.topic, context.relatedContent, context.mode, rescue]); - - // 卡壳超10分钟显示孵化建议(由外部 useStuckTimer 触发) - useEffect(() => { - if (!isOpen) setShowIncubation(false); - }, [isOpen]); - - const handleShowIncubation = useCallback(() => { - setShowIncubation(true); - }, []); - - // 暴露给父组件的触发方法(通过自定义事件) - useEffect(() => { - const handler = () => handleShowIncubation(); - window.addEventListener('rescue:show-incubation', handler); - return () => window.removeEventListener('rescue:show-incubation', handler); - }, [handleShowIncubation]); - - return ( - - {isOpen && ( - <> - {/* 背景遮罩 */} - - - {/* 滑出面板 */} - - {/* 头部 */} -
-
- -
-
-

学习救援

-

{context.topic}

-
- -
- - {/* 三级标签 */} -
- {([1, 2, 3] as RescueLevel[]).map((level) => { - const config = LEVEL_CONFIG[level]; - const Icon = config.icon; - const isActive = activeLevel === level; - return ( - - ); - })} -
- - {/* 内容区 */} -
- {loading && ( -
- - AI 正在思考救援方案… -
- )} - - {error && !loading && ( -
- {error} - {needsConfig && ( - - )} -
- )} - - {!loading && !error && data && ( - - {/* Level 1: 简化解释 */} - {activeLevel === 1 && ( -
-

让我换个方式解释…

- {data.hints.length > 0 ? ( - data.hints.map((hint, i) => ( -
-

{hint}

-
- )) - ) : ( -

暂无简化解释

- )} - {data.alternativeApproach && ( -
-

- - 另一种思路 -

-

{data.alternativeApproach}

-
- )} -
- )} - - {/* Level 2: 拆解子概念 */} - {activeLevel === 2 && ( -
-

将概念拆解为更小的部分:

- {data.hints.length > 0 ? ( - data.hints.map((hint, i) => ( -
-
- - {i + 1} - -

{hint}

-
-
- )) - ) : ( -

暂无子概念拆解

- )} -
- )} - - {/* Level 3: 前置知识 */} - {activeLevel === 3 && ( -
-

建议先掌握这些知识:

- {data.resources.length > 0 ? ( - data.resources.map((res, i) => ( - -

{res.title}

- {res.description && ( -

{res.description}

- )} -
- )) - ) : data.hints.length > 0 ? ( - data.hints.map((hint, i) => ( -
-

{hint}

-
- )) - ) : ( -

暂无前置知识推荐

- )} -
- )} -
- )} - - {/* 孵化建议区域 */} - {showIncubation && ( - -

- 卡壳超过10分钟,试试这些 -

-
- {SUGGESTIONS.map((s) => { - const Icon = s.icon; - return ( - - ); - })} -
-
- )} -
-
- - )} -
- ); -} +/** + * @ai-context: 通用组件:RescuePanel。 + */ +import { useState, useCallback, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { motion, AnimatePresence } from 'framer-motion'; +import { + X, HelpCircle, Lightbulb, Layers, BookOpen, + Coffee, RotateCcw, ArrowRight, Sparkles, +} from 'lucide-react'; +import { AIThinkingIndicator } from '@/components/ui/AIThinkingIndicator'; +import { cn } from '@/lib/utils'; +import { useAIRescue } from '@/lib/ai/useAI'; +import type { RescueContext } from '@/lib/ai/types'; + +type RescueLevel = 1 | 2 | 3; + +interface RescuePanelProps { + isOpen: boolean; + onClose: () => void; + context: { + topic: string; + relatedContent?: string; + mode?: string; + }; + /** 孵化建议回调 */ + onSuggestion?: (action: string) => void; +} + +const LEVEL_CONFIG: Record & { strokeWidth?: number | string }>; desc: string }> = { + 1: { label: '简化解释', icon: Lightbulb, desc: '换个方式重新理解' }, + 2: { label: '拆解子概念', icon: Layers, desc: '分解复杂概念' }, + 3: { label: '前置知识', icon: BookOpen, desc: '补充基础知识' }, +}; + +const SUGGESTIONS = [ + { key: 'pomodoro', label: '开始深潜休息', icon: Coffee, desc: '休息5分钟再继续' }, + { key: 'flashcard', label: '切换反衰减呼吸复习', icon: RotateCcw, desc: '换个学习方式' }, + { key: 'switch', label: '换个科目', icon: ArrowRight, desc: '转换思路' }, +]; + +export function RescuePanel({ isOpen, onClose, context, onSuggestion }: RescuePanelProps) { + const [activeLevel, setActiveLevel] = useState(1); + const [showIncubation, setShowIncubation] = useState(false); + const { loading, data, error, needsConfig, rescue } = useAIRescue(); + const navigate = useNavigate(); + + // 面板打开时触发救援请求 + useEffect(() => { + if (isOpen && context.topic) { + const rescueCtx: RescueContext = { + topic: context.topic, + relatedContent: context.relatedContent, + mode: (context.mode as RescueContext['mode']) ?? 'general', + }; + rescue(rescueCtx); + } + }, [isOpen, context.topic, context.relatedContent, context.mode, rescue]); + + // 卡壳超10分钟显示孵化建议(由外部 useStuckTimer 触发) + useEffect(() => { + if (!isOpen) setShowIncubation(false); + }, [isOpen]); + + const handleShowIncubation = useCallback(() => { + setShowIncubation(true); + }, []); + + // 暴露给父组件的触发方法(通过自定义事件) + useEffect(() => { + const handler = () => handleShowIncubation(); + window.addEventListener('rescue:show-incubation', handler); + return () => window.removeEventListener('rescue:show-incubation', handler); + }, [handleShowIncubation]); + + return ( + + {isOpen && ( + <> + {/* 背景遮罩 */} + + + {/* 滑出面板 */} + + {/* 头部 */} +
+
+ +
+
+

学习救援

+

{context.topic}

+
+ +
+ + {/* 三级标签 */} +
+ {([1, 2, 3] as RescueLevel[]).map((level) => { + const config = LEVEL_CONFIG[level]; + const Icon = config.icon; + const isActive = activeLevel === level; + return ( + + ); + })} +
+ + {/* 内容区 */} +
+ {loading && ( +
+ + AI 正在思考救援方案… +
+ )} + + {error && !loading && ( +
+ {error} + {needsConfig && ( + + )} +
+ )} + + {!loading && !error && data && ( + + {/* Level 1: 简化解释 */} + {activeLevel === 1 && ( +
+

让我换个方式解释…

+ {data.hints.length > 0 ? ( + data.hints.map((hint, i) => ( +
+

{hint}

+
+ )) + ) : ( +

暂无简化解释

+ )} + {data.alternativeApproach && ( +
+

+ + 另一种思路 +

+

{data.alternativeApproach}

+
+ )} +
+ )} + + {/* Level 2: 拆解子概念 */} + {activeLevel === 2 && ( +
+

将概念拆解为更小的部分:

+ {data.hints.length > 0 ? ( + data.hints.map((hint, i) => ( +
+
+ + {i + 1} + +

{hint}

+
+
+ )) + ) : ( +

暂无子概念拆解

+ )} +
+ )} + + {/* Level 3: 前置知识 */} + {activeLevel === 3 && ( +
+

建议先掌握这些知识:

+ {data.resources.length > 0 ? ( + data.resources.map((res, i) => ( + +

{res.title}

+ {res.description && ( +

{res.description}

+ )} +
+ )) + ) : data.hints.length > 0 ? ( + data.hints.map((hint, i) => ( +
+

{hint}

+
+ )) + ) : ( +

暂无前置知识推荐

+ )} +
+ )} +
+ )} + + {/* 孵化建议区域 */} + {showIncubation && ( + +

+ 卡壳超过10分钟,试试这些 +

+
+ {SUGGESTIONS.map((s) => { + const Icon = s.icon; + return ( + + ); + })} +
+
+ )} +
+
+ + )} +
+ ); +} diff --git a/client/src/components/layout/AppLayout.tsx b/client/src/components/layout/AppLayout.tsx index 6f4a78fe..e260895d 100644 --- a/client/src/components/layout/AppLayout.tsx +++ b/client/src/components/layout/AppLayout.tsx @@ -1,172 +1,175 @@ -import { useEffect, useState } from 'react'; -import { Outlet, useLocation, useNavigate } from 'react-router-dom'; -import { AnimatePresence, motion } from 'framer-motion'; -import { Home } from 'lucide-react'; -import CommandPalette from '../ui/CommandPalette'; -import { CloseConfirmDialog } from '../ui/CloseConfirmDialog'; -import { CustomTitlebar } from './CustomTitlebar'; -import BottomNav from './BottomNav'; -import { useSessionExpiry } from '@/hooks/useSessionExpiry'; -import { useSync } from '@/lib/sync/SyncContext'; -import { SceneProvider } from '@/lib/3d/core/SceneProvider'; -import { SceneTransition } from '@/lib/3d/scenes/SceneTransition'; -import { SpatialNav } from '@/lib/3d/navigation/SpatialNav'; -import { MobileNavGrid } from '@/lib/3d/scenes/MobileNavGrid'; -import { FunctionalOverlay } from '@/components/overlay/FunctionalOverlay'; -import { useOrbitalStore } from '@/lib/3d/navigation/OrbitalStore'; -import { OnboardingOverlay } from '@/components/onboarding/OnboardingOverlay'; -import { ModuleTourToast } from '@/components/onboarding/ModuleTourToast'; -import { HelpCenter } from '@/components/onboarding/HelpCenter'; -import { useOnboardingStore } from '@/components/onboarding/useOnboardingStore'; -import { useRuntimeEnv } from '@/lib/env/useRuntimeEnv'; -import { PWAInstallPrompt } from '@/components/PWAInstallPrompt'; - -export default function AppLayout() { - const { pathname } = useLocation(); - const navigate = useNavigate(); - const { isInModule, currentModule, enterModule, exitModule, syncWithRoute } = useOrbitalStore(); - const openHelp = useOnboardingStore((s) => s.openHelp); - const [showCloseDialog, setShowCloseDialog] = useState(false); - const { sync } = useSync(); - const { shouldDegrade3D } = useRuntimeEnv(); - - // 监听 session 过期事件 - useSessionExpiry(); - - // 路由 → 3D状态同步(刷新页面或直接URL访问时恢复状态) - useEffect(() => { - syncWithRoute(pathname); - }, [pathname, syncWithRoute]); - - // 监听 Electron 主进程发出的窗口关闭事件 - useEffect(() => { - if (!window.electronAPI?.onWindowClosing) return; - const cleanup = window.electronAPI.onWindowClosing(() => { - setShowCloseDialog(true); - }); - return cleanup; - }, []); - - // 监听退出前同步事件:主进程通知渲染进程执行一次同步 - useEffect(() => { - if (!window.electronAPI?.onSyncBeforeQuit) return; - const cleanup = window.electronAPI.onSyncBeforeQuit(async () => { - try { - await sync(); - } catch (err) { - console.error('[AppLayout] Sync before quit failed:', err); - } finally { - // 无论同步成功与否,都通知主进程可以继续退出 - window.electronAPI?.notifySyncComplete(); - } - }); - return cleanup; - }, [sync]); - - // 键盘快捷键:Esc退出模块,数字键导航 - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - // 如果焦点在输入元素中,不拦截 - const target = e.target as HTMLElement; - if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) { - return; - } - - if (e.key === 'Escape') { - if (isInModule) { - exitModule(); - } else { - // 在 3D 场景模式下按 Esc 返回仪表盘 - enterModule('dashboard'); - navigate('/'); - } - } - - // 数字键 0-7 快捷导航(需无修饰键) - if (!e.ctrlKey && !e.metaKey && !e.altKey) { - const moduleKeys: Record = { - '1': '/', '2': '/pomodoro', '3': '/notes', - '4': '/flashcards', '5': '/feynman', '6': '/inspiration', - '7': '/classroom', '0': '/settings', - }; - if (moduleKeys[e.key]) { - navigate(moduleKeys[e.key]); - } - } - - // Ctrl+/ 或 Cmd+/ 打开帮助中心 - if ((e.ctrlKey || e.metaKey) && e.key === '/') { - e.preventDefault(); - openHelp(); - } - }; - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); - }, [isInModule, enterModule, exitModule, navigate, openHelp]); - - return ( -
- {/* Layer 2: 始终最顶层 — Electron标题栏 */} - - - {/* Layer 0: 3D场景全屏背景 / 移动端2D降级 */} - {shouldDegrade3D ? ( - /* 移动端降级:显示 2D 模块导航网格代替 3D 场景 */ - !isInModule && - ) : ( - - - - - )} - - {/* Layer 1: 功能覆盖层 */} - - {isInModule && ( - - - - )} - - - {/* 非模块内时显示简洁的状态提示 + 返回按钮(仅桌面端) */} - {!isInModule && !shouldDegrade3D && ( - <> -
- - 点击3D物体进入模块 · 按 Esc 返回仪表盘 · 数字键 0-7 快捷跳转 - -
- {/* 浮动返回仪表盘按钮(仅桌面端) */} - { enterModule('dashboard'); navigate('/'); }} - className="fixed bottom-8 right-8 z-20 hidden md:flex w-12 h-12 rounded-full bg-black/30 backdrop-blur-xl border border-white/15 items-center justify-center text-white/70 hover:text-white hover:bg-black/50 transition-colors" - aria-label="返回仪表盘" - > - - - - )} - - {/* 移动端底部标签栏 — 置于功能覆盖层之上,避免被 3D 场景或模块遮罩覆盖 */} - - - {/* 全局组件 */} - - - - - - setShowCloseDialog(false)} /> -
- ); -} +/** + * @ai-context: 布局组件:AppLayout。 + */ +import { useEffect, useState } from 'react'; +import { Outlet, useLocation, useNavigate } from 'react-router-dom'; +import { AnimatePresence, motion } from 'framer-motion'; +import { Home } from 'lucide-react'; +import CommandPalette from '../ui/CommandPalette'; +import { CloseConfirmDialog } from '../ui/CloseConfirmDialog'; +import { CustomTitlebar } from './CustomTitlebar'; +import BottomNav from './BottomNav'; +import { useSessionExpiry } from '@/hooks/useSessionExpiry'; +import { useSync } from '@/lib/sync/SyncContext'; +import { SceneProvider } from '@/lib/3d/core/SceneProvider'; +import { SceneTransition } from '@/lib/3d/scenes/SceneTransition'; +import { SpatialNav } from '@/lib/3d/navigation/SpatialNav'; +import { MobileNavGrid } from '@/lib/3d/scenes/MobileNavGrid'; +import { FunctionalOverlay } from '@/components/overlay/FunctionalOverlay'; +import { useOrbitalStore } from '@/lib/3d/navigation/OrbitalStore'; +import { OnboardingOverlay } from '@/components/onboarding/OnboardingOverlay'; +import { ModuleTourToast } from '@/components/onboarding/ModuleTourToast'; +import { HelpCenter } from '@/components/onboarding/HelpCenter'; +import { useOnboardingStore } from '@/components/onboarding/useOnboardingStore'; +import { useRuntimeEnv } from '@/lib/env/useRuntimeEnv'; +import { PWAInstallPrompt } from '@/components/PWAInstallPrompt'; + +export default function AppLayout() { + const { pathname } = useLocation(); + const navigate = useNavigate(); + const { isInModule, currentModule, enterModule, exitModule, syncWithRoute } = useOrbitalStore(); + const openHelp = useOnboardingStore((s) => s.openHelp); + const [showCloseDialog, setShowCloseDialog] = useState(false); + const { sync } = useSync(); + const { shouldDegrade3D } = useRuntimeEnv(); + + // 监听 session 过期事件 + useSessionExpiry(); + + // 路由 → 3D状态同步(刷新页面或直接URL访问时恢复状态) + useEffect(() => { + syncWithRoute(pathname); + }, [pathname, syncWithRoute]); + + // 监听 Electron 主进程发出的窗口关闭事件 + useEffect(() => { + if (!window.electronAPI?.onWindowClosing) return; + const cleanup = window.electronAPI.onWindowClosing(() => { + setShowCloseDialog(true); + }); + return cleanup; + }, []); + + // 监听退出前同步事件:主进程通知渲染进程执行一次同步 + useEffect(() => { + if (!window.electronAPI?.onSyncBeforeQuit) return; + const cleanup = window.electronAPI.onSyncBeforeQuit(async () => { + try { + await sync(); + } catch (err) { + console.error('[AppLayout] Sync before quit failed:', err); + } finally { + // 无论同步成功与否,都通知主进程可以继续退出 + window.electronAPI?.notifySyncComplete(); + } + }); + return cleanup; + }, [sync]); + + // 键盘快捷键:Esc退出模块,数字键导航 + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + // 如果焦点在输入元素中,不拦截 + const target = e.target as HTMLElement; + if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) { + return; + } + + if (e.key === 'Escape') { + if (isInModule) { + exitModule(); + } else { + // 在 3D 场景模式下按 Esc 返回仪表盘 + enterModule('dashboard'); + navigate('/'); + } + } + + // 数字键 0-7 快捷导航(需无修饰键) + if (!e.ctrlKey && !e.metaKey && !e.altKey) { + const moduleKeys: Record = { + '1': '/', '2': '/pomodoro', '3': '/notes', + '4': '/flashcards', '5': '/feynman', '6': '/inspiration', + '7': '/classroom', '0': '/settings', + }; + if (moduleKeys[e.key]) { + navigate(moduleKeys[e.key]); + } + } + + // Ctrl+/ 或 Cmd+/ 打开帮助中心 + if ((e.ctrlKey || e.metaKey) && e.key === '/') { + e.preventDefault(); + openHelp(); + } + }; + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [isInModule, enterModule, exitModule, navigate, openHelp]); + + return ( +
+ {/* Layer 2: 始终最顶层 — Electron标题栏 */} + + + {/* Layer 0: 3D场景全屏背景 / 移动端2D降级 */} + {shouldDegrade3D ? ( + /* 移动端降级:显示 2D 模块导航网格代替 3D 场景 */ + !isInModule && + ) : ( + + + + + )} + + {/* Layer 1: 功能覆盖层 */} + + {isInModule && ( + + + + )} + + + {/* 非模块内时显示简洁的状态提示 + 返回按钮(仅桌面端) */} + {!isInModule && !shouldDegrade3D && ( + <> +
+ + 点击3D物体进入模块 · 按 Esc 返回仪表盘 · 数字键 0-7 快捷跳转 + +
+ {/* 浮动返回仪表盘按钮(仅桌面端) */} + { enterModule('dashboard'); navigate('/'); }} + className="fixed bottom-8 right-8 z-20 hidden md:flex w-12 h-12 rounded-full bg-black/30 backdrop-blur-xl border border-white/15 items-center justify-center text-white/70 hover:text-white hover:bg-black/50 transition-colors" + aria-label="返回仪表盘" + > + + + + )} + + {/* 移动端底部标签栏 — 置于功能覆盖层之上,避免被 3D 场景或模块遮罩覆盖 */} + + + {/* 全局组件 */} + + + + + + setShowCloseDialog(false)} /> +
+ ); +} diff --git a/client/src/components/layout/BottomNav.tsx b/client/src/components/layout/BottomNav.tsx index 995ea68b..8e0399b0 100644 --- a/client/src/components/layout/BottomNav.tsx +++ b/client/src/components/layout/BottomNav.tsx @@ -1,59 +1,62 @@ -import { NavLink, useLocation } from 'react-router-dom'; -import { Home, Timer, FileText, Layers, Lightbulb, Sparkles } from 'lucide-react'; -import { cn } from '@/lib/utils'; -import { soundPlayer } from '@/lib/audio/SoundPlayer'; - -const tabs = [ - { to: '/', label: '首页', icon: Home }, - { to: '/pomodoro', label: '深潜', icon: Timer }, - { to: '/notes', label: '结礁', icon: FileText }, - { to: '/flashcards', label: '闪卡', icon: Layers }, - { to: '/feynman', label: '费曼', icon: Lightbulb }, - { to: '/inspiration', label: '灵感', icon: Sparkles }, -]; - -export default function BottomNav() { - const { pathname } = useLocation(); - return ( - - ); -} +/** + * @ai-context: 布局组件:BottomNav。 + */ +import { NavLink, useLocation } from 'react-router-dom'; +import { Home, Timer, FileText, Layers, Lightbulb, Sparkles } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { soundPlayer } from '@/lib/audio/SoundPlayer'; + +const tabs = [ + { to: '/', label: '首页', icon: Home }, + { to: '/pomodoro', label: '深潜', icon: Timer }, + { to: '/notes', label: '结礁', icon: FileText }, + { to: '/flashcards', label: '闪卡', icon: Layers }, + { to: '/feynman', label: '费曼', icon: Lightbulb }, + { to: '/inspiration', label: '灵感', icon: Sparkles }, +]; + +export default function BottomNav() { + const { pathname } = useLocation(); + return ( + + ); +} diff --git a/client/src/components/layout/CustomTitlebar.tsx b/client/src/components/layout/CustomTitlebar.tsx index 5f1f137f..2f6b87a0 100644 --- a/client/src/components/layout/CustomTitlebar.tsx +++ b/client/src/components/layout/CustomTitlebar.tsx @@ -1,104 +1,104 @@ -import { useState, useEffect, useCallback } from 'react'; -import { Minus, Square, Maximize2, X } from 'lucide-react'; -import { cn } from '@/lib/utils'; - -/** - * 自定义标题栏组件属性 - * @param className - 可选的额外 CSS 类名,用于外部覆盖样式 - */ -interface CustomTitlebarProps { - className?: string; -} - -/** - * 自定义标题栏组件 — frameless 窗口顶部栏 - * - * @ai-context - * - Electron BrowserWindow `frame: false` 模式下替代系统标题栏 - * - 拖拽区域必须使用 CSS 类 `.drag-region`(禁止内联 style) - * - 交互元素必须使用 CSS 类 `.no-drag`(禁止内联 style) - * - 双击拖拽区域触发最大化/还原 - * - 自适应主题:跟随深浅模式变化 - * - * @param props - 组件属性 - * @returns 自定义标题栏 JSX 元素 - */ -export function CustomTitlebar({ className }: CustomTitlebarProps) { - const [isMaximized, setIsMaximized] = useState(false); - - useEffect(() => { - // 初始化时查询当前最大化状态 - window.electronAPI?.windowIsMaximized().then(setIsMaximized); - // 监听主进程发出的最大化状态变化事件 - const cleanup = window.electronAPI?.onMaximizedChanged(setIsMaximized); - return cleanup; - }, []); - - /** 最小化窗口 */ - const handleMinimize = useCallback(() => { - window.electronAPI?.windowMinimize(); - }, []); - - /** 切换最大化/还原 */ - const handleMaximize = useCallback(() => { - window.electronAPI?.windowMaximize(); - }, []); - - /** 关闭窗口(触发确认对话框) */ - const handleClose = useCallback(() => { - window.electronAPI?.windowClose(); - }, []); - - return ( -
- {/* 左侧:品牌 Logo + 应用名称(拖拽区域,双击最大化) */} -
- {/* 品牌 Logo — 深海青渐变圆角方块 + 内圈弧线 */} -
-
-
- - 熵减 - -
- - {/* 中间弹性占位 — 双击最大化 */} -
- - {/* 右侧:窗口控制按钮(禁止拖拽) */} -
- - - -
-
- ); -} +import { useState, useEffect, useCallback } from 'react'; +import { Minus, Square, Maximize2, X } from 'lucide-react'; +import { cn } from '@/lib/utils'; + +/** + * 自定义标题栏组件属性 + * @param className - 可选的额外 CSS 类名,用于外部覆盖样式 + */ +interface CustomTitlebarProps { + className?: string; +} + +/** + * 自定义标题栏组件 — frameless 窗口顶部栏 + * + * @ai-context + * - Electron BrowserWindow `frame: false` 模式下替代系统标题栏 + * - 拖拽区域必须使用 CSS 类 `.drag-region`(禁止内联 style) + * - 交互元素必须使用 CSS 类 `.no-drag`(禁止内联 style) + * - 双击拖拽区域触发最大化/还原 + * - 自适应主题:跟随深浅模式变化 + * + * @param props - 组件属性 + * @returns 自定义标题栏 JSX 元素 + */ +export function CustomTitlebar({ className }: CustomTitlebarProps) { + const [isMaximized, setIsMaximized] = useState(false); + + useEffect(() => { + // 初始化时查询当前最大化状态 + window.electronAPI?.windowIsMaximized().then(setIsMaximized); + // 监听主进程发出的最大化状态变化事件 + const cleanup = window.electronAPI?.onMaximizedChanged(setIsMaximized); + return cleanup; + }, []); + + /** 最小化窗口 */ + const handleMinimize = useCallback(() => { + window.electronAPI?.windowMinimize(); + }, []); + + /** 切换最大化/还原 */ + const handleMaximize = useCallback(() => { + window.electronAPI?.windowMaximize(); + }, []); + + /** 关闭窗口(触发确认对话框) */ + const handleClose = useCallback(() => { + window.electronAPI?.windowClose(); + }, []); + + return ( +
+ {/* 左侧:品牌 Logo + 应用名称(拖拽区域,双击最大化) */} +
+ {/* 品牌 Logo — 深海青渐变圆角方块 + 内圈弧线 */} +
+
+
+ + 熵减 + +
+ + {/* 中间弹性占位 — 双击最大化 */} +
+ + {/* 右侧:窗口控制按钮(禁止拖拽) */} +
+ + + +
+
+ ); +} diff --git a/client/src/components/layout/FeedbackPanel.tsx b/client/src/components/layout/FeedbackPanel.tsx index 6783bc31..c28e449b 100644 --- a/client/src/components/layout/FeedbackPanel.tsx +++ b/client/src/components/layout/FeedbackPanel.tsx @@ -1,538 +1,543 @@ -import { useState, useCallback, useEffect } from 'react'; -import { createPortal } from 'react-dom'; -import { X, Bug, Lightbulb, Star, Send, CheckCircle, Copy, Trash2 } from 'lucide-react'; -import { cn } from '@/lib/utils'; - -const SUCCESS_TOAST_DURATION_MS = 4000; -const COPY_TOAST_DURATION_MS = 2000; - -// ─── Types ────────────────────────────────────────────────────── - -type FeedbackType = 'bug' | 'suggestion' | 'experience'; -type FeedbackStatus = 'pending' | 'sent'; - -interface FeedbackItem { - id: string; - type: FeedbackType; - description: string; - rating?: number; - createdAt: string; // ISO string for JSON serialization - status: FeedbackStatus; -} - -interface FeedbackPanelProps { - isOpen: boolean; - onClose: () => void; -} - -// ─── Constants ────────────────────────────────────────────────── - -const STORAGE_KEY = 'keban_feedback'; -const MAX_LENGTH = 500; -const MAX_HISTORY = 20; - -const TYPE_OPTIONS: { value: FeedbackType; label: string; icon: typeof Bug; emoji: string }[] = [ - { value: 'bug', label: 'Bug', icon: Bug, emoji: '🐛' }, - { value: 'suggestion', label: '建议', icon: Lightbulb, emoji: '💡' }, - { value: 'experience', label: '体验', icon: Star, emoji: '⭐' }, -]; - -const TYPE_ICON_MAP: Record = { - bug: '🐛', - suggestion: '💡', - experience: '⭐', -}; - -const TYPE_LABEL_MAP: Record = { - bug: 'Bug', - suggestion: '建议', - experience: '体验', -}; - -// ─── Helpers ──────────────────────────────────────────────────── - -function loadFeedback(): FeedbackItem[] { - try { - const raw = localStorage.getItem(STORAGE_KEY); - if (!raw) return []; - return JSON.parse(raw) as FeedbackItem[]; - } catch { - return []; - } -} - -function saveFeedback(items: FeedbackItem[]): void { - localStorage.setItem(STORAGE_KEY, JSON.stringify(items)); -} - -function formatTime(iso: string): string { - const d = new Date(iso); - const now = new Date(); - const diffMs = now.getTime() - d.getTime(); - const diffMin = Math.floor(diffMs / 60_000); - if (diffMin < 1) return '刚刚'; - if (diffMin < 60) return `${diffMin}分钟前`; - const diffHour = Math.floor(diffMin / 60); - if (diffHour < 24) return `${diffHour}小时前`; - const diffDay = Math.floor(diffHour / 24); - if (diffDay < 7) return `${diffDay}天前`; - return d.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' }); -} - -/** 生成短反馈编号 */ -function shortId(id: string): string { - return id.replace(/-/g, '').slice(0, 8).toUpperCase(); -} - -/** 将反馈内容格式化为纯文本,便于复制 */ -function formatFeedbackText(item: FeedbackItem): string { - const lines = [ - `[熵减反馈] ${TYPE_LABEL_MAP[item.type]}`, - `编号: ${shortId(item.id)}`, - `时间: ${new Date(item.createdAt).toLocaleString('zh-CN')}`, - '', - item.description, - ]; - if (item.rating) { - lines.push(`\n评分: ${item.rating}/5`); - } - return lines.join('\n'); -} - -/** 复制文本到剪贴板 */ -async function copyToClipboard(text: string): Promise { - try { - await navigator.clipboard.writeText(text); - return true; - } catch { - // fallback for non-HTTPS environments - const textarea = document.createElement('textarea'); - textarea.value = text; - textarea.style.position = 'fixed'; - textarea.style.opacity = '0'; - document.body.appendChild(textarea); - textarea.select(); - const ok = document.execCommand('copy'); - document.body.removeChild(textarea); - return ok; - } -} - -// ─── Star Rating ──────────────────────────────────────────────── - -interface StarRatingProps { - value: number; - onChange: (v: number) => void; -} - -function StarRating({ value, onChange }: StarRatingProps) { - const [hover, setHover] = useState(0); - return ( -
- {[1, 2, 3, 4, 5].map((n) => ( - - ))} - - {value > 0 ? `${value}/5` : ''} - -
- ); -} - -// ─── Feedback Form ────────────────────────────────────────────── - -interface FeedbackFormProps { - onSubmit: (item: FeedbackItem) => void; -} - -function FeedbackForm({ onSubmit }: FeedbackFormProps) { - const [type, setType] = useState('bug'); - const [description, setDescription] = useState(''); - const [rating, setRating] = useState(0); - const [successInfo, setSuccessInfo] = useState<{ id: string; time: string } | null>(null); - - const charCount = description.length; - const isValid = description.trim().length > 0 && (type !== 'experience' || rating > 0); - - const handleSubmit = useCallback(() => { - if (!isValid) return; - const now = new Date(); - const item: FeedbackItem = { - id: crypto.randomUUID(), - type, - description: description.trim(), - rating: type === 'experience' ? rating : undefined, - createdAt: now.toISOString(), - status: 'sent', - }; - onSubmit(item); - setDescription(''); - setRating(0); - setSuccessInfo({ id: shortId(item.id), time: now.toLocaleString('zh-CN') }); - // 成功提示 4 秒后消失 - setTimeout(() => setSuccessInfo(null), SUCCESS_TOAST_DURATION_MS); - }, [type, description, rating, isValid, onSubmit]); - - return ( -
- {/* Type selector */} -
- {TYPE_OPTIONS.map(({ value, label, icon: _icon, emoji }) => ( - - ))} -
- - {/* Description */} -
-