yb 1 mese fa
commit
2fae9f3bd8
11 ha cambiato i file con 2574 aggiunte e 0 eliminazioni
  1. 16 0
      .dev.vars.example
  2. 21 0
      .gitignore
  3. 136 0
      README.md
  4. 1630 0
      package-lock.json
  5. 29 0
      package.json
  6. 65 0
      src/index.ts
  7. 316 0
      src/routes/stream.ts
  8. 187 0
      src/services/cloudflare.ts
  9. 134 0
      src/types/index.ts
  10. 22 0
      tsconfig.json
  11. 18 0
      wrangler.toml

+ 16 - 0
.dev.vars.example

@@ -0,0 +1,16 @@
+# 本地开发环境变量
+# 复制此文件为 .dev.vars 并填写配置
+
+# Cloudflare Account ID
+# 在 Cloudflare Dashboard 右侧可以找到
+CF_ACCOUNT_ID=your_account_id
+
+# Cloudflare API Token
+# 创建方式: https://dash.cloudflare.com/profile/api-tokens
+# 需要 Stream:Edit 权限
+CF_API_TOKEN=your_api_token
+
+# Customer Subdomain
+# 从任意视频播放地址获取: https://customer-xxx.cloudflarestream.com
+# 填写 xxx 部分
+CUSTOMER_SUBDOMAIN=your_subdomain

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+# 依赖
+node_modules/
+
+# 构建输出
+dist/
+
+# Wrangler
+.wrangler/
+
+# 环境变量(敏感信息)
+.dev.vars
+
+# 编辑器
+.vscode/
+.idea/
+
+# macOS
+.DS_Store
+
+# 日志
+*.log

+ 136 - 0
README.md

@@ -0,0 +1,136 @@
+# TG Live Game Hono API
+
+Cloudflare Stream API 后端服务,基于 Hono + Cloudflare Workers。
+
+## 功能
+
+- 视频管理(列表、详情、删除、导入)
+- 直播管理(创建、列表、详情、删除)
+- 播放地址生成
+- 录像管理
+
+## 快速开始
+
+### 1. 安装依赖
+
+```bash
+npm install
+```
+
+### 2. 配置环境变量
+
+```bash
+# 复制配置文件
+cp .dev.vars.example .dev.vars
+
+# 编辑配置,填入 Cloudflare 凭证
+vim .dev.vars
+```
+
+需要配置:
+- `CF_ACCOUNT_ID` - Cloudflare Account ID
+- `CF_API_TOKEN` - Cloudflare API Token(需要 Stream:Edit 权限)
+- `CUSTOMER_SUBDOMAIN` - 播放域名子域名
+
+### 3. 本地开发
+
+```bash
+npm run dev
+```
+
+服务将在 http://localhost:8787 启动。
+
+### 4. 部署到 Cloudflare Workers
+
+```bash
+# 设置 secrets(首次部署前)
+npx wrangler secret put CF_ACCOUNT_ID
+npx wrangler secret put CF_API_TOKEN
+npx wrangler secret put CUSTOMER_SUBDOMAIN
+
+# 部署
+npm run deploy
+```
+
+## API 接口
+
+### 视频管理
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/stream/video/list` | 获取视频列表 |
+| GET | `/api/stream/video/:videoId` | 获取视频详情 |
+| DELETE | `/api/stream/video/:videoId` | 删除视频 |
+| POST | `/api/stream/video/import` | 从 URL 导入视频 |
+| POST | `/api/stream/video/upload-url` | 获取上传 URL |
+| GET | `/api/stream/video/:videoId/playback` | 获取播放信息 |
+
+### 直播管理
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/stream/live/list` | 获取直播列表 |
+| POST | `/api/stream/live` | 创建直播 |
+| GET | `/api/stream/live/:liveInputId` | 获取直播详情 |
+| PUT | `/api/stream/live/:liveInputId` | 更新直播 |
+| DELETE | `/api/stream/live/:liveInputId` | 删除直播 |
+| GET | `/api/stream/live/:liveInputId/playback` | 获取播放信息 |
+| GET | `/api/stream/live/:liveInputId/recordings` | 获取录像列表 |
+
+## 响应格式
+
+所有接口返回统一格式:
+
+```json
+{
+  "code": 200,
+  "msg": "success",
+  "data": { ... }
+}
+```
+
+## 与前端集成
+
+### 开发环境
+
+修改 `tg-live-game-web/vite.config.ts`:
+
+```typescript
+proxy: {
+  '/api': {
+    target: 'http://localhost:8787',
+    changeOrigin: true
+  }
+}
+```
+
+### 生产环境
+
+部署后修改为 Workers 地址:
+
+```typescript
+proxy: {
+  '/api': {
+    target: 'https://tg-live-game-api.your-subdomain.workers.dev',
+    changeOrigin: true
+  }
+}
+```
+
+## 目录结构
+
+```
+tg-live-game-hono/
+├── src/
+│   ├── index.ts              # 入口
+│   ├── routes/
+│   │   └── stream.ts         # Stream API 路由
+│   ├── services/
+│   │   └── cloudflare.ts     # Cloudflare API 服务
+│   └── types/
+│       └── index.ts          # 类型定义
+├── wrangler.toml             # Workers 配置
+├── tsconfig.json             # TypeScript 配置
+├── package.json
+└── README.md
+```

