- contracts/src/api.ts 2733 行 → api/*.ts 13 个领域文件 + shared.ts;api.ts 按原顺序合并 Api。 新旧对比:354 个端点内容与顺序一致,分组键与对外导出一致 - acquisition-organize/services/organize.ts 2645 行 → organize-types / -plan / -exec / -finalize / -records, organize.ts 保留为汇总入口,外部引用不变 - browser/service.ts 类外的纯函数(视图映射、原因文案、坐标换算、图片尺寸、出口代理)移到 session-view.ts, service.ts 照旧转出 - organize-wizard:来源解析 useResolvedSource 移到 source.ts,FormSelect 移到 form-select.tsx 只挪位置不改逻辑;typecheck、lint、test:all、web build、server 编译与编译产物自检通过。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
234 lines
6.8 KiB
TypeScript
234 lines
6.8 KiB
TypeScript
import { z } from "zod";
|
||
import * as auth from "../auth.ts";
|
||
import { cursorPage, HealthStatus, IdParam } from "../common.ts";
|
||
import * as events from "../events.ts";
|
||
import * as ops from "../ops.ts";
|
||
import { EngineRunIdParam, ep, OkResult } from "./shared.ts";
|
||
|
||
export const systemApi = {
|
||
// ── 登录门禁 ──
|
||
/** /auth/setup、/auth/login、/auth/session 免鉴权;改密与 TOTP 只接受控制台 cookie 会话 */
|
||
auth: {
|
||
setup: ep({
|
||
method: "post",
|
||
path: "/auth/setup",
|
||
scope: "read",
|
||
auth: "public",
|
||
summary: "首次初始化管理员",
|
||
body: auth.AdminSetupRequest,
|
||
response: auth.SessionInfo,
|
||
}),
|
||
login: ep({
|
||
method: "post",
|
||
path: "/auth/login",
|
||
scope: "read",
|
||
auth: "public",
|
||
summary: "管理员登录",
|
||
body: auth.LoginRequest,
|
||
response: auth.LoginResult,
|
||
}),
|
||
logout: ep({ method: "post", path: "/auth/logout", scope: "read", summary: "注销当前会话", response: OkResult }),
|
||
session: ep({
|
||
method: "get",
|
||
path: "/auth/session",
|
||
scope: "read",
|
||
auth: "public",
|
||
summary: "当前登录态(免鉴权)",
|
||
response: auth.SessionInfo,
|
||
}),
|
||
password: ep({
|
||
method: "post",
|
||
path: "/auth/password",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "修改密码(吊销其它会话)",
|
||
body: auth.PasswordChangeRequest,
|
||
response: auth.PasswordChangeResult,
|
||
}),
|
||
totpStatus: ep({
|
||
method: "get",
|
||
path: "/auth/totp",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "TOTP 状态",
|
||
response: auth.TotpStatus,
|
||
}),
|
||
totp: ep({
|
||
method: "post",
|
||
path: "/auth/totp",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "TOTP 绑定/启用/停用/重新生成恢复码",
|
||
body: auth.TotpAction,
|
||
response: auth.TotpActionResult,
|
||
}),
|
||
totpSetup: ep({
|
||
method: "get",
|
||
path: "/auth/totp/setup",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "待确认的 TOTP 密钥与 otpauth URL(前端渲染二维码)",
|
||
response: auth.TotpSetup,
|
||
}),
|
||
passkeys: ep({
|
||
method: "get",
|
||
path: "/auth/passkeys",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "已登记的 Passkey",
|
||
response: auth.PasskeyList,
|
||
}),
|
||
passkeyRegisterOptions: ep({
|
||
method: "post",
|
||
path: "/auth/passkeys/register/options",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "Passkey 注册挑战",
|
||
response: auth.PasskeyChallenge,
|
||
}),
|
||
passkeyRegister: ep({
|
||
method: "post",
|
||
path: "/auth/passkeys/register/verify",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "校验并登记 Passkey",
|
||
body: auth.PasskeyRegisterRequest,
|
||
response: auth.PasskeyInfo,
|
||
}),
|
||
passkeyRename: ep({
|
||
method: "patch",
|
||
path: "/auth/passkeys/{id}",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "重命名 Passkey",
|
||
params: IdParam,
|
||
body: auth.PasskeyRenameRequest,
|
||
response: auth.PasskeyInfo,
|
||
}),
|
||
passkeyDelete: ep({
|
||
method: "delete",
|
||
path: "/auth/passkeys/{id}",
|
||
scope: "admin",
|
||
auth: "session",
|
||
summary: "删除 Passkey",
|
||
params: IdParam,
|
||
response: OkResult,
|
||
}),
|
||
passkeyLoginOptions: ep({
|
||
method: "post",
|
||
path: "/auth/passkeys/login/options",
|
||
scope: "read",
|
||
auth: "public",
|
||
summary: "Passkey 登录挑战(免鉴权)",
|
||
response: auth.PasskeyChallenge,
|
||
}),
|
||
passkeyLogin: ep({
|
||
method: "post",
|
||
path: "/auth/passkeys/login/verify",
|
||
scope: "read",
|
||
auth: "public",
|
||
summary: "Passkey 登录(免鉴权;成功即下发会话)",
|
||
body: auth.PasskeyLoginRequest,
|
||
response: auth.LoginResult,
|
||
}),
|
||
},
|
||
|
||
// ── 事件 ──
|
||
events: {
|
||
list: ep({
|
||
method: "get",
|
||
path: "/events",
|
||
scope: "read",
|
||
summary:
|
||
"事件流:控制台用 SSE(text/event-stream,cookie 会话);API Key 调用者带 limit 取 JSON 补读页(after=上次 nextAfter)",
|
||
query: events.EventReplayQuery,
|
||
response: events.EventReplayPage,
|
||
}),
|
||
},
|
||
|
||
// ── 系统 ──
|
||
system: {
|
||
health: ep({
|
||
method: "get",
|
||
path: "/health",
|
||
scope: "read",
|
||
summary: "服务健康状态(免鉴权)",
|
||
response: HealthStatus,
|
||
}),
|
||
healthDetail: ep({
|
||
method: "get",
|
||
path: "/system/health",
|
||
scope: "admin",
|
||
summary: "进程与健康:进程心跳 / 事件循环延迟 / SSE 连接 / DB / 磁盘 / 挂载根 / 引擎 / 定时任务",
|
||
response: ops.SystemHealth,
|
||
}),
|
||
healthHistory: ep({
|
||
method: "get",
|
||
path: "/system/health/history",
|
||
scope: "admin",
|
||
summary: "心跳采样时间序列(事件循环延迟、运行中 run、SSE 连接;按桶聚合)",
|
||
query: ops.SystemHealthHistoryQuery,
|
||
response: ops.SystemHealthHistory,
|
||
}),
|
||
storage: ep({
|
||
method: "get",
|
||
path: "/system/storage",
|
||
scope: "admin",
|
||
summary: "存储:表体积前 15、库总体积、各缓存用量与预算、备份占用、DATA_DIR 分目录用量、清理任务状态",
|
||
response: ops.SystemStorage,
|
||
}),
|
||
storageCleanup: ep({
|
||
method: "post",
|
||
path: "/system/storage/cleanup/{target}",
|
||
scope: "admin",
|
||
summary: "立即执行某个存储清理任务(排入对应定时任务,已在排队或运行中则合并)",
|
||
params: ops.StorageCleanupParam,
|
||
response: ops.StorageCleanupResult,
|
||
}),
|
||
},
|
||
|
||
// ── 引擎面板(仅 admin) ──
|
||
engine: {
|
||
runs: ep({
|
||
method: "get",
|
||
path: "/engine/runs",
|
||
scope: "admin",
|
||
summary: "引擎 runs(状态/名称/时间筛选,新→旧)",
|
||
query: ops.EngineRunQuery,
|
||
response: cursorPage(ops.EngineRun),
|
||
}),
|
||
run: ep({
|
||
method: "get",
|
||
path: "/engine/runs/{id}",
|
||
scope: "admin",
|
||
summary: "run 详情(step attempts + signals)",
|
||
params: EngineRunIdParam,
|
||
response: ops.EngineRunDetail,
|
||
}),
|
||
stats: ep({
|
||
method: "get",
|
||
path: "/engine/stats",
|
||
scope: "admin",
|
||
summary: "按状态计数 / 最老待处理 / 活跃 worker 快照",
|
||
response: ops.EngineStats,
|
||
}),
|
||
cancel: ep({
|
||
method: "post",
|
||
path: "/engine/runs/{id}/cancel",
|
||
scope: "admin",
|
||
summary: "取消 run",
|
||
params: EngineRunIdParam,
|
||
body: ops.EngineCancelRequest,
|
||
response: ops.EngineCancelResult,
|
||
}),
|
||
retry: ep({
|
||
method: "post",
|
||
path: "/engine/runs/{id}/retry",
|
||
scope: "admin",
|
||
summary: "按原任务名与输入重新入队(新幂等键 retry:<id>:<序号>)",
|
||
params: EngineRunIdParam,
|
||
response: z.object({ runId: z.string(), retryOf: z.string(), attempt: z.number().int().positive() }),
|
||
}),
|
||
},
|
||
} as const;
|