feat(api): 添加前端代理和静态资源处理逻辑

- 增加了对前端开发服务器的代理支持
- 实现了静态资源请求的处理
- 更新了类型定义以支持新环境变量
- 新增了 wrangler.jsonc 配置文件,替换原有的模板文件
This commit is contained in:
Jeff Gu committed 2026-04-09 09:39:40 +08:00
1 parent c36e3c1017
commit 6071f18f7a
14 files changed
+257 -3988

No files matched your search

+1 -2
View File
@@ -26,11 +26,10 @@ logs/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# misc
.DS_Store
wrangler.toml
public*/
bun.lock
*.local.jsonc
+11 -9
View File
@@ -7,14 +7,17 @@
- `src/db/`: D1 schema/init helpers.
- `public/`: built admin UI assets served by Workers.
- `frontend/`: React/Vite admin UI source (build outputs to `public/`).
- `wrangler.toml.template`: Workers config template (bindings, routes, D1, assets).
- `wrangler.jsonc`: production/deploy Wrangler config.
- `wrangler.local.jsonc`: local Worker-first development config.
- `type.d.ts`: shared types for bindings and data models.
## Build, Test, and Development Commands
- `pnpm -C frontend build`: Type-checks and builds the admin UI into `public/`.
- `pnpm dev`: Runs the Worker locally via `wrangler dev` (expects a local `wrangler.toml`).
- `pnpm run deploy`: Deploys the Worker to Cloudflare.
- `pnpm run cf-typegen`: Generates Cloudflare bindings/types.
- `bun run build`: Type-checks and builds the admin UI into `public/`.
- `bun run --filter frontend build`: Builds only the admin UI from the frontend workspace.
- `bun run dev`: Starts the Vite frontend and Worker locally for integrated development.
- `bun run dev:worker`: Runs only the Worker locally via `wrangler dev --config wrangler.local.jsonc`.
- `bun run deploy`: Deploys the Worker to Cloudflare.
- `bun run cf-typegen`: Generates Cloudflare bindings/types.
## Coding Style & Naming Conventions
- TypeScript throughout; follow existing patterns and file layout.
@@ -24,18 +27,17 @@
## Testing Guidelines
- No dedicated test framework is currently configured.
- Use `pnpm -C frontend build` as a basic safety check for UI changes.
- For backend changes, run `pnpm dev` and validate with the API Test page.
- Use `bun run build` as a basic safety check for UI changes.
- For backend changes, run `bun run dev` or `bun run dev:worker` and validate with the API Test page.
## Commit & Pull Request Guidelines
- No formal commit conventions are documented in-repo; use clear, imperative messages (e.g., "Add responses proxy").
- PRs should include:
- Summary of changes.
- Notes on config changes (`wrangler.toml`, env vars).
- Notes on config changes (`wrangler.jsonc`, `wrangler.local.jsonc`, env vars).
- Screenshots for UI changes (from `frontend/`).
## Security & Configuration Tips
- Admin endpoints require `x-admin-token` (`ADMIN_TOKEN` binding).
- Tokens and channel configs are stored in D1; validate permissions and quotas.
- For Azure Responses v1, leave `api_version` empty and set `endpoint` to the resource host.
- `wrangler.toml` is git-ignored; copy from `wrangler.toml.template` for local use.
+84 -28
View File
@@ -64,7 +64,8 @@ awsl-one-api/
├── public/ # 静态文件
│ └── index.html # Web 管理界面
├── type.d.ts # 类型定义
├── wrangler.toml # Cloudflare Workers 配置
├── wrangler.jsonc # 生产/部署配置
├── wrangler.local.jsonc # 本地开发配置
└── package.json # 项目配置
```
@@ -74,60 +75,115 @@ awsl-one-api/
### 环境要求
- Node.js 18+
- pnpm
- Bun 1.3+
- Cloudflare Workers 账户
### 安装依赖
```bash
pnpm install
bun install
```
仓库已配置为 Bun workspaces,根目录一次安装会同时安装 Worker 和 `frontend/` 的依赖。
### 配置环境
1. 复制 `wrangler.toml.template` 为 `wrangler.toml` 并修改配置:
1. 修改 `wrangler.jsonc`,用于生产部署:
```toml
name = "awsl-one-api"
main = "src/index.ts"
compatibility_date = "2025-04-28"
routes = [
{ pattern = "your-domain.com", custom_domain = true },
]
[vars]
ADMIN_TOKEN = "your-secure-admin-token-here"
[assets]
directory = "public"
binding = "ASSETS"
run_worker_first = true
[[d1_databases]]
binding = "DB"
database_name = "your-database-name"
database_id = "your-database-id"
```jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "awsl-one-api",
"main": "src/index.ts",
"compatibility_date": "2025-04-28",
"workers_dev": false,
"vars": {
"ADMIN_TOKEN": "your-secure-admin-token-here"
},
"assets": {
"directory": "./public",
"binding": "ASSETS",
"run_worker_first": true
},
"d1_databases": [
{
"binding": "DB",
"database_name": "your-database-name",
"database_id": "your-database-id"
}
]
}
```
1. 创建 Cloudflare D1 数据库:
2. 修改 `wrangler.local.jsonc`,用于本地开发:
```jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "awsl-one-api",
"main": "src/index.ts",
"compatibility_date": "2025-04-28",
"workers_dev": false,
"vars": {
"ADMIN_TOKEN": "your-local-admin-token",
"FRONTEND_DEV_SERVER_URL": "http://127.0.0.1:5173"
}
}
```
3. 创建 Cloudflare D1 数据库:
```bash
wrangler d1 create awsl-one-api
```
4. 在 Cloudflare Dashboard 中手动绑定生产域名:
1. 进入 `Workers & Pages`
2. 选择当前 Worker
3. 打开 `Settings > Domains & Routes`
4. 选择 `Add > Custom Domain`
5. 添加你的生产域名
如果你选择在 Dashboard 管理生产域名,就不要再把 `routes` / `custom_domain` 写回 `wrangler.jsonc`,否则下次 `wrangler deploy` 会用配置文件覆盖 Dashboard 中的路由设置。
### 本地开发
```bash
pnpm dev
bun run dev
```
执行后会同时启动:
- 前端 Vite 开发服务器:`http://127.0.0.1:5173`(作为 Worker 的上游)
- Cloudflare Worker 本地服务:`http://127.0.0.1:8788`(浏览器访问入口)
Worker 会代理非 `/api/*`、`/v1/*` 的请求到本地 Vite dev server,因此本地联调时应访问 `http://127.0.0.1:8788`,而不是直接打开 `5173`。
这里不需要再给前端配置 Vite `server.proxy`,但仍然需要同时启动 Vite dev server,因为 HMR 和未构建源码都是由它提供,Worker 只是统一入口。
`bun run dev:worker` 会显式使用 `wrangler.local.jsonc`,并固定 `--host localhost`,避免本地开发被生产配置干扰。
如果只想单独调试后端,可运行:
```bash
bun run dev:worker
```
如果只想单独启动前端,可运行:
```bash
bun run dev:web
```
此模式只启动 Vite dev server,适合做纯前端样式开发;如果需要直接从 `5173` 调 API,请自行设置 `VITE_API_BASE_URL=http://127.0.0.1:8788`。
### 部署到生产环境
```bash
pnpm run deploy
bun run deploy
```
部署前会自动构建前端资源到 `public/`。
<details>
<summary><h2>📖 使用与配置</h2></summary>
-1
View File
@@ -1 +0,0 @@
VITE_API_BASE_URL=http://localhost:8787
+23 -12
View File
@@ -17,17 +17,23 @@ Modern React + Vite + TypeScript frontend for AWSL One API management platform.
## Development
```bash
# Install dependencies
pnpm install
# From the repo root, install both backend and frontend dependencies
bun install
# Start development server
pnpm dev
# Start frontend + worker together from the repo root
bun run dev
# Open the app through the Worker entry
# http://127.0.0.1:8788
# Or start only the frontend from ./frontend
cd frontend
# Start only the frontend development server
bun run dev
# Build for production
pnpm build
# Preview production build
pnpm preview
bun run build
```
## Project Structure
@@ -49,7 +55,13 @@ src/
## Environment Variables
No environment variables required. The frontend communicates with the backend API at the same domain.
Root `bun run dev` uses Worker-first local development.
The browser should access the Worker URL, while the Worker proxies frontend requests to the Vite dev server via repo-root `wrangler.local.jsonc`.
No Vite `server.proxy` is required in this mode.
You still need the Vite dev server running, because the Worker proxies page/module/HMR requests to it instead of serving built assets.
If you open `http://127.0.0.1:5173` directly, set `VITE_API_BASE_URL=http://127.0.0.1:8788` yourself.
## Features
@@ -58,12 +70,11 @@ No environment variables required. The frontend communicates with the backend AP
- **Channels**: Manage OpenAI, Azure OpenAI, and Claude channels
- **Tokens**: Create and manage API tokens with quota limits
- **Pricing**: Configure model pricing multipliers
- **Database**: Initialize database tables
## Building
```bash
pnpm build
bun run build
```
The built files will be in the `dist` directory.
The built files will be emitted to `../public`.
+1 -2
View File
@@ -6,8 +6,7 @@
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint .",
"preview": "vite preview"
"lint": "eslint ."
},
"devDependencies": {
"@eslint/js": "^9.39.2",
-2970
View File
File diff suppressed because it is too large. Load diff
+5 -1
View File
@@ -2,7 +2,6 @@ import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
@@ -10,6 +9,11 @@ export default defineConfig({
"@": path.resolve(__dirname, "./src"),
},
},
server: {
host: '0.0.0.0',
port: 5173,
strictPort: true,
},
build: {
outDir: '../public',
emptyOutDir: true,
+11 -4
View File
@@ -1,9 +1,15 @@
{
"name": "awsl-ai-proxy",
"workspaces": [
"frontend"
],
"scripts": {
"dev": "npx wrangler dev",
"deploy": "npx wrangler deploy --minify",
"cf-typegen": "npx wrangler types --include-env=false"
"dev": "concurrently --kill-others-on-fail -n web,worker -c cyan,green \"bun run dev:web\" \"bun run dev:worker\"",
"dev:web": "bun run --filter frontend dev",
"dev:worker": "wrangler dev --config wrangler.local.jsonc --local --host localhost",
"build": "bun run --filter frontend build",
"deploy": "bun run build && wrangler deploy --config wrangler.jsonc --minify",
"cf-typegen": "wrangler types --config wrangler.jsonc --include-env=false"
},
"dependencies": {
"chanfana": "^2.8.3",
@@ -11,8 +17,9 @@
"zod": "^3.25.76"
},
"devDependencies": {
"concurrently": "^9.2.1",
"typescript": "^5.9.3",
"wrangler": "^4.61.1"
},
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
"packageManager": "bun@1.3.11"
}
-939
View File
@@ -1,939 +0,0 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
chanfana:
specifier: ^2.8.3
version: 2.8.3
hono:
specifier: ^4.12.8
version: 4.12.8
zod:
specifier: ^3.25.76
version: 3.25.76
devDependencies:
typescript:
specifier: ^5.9.3
version: 5.9.3
wrangler:
specifier: ^4.61.1
version: 4.61.1
packages:
'@asteasolutions/zod-to-openapi@7.3.4':
resolution: {integrity: sha512-/2rThQ5zPi9OzVwes6U7lK1+Yvug0iXu25olp7S0XsYmOqnyMfxH7gdSQjn/+DSOHRg7wnotwGJSyL+fBKdnEA==}
peerDependencies:
zod: ^3.20.2
'@cloudflare/kv-asset-handler@0.4.2':
resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==}
engines: {node: '>=18.0.0'}
'@cloudflare/unenv-preset@2.12.0':
resolution: {integrity: sha512-NK4vN+2Z/GbfGS4BamtbbVk1rcu5RmqaYGiyHJQrA09AoxdZPHDF3W/EhgI0YSK8p3vRo/VNCtbSJFPON7FWMQ==}
peerDependencies:
unenv: 2.0.0-rc.24
workerd: ^1.20260115.0
peerDependenciesMeta:
workerd:
optional: true
'@cloudflare/workerd-darwin-64@1.20260128.0':
resolution: {integrity: sha512-XJN8zWWNG3JwAUqqwMLNKJ9fZfdlQkx/zTTHW/BB8wHat9LjKD6AzxqCu432YmfjR+NxEKCzUOxMu1YOxlVxmg==}
engines: {node: '>=16'}
cpu: [x64]
os: [darwin]
'@cloudflare/workerd-darwin-arm64@1.20260128.0':
resolution: {integrity: sha512-vKnRcmnm402GQ5DOdfT5H34qeR2m07nhnTtky8mTkNWP+7xmkz32AMdclwMmfO/iX9ncyKwSqmml2wPG32eq/w==}
engines: {node: '>=16'}
cpu: [arm64]
os: [darwin]
'@cloudflare/workerd-linux-64@1.20260128.0':
resolution: {integrity: sha512-RiaR+Qugof/c6oI5SagD2J5wJmIfI8wQWaV2Y9905Raj6sAYOFaEKfzkKnoLLLNYb4NlXicBrffJi1j7R/ypUA==}
engines: {node: '>=16'}
cpu: [x64]
os: [linux]
'@cloudflare/workerd-linux-arm64@1.20260128.0':
resolution: {integrity: sha512-U39U9vcXLXYDbrJ112Q7D0LDUUnM54oXfAxPgrL2goBwio7Z6RnsM25TRvm+Q06F4+FeDOC4D51JXlFHb9t1OA==}
engines: {node: '>=16'}
cpu: [arm64]
os: [linux]
'@cloudflare/workerd-windows-64@1.20260128.0':
resolution: {integrity: sha512-fdJwSqRkJsAJFJ7+jy0th2uMO6fwaDA8Ny6+iFCssfzlNkc4dP/twXo+3F66FMLMe/6NIqjzVts0cpiv7ERYbQ==}
engines: {node: '>=16'}
cpu: [x64]
os: [win32]
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
'@emnapi/runtime@1.8.1':
resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==}
'@esbuild/aix-ppc64@0.27.0':
resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.27.0':
resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.27.0':
resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.27.0':
resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.27.0':
resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.27.0':
resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.27.0':
resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.27.0':
resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.27.0':
resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.27.0':
resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.27.0':
resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.27.0':
resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.27.0':
resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.27.0':
resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.27.0':
resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.27.0':
resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.27.0':
resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.27.0':
resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.27.0':
resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.27.0':
resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.27.0':
resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/openharmony-arm64@0.27.0':
resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/sunos-x64@0.27.0':
resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.27.0':
resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.27.0':
resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.27.0':
resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@img/colour@1.0.0':
resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==}
engines: {node: '>=18'}
'@img/sharp-darwin-arm64@0.34.5':
resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [darwin]
'@img/sharp-darwin-x64@0.34.5':
resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [darwin]
'@img/sharp-libvips-darwin-arm64@1.2.4':
resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
cpu: [arm64]
os: [darwin]
'@img/sharp-libvips-darwin-x64@1.2.4':
resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
cpu: [x64]
os: [darwin]
'@img/sharp-libvips-linux-arm64@1.2.4':
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
cpu: [arm64]
os: [linux]
'@img/sharp-libvips-linux-arm@1.2.4':
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
cpu: [arm]
os: [linux]
'@img/sharp-libvips-linux-ppc64@1.2.4':
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
cpu: [ppc64]
os: [linux]
'@img/sharp-libvips-linux-riscv64@1.2.4':
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
cpu: [riscv64]
os: [linux]
'@img/sharp-libvips-linux-s390x@1.2.4':
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
cpu: [s390x]
os: [linux]
'@img/sharp-libvips-linux-x64@1.2.4':
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
cpu: [x64]
os: [linux]
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
cpu: [arm64]
os: [linux]
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
cpu: [x64]
os: [linux]
'@img/sharp-linux-arm64@0.34.5':
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
'@img/sharp-linux-arm@0.34.5':
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
'@img/sharp-linux-ppc64@0.34.5':
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ppc64]
os: [linux]
'@img/sharp-linux-riscv64@0.34.5':
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [riscv64]
os: [linux]
'@img/sharp-linux-s390x@0.34.5':
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
'@img/sharp-linux-x64@0.34.5':
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
'@img/sharp-linuxmusl-arm64@0.34.5':
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
'@img/sharp-linuxmusl-x64@0.34.5':
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
'@img/sharp-wasm32@0.34.5':
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [wasm32]
'@img/sharp-win32-arm64@0.34.5':
resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [win32]
'@img/sharp-win32-ia32@0.34.5':
resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ia32]
os: [win32]
'@img/sharp-win32-x64@0.34.5':
resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [win32]
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
'@jridgewell/trace-mapping@0.3.9':
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
'@poppinss/colors@4.1.6':
resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==}
'@poppinss/dumper@0.6.5':
resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==}
'@poppinss/exception@1.2.3':
resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==}
'@sindresorhus/is@7.2.0':
resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==}
engines: {node: '>=18'}
'@speed-highlight/core@1.2.14':
resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
blake3-wasm@2.1.5:
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
chanfana@2.8.3:
resolution: {integrity: sha512-OBefbT8n+CeRYkC6lUoRgySTFbth+3LetxiNrCe0t+WgpQhhoIxPlo+lDYvNrLJgtsQr7XuPazm8yyxR8zwB7g==}
hasBin: true
cookie@1.1.1:
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
engines: {node: '>=18'}
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
error-stack-parser-es@1.0.5:
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
esbuild@0.27.0:
resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==}
engines: {node: '>=18'}
hasBin: true
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
hono@4.12.8:
resolution: {integrity: sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==}
engines: {node: '>=16.9.0'}
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
kleur@4.1.5:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
miniflare@4.20260128.0:
resolution: {integrity: sha512-AVCn3vDRY+YXu1sP4mRn81ssno6VUqxo29uY2QVfgxXU2TMLvhRIoGwm7RglJ3Gzfuidit5R86CMQ6AvdFTGAw==}
engines: {node: '>=18.0.0'}
hasBin: true
openapi3-ts@4.5.0:
resolution: {integrity: sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ==}
path-to-regexp@6.3.0:
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
semver@7.7.3:
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
engines: {node: '>=10'}
hasBin: true
sharp@0.34.5:
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
supports-color@10.2.2:
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
engines: {node: '>=18'}
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
hasBin: true
undici@7.18.2:
resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==}
engines: {node: '>=20.18.1'}
unenv@2.0.0-rc.24:
resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
workerd@1.20260128.0:
resolution: {integrity: sha512-EhLJGptSGFi8AEErLiamO3PoGpbRqL+v4Ve36H2B38VxmDgFOSmDhfepBnA14sCQzGf1AEaoZX2DCwZsmO74yQ==}
engines: {node: '>=16'}
hasBin: true
wrangler@4.61.1:
resolution: {integrity: sha512-hfYQ16VLPkNi8xE1/V3052S2stM5e+vq3Idpt83sXoDC3R7R1CLgMkK6M6+Qp3G+9GVDNyHCkvohMPdfFTaD4Q==}
engines: {node: '>=20.0.0'}
hasBin: true
peerDependencies:
'@cloudflare/workers-types': ^4.20260128.0
peerDependenciesMeta:
'@cloudflare/workers-types':
optional: true
ws@8.18.0:
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
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
yaml@2.8.2:
resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
engines: {node: '>= 14.6'}
hasBin: true
yargs-parser@22.0.0:
resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==}
engines: {node: ^20.19.0 || ^22.12.0 || >=23}
youch-core@0.3.3:
resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==}
youch@4.1.0-beta.10:
resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==}
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
snapshots:
'@asteasolutions/zod-to-openapi@7.3.4(zod@3.25.76)':
dependencies:
openapi3-ts: 4.5.0
zod: 3.25.76
'@cloudflare/kv-asset-handler@0.4.2': {}
'@cloudflare/unenv-preset@2.12.0(unenv@2.0.0-rc.24)(workerd@1.20260128.0)':
dependencies:
unenv: 2.0.0-rc.24
optionalDependencies:
workerd: 1.20260128.0
'@cloudflare/workerd-darwin-64@1.20260128.0':
optional: true
'@cloudflare/workerd-darwin-arm64@1.20260128.0':
optional: true
'@cloudflare/workerd-linux-64@1.20260128.0':
optional: true
'@cloudflare/workerd-linux-arm64@1.20260128.0':
optional: true
'@cloudflare/workerd-windows-64@1.20260128.0':
optional: true
'@cspotcode/source-map-support@0.8.1':
dependencies:
'@jridgewell/trace-mapping': 0.3.9
'@emnapi/runtime@1.8.1':
dependencies:
tslib: 2.8.1
optional: true
'@esbuild/aix-ppc64@0.27.0':
optional: true
'@esbuild/android-arm64@0.27.0':
optional: true
'@esbuild/android-arm@0.27.0':
optional: true
'@esbuild/android-x64@0.27.0':
optional: true
'@esbuild/darwin-arm64@0.27.0':
optional: true
'@esbuild/darwin-x64@0.27.0':
optional: true
'@esbuild/freebsd-arm64@0.27.0':
optional: true
'@esbuild/freebsd-x64@0.27.0':
optional: true
'@esbuild/linux-arm64@0.27.0':
optional: true
'@esbuild/linux-arm@0.27.0':
optional: true
'@esbuild/linux-ia32@0.27.0':
optional: true
'@esbuild/linux-loong64@0.27.0':
optional: true
'@esbuild/linux-mips64el@0.27.0':
optional: true
'@esbuild/linux-ppc64@0.27.0':
optional: true
'@esbuild/linux-riscv64@0.27.0':
optional: true
'@esbuild/linux-s390x@0.27.0':
optional: true
'@esbuild/linux-x64@0.27.0':
optional: true
'@esbuild/netbsd-arm64@0.27.0':
optional: true
'@esbuild/netbsd-x64@0.27.0':
optional: true
'@esbuild/openbsd-arm64@0.27.0':
optional: true
'@esbuild/openbsd-x64@0.27.0':
optional: true
'@esbuild/openharmony-arm64@0.27.0':
optional: true
'@esbuild/sunos-x64@0.27.0':
optional: true
'@esbuild/win32-arm64@0.27.0':
optional: true
'@esbuild/win32-ia32@0.27.0':
optional: true
'@esbuild/win32-x64@0.27.0':
optional: true
'@img/colour@1.0.0': {}
'@img/sharp-darwin-arm64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.2.4
optional: true
'@img/sharp-darwin-x64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-darwin-x64': 1.2.4
optional: true
'@img/sharp-libvips-darwin-arm64@1.2.4':
optional: true
'@img/sharp-libvips-darwin-x64@1.2.4':
optional: true
'@img/sharp-libvips-linux-arm64@1.2.4':
optional: true
'@img/sharp-libvips-linux-arm@1.2.4':
optional: true
'@img/sharp-libvips-linux-ppc64@1.2.4':
optional: true
'@img/sharp-libvips-linux-riscv64@1.2.4':
optional: true
'@img/sharp-libvips-linux-s390x@1.2.4':
optional: true
'@img/sharp-libvips-linux-x64@1.2.4':
optional: true
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
optional: true
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
optional: true
'@img/sharp-linux-arm64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.2.4
optional: true
'@img/sharp-linux-arm@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.2.4
optional: true
'@img/sharp-linux-ppc64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-ppc64': 1.2.4
optional: true
'@img/sharp-linux-riscv64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-riscv64': 1.2.4
optional: true
'@img/sharp-linux-s390x@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.2.4
optional: true
'@img/sharp-linux-x64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.2.4
optional: true
'@img/sharp-linuxmusl-arm64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4
optional: true
'@img/sharp-linuxmusl-x64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.2.4
optional: true
'@img/sharp-wasm32@0.34.5':
dependencies:
'@emnapi/runtime': 1.8.1
optional: true
'@img/sharp-win32-arm64@0.34.5':
optional: true
'@img/sharp-win32-ia32@0.34.5':
optional: true
'@img/sharp-win32-x64@0.34.5':
optional: true
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/sourcemap-codec@1.5.5': {}
'@jridgewell/trace-mapping@0.3.9':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
'@poppinss/colors@4.1.6':
dependencies:
kleur: 4.1.5
'@poppinss/dumper@0.6.5':
dependencies:
'@poppinss/colors': 4.1.6
'@sindresorhus/is': 7.2.0
supports-color: 10.2.2
'@poppinss/exception@1.2.3': {}
'@sindresorhus/is@7.2.0': {}
'@speed-highlight/core@1.2.14': {}
argparse@2.0.1: {}
blake3-wasm@2.1.5: {}
chanfana@2.8.3:
dependencies:
'@asteasolutions/zod-to-openapi': 7.3.4(zod@3.25.76)
js-yaml: 4.1.1
openapi3-ts: 4.5.0
yargs-parser: 22.0.0
zod: 3.25.76
cookie@1.1.1: {}
detect-libc@2.1.2: {}
error-stack-parser-es@1.0.5: {}
esbuild@0.27.0:
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
fsevents@2.3.3:
optional: true
hono@4.12.8: {}
js-yaml@4.1.1:
dependencies:
argparse: 2.0.1
kleur@4.1.5: {}
miniflare@4.20260128.0:
dependencies:
'@cspotcode/source-map-support': 0.8.1
sharp: 0.34.5
undici: 7.18.2
workerd: 1.20260128.0
ws: 8.18.0
youch: 4.1.0-beta.10
transitivePeerDependencies:
- bufferutil
- utf-8-validate
openapi3-ts@4.5.0:
dependencies:
yaml: 2.8.2
path-to-regexp@6.3.0: {}
pathe@2.0.3: {}
semver@7.7.3: {}
sharp@0.34.5:
dependencies:
'@img/colour': 1.0.0
detect-libc: 2.1.2
semver: 7.7.3
optionalDependencies:
'@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
supports-color@10.2.2: {}
tslib@2.8.1:
optional: true
typescript@5.9.3: {}
undici@7.18.2: {}
unenv@2.0.0-rc.24:
dependencies:
pathe: 2.0.3
workerd@1.20260128.0:
optionalDependencies:
'@cloudflare/workerd-darwin-64': 1.20260128.0
'@cloudflare/workerd-darwin-arm64': 1.20260128.0
'@cloudflare/workerd-linux-64': 1.20260128.0
'@cloudflare/workerd-linux-arm64': 1.20260128.0
'@cloudflare/workerd-windows-64': 1.20260128.0
wrangler@4.61.1:
dependencies:
'@cloudflare/kv-asset-handler': 0.4.2
'@cloudflare/unenv-preset': 2.12.0(unenv@2.0.0-rc.24)(workerd@1.20260128.0)
blake3-wasm: 2.1.5
esbuild: 0.27.0
miniflare: 4.20260128.0
path-to-regexp: 6.3.0
unenv: 2.0.0-rc.24
workerd: 1.20260128.0
optionalDependencies:
fsevents: 2.3.3
transitivePeerDependencies:
- bufferutil
- utf-8-validate
ws@8.18.0: {}
yaml@2.8.2: {}
yargs-parser@22.0.0: {}
youch-core@0.3.3:
dependencies:
'@poppinss/exception': 1.2.3
error-stack-parser-es: 1.0.5
youch@4.1.0-beta.10:
dependencies:
'@poppinss/colors': 4.1.6
'@poppinss/dumper': 0.6.5
'@speed-highlight/core': 1.2.14
cookie: 1.1.1
youch-core: 0.3.3
zod@3.25.76: {}
+97
View File
@@ -1,9 +1,82 @@
import type { Context } from 'hono'
import { Hono } from 'hono'
import { cors } from 'hono/cors';
import { api as providerApi } from './providers'
import { api as adminApi } from './admin'
import { fromHono } from 'chanfana';
const FRONTEND_ENTRY = '/'
const FRONTEND_STATIC_PATHS = new Set([
'/__vite_ping',
'/favicon.ico',
'/favicon.svg',
'/index.html',
])
const FRONTEND_STATIC_PREFIXES = [
'/@fs/',
'/@id/',
'/@react-refresh',
'/@vite/',
'/assets/',
'/node_modules/',
'/src/',
]
const LOCAL_DEV_HOSTNAMES = new Set(['0.0.0.0', '127.0.0.1', '::1', 'localhost'])
type AppContext = Context<HonoCustomType>
function isApiRequest(pathname: string): boolean {
return pathname === '/api'
|| pathname === '/v1'
|| pathname.startsWith('/api/')
|| pathname.startsWith('/v1/')
}
function isFrontendAssetRequest(pathname: string): boolean {
if (FRONTEND_STATIC_PATHS.has(pathname)) {
return true
}
if (FRONTEND_STATIC_PREFIXES.some((prefix) => pathname.startsWith(prefix))) {
return true
}
return /\.[a-z0-9]+$/i.test(pathname)
}
function isWebSocketUpgradeRequest(request: Request): boolean {
return request.headers.get('upgrade')?.toLowerCase() === 'websocket'
}
function shouldProxyToFrontendDevServer(c: AppContext): boolean {
const frontendDevServerUrl = c.env.FRONTEND_DEV_SERVER_URL
if (!frontendDevServerUrl) {
return false
}
const host = c.req.header('host') ?? new URL(c.req.url).host
const hostname = host.replace(/:\d+$/, '')
return LOCAL_DEV_HOSTNAMES.has(hostname)
}
async function fetchFrontendResponse(
c: AppContext,
pathname: string,
search = '',
): Promise<Response> {
if (shouldProxyToFrontendDevServer(c)) {
const targetUrl = new URL(`${pathname}${search}`, c.env.FRONTEND_DEV_SERVER_URL)
try {
return await fetch(new Request(targetUrl.toString(), c.req.raw))
} catch (error) {
console.warn(`Failed to proxy frontend request to ${targetUrl.toString()}, falling back to static assets.`, error)
}
}
const assetUrl = new URL(`${pathname}${search}`, c.req.url)
return c.env.ASSETS.fetch(new Request(assetUrl, c.req.raw))
}
const app = new Hono<HonoCustomType>()
const openapi = fromHono(app, {
schema: {
@@ -19,6 +92,30 @@ const openapi = fromHono(app, {
// cors
openapi.use('/*', cors());
app.use('*', async (c, next) => {
const requestUrl = new URL(c.req.url)
if (isApiRequest(requestUrl.pathname)) {
await next()
return
}
if (isWebSocketUpgradeRequest(c.req.raw) && shouldProxyToFrontendDevServer(c)) {
return fetchFrontendResponse(c, requestUrl.pathname, requestUrl.search)
}
if (isFrontendAssetRequest(requestUrl.pathname)) {
return fetchFrontendResponse(c, requestUrl.pathname, requestUrl.search)
}
if (c.req.method === 'GET' || c.req.method === 'HEAD') {
return fetchFrontendResponse(c, FRONTEND_ENTRY)
}
await next()
})
// global error handler
openapi.onError((err, c) => {
console.error(err)
Vendored
+1
View File
@@ -6,6 +6,7 @@ type CloudflareBindings = {
DB: D1Database;
ASSETS: Fetcher;
ADMIN_TOKEN: string;
FRONTEND_DEV_SERVER_URL?: string;
}
type HonoCustomType = {
+23
View File
@@ -0,0 +1,23 @@
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "one-api-workers",
"main": "src/index.ts",
"compatibility_date": "2025-04-28",
"workers_dev": false,
"vars": {
"ADMIN_TOKEN": "CHANGE_ME",
},
"assets": {
"directory": "./public",
"not_found_handling": "single-page-application",
"binding": "ASSETS",
"run_worker_first": true
},
"d1_databases": [
{
"binding": "DB",
"database_name": "one-api",
"database_id": "00000000-0000-0000-0000-000000000000"
}
]
}
-20
View File
@@ -1,20 +0,0 @@
name = "awsl-one-api"
main = "src/index.ts"
compatibility_date = "2025-04-28"
routes = [
{ pattern = "your-domain.com-here", custom_domain = true },
]
[vars]
ADMIN_TOKEN = "your-secure-admin-token-here"
[assets]
directory = "./public"
not_found_handling = "single-page-application"
binding = "ASSETS"
run_worker_first = ["/api/*", "/v1/*"]
[[d1_databases]]
binding = "DB"
database_name = "your-database-name-here"
database_id = "your-database-id-here"