+ 1630 - 0
package-lock.json

@@ -0,0 +1,1630 @@
+{
+  "name": "tg-live-game-hono",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "tg-live-game-hono",
+      "version": "1.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "@hono/node-server": "^1.19.7",
+        "hono": "^4.11.1"
+      },
+      "devDependencies": {
+        "@cloudflare/workers-types": "^4.20251225.0",
+        "tsx": "^4.21.0",
+        "typescript": "^5.9.3",
+        "wrangler": "^4.56.0"
+      }
+    },
+    "node_modules/@cloudflare/kv-asset-handler": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmmirror.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.1.tgz",
+      "integrity": "sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==",
+      "dev": true,
+      "license": "MIT OR Apache-2.0",
+      "dependencies": {
+        "mime": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@cloudflare/unenv-preset": {
+      "version": "2.7.13",
+      "resolved": "https://registry.npmmirror.com/@cloudflare/unenv-preset/-/unenv-preset-2.7.13.tgz",
+      "integrity": "sha512-NulO1H8R/DzsJguLC0ndMuk4Ufv0KSlN+E54ay9rn9ZCQo0kpAPwwh3LhgpZ96a3Dr6L9LqW57M4CqC34iLOvw==",
+      "dev": true,
+      "license": "MIT OR Apache-2.0",
+      "peerDependencies": {
+        "unenv": "2.0.0-rc.24",
+        "workerd": "^1.20251202.0"
+      },
+      "peerDependenciesMeta": {
+        "workerd": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@cloudflare/workerd-darwin-64": {
+      "version": "1.20251217.0",
+      "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20251217.0.tgz",
+      "integrity": "sha512-DN6vT+9ho61d/1/YuILW4VS+N1JBLaixWRL1vqNmhgbf8J8VHwWWotrRruEUYigJKx2yZyw6YsasE+yLXgx/Fw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/@cloudflare/workerd-darwin-arm64": {
+      "version": "1.20251217.0",
+      "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20251217.0.tgz",
+      "integrity": "sha512-5nZOpRTkHmtcTc4Wbr1mj/O3dLb6aHZSiJuVBgtdbVcVmOXueSay3hnw1PXEyR+vpTKGUPkM+omUIslKHWnXDw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/@cloudflare/workerd-linux-64": {
+      "version": "1.20251217.0",
+      "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20251217.0.tgz",
+      "integrity": "sha512-uoPGhMaZVXPpCsU0oG3HQzyVpXCGi5rU+jcHRjUI7DXM4EwctBGvZ380Knkja36qtl+ZvSKVR1pUFSGdK+45Pg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/@cloudflare/workerd-linux-arm64": {
+      "version": "1.20251217.0",
+      "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20251217.0.tgz",
+      "integrity": "sha512-ixHnHKsiz1Xko+eDgCJOZ7EEUZKtmnYq3AjW3nkVcLFypSLks4C29E45zVewdaN4wq8sCLeyQCl6r1kS17+DQQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/@cloudflare/workerd-windows-64": {
+      "version": "1.20251217.0",
+      "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20251217.0.tgz",
+      "integrity": "sha512-rP6USX+7ctynz3AtmKi+EvlLP3Xdr1ETrSdcnv693/I5QdUwBxq4yE1Lj6CV7GJizX6opXKYg8QMq0Q4eB9zRQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/@cloudflare/workers-types": {
+      "version": "4.20251225.0",
+      "resolved": "https://registry.npmmirror.com/@cloudflare/workers-types/-/workers-types-4.20251225.0.tgz",
+      "integrity": "sha512-ZZl0cNLFcsBRFKtMftKWOsfAybUYSeiTMzpQV1NlTVlByHAs1rGQt45Jw/qz8LrfHoq9PGTieSj9W350Gi4Pvg==",
+      "dev": true,
+      "license": "MIT OR Apache-2.0"
+    },
+    "node_modules/@cspotcode/source-map-support": {
+      "version": "0.8.1",
+      "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",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "0.3.9"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@emnapi/runtime": {
+      "version": "1.7.1",
+      "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.7.1.tgz",
+      "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz",
+      "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.0.tgz",
+      "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz",
+      "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.0.tgz",
+      "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz",
+      "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz",
+      "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz",
+      "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz",
+      "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz",
+      "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz",
+      "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz",
+      "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz",
+      "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz",
+      "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz",
+      "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz",
+      "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz",
+      "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz",
+      "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz",
+      "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz",
+      "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz",
+      "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz",
+      "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openharmony-arm64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz",
+      "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz",
+      "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz",
+      "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz",
+      "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz",
+      "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@hono/node-server": {
+      "version": "1.19.7",
+      "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.7.tgz",
+      "integrity": "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.14.1"
+      },
+      "peerDependencies": {
+        "hono": "^4"
+      }
+    },
+    "node_modules/@img/sharp-darwin-arm64": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
+      "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-darwin-arm64": "1.0.4"
+      }
+    },
+    "node_modules/@img/sharp-darwin-x64": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
+      "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-darwin-x64": "1.0.4"
+      }
+    },
+    "node_modules/@img/sharp-libvips-darwin-arm64": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
+      "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-darwin-x64": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
+      "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-arm": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
+      "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-arm64": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
+      "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
+      "cpu": [
+        "arm64"
+      ],
+      "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.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
+      "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-x64": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
+      "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
+      "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
+      "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-linux-arm": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
+      "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
+      "cpu": [
+        "arm"
+      ],
+      "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-arm": "1.0.5"
+      }
+    },
+    "node_modules/@img/sharp-linux-arm64": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
+      "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
+      "cpu": [
+        "arm64"
+      ],
+      "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-arm64": "1.0.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-s390x": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
+      "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
+      "cpu": [
+        "s390x"
+      ],
+      "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-s390x": "1.0.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-x64": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
+      "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
+      "cpu": [
+        "x64"
+      ],
+      "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-x64": "1.0.4"
+      }
+    },
+    "node_modules/@img/sharp-linuxmusl-arm64": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
+      "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
+      "cpu": [
+        "arm64"
+      ],
+      "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-linuxmusl-arm64": "1.0.4"
+      }
+    },
+    "node_modules/@img/sharp-linuxmusl-x64": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
+      "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
+      "cpu": [
+        "x64"
+      ],
+      "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-linuxmusl-x64": "1.0.4"
+      }
+    },
+    "node_modules/@img/sharp-wasm32": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
+      "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
+      "cpu": [
+        "wasm32"
+      ],
+      "dev": true,
+      "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/runtime": "^1.2.0"
+      },
+      "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.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
+      "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "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-x64": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
+      "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
+      "cpu": [
+        "x64"
+      ],
+      "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/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.0.3",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
+    "node_modules/@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",
+      "dependencies": {
+        "kleur": "^4.1.5"
+      }
+    },
+    "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": {
+        "@poppinss/colors": "^4.1.5",
+        "@sindresorhus/is": "^7.0.2",
+        "supports-color": "^10.0.0"
+      }
+    },
+    "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/@sindresorhus/is": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-7.1.1.tgz",
+      "integrity": "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/is?sponsor=1"
+      }
+    },
+    "node_modules/@speed-highlight/core": {
+      "version": "1.2.12",
+      "resolved": "https://registry.npmmirror.com/@speed-highlight/core/-/core-1.2.12.tgz",
+      "integrity": "sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA==",
+      "dev": true,
+      "license": "CC0-1.0"
+    },
+    "node_modules/acorn": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmmirror.com/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.npmmirror.com/acorn-walk/-/acorn-walk-8.3.2.tgz",
+      "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/blake3-wasm": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmmirror.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
+      "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/color": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmmirror.com/color/-/color-4.2.3.tgz",
+      "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+      "dev": true,
+      "license": "MIT",
+      "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.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/color-string": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
+    "node_modules/cookie": {
+      "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": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz",
+      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "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.27.0",
+      "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.0.tgz",
+      "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.27.0",
+        "@esbuild/android-arm": "0.27.0",
+        "@esbuild/android-arm64": "0.27.0",
+        "@esbuild/android-x64": "0.27.0",
+        "@esbuild/darwin-arm64": "0.27.0",
+        "@esbuild/darwin-x64": "0.27.0",
+        "@esbuild/freebsd-arm64": "0.27.0",
+        "@esbuild/freebsd-x64": "0.27.0",
+        "@esbuild/linux-arm": "0.27.0",
+        "@esbuild/linux-arm64": "0.27.0",
+        "@esbuild/linux-ia32": "0.27.0",
+        "@esbuild/linux-loong64": "0.27.0",
+        "@esbuild/linux-mips64el": "0.27.0",
+        "@esbuild/linux-ppc64": "0.27.0",
+        "@esbuild/linux-riscv64": "0.27.0",
+        "@esbuild/linux-s390x": "0.27.0",
+        "@esbuild/linux-x64": "0.27.0",
+        "@esbuild/netbsd-arm64": "0.27.0",
+        "@esbuild/netbsd-x64": "0.27.0",
+        "@esbuild/openbsd-arm64": "0.27.0",
+        "@esbuild/openbsd-x64": "0.27.0",
+        "@esbuild/openharmony-arm64": "0.27.0",
+        "@esbuild/sunos-x64": "0.27.0",
+        "@esbuild/win32-arm64": "0.27.0",
+        "@esbuild/win32-ia32": "0.27.0",
+        "@esbuild/win32-x64": "0.27.0"
+      }
+    },
+    "node_modules/exit-hook": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmmirror.com/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"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/get-tsconfig": {
+      "version": "4.13.0",
+      "resolved": "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
+      "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "resolve-pkg-maps": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+      }
+    },
+    "node_modules/glob-to-regexp": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmmirror.com/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/hono": {
+      "version": "4.11.1",
+      "resolved": "https://registry.npmmirror.com/hono/-/hono-4.11.1.tgz",
+      "integrity": "sha512-KsFcH0xxHes0J4zaQgWbYwmz3UPOOskdqZmItstUG93+Wk1ePBLkLGwbP9zlmh1BFUiL8Qp+Xfu9P7feJWpGNg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=16.9.0"
+      }
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.4.tgz",
+      "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "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",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/mime": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/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_modules/miniflare": {
+      "version": "4.20251217.0",
+      "resolved": "https://registry.npmmirror.com/miniflare/-/miniflare-4.20251217.0.tgz",
+      "integrity": "sha512-8xsTQbPS6YV+ABZl9qiJIbsum6hbpbhqiyKpOVdzZrhK+1N8EFpT8R6aBZff7kezGmxYZSntjgjqTwJmj3JLgA==",
+      "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",
+        "sharp": "^0.33.5",
+        "stoppable": "1.1.0",
+        "undici": "7.14.0",
+        "workerd": "1.20251217.0",
+        "ws": "8.18.0",
+        "youch": "4.1.0-beta.10",
+        "zod": "3.22.3"
+      },
+      "bin": {
+        "miniflare": "bootstrap.js"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/path-to-regexp": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmmirror.com/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.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
+      "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/resolve-pkg-maps": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+      "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.7.3",
+      "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
+      "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/sharp": {
+      "version": "0.33.5",
+      "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.33.5.tgz",
+      "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "color": "^4.2.3",
+        "detect-libc": "^2.0.3",
+        "semver": "^7.6.3"
+      },
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "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.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+      "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
+    "node_modules/stoppable": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/stoppable/-/stoppable-1.1.0.tgz",
+      "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4",
+        "npm": ">=6"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-10.2.2.tgz",
+      "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "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/tsx": {
+      "version": "4.21.0",
+      "resolved": "https://registry.npmmirror.com/tsx/-/tsx-4.21.0.tgz",
+      "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "~0.27.0",
+        "get-tsconfig": "^4.7.5"
+      },
+      "bin": {
+        "tsx": "dist/cli.mjs"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.9.3",
+      "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
+      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/undici": {
+      "version": "7.14.0",
+      "resolved": "https://registry.npmmirror.com/undici/-/undici-7.14.0.tgz",
+      "integrity": "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20.18.1"
+      }
+    },
+    "node_modules/unenv": {
+      "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": {
+        "pathe": "^2.0.3"
+      }
+    },
+    "node_modules/workerd": {
+      "version": "1.20251217.0",
+      "resolved": "https://registry.npmmirror.com/workerd/-/workerd-1.20251217.0.tgz",
+      "integrity": "sha512-s3mHDSWwHTduyY8kpHOsl27ZJ4ziDBJlc18PfBvNMqNnhO7yBeemlxH7bo7yQyU1foJrIZ6IENHDDg0Z9N8zQA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "workerd": "bin/workerd"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "optionalDependencies": {
+        "@cloudflare/workerd-darwin-64": "1.20251217.0",
+        "@cloudflare/workerd-darwin-arm64": "1.20251217.0",
+        "@cloudflare/workerd-linux-64": "1.20251217.0",
+        "@cloudflare/workerd-linux-arm64": "1.20251217.0",
+        "@cloudflare/workerd-windows-64": "1.20251217.0"
+      }
+    },
+    "node_modules/wrangler": {
+      "version": "4.56.0",
+      "resolved": "https://registry.npmmirror.com/wrangler/-/wrangler-4.56.0.tgz",
+      "integrity": "sha512-Nqi8duQeRbA+31QrD6QlWHW3IZVnuuRxMy7DEg46deUzywivmaRV/euBN5KKXDPtA24VyhYsK7I0tkb7P5DM2w==",
+      "dev": true,
+      "license": "MIT OR Apache-2.0",
+      "dependencies": {
+        "@cloudflare/kv-asset-handler": "0.4.1",
+        "@cloudflare/unenv-preset": "2.7.13",
+        "blake3-wasm": "2.1.5",
+        "esbuild": "0.27.0",
+        "miniflare": "4.20251217.0",
+        "path-to-regexp": "6.3.0",
+        "unenv": "2.0.0-rc.24",
+        "workerd": "1.20251217.0"
+      },
+      "bin": {
+        "wrangler": "bin/wrangler.js",
+        "wrangler2": "bin/wrangler.js"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      },
+      "peerDependencies": {
+        "@cloudflare/workers-types": "^4.20251217.0"
+      },
+      "peerDependenciesMeta": {
+        "@cloudflare/workers-types": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/ws": {
+      "version": "8.18.0",
+      "resolved": "https://registry.npmmirror.com/ws/-/ws-8.18.0.tgz",
+      "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/youch": {
+      "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": {
+        "@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/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",
+      "dependencies": {
+        "@poppinss/exception": "^1.2.2",
+        "error-stack-parser-es": "^1.0.5"
+      }
+    },
+    "node_modules/zod": {
+      "version": "3.22.3",
+      "resolved": "https://registry.npmmirror.com/zod/-/zod-3.22.3.tgz",
+      "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/colinhacks"
+      }
+    }
+  }
+}

