/** * 共享的后端 envelope 解析工具 * * 4 个 `*_api.ts` 文件中重复的 `interface ApiEnvelope` 与 `function unwrap` * 集中到这里。HTTP 拦截器(`http_client.ts`)已经对非 2xx 响应抛 `ApiError`; * 本工具处理第二种失败:2xx 但 `success: false` 的 envelope。 * * 行为升级:失败时抛 `ApiError`(`ApiError extends Error`),而不是裸 `Error`。 * 这样调用方在 `Result.err` 内能 `instanceof ApiError` 检查 `.code` / `.status`。 * * 原始 Dart: lib/data/services/api/api_client.dart 的 `NetResult` 解析。 */ 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; }