1
0

refactor: 全面优化后端代码质量与架构

- app.ts 单体路由拆分为 routes/ + helpers + middleware + static 独立模块
- 类型去重:CheckFailure/CheckResult 以 shared/api.ts 为唯一源头,收紧 phase 联合类型
- es-toolkit 替换:isPlainObject/isNil/isEmptyObject/isEqual/isError/Semaphore/groupBy
- Bun 内置 API:Object.fromEntries 替代手写 headersToRecord
- bun:sqlite 规范:prepare() → query() 利用内置缓存,避免 N+1 查询
- 新增 getLatestChecksMap/allGetTargetStats 批量查询方法
- 新增 backend-code-quality/api-route-separation/batch-data-queries 规范
- 补充 openspec/config.yaml 后端开发规范与 DEVELOPMENT.md 后端开发指引
This commit is contained in:
2026-05-12 15:15:36 +08:00
parent 696db6ffb5
commit f7facb7232
24 changed files with 868 additions and 368 deletions

58
src/server/middleware.ts Normal file
View File

@@ -0,0 +1,58 @@
import type { RuntimeMode } from "../shared/api";
import { allowsGetHead, createApiError, jsonResponse, methodNotAllowedResponse } from "./helpers";
export function guardGetHead(method: string, mode: RuntimeMode): Response | null {
if (!allowsGetHead(method)) {
return methodNotAllowedResponse(["GET", "HEAD"], mode);
}
return null;
}
export function validateTargetId(idStr: string, mode: RuntimeMode): { id: number } | Response {
const id = Number(idStr);
if (!Number.isInteger(id) || id <= 0) {
return jsonResponse(createApiError("Invalid target ID", 400), { mode, status: 400 });
}
return { id };
}
export function validateTimeRange(
from: string | null,
to: string | null,
mode: RuntimeMode,
): { from: string; to: string } | Response {
if (!from || !to) {
return jsonResponse(createApiError("from and to parameters are required", 400), { mode, status: 400 });
}
if (isNaN(new Date(from).getTime()) || isNaN(new Date(to).getTime())) {
return jsonResponse(createApiError("Invalid from or to parameter format", 400), { mode, status: 400 });
}
return { from, to };
}
export function validatePagination(
pageParam: string | null,
pageSizeParam: string | null,
mode: RuntimeMode,
): { page: number; pageSize: number } | Response {
let page = 1;
let pageSize = 20;
if (pageParam !== null) {
page = Number(pageParam);
if (!Number.isInteger(page) || page <= 0) {
return jsonResponse(createApiError("Invalid page parameter", 400), { mode, status: 400 });
}
}
if (pageSizeParam !== null) {
pageSize = Number(pageSizeParam);
if (!Number.isInteger(pageSize) || pageSize <= 0) {
return jsonResponse(createApiError("Invalid pageSize parameter", 400), { mode, status: 400 });
}
}
return { page, pageSize };
}