+ 29 - 0
package.json

@@ -0,0 +1,29 @@
+{
+  "name": "tg-live-game-hono",
+  "version": "1.0.0",
+  "description": "Cloudflare Stream API Backend for TG Live Game",
+  "type": "module",
+  "scripts": {
+    "dev": "wrangler dev",
+    "deploy": "wrangler deploy",
+    "dev:node": "npx tsx watch src/node.ts"
+  },
+  "keywords": [
+    "cloudflare",
+    "hono",
+    "stream",
+    "live"
+  ],
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "@hono/node-server": "^1.19.7",
+    "hono": "^4.11.1"
+  },
+  "devDependencies": {
+    "@cloudflare/workers-types": "^4.20251225.0",
+    "tsx": "^4.21.0",
+    "typescript": "^5.9.3",
+    "wrangler": "^4.56.0"
+  }
+}

+ 65 - 0
src/index.ts

@@ -0,0 +1,65 @@
+import { Hono } from 'hono'
+import { cors } from 'hono/cors'
+import { logger } from 'hono/logger'
+import stream from './routes/stream'
+import type { Env } from './types'
+
+const app = new Hono<{ Bindings: Env }>()
+
+// 中间件
+app.use('*', logger())
+app.use('*', cors({
+  origin: '*',
+  allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
+  allowHeaders: ['Content-Type', 'Authorization'],
+}))
+
+// 健康检查
+app.get('/', (c) => {
+  return c.json({
+    code: 200,
+    msg: 'TG Live Game API',
+    data: {
+      version: '1.0.0',
+      endpoints: [
+        'GET  /api/stream/video/list',
+        'GET  /api/stream/video/:videoId',
+        'DELETE /api/stream/video/:videoId',
+        'POST /api/stream/video/import',
+        'POST /api/stream/video/upload-url',
+        'GET  /api/stream/video/:videoId/playback',
+        'GET  /api/stream/live/list',
+        'POST /api/stream/live',
+        'GET  /api/stream/live/:liveInputId',
+        'PUT  /api/stream/live/:liveInputId',
+        'DELETE /api/stream/live/:liveInputId',
+        'GET  /api/stream/live/:liveInputId/playback',
+        'GET  /api/stream/live/:liveInputId/recordings',
+      ]
+    }
+  })
+})
+
+// 挂载路由
+app.route('/api/stream', stream)
+
+// 404 处理
+app.notFound((c) => {
+  return c.json({
+    code: 404,
+    msg: 'Not Found',
+    data: null
+  }, 404)
+})
+
+// 错误处理
+app.onError((err, c) => {
+  console.error('Error:', err)
+  return c.json({
+    code: 500,
+    msg: err.message || 'Internal Server Error',
+    data: null
+  }, 500)
+})
+
+export default app

