feat: WmailHub v1.0.0 —— Cloudflare Email Workers 邮件接收与转发平台(本地可用版本)
- Console:React 19 + antd 6.6.5 前端(登录 admin/admin)+ Hono 管理 API (Nodes/Domains/Mailboxes/Emails/Webhooks/Keys/OAuth/Admin) - Node:Bun 转发节点(HMAC 签名、有限重试、心跳、结构化日志、优雅退出) - Email Worker:Cloudflare email handler + 本地联调入口 - shared:HMAC 协议(docs/04)、wmh_ Key(32 位)、AES-GCM 加密、SSRF 防护 - 邮件管线:postal-mime 解析、附件、catch-all、限额、malformed 降级、TTL 1 天 - Webhook:签名投递、指数退避重试、SSRF 校验、投递日志 - API v1 + MCP(JSON-RPC,六工具,凭据 kind 隔离) - Cloudflare OAuth:真实 + 本地 sim 模式,自动安装管线(幂等,无需手工命令) - 测试:bun test 41 例(协议安全/管线/TTL/Webhook/SSRF/MCP/OAuth/鉴权)+ Playwright UI 冒烟 - LOGO/favicon 由 codex CLI 生成
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Console 应用装配(Hono,Workers/Bun 双运行时)。
|
||||
*
|
||||
* 路由分区:
|
||||
* /api/health 健康检查
|
||||
* /api/auth/* 用户登录/登出/会话(cookie)
|
||||
* /api/nodes|domains|mailboxes|emails 管理资源 CRUD(会话保护)
|
||||
* /api/webhooks/* Webhook 管理(会话保护)
|
||||
* /api/keys/* API/MCP Key 管理(会话保护)
|
||||
* /api/oauth/* Cloudflare OAuth(会话保护)
|
||||
* /api/admin/* 版本/统计/Cron(会话保护)
|
||||
* /api/internal/* Node 内部协议(HMAC 签名)
|
||||
* /api/v1/mcp MCP JSON-RPC(Bearer MCP Key wmh_)
|
||||
* /api/v1/* 外部 API(Bearer API Key wmh_)
|
||||
* /* 前端 SPA 静态资源
|
||||
*/
|
||||
|
||||
import { Hono } from "hono";
|
||||
import type { Env, AppVars } from "./env.ts";
|
||||
import { ensureSeeded } from "./db.ts";
|
||||
import { csrfOriginCheck } from "./middleware.ts";
|
||||
import { authRoutes } from "./auth.ts";
|
||||
import { internalRoutes } from "./routes/internal.ts";
|
||||
import { resourceRoutes } from "./routes/resources.ts";
|
||||
import { webhookRoutes } from "./routes/webhooks.ts";
|
||||
import { keyRoutes } from "./routes/keys.ts";
|
||||
import { oauthRoutes } from "./routes/oauth.ts";
|
||||
import { apiV1Routes } from "./routes/apiv1.ts";
|
||||
import { mcpRoutes } from "./routes/mcp.ts";
|
||||
import { adminRoutes } from "./routes/admin.ts";
|
||||
import { APP_NAME, APP_VERSION } from "./version.ts";
|
||||
|
||||
/** # 函数
|
||||
* 构造 Console Hono 应用实例
|
||||
* 参数: opts.serveStatic - 静态资源处理器(本地运行时注入;Workers 端走 ASSETS 绑定)
|
||||
*/
|
||||
export function createApp(
|
||||
opts: {
|
||||
serveStatic?: (request: Request) => Promise<Response>;
|
||||
} = {},
|
||||
): Hono<{ Bindings: Env; Variables: AppVars }> {
|
||||
const app = new Hono<{ Bindings: Env; Variables: AppVars }>();
|
||||
|
||||
// 每个请求先保证种子数据(幂等,内存标志去重)
|
||||
app.use("*", async (c, next) => {
|
||||
await ensureSeeded(c.env);
|
||||
await next();
|
||||
});
|
||||
|
||||
app.use("/api/*", csrfOriginCheck);
|
||||
|
||||
app.get("/api/health", (c) => c.json({ ok: true, name: APP_NAME, version: APP_VERSION }));
|
||||
|
||||
app.route("/api/auth", authRoutes());
|
||||
app.route("/api/internal", internalRoutes());
|
||||
app.route("/api/oauth", oauthRoutes());
|
||||
app.route("/api/webhooks", webhookRoutes());
|
||||
app.route("/api/keys", keyRoutes());
|
||||
app.route("/api/admin", adminRoutes());
|
||||
app.route("/api/v1/mcp", mcpRoutes());
|
||||
app.route("/api/v1", apiV1Routes());
|
||||
app.route("/api", resourceRoutes());
|
||||
|
||||
// 静态资源 / SPA fallback
|
||||
app.get("/*", async (c) => {
|
||||
const path = new URL(c.req.url).pathname;
|
||||
if (path.startsWith("/api/")) return c.json({ error: "not found" }, 404);
|
||||
if (opts.serveStatic) return opts.serveStatic(c.req.raw);
|
||||
if (c.env.ASSETS) return c.env.ASSETS.fetch(c.req.raw);
|
||||
return c.text("frontend assets not configured", 404);
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
Reference in New Issue
Block a user