v2.9.2: 开放 API 域名可见性修复——GET /api/v1/domains 与 MCP list_domains 只返回可用域名(active+已绑 zone),指定 domain_id 建邮箱同样校验可用,杜绝未接入域名被报成可用
This commit is contained in:
@@ -22,9 +22,9 @@ const MCP_TOOLS = [
|
||||
/** # 成员变量: REST API 端点清单(与 routes/apiv1.ts 一致) **/
|
||||
const API_ENDPOINTS = [
|
||||
{ method: "GET", path: "/accounts", desc: "账号列表(不含已撤销)" },
|
||||
{ method: "GET", path: "/domains", desc: "域名列表" },
|
||||
{ method: "GET", path: "/domains", desc: "可用域名列表(仅 status=active 且已绑定 zone,即 Email Workers 就绪)" },
|
||||
{ method: "GET", path: "/mailboxes", desc: "邮箱列表" },
|
||||
{ method: "POST", path: "/mailboxes", desc: "创建邮箱,body: { address, domain_id?, retention_seconds?, webhook? };省略 domain_id 随机分配;409 已存在/无可用域名" },
|
||||
{ method: "POST", path: "/mailboxes", desc: "创建邮箱,body: { address, domain_id?, retention_seconds?, webhook? };省略 domain_id 随机分配;指定域名须可用(400 domain not available);409 已存在/无可用域名" },
|
||||
{ method: "DELETE", path: "/mailboxes/:id", desc: "删除邮箱" },
|
||||
{ method: "GET", path: "/emails", desc: "未过期邮件列表,query: mailbox_id? / limit / offset" },
|
||||
{ method: "GET", path: "/emails/:id", desc: "邮件详情 + 附件元数据;410 已过期" },
|
||||
|
||||
@@ -29,10 +29,11 @@ export function apiV1Routes(): App {
|
||||
return c.json({ items: rows.results });
|
||||
});
|
||||
|
||||
/** 域名列表 */
|
||||
/** 域名列表(只返回可用域名:status='active' 且已绑定 zone,即 Email Workers 就绪;与随机分配建邮箱同一判据) */
|
||||
app.get("/domains", async (c) => {
|
||||
const rows = await c.env.DB.prepare(
|
||||
"SELECT id, name, status, account_id, created_at FROM domains ORDER BY created_at DESC",
|
||||
`SELECT id, name, status, account_id, created_at FROM domains
|
||||
WHERE status = 'active' AND zone_id IS NOT NULL ORDER BY created_at DESC`,
|
||||
).all();
|
||||
return c.json({ items: rows.results });
|
||||
});
|
||||
@@ -50,12 +51,16 @@ export function apiV1Routes(): App {
|
||||
app.post("/mailboxes", async (c) => {
|
||||
const body = await readJson<{ domain_id?: string; address?: string; retention_seconds?: number; webhook?: string }>(c.req.raw);
|
||||
if (!body.address) return c.json({ error: "address required" }, 400);
|
||||
let domain: { id: string; name: string } | null;
|
||||
let domain: { id: string; name: string; status?: string; zone_id?: string | null } | null;
|
||||
if (body.domain_id) {
|
||||
domain = await c.env.DB.prepare("SELECT id, name FROM domains WHERE id = ?")
|
||||
domain = await c.env.DB.prepare("SELECT id, name, status, zone_id FROM domains WHERE id = ?")
|
||||
.bind(body.domain_id)
|
||||
.first<{ id: string; name: string }>();
|
||||
.first<{ id: string; name: string; status: string; zone_id: string | null }>();
|
||||
if (!domain) return c.json({ error: "domain not found" }, 404);
|
||||
// 指定域名同样必须可用(未装 Email Workers 的 pending 域名收不到件,不可用于建邮箱)
|
||||
if (domain.status !== "active" || !domain.zone_id) {
|
||||
return c.json({ error: "domain not available (Email Workers not enabled)" }, 400);
|
||||
}
|
||||
} else {
|
||||
domain = await c.env.DB.prepare(
|
||||
"SELECT id, name FROM domains WHERE status = 'active' AND zone_id IS NOT NULL ORDER BY RANDOM() LIMIT 1",
|
||||
|
||||
@@ -173,8 +173,10 @@ async function callTool(
|
||||
async function dispatchTool(env: Env, name: string, args: Record<string, unknown>): Promise<unknown> {
|
||||
switch (name) {
|
||||
case "list_domains": {
|
||||
// 只返回可用域名(active + 已绑定 zone,Email Workers 就绪),与随机分配建邮箱同一判据
|
||||
const rows = await env.DB.prepare(
|
||||
"SELECT id, name, status, account_id, created_at FROM domains ORDER BY created_at DESC",
|
||||
`SELECT id, name, status, account_id, created_at FROM domains
|
||||
WHERE status = 'active' AND zone_id IS NOT NULL ORDER BY created_at DESC`,
|
||||
).all();
|
||||
return { domains: rows.results };
|
||||
}
|
||||
@@ -230,11 +232,15 @@ async function dispatchTool(env: Env, name: string, args: Record<string, unknown
|
||||
if (!rawAddress) throw new McpToolError("address required", -32602);
|
||||
let domain: { id: string; name: string } | null;
|
||||
if (domainId) {
|
||||
// 指定域名:校验存在
|
||||
domain = await env.DB.prepare("SELECT id, name FROM domains WHERE id = ?")
|
||||
// 指定域名:校验存在且可用(pending/未装 Email Workers 的域名收不到件)
|
||||
const row = await env.DB.prepare("SELECT id, name, status, zone_id FROM domains WHERE id = ?")
|
||||
.bind(domainId)
|
||||
.first<{ id: string; name: string }>();
|
||||
if (!domain) throw new McpToolError("domain not found", -32002);
|
||||
.first<{ id: string; name: string; status: string; zone_id: string | null }>();
|
||||
if (!row) throw new McpToolError("domain not found", -32002);
|
||||
if (row.status !== "active" || !row.zone_id) {
|
||||
throw new McpToolError("domain not available (Email Workers not enabled)", -32002);
|
||||
}
|
||||
domain = row;
|
||||
} else {
|
||||
// 省略域名:随机分配一个已启用 Email Workers 的域名;此时地址必须是本地部分
|
||||
if (rawAddress.includes("@")) {
|
||||
|
||||
Reference in New Issue
Block a user