+ 316 - 0
src/routes/stream.ts

@@ -0,0 +1,316 @@
+import { Hono } from 'hono'
+import { CloudflareStreamService } from '../services/cloudflare'
+import type { Env, ApiResponse, PageResponse, CloudflareVideo, CloudflareLiveInput, CreateLiveInputParams } from '../types'
+
+const stream = new Hono<{ Bindings: Env }>()
+
+/**
+ * 创建成功响应
+ */
+function success<T>(data: T, msg = 'success'): ApiResponse<T> {
+  return { code: 200, msg, data }
+}
+
+/**
+ * 创建错误响应
+ */
+function error(msg: string, code = 500): ApiResponse<null> {
+  return { code, msg, data: null }
+}
+
+// ==================== 视频管理 ====================
+
+/**
+ * 获取视频列表
+ * GET /api/stream/video/list
+ */
+stream.get('/video/list', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const { search, status, pageSize } = c.req.query()
+
+    const res = await service.listVideos({
+      search,
+      status,
+      limit: pageSize ? parseInt(pageSize) : 50,
+    })
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to list videos'))
+    }
+
+    const data: PageResponse<CloudflareVideo> = {
+      rows: res.result,
+      total: res.result.length,
+    }
+
+    return c.json(success(data))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 获取视频详情
+ * GET /api/stream/video/:videoId
+ */
+stream.get('/video/:videoId', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const videoId = c.req.param('videoId')
+
+    const res = await service.getVideo(videoId)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Video not found', 404))
+    }
+
+    return c.json(success(res.result))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 删除视频
+ * DELETE /api/stream/video/:videoId
+ */
+stream.delete('/video/:videoId', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const videoId = c.req.param('videoId')
+
+    const res = await service.deleteVideo(videoId)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to delete video'))
+    }
+
+    return c.json(success(null, 'Video deleted'))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 从 URL 导入视频
+ * POST /api/stream/video/import
+ */
+stream.post('/video/import', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const body = await c.req.json<{ url: string; name?: string; meta?: Record<string, unknown> }>()
+
+    if (!body.url) {
+      return c.json(error('URL is required', 400))
+    }
+
+    const meta = body.meta || {}
+    if (body.name) {
+      meta.name = body.name
+    }
+
+    const res = await service.importFromUrl(body.url, meta)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to import video'))
+    }
+
+    return c.json(success(res.result, 'Video import started'))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 获取上传 URL
+ * POST /api/stream/video/upload-url
+ */
+stream.post('/video/upload-url', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const body = await c.req.json<{ maxDurationSeconds?: number; meta?: Record<string, unknown> }>()
+
+    const res = await service.createUploadUrl(body)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to create upload URL'))
+    }
+
+    return c.json(success(res.result))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 获取视频播放信息
+ * GET /api/stream/video/:videoId/playback
+ */
+stream.get('/video/:videoId/playback', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const videoId = c.req.param('videoId')
+
+    const playbackInfo = service.getPlaybackInfo(videoId)
+    return c.json(success(playbackInfo))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+// ==================== 直播管理 ====================
+
+/**
+ * 获取直播列表
+ * GET /api/stream/live/list
+ */
+stream.get('/live/list', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+
+    const res = await service.listLiveInputs()
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to list live inputs'))
+    }
+
+    const data: PageResponse<CloudflareLiveInput> = {
+      rows: res.result,
+      total: res.result.length,
+    }
+
+    return c.json(success(data))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 创建直播输入
+ * POST /api/stream/live
+ */
+stream.post('/live', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const body = await c.req.json<CreateLiveInputParams>()
+
+    const res = await service.createLiveInput(body)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to create live input'))
+    }
+
+    return c.json(success(res.result, 'Live input created'))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 获取直播详情
+ * GET /api/stream/live/:liveInputId
+ */
+stream.get('/live/:liveInputId', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const liveInputId = c.req.param('liveInputId')
+
+    const res = await service.getLiveInput(liveInputId)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Live input not found', 404))
+    }
+
+    return c.json(success(res.result))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 更新直播输入
+ * PUT /api/stream/live/:liveInputId
+ */
+stream.put('/live/:liveInputId', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const liveInputId = c.req.param('liveInputId')
+    const body = await c.req.json<CreateLiveInputParams>()
+
+    const res = await service.updateLiveInput(liveInputId, body)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to update live input'))
+    }
+
+    return c.json(success(res.result, 'Live input updated'))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 删除直播输入
+ * DELETE /api/stream/live/:liveInputId
+ */
+stream.delete('/live/:liveInputId', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const liveInputId = c.req.param('liveInputId')
+
+    const res = await service.deleteLiveInput(liveInputId)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to delete live input'))
+    }
+
+    return c.json(success(null, 'Live input deleted'))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 获取直播播放信息
+ * GET /api/stream/live/:liveInputId/playback
+ */
+stream.get('/live/:liveInputId/playback', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const liveInputId = c.req.param('liveInputId')
+
+    const playbackInfo = service.getLivePlaybackInfo(liveInputId)
+    return c.json(success(playbackInfo))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+/**
+ * 获取直播录像列表
+ * GET /api/stream/live/:liveInputId/recordings
+ */
+stream.get('/live/:liveInputId/recordings', async (c) => {
+  try {
+    const service = new CloudflareStreamService(c.env)
+    const liveInputId = c.req.param('liveInputId')
+
+    const res = await service.listLiveRecordings(liveInputId)
+
+    if (!res.success) {
+      return c.json(error(res.errors[0]?.message || 'Failed to list recordings'))
+    }
+
+    const data: PageResponse<CloudflareVideo> = {
+      rows: res.result,
+      total: res.result.length,
+    }
+
+    return c.json(success(data))
+  } catch (err) {
+    return c.json(error(err instanceof Error ? err.message : 'Unknown error'))
+  }
+})
+
+export default stream

+ 187 - 0
src/services/cloudflare.ts

@@ -0,0 +1,187 @@
+import type {
+  Env,
+  CloudflareVideo,
+  CloudflareLiveInput,
+  CloudflareApiResponse,
+  CreateLiveInputParams,
+  VideoPlaybackInfo
+} from '../types'
+
+/**
+ * Cloudflare Stream API 服务
+ */
+export class CloudflareStreamService {
+  private accountId: string
+  private apiToken: string
+  private customerSubdomain: string
+  private baseUrl: string
+
+  constructor(env: Env) {
+    this.accountId = env.CF_ACCOUNT_ID
+    this.apiToken = env.CF_API_TOKEN
+    this.customerSubdomain = env.CUSTOMER_SUBDOMAIN
+    this.baseUrl = `https://api.cloudflare.com/client/v4/accounts/${this.accountId}/stream`
+  }
+
+  /**
+   * 发送请求到 Cloudflare API
+   */
+  private async request<T>(
+    path: string,
+    options: RequestInit = {}
+  ): Promise<CloudflareApiResponse<T>> {
+    const url = `${this.baseUrl}${path}`
+    const response = await fetch(url, {
+      ...options,
+      headers: {
+        'Authorization': `Bearer ${this.apiToken}`,
+        'Content-Type': 'application/json',
+        ...options.headers,
+      },
+    })
+
+    if (!response.ok) {
+      const error = await response.text()
+      throw new Error(`Cloudflare API Error: ${response.status} - ${error}`)
+    }
+
+    return response.json()
+  }
+
+  /**
+   * 获取客户播放域名
+   */
+  getCustomerDomain(): string {
+    return `customer-${this.customerSubdomain}.cloudflarestream.com`
+  }
+
+  // ==================== 视频管理 ====================
+
+  /**
+   * 获取视频列表
+   */
+  async listVideos(params?: {
+    search?: string
+    status?: string
+    limit?: number
+  }): Promise<CloudflareApiResponse<CloudflareVideo[]>> {
+    const searchParams = new URLSearchParams()
+    if (params?.search) searchParams.set('search', params.search)
+    if (params?.status) searchParams.set('status', params.status)
+    if (params?.limit) searchParams.set('limit', params.limit.toString())
+
+    const query = searchParams.toString()
+    return this.request<CloudflareVideo[]>(`${query ? `?${query}` : ''}`)
+  }
+
+  /**
+   * 获取视频详情
+   */
+  async getVideo(videoId: string): Promise<CloudflareApiResponse<CloudflareVideo>> {
+    return this.request<CloudflareVideo>(`/${videoId}`)
+  }
+
+  /**
+   * 删除视频
+   */
+  async deleteVideo(videoId: string): Promise<CloudflareApiResponse<null>> {
+    return this.request<null>(`/${videoId}`, { method: 'DELETE' })
+  }
+
+  /**
+   * 从 URL 导入视频
+   */
+  async importFromUrl(url: string, meta?: Record<string, unknown>): Promise<CloudflareApiResponse<CloudflareVideo>> {
+    return this.request<CloudflareVideo>('/copy', {
+      method: 'POST',
+      body: JSON.stringify({ url, meta }),
+    })
+  }
+
+  /**
+   * 创建上传 URL (TUS 协议)
+   */
+  async createUploadUrl(params?: {
+    maxDurationSeconds?: number
+    meta?: Record<string, unknown>
+  }): Promise<CloudflareApiResponse<{ uploadURL: string; uid: string }>> {
+    return this.request<{ uploadURL: string; uid: string }>('/direct_upload', {
+      method: 'POST',
+      body: JSON.stringify(params || {}),
+    })
+  }
+
+  /**
+   * 获取视频播放信息
+   */
+  getPlaybackInfo(videoId: string): VideoPlaybackInfo {
+    const domain = this.getCustomerDomain()
+    return {
+      uid: videoId,
+      preview: `https://${domain}/${videoId}/watch`,
+      thumbnail: `https://${domain}/${videoId}/thumbnails/thumbnail.jpg`,
+      playback: {
+        hls: `https://${domain}/${videoId}/manifest/video.m3u8`,
+        dash: `https://${domain}/${videoId}/manifest/video.mpd`,
+      },
+      iframe: `https://${domain}/${videoId}/iframe`,
+    }
+  }
+
+  // ==================== 直播管理 ====================
+
+  /**
+   * 获取直播输入列表
+   */
+  async listLiveInputs(): Promise<CloudflareApiResponse<CloudflareLiveInput[]>> {
+    return this.request<CloudflareLiveInput[]>('/live_inputs')
+  }
+
+  /**
+   * 创建直播输入
+   */
+  async createLiveInput(params?: CreateLiveInputParams): Promise<CloudflareApiResponse<CloudflareLiveInput>> {
+    return this.request<CloudflareLiveInput>('/live_inputs', {
+      method: 'POST',
+      body: JSON.stringify(params || {}),
+    })
+  }
+
+  /**
+   * 获取直播输入详情
+   */
+  async getLiveInput(liveInputId: string): Promise<CloudflareApiResponse<CloudflareLiveInput>> {
+    return this.request<CloudflareLiveInput>(`/live_inputs/${liveInputId}`)
+  }
+
+  /**
+   * 更新直播输入
+   */
+  async updateLiveInput(liveInputId: string, params: CreateLiveInputParams): Promise<CloudflareApiResponse<CloudflareLiveInput>> {
+    return this.request<CloudflareLiveInput>(`/live_inputs/${liveInputId}`, {
+      method: 'PUT',
+      body: JSON.stringify(params),
+    })
+  }
+
+  /**
+   * 删除直播输入
+   */
+  async deleteLiveInput(liveInputId: string): Promise<CloudflareApiResponse<null>> {
+    return this.request<null>(`/live_inputs/${liveInputId}`, { method: 'DELETE' })
+  }
+
+  /**
+   * 获取直播录像列表
+   */
+  async listLiveRecordings(liveInputId: string): Promise<CloudflareApiResponse<CloudflareVideo[]>> {
+    return this.request<CloudflareVideo[]>(`/live_inputs/${liveInputId}/videos`)
+  }
+
+  /**
+   * 获取直播播放信息
+   */
+  getLivePlaybackInfo(liveInputId: string): VideoPlaybackInfo {
+    return this.getPlaybackInfo(liveInputId)
+  }
+}

+ 134 - 0
src/types/index.ts

@@ -0,0 +1,134 @@
+// Cloudflare Workers 环境变量类型
+export interface Env {
+  CF_ACCOUNT_ID: string
+  CF_API_TOKEN: string
+  CUSTOMER_SUBDOMAIN: string
+}
+
+// API 响应格式(RuoYi 兼容)
+export interface ApiResponse<T = unknown> {
+  code: number
+  msg: string
+  data: T
+}
+
+// 分页响应
+export interface PageResponse<T> {
+  rows: T[]
+  total: number
+}
+
+// Cloudflare Stream 视频
+export interface CloudflareVideo {
+  uid: string
+  creator?: string
+  thumbnail: string
+  readyToStream: boolean
+  status: {
+    state: 'pendingupload' | 'downloading' | 'queued' | 'inprogress' | 'ready' | 'error'
+    pctComplete?: string
+    errorReasonCode?: string
+    errorReasonText?: string
+  }
+  meta: Record<string, unknown>
+  created: string
+  modified: string
+  size: number
+  preview: string
+  allowedOrigins: string[]
+  requireSignedURLs: boolean
+  duration: number
+  input?: {
+    width: number
+    height: number
+  }
+  playback?: {
+    hls: string
+    dash: string
+  }
+}
+
+// Cloudflare 直播输入
+export interface CloudflareLiveInput {
+  uid: string
+  created: string
+  modified: string
+  meta: Record<string, unknown>
+  deleteRecordingAfterDays?: number
+  status?: {
+    current: {
+      state: 'connected' | 'disconnected'
+      statusEnteredAt?: string
+      statusLastChangedAt?: string
+    }
+  }
+  rtmps: {
+    url: string
+    streamKey: string
+  }
+  rtmpsPlayback?: {
+    url: string
+    streamKey: string
+  }
+  srt?: {
+    url: string
+    streamId: string
+    passphrase: string
+  }
+  srtPlayback?: {
+    url: string
+    streamId: string
+    passphrase: string
+  }
+  webRTC?: {
+    url: string
+  }
+  webRTCPlayback?: {
+    url: string
+  }
+  recording?: {
+    mode: 'off' | 'automatic'
+    requireSignedURLs?: boolean
+    allowedOrigins?: string[]
+    timeoutSeconds?: number
+  }
+}
+
+// 创建直播输入参数
+export interface CreateLiveInputParams {
+  meta?: Record<string, unknown>
+  recording?: {
+    mode: 'off' | 'automatic'
+    requireSignedURLs?: boolean
+    allowedOrigins?: string[]
+    timeoutSeconds?: number
+  }
+  deleteRecordingAfterDays?: number
+}
+
+// 播放信息
+export interface VideoPlaybackInfo {
+  uid: string
+  preview: string
+  thumbnail: string
+  playback: {
+    hls: string
+    dash: string
+  }
+  iframe: string
+}
+
+// Cloudflare API 响应
+export interface CloudflareApiResponse<T> {
+  success: boolean
+  errors: Array<{ code: number; message: string }>
+  messages: string[]
+  result: T
+  result_info?: {
+    page: number
+    per_page: number
+    total_pages: number
+    count: number
+    total_count: number
+  }
+}

+ 22 - 0
tsconfig.json

@@ -0,0 +1,22 @@
+{
+  "compilerOptions": {
+    "target": "ESNext",
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "strict": true,
+    "skipLibCheck": true,
+    "lib": ["ESNext"],
+    "types": ["@cloudflare/workers-types"],
+    "jsx": "react-jsx",
+    "jsxImportSource": "hono/jsx",
+    "rootDir": "./src",
+    "outDir": "./dist",
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true
+  },
+  "include": ["src/**/*"],
+  "exclude": ["node_modules", "dist"]
+}

+ 18 - 0
wrangler.toml

@@ -0,0 +1,18 @@
+# Cloudflare Workers 配置
+name = "tg-live-game-api"
+main = "src/index.ts"
+compatibility_date = "2024-12-01"
+
+# 开发环境变量(部署时使用 wrangler secret 设置)
+[vars]
+# CUSTOMER_SUBDOMAIN = "your_subdomain"
+
+# 敏感信息使用 secrets(通过 wrangler secret put 设置)
+# wrangler secret put CF_ACCOUNT_ID
+# wrangler secret put CF_API_TOKEN
+# wrangler secret put CUSTOMER_SUBDOMAIN
+
+# 本地开发配置
+[dev]
+port = 8787
+local_protocol = "http"