diff --git a/.env.example b/.env.example index 31f1005..c883f52 100644 --- a/.env.example +++ b/.env.example @@ -6,5 +6,6 @@ # 生产环境: https://two-sum.YOUR-SUBDOMAIN.workers.dev/api/push WORKER_API=http://localhost:8787/api/push -# API 密钥(需要与 Worker 中配置的一致) -API_KEY=dev-secret-key-2024 +# ja3 Proxy 地址 +PROXY_URL=http://localhost:8081 +PROXY_API_KEY=proxy_secret-key-2024 diff --git a/.github/workflows/collect.yml b/.github/workflows/collect.yml deleted file mode 100644 index 2baeb82..0000000 --- a/.github/workflows/collect.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: LeetCode Data Collector - -on: - schedule: - # 每 5 分钟运行一次(GitHub Actions 的最小间隔) - - cron: '*/15 * * * *' - workflow_dispatch: # 支持手动触发 - push: - branches: [ main, master ] # 推送代码时也运行一次(用于测试) - -jobs: - collect: - runs-on: ubuntu-latest - timeout-minutes: 2 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '18' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Run collector - run: node collector.js - env: - WORKER_API: ${{ secrets.WORKER_API }} - API_KEY: ${{ secrets.API_KEY }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1bf26a2..2c6dbef 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ node_modules/ .DS_Store dist/ .cache/ +*.ps1 +CLAUDE.md +.workbuddy/ # Wrangler local state .mf/ diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 9d549d6..b47945f 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -5,10 +5,10 @@ ## 📋 目录 - [环境准备](#环境准备) +- [技术架构说明](#技术架构说明) - [本地开发](#本地开发) - [测试验证](#测试验证) - [生产部署](#生产部署) -- [自动采集设置](#自动采集设置) - [监控运维](#监控运维) - [故障排查](#故障排查) - [API 文档](#api-文档) @@ -37,12 +37,52 @@ npm --version ### 3. 安装项目依赖 ```bash -cd /Users/lhp/Project/two-sum +cd /path/to/two-sum npm install ``` --- +## 技术架构说明 + +### 数据采集架构 + +本系统采用 **Cloudflare Worker Cron** 直接采集数据: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Cloudflare Worker │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Cron Job │──│ collector │──│ D1 Database │ │ +│ │ (每分钟) │ │ 模块 │ │ │ │ +│ └──────────────┘ └──────┬───────┘ └──────────────┘ │ +│ │ │ +│ ┌───────────────┼───────────────┐ │ +│ ▼ ▼ ▼ │ +│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ +│ │ CN 区 │ │ ja3 代理 │ │ US 区 │ │ +│ │ 直接连接 │ │ 服务 │ │ 通过代理 │ │ +│ └────────────┘ └────────────┘ └────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +**说明:** +- **CN 区**:Worker 直接通过 WebSocket 连接 `wss://collaboration-ws.leetcode.cn` +- **US 区**:Worker 通过 ja3 代理服务连接,绕过 TLS 指纹检测 +- **定时任务**:Worker Cron 每分钟触发一次,自动采集并存储到 D1 数据库 + +### ja3 代理服务 + +LeetCode 国际站(US)有反爬虫机制,会检测 TLS 指纹。需要使用 [ja3-proxy-python](https://github.com/moss-code/ja3-proxy-python/tree/main) 代理服务来绕过检测。 + +**工作原理:** +``` +Worker ──HTTP──▶ ja3-proxy ──WebSocket──▶ LeetCode US + (带TLS) (模拟浏览器指纹) +``` + +--- + ## 本地开发 ### Step 1: 创建数据库 @@ -82,12 +122,36 @@ npm run db:init **验证表创建成功:** ```bash -npx wrangler d1 execute two-sum-db --local --command "SELECT name FROM sqlite_master WHERE type='table'" +npx wrangler d1 execute two-sum-db --local --command "SELECT name FROM sqlite_master WHERE type='tables'" ``` 应该看到 `records` 表。 -### Step 4: 启动 Worker 开发服务器 +### Step 4: 配置 ja3 代理(可选,仅测试 US 区时需要) + +如果你在本地开发时需要测试 US 区数据采集,需要配置 ja3 代理: + +**方式 1:使用已部署的代理** + +在 `wrangler.toml` 中添加: + +```toml +[vars] +PROXY_URL = "https://your-ja3-proxy.onrender.com" +PROXY_API_KEY = "your-proxy-api-key" +``` + +**方式 2:本地启动代理** + +参考 [ja3-proxy-python](https://github.com/moss-code/ja3-proxy-python/tree/main) 项目在本地启动代理服务,然后配置: + +```toml +[vars] +PROXY_URL = "http://localhost:8080" +PROXY_API_KEY = "proxy_secret-key-2024" +``` + +### Step 5: 启动 Worker 开发服务器 在一个终端窗口运行: @@ -105,7 +169,7 @@ npm run dev 保持此终端运行。 -### Step 5: 启动前端页面 +### Step 6: 启动前端页面 在另一个新终端运行: @@ -117,28 +181,18 @@ npm run pages:dev > **注意**:前端会自动使用 `http://localhost:8787` 作为 API 地址(在 localhost 环境下)。 -### Step 6: 测试数据采集 +### Step 7: 测试数据采集 -在第三个新终端运行: +Worker 会在 Cron 触发时自动采集数据。在本地开发环境,你可以: -```bash -npm run collect -``` - -**预期输出:** -``` -========== LeetCode 数据采集 ========== -时间: 2026-02-10T15:30:00.000Z -[US] 连接中... -[CN] 连接中... -[CN] 已连接 -[CN] 收到消息: 550 -[CN] ✅ 在线人数: 550 +1. **等待 Cron 触发**(如果配置了每分钟触发) +2. **手动触发**(通过代码调用) -准备推送数据: [ { region: 'CN', count: 550, timestamp: 1770737400000 } ] -✅ 数据推送成功: { success: true, saved: 1, message: 'Successfully saved 1 records' } +查看采集日志: -✅ 采集完成! +```bash +# 在另一个终端运行 +npx wrangler tail ``` **验证数据写入:** @@ -162,8 +216,8 @@ curl http://localhost:8787/api/latest # 3. 获取历史数据(原始) curl "http://localhost:8787/api/data?hours=1" -# 4. 按分钟聚合 -curl "http://localhost:8787/api/aggregated?granularity=minute&limit=20" +# 4. 按 5 分钟聚合 +curl "http://localhost:8787/api/aggregated?granularity=fivemin&limit=20" # 5. 按半小时聚合 curl "http://localhost:8787/api/aggregated?granularity=halfhour&limit=10" @@ -185,24 +239,30 @@ curl http://localhost:8787/api/stats 访问 `http://localhost:3000`,测试以下功能: -- ✅ **粒度切换**:点击"按分钟"/"按半小时"/"按小时"/"按天"/"按月"按钮 +- ✅ **粒度切换**:点击"按 5 分钟"/"按半小时"/"按小时"/"按天"/"按月"按钮 - ✅ **统计卡片**:查看最新的在线人数 - ✅ **趋势图表**:查看数据趋势线 - ✅ **交互缩放**:拖拽图表下方的滑块 - ✅ **Tooltip**:鼠标悬停查看详细数据 - ✅ **自动刷新**:等待 60 秒观察自动更新 -### 持续采集测试数据 +### 采集测试数据 + +为了让图表更好看,可以连续触发几次采集: + +```bash +# 在 wrangler tail 窗口查看日志的同时 +# 重启 Worker 会触发 Cron 立即执行 +``` -为了让图表更好看,可以连续采集一些数据: +或者手动插入测试数据: ```bash -# 连续采集 20 次,间隔 3 秒 -for i in {1..20}; do - echo "=== 第 $i 次采集 ===" - npm run collect - sleep 3 -done +npx wrangler d1 execute two-sum-db --local --command " +INSERT INTO records (region, count, timestamp) VALUES +('CN', 500, $(($(date +%s) * 1000))), +('US', 1200, $(($(date +%s) * 1000))) +" ``` --- @@ -239,24 +299,50 @@ npm run db:init:remote npx wrangler d1 execute two-sum-db --remote --command "SELECT name FROM sqlite_master WHERE type='table'" ``` -### Step 4: 设置 API 密钥(生产环境) +### Step 4: 部署 ja3 代理服务 + +**使用 Render 部署(推荐,免费)** + +1. 访问 [render.com](https://render.com) 注册账号 +2. 创建新的 Web Service +3. 连接 [ja3-proxy-python](https://github.com/moss-code/ja3-proxy-python/tree/main) 仓库 +4. 配置: + - **Build Command**: `pip install -r requirements.txt` + - **Start Command**: `python app.py` + - **Instance Type**: Free +5. 记下分配的 URL,如 `https://your-ja3-proxy.onrender.com` + +**部署完成后测试:** -**方式 1: 使用 Secrets(推荐)** ```bash -# 设置生产环境的 API 密钥 -npx wrangler secret put API_KEY -# 输入密钥,例如:prod-secret-key-2024-abc123 +curl https://your-ja3-proxy.onrender.com/health ``` -**方式 2: 使用环境变量(仅本地)** +应该返回 `{"status": "ok"}`。 -`wrangler.toml` 中已配置了本地开发用的 API_KEY: -```toml -[vars] -API_KEY = "dev-secret-key-2024" +### Step 5: 配置生产环境 Secrets + +设置 ja3 代理的配置: + +```bash +# 设置代理 URL +npx wrangler secret put PROXY_URL +# 输入你的 ja3 代理地址,如:https://your-ja3-proxy.onrender.com + +# 设置代理 API 密钥 +npx wrangler secret put PROXY_API_KEY +# 输入你的代理 API 密钥 ``` -### Step 5: 部署 Worker +**验证 Secrets:** + +```bash +npx wrangler secret list +``` + +应该看到 `PROXY_URL` 和 `PROXY_API_KEY`。 + +### Step 6: 部署 Worker ```bash npm run deploy @@ -271,7 +357,7 @@ npm run deploy **重要**:记下这个 URL! -### Step 6: 测试生产 Worker +### Step 7: 测试生产 Worker ```bash # 替换为你的实际 URL @@ -283,35 +369,18 @@ curl $WORKER_URL/api/latest curl "$WORKER_URL/api/stats" ``` -### Step 7: 配置采集脚本 +### Step 8: 验证数据采集 -创建 `.env` 文件: +等待 1-2 分钟后,检查数据是否写入: ```bash -cp .env.example .env -``` - -编辑 `.env`: - -```env -# Worker API 地址(替换为实际 URL) -WORKER_API=https://two-sum.YOUR-SUBDOMAIN.workers.dev/api/push - -# API 密钥(与 Worker Secrets 中设置的一致) -API_KEY=secret-020214xafs921w -``` - -### Step 8: 测试生产环境采集 - -```bash -npm run collect +npx wrangler d1 execute two-sum-db --remote --command "SELECT * FROM records ORDER BY timestamp DESC LIMIT 5" ``` -应该能看到数据成功推送到生产环境。 +查看 Worker 日志确认采集情况: -**验证:** ```bash -npx wrangler d1 execute two-sum-db --remote --command "SELECT * FROM records ORDER BY timestamp DESC LIMIT 5" +npx wrangler tail ``` ### Step 9: 部署前端 @@ -358,171 +427,6 @@ npm run pages:deploy --- -## 自动采集设置 - -数据采集需要每分钟运行一次 `collector.js`。以下是多种自动化方案: - -### 方案 1: GitHub Actions(推荐,免费且可靠) - -创建 `.github/workflows/collect.yml`: - -```yaml -name: LeetCode Data Collector - -on: - schedule: - # 每分钟运行一次 - - cron: '* * * * *' - workflow_dispatch: # 支持手动触发 - -jobs: - collect: - runs-on: ubuntu-latest - timeout-minutes: 2 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '18' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Run collector - run: node collector.js - env: - WORKER_API: ${{ secrets.WORKER_API }} - API_KEY: ${{ secrets.API_KEY }} -``` - -**设置 GitHub Secrets:** - -1. 访问你的 GitHub 仓库 -2. Settings → Secrets and variables → Actions -3. 添加以下 secrets: - - `WORKER_API`: `https://two-sum.YOUR-SUBDOMAIN.workers.dev/api/push` - - `API_KEY`: `prod-secret-key-2024-abc123` - -**优点:** -- ✅ 完全免费 -- ✅ 自动运行,无需服务器 -- ✅ 有日志记录 -- ✅ 可查看运行历史 - -**缺点:** -- ⚠️ 最小间隔是 5 分钟(GitHub Actions 限制) - -**注意**:GitHub Actions 的 cron 最短间隔是 5 分钟,不是 1 分钟。如果需要每分钟采集,使用下面的其他方案。 - -### 方案 2: cron(Linux/macOS 服务器) - -适合有自己的服务器或 VPS。 - -```bash -# 编辑 crontab -crontab -e - -# 添加以下行(每分钟运行) -* * * * * cd /path/to/two-sum && /usr/local/bin/node collector.js >> /var/log/leetcode-collector.log 2>&1 -``` - -**查看日志:** -```bash -tail -f /var/log/leetcode-collector.log -``` - -**优点:** -- ✅ 精确到每分钟 -- ✅ 简单可靠 -- ✅ 完全控制 - -**缺点:** -- ❌ 需要一台持续运行的服务器 - -### 方案 3: PM2(推荐用于服务器) - -PM2 是一个强大的 Node.js 进程管理器。 - -```bash -# 安装 PM2 -npm install -g pm2 - -# 启动采集器(每分钟运行) -pm2 start collector.js --cron "* * * * *" --no-autorestart --name leetcode-collector - -# 查看日志 -pm2 logs leetcode-collector - -# 查看状态 -pm2 status - -# 设置开机自启 -pm2 startup -pm2 save - -# 停止采集 -pm2 stop leetcode-collector - -# 删除任务 -pm2 delete leetcode-collector -``` - -**优点:** -- ✅ 精确到每分钟 -- ✅ 自动重启 -- ✅ 日志管理 -- ✅ 监控面板 - -**缺点:** -- ❌ 需要服务器 - -### 方案 4: Cloudflare Workers Cron(已废弃) - -**注意**:原计划使用 Worker Cron,但由于 Workers 不支持作为 WebSocket 客户端,已改用外部采集脚本。 - -`wrangler.toml` 中的 cron 配置已保留但不再使用: - -```toml -[triggers] -crons = ["* * * * *"] # 已废弃,不执行采集 -``` - -### 方案 5: watch 命令(临时测试) - -适合短期测试,不推荐生产使用。 - -```bash -# 安装 watch (macOS) -brew install watch - -# 每 60 秒运行一次 -watch -n 60 'cd /path/to/two-sum && node collector.js' -``` - -**优点:** -- ✅ 简单快速 -- ✅ 适合测试 - -**缺点:** -- ❌ 终端必须保持打开 -- ❌ 不适合生产环境 - -### 推荐方案总结 - -| 场景 | 推荐方案 | 间隔精度 | -|------|----------|----------| -| **无服务器** | GitHub Actions | 5 分钟 | -| **有服务器** | PM2 | 1 分钟 | -| **简单 VPS** | cron | 1 分钟 | -| **本地测试** | watch | 自定义 | - ---- - ## 监控运维 ### 查看数据库统计 @@ -561,17 +465,18 @@ npx wrangler tail ``` 你会看到: -- API 请求日志 -- 数据采集推送日志 +- Cron 任务触发日志 +- 数据采集结果(US 和 CN 区的在线人数) +- 数据写入日志 - 错误信息(如果有) ### 数据清理 -**删除 7 天前的数据:** +**删除 90 天前的数据:** ```bash npx wrangler d1 execute two-sum-db --remote --command " DELETE FROM records -WHERE timestamp < (strftime('%s', 'now', '-7 days') * 1000) +WHERE timestamp < (strftime('%s', 'now', '-90 days') * 1000) " ``` @@ -605,14 +510,6 @@ cat backup-*.json | jq '.[0].results | length' - Storage & Databases → D1 → two-sum-db → Metrics - 查看查询次数、行数读取 -### 设置告警(可选) - -使用 Cloudflare Notifications 或第三方服务(如 Better Stack)设置告警: - -- Worker 错误率 > 5% -- D1 查询失败 -- API 响应时间 > 1s - --- ## 故障排查 @@ -642,37 +539,43 @@ SELECT name FROM sqlite_master WHERE type='table' [US] ❌ 错误: Unexpected server response: 403 ``` -**原因:** LeetCode 国际站有反爬虫机制。 +**原因:** LeetCode 国际站有 TLS 指纹检测机制。 **解决方案:** -**方案 A: 专注 CN 区(推荐)** - -目前 CN 区采集稳定,可以先专注于 CN 区数据。前端会自动处理 US 区为 null 的情况。 +1. **检查 ja3 代理服务状态:** + ```bash + curl https://your-ja3-proxy.onrender.com/health + ``` -**方案 B: 使用代理** +2. **检查 Secrets 配置:** + ```bash + npx wrangler secret list + + # 重新设置 + npx wrangler secret put PROXY_URL + npx wrangler secret put PROXY_API_KEY + ``` -修改 `collector.js`,通过代理访问: +3. **重新部署 Worker:** + ```bash + npm run deploy + ``` -```javascript -// 需要安装:npm install https-proxy-agent -const { HttpsProxyAgent } = require('https-proxy-agent'); +### 问题 3: CN 区连接失败 -const ws = new WebSocket(url, { - headers: headers, - agent: new HttpsProxyAgent('http://your-proxy:port') -}); +**错误信息:** +``` +[CN] ❌ 错误: WebSocket 连接失败 ``` -**方案 C: 降低频率** - -仅采集 CN 区,或者 US 区改为每 5 分钟采集一次。 - -**方案 D: 添加更多请求头** +CN 区通常连接稳定。如果失败: -在 `collector.js` 中尝试添加 Cookie、Referer 等(需要手动从浏览器复制)。 +1. 检查网络连接 +2. 查看 Worker 日志确认重试情况 +3. Worker 会自动重试 3 次 -### 问题 3: 前端无法加载数据 +### 问题 4: 前端无法加载数据 **检查清单:** @@ -704,68 +607,40 @@ const ws = new WebSocket(url, { " ``` - 如果为 0,说明还没有采集数据。 - -### 问题 4: 采集脚本推送失败 401 - -**错误信息:** -``` -❌ 推送失败: HTTP 401: Unauthorized -``` - -**原因:** API Key 不匹配。 - -**解决方案:** - -1. **检查 Worker Secrets:** + 如果为 0,说明 Cron 还未触发或采集失败。查看日志: ```bash - # 重新设置密钥 - npx wrangler secret put API_KEY + npx wrangler tail ``` -2. **检查 .env 文件:** - ```env - API_KEY=prod-secret-key-2024-abc123 # 必须与 Worker Secret 一致 - ``` +### 问题 5: 定时任务没有执行 -3. **重新部署 Worker:** - ```bash - npm run deploy - ``` +**检查 Cron 配置:** -### 问题 5: GitHub Actions 无法运行 - -**原因:** GitHub Actions 的 cron 最短间隔是 **5 分钟**,不是 1 分钟。 - -**解决方案:** - -修改 `.github/workflows/collect.yml` 中的 cron 表达式: - -```yaml -schedule: - # 每 5 分钟运行一次 - - cron: '*/5 * * * *' +```bash +npx wrangler trigger list ``` -或者使用其他方案(cron/PM2)实现每分钟采集。 +应该看到 `* * * * *`(每分钟)。 -### 问题 6: 前端粒度切换无响应 - -**检查:** - -1. **浏览器控制台是否有错误** +**查看日志:** - 打开开发者工具 → Console,查看错误信息。 +```bash +npx wrangler tail +``` -2. **API 端点是否正常** +观察是否有 Cron 触发日志: +``` +Cron triggered at: 2026-04-10T12:34:56.789Z +``` - ```bash - curl "https://two-sum.YOUR-SUBDOMAIN.workers.dev/api/aggregated?granularity=minute&limit=10" - ``` +### 问题 6: ja3 代理服务返回 500 错误 -3. **数据是否足够** +**解决方案:** - 某些粒度需要足够的数据才能显示(如按天、按月)。 +1. 检查代理服务是否正常运行 +2. 检查代理服务的日志 +3. 确保代理服务的 API 密钥正确 +4. 重启代理服务 --- @@ -850,18 +725,18 @@ curl "http://localhost:8787/api/data?hours=6" 按时间粒度聚合数据(核心 API)。 **查询参数:** -- `granularity` (必需):时间粒度 - - `minute` - 按分钟 +- `granularity` (可选):时间粒度,可选值: + - `fivemin` - 按 5 分钟 - `halfhour` - 按半小时 - - `hour` - 按小时 + - `hour`(默认)- 按小时 - `day` - 按天 - `month` - 按月 -- `limit` (可选):返回的数据点数量 +- `limit` (可选):返回的数据点数量,默认 168 **请求示例:** ```bash -# 按分钟(最近 180 分钟) -curl "http://localhost:8787/api/aggregated?granularity=minute&limit=180" +# 按 5 分钟(最近 24 小时) +curl "http://localhost:8787/api/aggregated?granularity=fivemin&limit=288" # 按半小时(最近 7 天) curl "http://localhost:8787/api/aggregated?granularity=halfhour&limit=336" @@ -881,7 +756,7 @@ curl "http://localhost:8787/api/aggregated?granularity=month&limit=24" [ { "region": "CN", - "time": "2026-02-10 15:30", + "time": "2026-02-10 15:00", "avg_count": 547.82, "min_count": 546, "max_count": 550, @@ -924,41 +799,6 @@ curl "http://localhost:8787/api/aggregated?granularity=month&limit=24" } ``` -### POST /api/push - -接收采集器推送的数据(需要 API Key 验证)。 - -**请求头:** -- `Content-Type`: `application/json` -- `X-API-Key`: API 密钥 - -**请求体:** -```json -{ - "records": [ - { - "region": "US", - "count": 1234, - "timestamp": 1707580800000 - }, - { - "region": "CN", - "count": 567, - "timestamp": 1707580800000 - } - ] -} -``` - -**响应示例:** -```json -{ - "success": true, - "saved": 2, - "message": "Successfully saved 2 records" -} -``` - --- ## 性能优化建议 @@ -973,7 +813,7 @@ curl "http://localhost:8787/api/aggregated?granularity=month&limit=24" ### 2. 限制数据点数量 前端已自动设置合理的 limit: -- 按分钟:180 点(3 小时) +- 按 5 分钟:288 点(24 小时) - 按半小时:336 点(7 天) - 按小时:168 点(7 天) - 按天:90 点(90 天) @@ -989,7 +829,7 @@ CREATE INDEX idx_timestamp ON records(timestamp DESC); ### 4. 定期清理历史数据 -建议保留最近 30-90 天的数据,定期清理旧数据: +建议保留最近 90 天的数据,定期清理旧数据: ```bash # 每周运行一次(保留 90 天) @@ -1003,59 +843,51 @@ WHERE timestamp < (strftime('%s', 'now', '-90 days') * 1000) ## 常见问题 FAQ -### Q1: 为什么 Worker 不能直接采集数据? +### Q1: 为什么需要 ja3 代理? -A: Cloudflare Workers **不支持作为 WebSocket 客户端**连接外部服务器。因此需要使用独立的 Node.js 脚本(`collector.js`)进行采集,然后通过 HTTP API 推送到 Worker。 +A: LeetCode 国际站(US)有 TLS 指纹检测机制,会阻止来自 Cloudflare Workers 的直接连接。通过 [ja3-proxy-python](https://github.com/moss-code/ja3-proxy-python/tree/main) 代理服务可以模拟浏览器指纹,绕过检测。 + +中国区(CN)没有这种限制,Worker 可以直接连接。 ### Q2: 免费额度够用吗? A: 完全够用!Cloudflare 免费额度: -- **Workers**: 100,000 请求/天 +- **Workers**: 100,000 请求/天 + Cron 触发 - **D1**: 100,000 行读取/天,1 GB 存储 - **Pages**: 无限请求 按每分钟采集 2 次(US + CN),每天约 2,880 次写入,远低于限制。 -### Q3: 如何添加更多题目监控? - -A: 修改 `collector.js`: +### Q3: 如何部署自己的 ja3 代理? -```javascript -const CONFIG = { - WS_URLS: { - US_TWO_SUM: 'wss://collaboration-ws.leetcode.com/problems/two-sum', - US_THREE_SUM: 'wss://collaboration-ws.leetcode.com/problems/3sum', - CN_TWO_SUM: 'wss://collaboration-ws.leetcode.cn/problems/two-sum', - // 添加更多... - } -}; -``` +A: 参考 [ja3-proxy-python](https://github.com/moss-code/ja3-proxy-python/tree/main) 项目: -然后修改数据库表结构,添加 `problem` 字段。 +1. 克隆仓库 +2. 部署到 Render、Heroku 或自己的服务器 +3. 配置 `PROXY_URL` 和 `PROXY_API_KEY` ### Q4: 数据会丢失吗? A: Cloudflare D1 是持久化存储,数据不会丢失。建议定期备份(导出 JSON)。 -### Q5: 如何更换 API 密钥? +### Q5: 如何更换 ja3 代理地址? A: ```bash # 1. 更新 Worker Secret -npx wrangler secret put API_KEY -# 输入新密钥 - -# 2. 更新 .env 文件 -echo "API_KEY=new-secret-key" > .env +npx wrangler secret put PROXY_URL +# 输入新的代理地址 -# 3. 重新部署 Worker +# 2. 重新部署 Worker npm run deploy - -# 4. 重启采集脚本 ``` +### Q6: 可以只监控 CN 区吗? + +A: 可以。如果不配置 `PROXY_URL`,US 区采集会失败,但 CN 区仍会正常工作。前端会显示 US 区为 "暂无"。 + --- ## 下一步 @@ -1063,16 +895,16 @@ npm run deploy ### ✅ 已完成 - [x] Worker API 部署 - [x] D1 数据库创建 -- [x] 数据采集脚本 +- [x] Worker 直接采集数据(Cron) +- [x] CN 区直接 WebSocket 采集 +- [x] US 区通过 ja3 代理采集 - [x] 前端可视化(5 种粒度) -- [x] CN 区数据采集成功 ### 🔄 待优化 -- [ ] 解决 US 区 403 问题 -- [ ] 设置自动采集(GitHub Actions/cron) - [ ] 绑定自定义域名 - [ ] 添加数据导出功能 - [ ] 添加更多题目监控 +- [ ] 设置告警通知 --- @@ -1081,6 +913,7 @@ npm run deploy - **GitHub Issues**: 报告 bug 或提出建议 - **文档**: README.md 查看项目概览 - **Cloudflare Docs**: https://developers.cloudflare.com +- **ja3-proxy**: https://github.com/moss-code/ja3-proxy-python --- diff --git a/README.md b/README.md index c8d696d..01e6bea 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ - ⏱️ **实时采集**:每分钟自动采集一次数据 - 📊 **双 Y 轴图表**:完美展示不同数量级的数据对比 -- 🔍 **多时间范围**:支持 1 小时到 7 天的历史数据查询 +- 🔍 **多时间范围**:支持 5分钟、半小时、小时、天、月多种粒度 - 🎨 **精美可视化**:基于 ECharts 的交互式图表 - 💰 **零成本部署**:完全基于 Cloudflare 免费套餐 - ⚡ **高性能**:全球 CDN 加速,毫秒级响应 @@ -17,13 +17,17 @@ - **数据库**:Cloudflare D1(SQLite) - **前端**:纯静态页面(ECharts) - **部署**:Cloudflare Pages +- **数据采集**: + - CN 区:直接 WebSocket 连接 + - US 区:通过 [ja3-proxy-python](https://github.com/moss-code/ja3-proxy-python/tree/main) 代理服务绕过 TLS 指纹检测 ## 📦 项目结构 ``` two-sum/ ├── src/ -│ └── index.js # Worker 主逻辑(Cron + API) +│ ├── index.js # Worker 主逻辑(Cron + API) +│ └── collector.js # 数据采集模块(WebSocket + 代理) ├── public/ │ └── index.html # 前端页面 ├── schema.sql # 数据库表结构 @@ -39,6 +43,7 @@ two-sum/ - Node.js 16+ - npm 或 yarn - Cloudflare 账号(免费) +- ja3 代理服务(用于采集 US 区数据,可自行部署) ### 1. 安装依赖 @@ -73,7 +78,38 @@ npm run db:init npm run db:init:remote ``` -### 4. 本地开发调试 +### 4. 配置 ja3 代理(用于 US 区数据采集) + +US 区的 LeetCode WebSocket 有 TLS 指纹检测机制,需要通过 ja3 代理服务访问。 + +**选项 A:自行部署 ja3 代理** + +使用 [ja3-proxy-python](https://github.com/moss-code/ja3-proxy-python/tree/main) 项目部署: + +```bash +# 克隆项目 +git clone https://github.com/moss-code/ja3-proxy-python.git +cd ja3-proxy-python + +# 部署到 Render(免费) +# 或者使用 Docker 部署到自己的服务器 +``` + +**选项 B:使用已有的代理服务** + +如果你已经有可用的 ja3 代理服务,记录其地址和 API 密钥。 + +**配置代理地址:** + +编辑 `wrangler.toml`,添加代理配置: + +```toml +[vars] +PROXY_URL = "https://your-ja3-proxy.onrender.com" # 你的 ja3 代理地址 +PROXY_API_KEY = "your-proxy-api-key" # 代理 API 密钥 +``` + +### 5. 本地开发调试 启动 Worker 开发服务器: @@ -86,9 +122,9 @@ npm run dev - `http://localhost:8787/api/data?hours=24` - 获取历史数据 - `http://localhost:8787/api/latest` - 获取最新数据 - `http://localhost:8787/api/stats` - 获取统计信息 -- `http://localhost:8787/api/collect` - 手动触发采集 +- `http://localhost:8787/api/aggregated?granularity=hour` - 获取聚合数据 -### 5. 测试前端页面 +### 6. 测试前端页面 在另一个终端启动前端服务器: @@ -104,14 +140,16 @@ npm run pages:dev const API_URL = 'http://localhost:8787'; // 本地开发时使用 ``` -### 6. 手动测试数据采集 +### 7. 验证数据采集 -在浏览器访问: -``` -http://localhost:8787/api/collect +Worker 会自动通过 Cron 任务采集数据。在本地开发时,可以手动触发采集: + +```bash +# 查看实时日志 +npx wrangler tail ``` -然后查询数据库验证: +然后查询数据库验证数据是否写入: ```bash npx wrangler d1 execute two-sum-db --local --command "SELECT * FROM records ORDER BY timestamp DESC LIMIT 10" @@ -136,63 +174,82 @@ npm run deploy https://two-sum.your-subdomain.workers.dev ``` +**重要**:记下这个 URL! + ### 3. 初始化生产数据库 ```bash npm run db:init:remote ``` -### 4. 测试定时任务 +### 4. 配置生产环境变量 -由于 Cron 是每分钟执行,等待 1-2 分钟后查询数据库: +设置 ja3 代理的配置(生产环境): + +```bash +# 设置代理 URL +npx wrangler secret put PROXY_URL +# 输入你的 ja3 代理地址,如:https://your-ja3-proxy.onrender.com + +# 设置代理 API 密钥 +npx wrangler secret put PROXY_API_KEY +# 输入你的代理 API 密钥 +``` + +### 5. 测试数据采集 + +Cron 任务会每分钟自动执行。等待 1-2 分钟后查询数据库: ```bash npx wrangler d1 execute two-sum-db --remote --command "SELECT COUNT(*) as count FROM records" ``` -或者手动触发采集: +或者查看实时日志: ```bash -curl https://two-sum.your-subdomain.workers.dev/api/collect +npx wrangler tail ``` -### 5. 部署前端页面 +### 6. 部署前端页面 -**方式一:通过 CLI 部署** +**更新 API URL** + +编辑 `public/index.html`,找到这一行: -修改 `public/index.html` 中的 API_URL: ```javascript -const API_URL = 'https://two-sum.your-subdomain.workers.dev'; +const API_URL = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1' + ? 'http://localhost:8787' + : 'https://two-sum.YOUR-SUBDOMAIN.workers.dev'; // 替换为实际 URL ``` -然后部署: +将 `YOUR-SUBDOMAIN` 替换为你的实际子域名。 + +**部署到 Pages** + ```bash npm run pages:deploy ``` -**方式二:通过 GitHub 自动部署(推荐)** +**预期输出:** +``` +✨ Success! Deployed to https://two-sum-web.pages.dev +``` -1. 将代码推送到 GitHub -2. 登录 Cloudflare Dashboard → Pages -3. 点击 "Create a project" → "Connect to Git" -4. 选择你的仓库 -5. 配置构建设置: - - **Build command**: (留空) - - **Build output directory**: `public` -6. 点击 "Save and Deploy" +访问这个 URL,你应该能看到完整的可视化页面! -部署完成后,你会得到一个 `.pages.dev` 域名。 +### 7. 绑定自定义域名(可选) -### 6. 绑定自定义域名(可选) +#### Worker 自定义域名 -在 Cloudflare Dashboard 中: +1. 访问 [Cloudflare Dashboard](https://dash.cloudflare.com) +2. Workers & Pages → two-sum → Settings → Triggers +3. Custom Domains → Add Custom Domain +4. 输入你的域名(如 `api.example.com`) -1. **Worker 绑定自定义域名**: - - Workers & Pages → two-sum → Settings → Triggers - - 添加自定义域名(需要域名托管在 Cloudflare) +#### Pages 自定义域名 -2. **Pages 绑定自定义域名**: - - Pages → two-sum-web → Custom domains - - 添加你的域名 +1. Pages → two-sum-web → Custom domains +2. Set up a custom domain +3. 输入你的域名(如 `leetcode.example.com`) ## 🔧 运维管理 @@ -225,11 +282,11 @@ GROUP BY region ### 清理历史数据 -保留最近 7 天的数据: +保留最近 90 天的数据: ```bash npx wrangler d1 execute two-sum-db --remote --command " DELETE FROM records -WHERE timestamp < strftime('%s', 'now', '-7 days') * 1000 +WHERE timestamp < (strftime('%s', 'now', '-90 days') * 1000) " ``` @@ -262,15 +319,33 @@ npm run deploy ## 🐛 常见问题 -### 1. WebSocket 连接失败? +### 1. US 区 WebSocket 403 错误 + +**错误信息:** +``` +[US] ❌ 错误: Unexpected server response: 403 +``` + +**原因:** LeetCode 国际站有 TLS 指纹检测机制。 + +**解决方案:** + +确保 ja3 代理服务正常运行,且 `PROXY_URL` 和 `PROXY_API_KEY` 配置正确: + +```bash +# 检查 secrets 是否设置正确 +npx wrangler secret list + +# 重新设置 +npx wrangler secret put PROXY_URL +npx wrangler secret put PROXY_API_KEY +``` -LeetCode 的 WebSocket 协议可能需要调整。建议: +### 2. CN 区连接失败 -1. 在浏览器开发者工具中观察真实的 WebSocket 消息格式 -2. 修改 `src/index.js` 中的 `getOnlineCount()` 函数 -3. 调整消息解析逻辑 +CN 区通常连接稳定,如果失败可能是网络问题。Worker 会自动重试 3 次。 -### 2. 数据库写入失败? +### 3. 数据库写入失败 检查 `wrangler.toml` 中的 `database_id` 是否正确: @@ -278,21 +353,21 @@ LeetCode 的 WebSocket 协议可能需要调整。建议: npx wrangler d1 list ``` -### 3. 前端无法获取数据? +### 4. 前端无法获取数据 检查 CORS 配置和 API URL: 1. 确保 `public/index.html` 中的 `API_URL` 指向正确的 Worker 地址 2. 在浏览器控制台查看网络请求错误 -### 4. 定时任务没有执行? +### 5. 定时任务没有执行 ```bash # 查看实时日志 npx wrangler tail -# 手动触发测试 -curl https://your-worker.workers.dev/api/collect +# 检查 Cron 配置 +npx wrangler trigger list ``` ## 📊 API 文档 @@ -320,6 +395,28 @@ curl https://your-worker.workers.dev/api/collect ] ``` +### GET /api/aggregated + +按时间粒度聚合数据。 + +**查询参数:** +- `granularity` (可选):时间粒度,可选值:`fivemin`、`halfhour`、`hour`(默认)、`day`、`month` +- `limit` (可选):返回的数据点数量,默认 168 + +**响应示例:** +```json +[ + { + "region": "CN", + "time": "2026-02-10 15:00", + "avg_count": 547.82, + "min_count": 546, + "max_count": 550, + "sample_count": 11 + } +] +``` + ### GET /api/latest 获取最新数据。 diff --git a/collector.js b/collector.js deleted file mode 100644 index f93675e..0000000 --- a/collector.js +++ /dev/null @@ -1,188 +0,0 @@ -/** - * 数据采集脚本(Node.js) - * 用于采集 LeetCode Two-Sum 的在线人数,并推送到 Cloudflare Worker - * - * 运行方式: - * 1. 本地运行:node collector.js - * 2. 服务器 cron:crontab -e,添加:* * * * * node /path/to/collector.js - * 3. GitHub Actions:每分钟自动运行 - */ - -const WebSocket = require('ws'); - -// 配置 -const CONFIG = { - // Cloudflare Worker API 地址(本地开发默认 localhost:8787) - WORKER_API: process.env.WORKER_API || 'http://localhost:8787/api/push', - - // API 密钥(用于验证) - API_KEY: process.env.API_KEY || 'dev-secret-key-2024', - - // WebSocket 地址 - WS_URLS: { - US: 'wss://collaboration-ws.leetcode.com/problems/two-sum', - CN: 'wss://collaboration-ws.leetcode.cn/problems/two-sum' - }, - - // 请求头配置(绕过反爬虫) - WS_HEADERS: { - US: { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', - 'Origin': 'https://leetcode.com', - 'Accept-Language': 'en-US,en;q=0.9', - 'Cache-Control': 'no-cache', - 'Pragma': 'no-cache' - }, - CN: { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', - 'Origin': 'https://leetcode.cn', - 'Accept-Language': 'zh-CN,zh;q=0.9', - 'Cache-Control': 'no-cache', - 'Pragma': 'no-cache' - } - }, - - // 超时时间(毫秒) - TIMEOUT: 10000 -}; - -/** - * 从 WebSocket 获取在线人数 - */ -function getOnlineCount(region) { - return new Promise((resolve) => { - const url = CONFIG.WS_URLS[region]; - const headers = CONFIG.WS_HEADERS[region] || {}; - - console.log(`[${region}] 连接中...`); - - const ws = new WebSocket(url, { - headers: headers - }); - let resolved = false; - - // 超时处理 - const timeout = setTimeout(() => { - if (!resolved) { - resolved = true; - console.warn(`[${region}] 超时`); - ws.close(); - resolve(null); - } - }, CONFIG.TIMEOUT); - - ws.on('open', () => { - console.log(`[${region}] 已连接`); - }); - - ws.on('message', (data) => { - if (resolved) return; - - const message = data.toString(); - console.log(`[${region}] 收到消息: ${message}`); - - const count = parseInt(message, 10); - if (!isNaN(count) && count >= 0) { - resolved = true; - clearTimeout(timeout); - ws.close(); - console.log(`[${region}] ✅ 在线人数: ${count}`); - resolve(count); - } - }); - - ws.on('error', (error) => { - if (!resolved) { - resolved = true; - clearTimeout(timeout); - console.error(`[${region}] ❌ 错误:`, error.message); - resolve(null); - } - }); - - ws.on('close', () => { - if (!resolved) { - resolved = true; - clearTimeout(timeout); - console.log(`[${region}] 连接已关闭`); - resolve(null); - } - }); - }); -} - -/** - * 推送数据到 Cloudflare Worker - */ -async function pushToWorker(data) { - try { - const response = await fetch(CONFIG.WORKER_API, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-API-Key': CONFIG.API_KEY - }, - body: JSON.stringify(data) - }); - - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${await response.text()}`); - } - - const result = await response.json(); - console.log('✅ 数据推送成功:', result); - return true; - } catch (error) { - console.error('❌ 推送失败:', error.message); - return false; - } -} - -/** - * 主函数 - */ -async function main() { - console.log('\n========== LeetCode 数据采集 =========='); - console.log('时间:', new Date().toISOString()); - - // 并行采集 - const [usCount, cnCount] = await Promise.all([ - getOnlineCount('US'), - getOnlineCount('CN') - ]); - - const timestamp = Date.now(); - const records = []; - - if (usCount !== null) { - records.push({ region: 'US', count: usCount, timestamp }); - } - - if (cnCount !== null) { - records.push({ region: 'CN', count: cnCount, timestamp }); - } - - if (records.length === 0) { - console.error('❌ 没有采集到任何数据'); - process.exit(1); - } - - console.log('\n准备推送数据:', records); - - // 推送到 Worker - const success = await pushToWorker({ records }); - - if (success) { - console.log('\n✅ 采集完成!'); - process.exit(0); - } else { - console.error('\n❌ 采集失败'); - process.exit(1); - } -} - -// 运行 -main().catch((error) => { - console.error('❌ 意外错误:', error); - process.exit(1); -}); diff --git a/package-lock.json b/package-lock.json index 4495a41..042842f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,31 +12,28 @@ "ws": "^8.16.0" }, "devDependencies": { - "wrangler": "^3.0.0" + "wrangler": "^4.0.0" } }, "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz", - "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==", + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz", + "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==", "dev": true, "license": "MIT OR Apache-2.0", - "dependencies": { - "mime": "^3.0.0" - }, "engines": { - "node": ">=16.13" + "node": ">=18.0.0" } }, "node_modules/@cloudflare/unenv-preset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.0.2.tgz", - "integrity": "sha512-nyzYnlZjjV5xT3LizahG1Iu6mnrCaxglJ04rZLpDwlDVDZ7v46lNsfxhV3A/xtfgQuSHmLnc6SVI+KwBpc3Lwg==", + "version": "2.16.0", + "resolved": "https://registry.npmmirror.com/@cloudflare/unenv-preset/-/unenv-preset-2.16.0.tgz", + "integrity": "sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg==", "dev": true, "license": "MIT OR Apache-2.0", "peerDependencies": { - "unenv": "2.0.0-rc.14", - "workerd": "^1.20250124.0" + "unenv": "2.0.0-rc.24", + "workerd": "1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0" }, "peerDependenciesMeta": { "workerd": { @@ -45,9 +42,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20250718.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250718.0.tgz", - "integrity": "sha512-FHf4t7zbVN8yyXgQ/r/GqLPaYZSGUVzeR7RnL28Mwj2djyw2ZergvytVc7fdGcczl6PQh+VKGfZCfUqpJlbi9g==", + "version": "1.20260405.1", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260405.1.tgz", + "integrity": "sha512-EbmdBcmeIGogKG4V1odSWQe7z4rHssUD4iaXv0cXA22/MFrzH3iQT0R+FJFyhucGtih/9B9E+6j0QbSQD8xT3w==", "cpu": [ "x64" ], @@ -62,9 +59,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20250718.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250718.0.tgz", - "integrity": "sha512-fUiyUJYyqqp4NqJ0YgGtp4WJh/II/YZsUnEb6vVy5Oeas8lUOxnN+ZOJ8N/6/5LQCVAtYCChRiIrBbfhTn5Z8Q==", + "version": "1.20260405.1", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260405.1.tgz", + "integrity": "sha512-r44r418bOQtoP+Odu+L/BQM9q5cRSXRd1N167PgZQIo4MlqzTwHO4L0wwXhxbcV/PF46rrQre/uTFS8R0R+xSQ==", "cpu": [ "arm64" ], @@ -79,9 +76,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20250718.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250718.0.tgz", - "integrity": "sha512-5+eb3rtJMiEwp08Kryqzzu8d1rUcK+gdE442auo5eniMpT170Dz0QxBrqkg2Z48SFUPYbj+6uknuA5tzdRSUSg==", + "version": "1.20260405.1", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260405.1.tgz", + "integrity": "sha512-Aaq3RWnaTCzMBo77wC8fjOx+SFdO/rlcXa6HAf+PJs51LyMISFOBCJKqSlS6Irphen0WHHxFKPHUO9bjfj8g2g==", "cpu": [ "x64" ], @@ -96,9 +93,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20250718.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250718.0.tgz", - "integrity": "sha512-Aa2M/DVBEBQDdATMbn217zCSFKE+ud/teS+fFS+OQqKABLn0azO2qq6ANAHYOIE6Q3Sq4CxDIQr8lGdaJHwUog==", + "version": "1.20260405.1", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260405.1.tgz", + "integrity": "sha512-Lbp9Z2wiMzy3Sji3YwMHK5WDlejsH3jF4swAFEv7+jIf3NowZHga3GzwTypNRmcwnfz/XrqQ7Hc0Ul9OoU/lCw==", "cpu": [ "arm64" ], @@ -113,9 +110,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20250718.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250718.0.tgz", - "integrity": "sha512-dY16RXKffmugnc67LTbyjdDHZn5NoTF1yHEf2fN4+OaOnoGSp3N1x77QubTDwqZ9zECWxgQfDLjddcH8dWeFhg==", + "version": "1.20260405.1", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260405.1.tgz", + "integrity": "sha512-FhE0kt93kj5JnSPVqi4BAXpQQENyKnuSOoJLd35mkMMGhtPrwv5EsReJdck0S8hUocCBlb+U0RmP8ta6k41HjQ==", "cpu": [ "x64" ], @@ -131,7 +128,7 @@ }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "resolved": "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", @@ -143,9 +140,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "version": "1.9.2", + "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", "dev": true, "license": "MIT", "optional": true, @@ -153,34 +150,27 @@ "tslib": "^2.4.0" } }, - "node_modules/@esbuild-plugins/node-globals-polyfill": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", - "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "esbuild": "*" - } - }, - "node_modules/@esbuild-plugins/node-modules-polyfill": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", - "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "escape-string-regexp": "^4.0.0", - "rollup-plugin-node-polyfills": "^0.2.1" - }, - "peerDependencies": { - "esbuild": "*" + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", "cpu": [ "arm" ], @@ -191,13 +181,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", "cpu": [ "arm64" ], @@ -208,13 +198,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", "cpu": [ "x64" ], @@ -225,13 +215,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", "cpu": [ "arm64" ], @@ -242,13 +232,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", "cpu": [ "x64" ], @@ -259,13 +249,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "cpu": [ "arm64" ], @@ -276,13 +266,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "cpu": [ "x64" ], @@ -293,13 +283,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", "cpu": [ "arm" ], @@ -310,13 +300,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "cpu": [ "arm64" ], @@ -327,13 +317,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", "cpu": [ "ia32" ], @@ -344,13 +334,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", "cpu": [ "loong64" ], @@ -361,13 +351,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", "cpu": [ "mips64el" ], @@ -378,13 +368,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", "cpu": [ "ppc64" ], @@ -395,13 +385,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "cpu": [ "riscv64" ], @@ -412,13 +402,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "cpu": [ "s390x" ], @@ -429,13 +419,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", "cpu": [ "x64" ], @@ -446,13 +436,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "cpu": [ "x64" ], @@ -463,13 +470,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "cpu": [ "x64" ], @@ -480,13 +504,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "cpu": [ "x64" ], @@ -497,13 +538,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "cpu": [ "arm64" ], @@ -514,13 +555,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "cpu": [ "ia32" ], @@ -531,13 +572,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], @@ -548,23 +589,23 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", "cpu": [ "arm64" ], @@ -581,13 +622,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", "cpu": [ "x64" ], @@ -604,13 +645,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", "cpu": [ "arm64" ], @@ -625,9 +666,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", "cpu": [ "x64" ], @@ -642,9 +683,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", "cpu": [ "arm" ], @@ -659,9 +700,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", "cpu": [ "arm64" ], @@ -675,10 +716,44 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", "cpu": [ "s390x" ], @@ -693,9 +768,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", "cpu": [ "x64" ], @@ -710,9 +785,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", "cpu": [ "arm64" ], @@ -727,9 +802,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", "cpu": [ "x64" ], @@ -744,9 +819,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", "cpu": [ "arm" ], @@ -763,13 +838,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" + "@img/sharp-libvips-linux-arm": "1.2.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", "cpu": [ "arm64" ], @@ -786,13 +861,59 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", "cpu": [ "s390x" ], @@ -809,13 +930,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" + "@img/sharp-libvips-linux-s390x": "1.2.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", "cpu": [ "x64" ], @@ -832,13 +953,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" + "@img/sharp-libvips-linux-x64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", "cpu": [ "arm64" ], @@ -855,13 +976,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", "cpu": [ "x64" ], @@ -878,13 +999,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", "cpu": [ "wasm32" ], @@ -892,7 +1013,7 @@ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.2.0" + "@emnapi/runtime": "^1.7.0" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -901,10 +1022,30 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", "cpu": [ "ia32" ], @@ -922,9 +1063,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", "cpu": [ "x64" ], @@ -943,7 +1084,7 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", @@ -953,14 +1094,14 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", @@ -969,134 +1110,98 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "node_modules/@poppinss/colors": { + "version": "4.1.6", + "resolved": "https://registry.npmmirror.com/@poppinss/colors/-/colors-4.1.6.tgz", + "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.4.0" + "dependencies": { + "kleur": "^4.1.5" } }, - "node_modules/as-table": { - "version": "1.0.55", - "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", - "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "node_modules/@poppinss/dumper": { + "version": "0.6.5", + "resolved": "https://registry.npmmirror.com/@poppinss/dumper/-/dumper-0.6.5.tgz", + "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", "dev": true, "license": "MIT", "dependencies": { - "printable-characters": "^1.0.42" + "@poppinss/colors": "^4.1.5", + "@sindresorhus/is": "^7.0.2", + "supports-color": "^10.0.0" } }, - "node_modules/blake3-wasm": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", - "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "node_modules/@poppinss/exception": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@poppinss/exception/-/exception-1.2.3.tgz", + "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", "dev": true, "license": "MIT" }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "node_modules/@sindresorhus/is": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "~1.1.4" + "node": ">=18" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@speed-highlight/core": { + "version": "1.2.15", + "resolved": "https://registry.npmmirror.com/@speed-highlight/core/-/core-1.2.15.tgz", + "integrity": "sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==", "dev": true, - "license": "MIT", - "optional": true + "license": "CC0-1.0" }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "node_modules/blake3-wasm": { + "version": "2.1.5", "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } + "license": "MIT" }, "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/data-uri-to-buffer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", - "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", - "dev": true, - "license": "MIT" - }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true, - "license": "MIT" - }, "node_modules/detect-libc": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } }, + "node_modules/error-stack-parser-es": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.27.3", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1104,76 +1209,40 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/exit-hook": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", - "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, - "node_modules/exsolve": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", - "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", - "dev": true, - "license": "MIT" - }, "node_modules/fsevents": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, @@ -1186,159 +1255,95 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/get-source": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", - "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", - "dev": true, - "license": "Unlicense", - "dependencies": { - "data-uri-to-buffer": "^2.0.0", - "source-map": "^0.6.1" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/is-arrayish": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", - "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, "license": "MIT", - "optional": true - }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, "engines": { - "node": ">=10.0.0" + "node": ">=6" } }, "node_modules/miniflare": { - "version": "3.20250718.3", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20250718.3.tgz", - "integrity": "sha512-JuPrDJhwLrNLEJiNLWO7ZzJrv/Vv9kZuwMYCfv0LskQDM6Eonw4OvywO3CH/wCGjgHzha/qyjUh8JQ068TjDgQ==", + "version": "4.20260405.0", + "resolved": "https://registry.npmmirror.com/miniflare/-/miniflare-4.20260405.0.tgz", + "integrity": "sha512-tpr4XdWMq7zFdsHH+CS0XS47nQzlRZH0rMJ1vobOZbkrs3cIj7qbD40ON616hDnzHxwqwB2qKHzmmuj6oRisSQ==", "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", - "acorn": "8.14.0", - "acorn-walk": "8.3.2", - "exit-hook": "2.2.1", - "glob-to-regexp": "0.4.1", - "stoppable": "1.1.0", - "undici": "^5.28.5", - "workerd": "1.20250718.0", + "sharp": "^0.34.5", + "undici": "7.24.4", + "workerd": "1.20260405.1", "ws": "8.18.0", - "youch": "3.3.4", - "zod": "3.22.3" + "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" }, "engines": { - "node": ">=16.13" + "node": ">=18.0.0" } }, - "node_modules/mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "dev": true, - "license": "MIT", - "bin": { - "mustache": "bin/mustache" - } - }, - "node_modules/ohash": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", - "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", - "dev": true, - "license": "MIT" - }, "node_modules/path-to-regexp": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true, "license": "MIT" }, "node_modules/pathe": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, - "node_modules/printable-characters": { - "version": "1.0.42", - "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", - "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", - "dev": true, - "license": "Unlicense" - }, - "node_modules/rollup-plugin-inject": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", - "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", - "dev": true, - "license": "MIT", + "node_modules/playwright": { + "version": "1.59.1", + "license": "Apache-2.0", "dependencies": { - "estree-walker": "^0.6.1", - "magic-string": "^0.25.3", - "rollup-pluginutils": "^2.8.1" + "playwright-core": "1.59.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" } }, - "node_modules/rollup-plugin-node-polyfills": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", - "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", - "dev": true, - "license": "MIT", - "dependencies": { - "rollup-plugin-inject": "^3.0.0" + "node_modules/playwright-core": { + "version": "1.59.1", + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" } }, - "node_modules/rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "estree-walker": "^0.6.1" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/semver": { "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz", "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", - "optional": true, "bin": { "semver": "bin/semver.js" }, @@ -1347,17 +1352,16 @@ } }, "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "version": "0.34.5", + "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", - "optional": true, "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -1366,124 +1370,77 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", - "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true, - "license": "MIT" - }, - "node_modules/stacktracey": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", - "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", - "dev": true, - "license": "Unlicense", - "dependencies": { - "as-table": "^1.0.36", - "get-source": "^2.0.12" - } - }, - "node_modules/stoppable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", - "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "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": ">=4", - "npm": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD", "optional": true }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "dev": true, - "license": "MIT" - }, "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "version": "7.24.4", + "resolved": "https://registry.npmmirror.com/undici/-/undici-7.24.4.tgz", + "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", "dev": true, "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, "engines": { - "node": ">=14.0" + "node": ">=20.18.1" } }, "node_modules/unenv": { - "version": "2.0.0-rc.14", - "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.14.tgz", - "integrity": "sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q==", + "version": "2.0.0-rc.24", + "resolved": "https://registry.npmmirror.com/unenv/-/unenv-2.0.0-rc.24.tgz", + "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", "dev": true, "license": "MIT", "dependencies": { - "defu": "^6.1.4", - "exsolve": "^1.0.1", - "ohash": "^2.0.10", - "pathe": "^2.0.3", - "ufo": "^1.5.4" + "pathe": "^2.0.3" } }, "node_modules/workerd": { - "version": "1.20250718.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250718.0.tgz", - "integrity": "sha512-kqkIJP/eOfDlUyBzU7joBg+tl8aB25gEAGqDap+nFWb+WHhnooxjGHgxPBy3ipw2hnShPFNOQt5lFRxbwALirg==", + "version": "1.20260405.1", + "resolved": "https://registry.npmmirror.com/workerd/-/workerd-1.20260405.1.tgz", + "integrity": "sha512-bSaRWCv9iO8/FWpgZRjHLGZLolX5s1AErRSYaTECMMHOZKuCbl2+ehnSyc+ZZ/70y+9owADmN6HoYEWvBlJdYw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -1494,44 +1451,41 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20250718.0", - "@cloudflare/workerd-darwin-arm64": "1.20250718.0", - "@cloudflare/workerd-linux-64": "1.20250718.0", - "@cloudflare/workerd-linux-arm64": "1.20250718.0", - "@cloudflare/workerd-windows-64": "1.20250718.0" + "@cloudflare/workerd-darwin-64": "1.20260405.1", + "@cloudflare/workerd-darwin-arm64": "1.20260405.1", + "@cloudflare/workerd-linux-64": "1.20260405.1", + "@cloudflare/workerd-linux-arm64": "1.20260405.1", + "@cloudflare/workerd-windows-64": "1.20260405.1" } }, "node_modules/wrangler": { - "version": "3.114.17", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.114.17.tgz", - "integrity": "sha512-tAvf7ly+tB+zwwrmjsCyJ2pJnnc7SZhbnNwXbH+OIdVas3zTSmjcZOjmLKcGGptssAA3RyTKhcF9BvKZzMUycA==", + "version": "4.81.0", + "resolved": "https://registry.npmmirror.com/wrangler/-/wrangler-4.81.0.tgz", + "integrity": "sha512-9fLPDuDcb8Nu6iXrl5E3HGYt3TVhQr/UvqtTvWr9Nl1X7PlQrmWMwQCfSioqN8VHYyQCyESV5jQsoKg8Sx+sEA==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { - "@cloudflare/kv-asset-handler": "0.3.4", - "@cloudflare/unenv-preset": "2.0.2", - "@esbuild-plugins/node-globals-polyfill": "0.2.3", - "@esbuild-plugins/node-modules-polyfill": "0.2.2", + "@cloudflare/kv-asset-handler": "0.4.2", + "@cloudflare/unenv-preset": "2.16.0", "blake3-wasm": "2.1.5", - "esbuild": "0.17.19", - "miniflare": "3.20250718.3", + "esbuild": "0.27.3", + "miniflare": "4.20260405.0", "path-to-regexp": "6.3.0", - "unenv": "2.0.0-rc.14", - "workerd": "1.20250718.0" + "unenv": "2.0.0-rc.24", + "workerd": "1.20260405.1" }, "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" }, "engines": { - "node": ">=16.17.0" + "node": ">=20.3.0" }, "optionalDependencies": { - "fsevents": "~2.3.2", - "sharp": "^0.33.5" + "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20250408.0" + "@cloudflare/workers-types": "^4.20260405.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -1541,8 +1495,6 @@ }, "node_modules/ws": { "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -1561,25 +1513,28 @@ } }, "node_modules/youch": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.4.tgz", - "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==", + "version": "4.1.0-beta.10", + "resolved": "https://registry.npmmirror.com/youch/-/youch-4.1.0-beta.10.tgz", + "integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==", "dev": true, "license": "MIT", "dependencies": { - "cookie": "^0.7.1", - "mustache": "^4.2.0", - "stacktracey": "^2.1.8" + "@poppinss/colors": "^4.1.5", + "@poppinss/dumper": "^0.6.4", + "@speed-highlight/core": "^1.2.7", + "cookie": "^1.0.2", + "youch-core": "^0.3.3" } }, - "node_modules/zod": { - "version": "3.22.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz", - "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==", + "node_modules/youch-core": { + "version": "0.3.3", + "resolved": "https://registry.npmmirror.com/youch-core/-/youch-core-0.3.3.tgz", + "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "dependencies": { + "@poppinss/exception": "^1.2.2", + "error-stack-parser-es": "^1.0.5" } } } diff --git a/package.json b/package.json index 0d0f361..699475e 100644 --- a/package.json +++ b/package.json @@ -16,13 +16,18 @@ "pages:dev": "npx serve public", "pages:deploy": "wrangler pages deploy public --project-name two-sum-web" }, - "keywords": ["leetcode", "monitoring", "cloudflare", "workers"], + "keywords": [ + "leetcode", + "monitoring", + "cloudflare", + "workers" + ], "author": "", "license": "MIT", "dependencies": { "ws": "^8.16.0" }, "devDependencies": { - "wrangler": "^3.0.0" + "wrangler": "^4.0.0" } -} +} \ No newline at end of file diff --git a/public/index.html b/public/index.html index 7bcd4c7..72deab9 100644 --- a/public/index.html +++ b/public/index.html @@ -105,6 +105,25 @@ font-size: 0.9em; } + /* 时区下拉框 */ + #tz-select { + padding: 10px 16px; + border: 2px solid #667eea; + background: white; + color: #667eea; + cursor: pointer; + border-radius: 8px; + font-size: 0.9em; + font-weight: 600; + outline: none; + transition: all 0.3s; + } + + #tz-select:hover, #tz-select:focus { + border-color: #764ba2; + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); + } + button { padding: 10px 20px; border: 2px solid #667eea; @@ -232,11 +251,17 @@