/** * 共享的后端 envelope 解析工具 * * 4 个 `*_api.ts` 文件中重复的 `interface ApiEnvelope` 与 `function unwrap` * 集中到这里。HTTP 拦截器(`http_client.ts`)已经对非 2xx 响应抛 `ApiError`; * 本工具处理第二种失败:2xx 但 `success: false` 的 envelope。 * * 失败时仍抛 `ApiError`,让底层保留 HTTP/API 上下文;进入仓库层 `Result` * 后会被 `ExceptionHandler` 统一收敛为应用可消费的 `{ code, message }`。 */ import { ApiError, ErrorCode } from "./api_result"; /** 后端统一响应包装。 */ export interface ApiEnvelope { success: boolean; data?: T; message?: string; error?: string; } /** * 解包 envelope,失败时抛 `ApiError`。 * 用于:data 字段必有(API 一定返回业务数据)的端点。 */ export function unwrap(envelope: ApiEnvelope): T { if (!envelope.success || envelope.data === undefined) { throw new ApiError( ErrorCode.unknownError, envelope.message ?? envelope.error ?? "API call failed", ); } return envelope.data; } /** * 解包 envelope,但允许 `data` 字段为 `undefined`(用于 fire-and-forget 类端点)。 * 失败时仍抛 `ApiError`。 */ export function unwrapOptional(envelope: ApiEnvelope): T | undefined { if (!envelope.success) { throw new ApiError( ErrorCode.unknownError, envelope.message ?? envelope.error ?? "API call failed", ); } return envelope.data; }