重构 seed 为 WC2026 72 场小组赛与 48 强优胜盘;新增 production 模式仅保留 admin 与赛事示例;提供 prod-init-db 全量重置脚本;管理端 i18n 分包与赛事归档能力。 Co-authored-by: Cursor <cursoragent@cursor.com>
56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import {
|
|
BadRequestException,
|
|
ForbiddenException,
|
|
HttpException,
|
|
HttpStatus,
|
|
NotFoundException,
|
|
UnauthorizedException,
|
|
} from '@nestjs/common';
|
|
import type { ApiErrorCode, ApiErrorParams } from '@thebet365/shared';
|
|
|
|
function body(code: ApiErrorCode, params?: ApiErrorParams) {
|
|
const clean = params
|
|
? Object.fromEntries(
|
|
Object.entries(params)
|
|
.filter(([, v]) => v !== undefined && v !== null)
|
|
.map(([k, v]) => [k, String(v)]),
|
|
)
|
|
: undefined;
|
|
return { code, params: clean };
|
|
}
|
|
|
|
export function appBadRequest(code: ApiErrorCode, params?: ApiErrorParams) {
|
|
return new BadRequestException(body(code, params));
|
|
}
|
|
|
|
export function appNotFound(code: ApiErrorCode, params?: ApiErrorParams) {
|
|
return new NotFoundException(body(code, params));
|
|
}
|
|
|
|
export function appForbidden(code: ApiErrorCode, params?: ApiErrorParams) {
|
|
return new ForbiddenException(body(code, params));
|
|
}
|
|
|
|
export function appConflict(code: ApiErrorCode, data?: unknown, params?: ApiErrorParams) {
|
|
return new HttpException({ ...body(code, params), data: data ?? null }, HttpStatus.CONFLICT);
|
|
}
|
|
|
|
export function appUnauthorized(code: ApiErrorCode, params?: ApiErrorParams) {
|
|
return new UnauthorizedException(body(code, params));
|
|
}
|
|
|
|
export function appTooManyRequests(code: ApiErrorCode, params?: ApiErrorParams) {
|
|
return new HttpException(body(code, params), HttpStatus.TOO_MANY_REQUESTS);
|
|
}
|
|
|
|
export function isCodedExceptionResponse(
|
|
res: unknown,
|
|
): res is { code: ApiErrorCode; params?: ApiErrorParams } {
|
|
return (
|
|
typeof res === 'object' &&
|
|
res !== null &&
|
|
'code' in res &&
|
|
typeof (res as { code: unknown }).code === 'string'
|
|
);
|
|
}
|