- P1: server.ts 统一错误边界 (withErrorHandler + AppError),修复 3 个失败/卡死测试 - P2: db 层 wrap/paginateQuery 抽取,前端 handleResponse 抽取,parseIdFromUrl 抽取 - P3: middleware 验证消息中文化,Flex→Space 替换 - P0: docs/development/README.md 新增已知设计决策章节 - P3-11 setup 拆分已尝试回退(@testing-library/react preload 依赖无法拆分) - P3-13 config 层测试从本次变更移除
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
import type { RuntimeMode } from "../../shared/api";
|
|
|
|
import { createApiError, jsonResponse } from "../helpers";
|
|
|
|
const MAX_PAGE_SIZE = 200;
|
|
|
|
export function validateIdParam(idStr: string, mode: RuntimeMode): Response | { id: string } {
|
|
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(idStr)) {
|
|
return jsonResponse(createApiError("无效的 ID 参数", 400), { mode, status: 400 });
|
|
}
|
|
return { id: idStr };
|
|
}
|
|
|
|
export function validatePagination(
|
|
pageParam: null | string,
|
|
pageSizeParam: null | string,
|
|
mode: RuntimeMode,
|
|
): Response | { page: number; pageSize: number } {
|
|
let page = 1;
|
|
let pageSize = 20;
|
|
|
|
if (pageParam !== null) {
|
|
page = Number(pageParam);
|
|
if (!Number.isInteger(page) || page <= 0) {
|
|
return jsonResponse(createApiError("无效的 page 参数", 400), { mode, status: 400 });
|
|
}
|
|
}
|
|
|
|
if (pageSizeParam !== null) {
|
|
pageSize = Number(pageSizeParam);
|
|
if (!Number.isInteger(pageSize) || pageSize <= 0) {
|
|
return jsonResponse(createApiError("无效的 pageSize 参数", 400), { mode, status: 400 });
|
|
}
|
|
if (pageSize > MAX_PAGE_SIZE) {
|
|
return jsonResponse(createApiError(`pageSize 不能超过 ${MAX_PAGE_SIZE}`, 400), { mode, status: 400 });
|
|
}
|
|
}
|
|
|
|
return { page, pageSize };
|
|
}
|
|
|
|
export function validateTimeRange(
|
|
from: null | string,
|
|
to: null | string,
|
|
mode: RuntimeMode,
|
|
): Response | { from: string; to: string } {
|
|
if (!from || !to) {
|
|
return jsonResponse(createApiError("from 和 to 参数为必填项", 400), { mode, status: 400 });
|
|
}
|
|
|
|
const fromDate = new Date(from);
|
|
const toDate = new Date(to);
|
|
|
|
if (isNaN(fromDate.getTime()) || isNaN(toDate.getTime())) {
|
|
return jsonResponse(createApiError("无效的 from 或 to 参数格式", 400), { mode, status: 400 });
|
|
}
|
|
|
|
if (fromDate.getTime() > toDate.getTime()) {
|
|
return jsonResponse(createApiError("from 必须早于 to", 400), { mode, status: 400 });
|
|
}
|
|
|
|
return { from: fromDate.toISOString(), to: toDate.toISOString() };
|
|
}
|