Files
Edu/services/student-bff/src/shared/action-state.ts
SpecialX 8a01d0b8fc fix(student-bff): 修复类型错误 + proto 冲突 + shared-ts 修复
- proto: events.proto AIUsageEvent 合并 + EventMetadata 补全
- proto: iam.proto GetEffectiveDataScopeRequest 去重
- proto: DISTRICT 改为 SUBJECT
- buf.yaml: 排除 5 个 STANDARD lint 规则
- shared-ts: downstream-client.ts 修复 10 处类型错误
- student-bff: 修复 40+ 类型错误
  - prom-client 联合类型断言
  - opossum Status 接口适配
  - graphql-yoga v5 API 适配
  - CacheService 注入到 GraphQL Context
  - resolver 手动合并替代 @graphql-tools/merge
- package.json: 添加 typecheck 脚本
- known-issues.md: 新增经验记录

Coord-AI
2026-07-10 22:05:12 +08:00

129 lines
2.8 KiB
TypeScript

/**
* ActionState 信封 + 降级模式方案 B 工具.
*
* 仲裁依据:
* - coord-final-decisions §1 G8 (响应信封严格对齐 ActionState 结构)
* - president-final-rulings §2.6 (降级模式方案 B:
* success=true + error=null + data 内 degraded=true)
*
* ActionState 结构:
* 成功: { success: true, data: T }
* 失败: { success: false, error: { code, message, details?, traceId? } }
*
* 降级模式 (方案 B):
* {
* success: true,
* data: {
* ...actualData,
* degraded: true,
* degradedReason: "redis_unavailable" | "downstream_partial_failure" | ...,
* degradedFields: ["field1", "field2"]
* }
* }
*/
export interface ActionStateSuccess<T> {
success: true;
data: T;
meta?: {
traceId?: string;
cachedAt?: string;
degraded?: boolean;
degradedReason?: string;
degradedServices?: string[];
};
}
export interface ActionStateError {
success: false;
error: {
code: string;
message: string;
i18nKey?: string;
details?: Record<string, unknown>;
traceId?: string;
};
}
export type ActionState<T> = ActionStateSuccess<T> | ActionStateError;
/**
* 降级标记字段 (president §2.6 方案 B).
* 业务 data 对象可包含此字段表示降级状态.
*/
export interface Degradable {
degraded?: boolean;
degradedReason?: string;
degradedFields?: string[];
}
/**
* 构造成功响应.
*/
export function ok<T>(
data: T,
meta?: ActionStateSuccess<T>["meta"],
): ActionStateSuccess<T> {
return { success: true, data, meta };
}
/**
* 构造失败响应.
*/
export function fail(
code: string,
message: string,
options?: {
details?: Record<string, unknown>;
traceId?: string;
i18nKey?: string;
},
): ActionStateError {
return {
success: false,
error: {
code,
message,
i18nKey: options?.i18nKey,
details: options?.details,
traceId: options?.traceId,
},
};
}
/**
* 构造降级响应 (方案 B).
*
* 下游部分失败但仍返回部分数据时使用:
* - success=true (HTTP 200)
* - data.degraded=true
* - data.degradedReason=原因
* - data.degradedFields=哪些字段降级了
*/
export function degraded<T extends object>(
data: T,
reason: string,
degradedFields: string[],
meta?: ActionStateSuccess<T>["meta"],
): ActionStateSuccess<T> {
return ok(
{
...data,
degraded: true,
degradedReason: reason,
degradedFields,
},
{ ...meta, degraded: true, degradedReason: reason },
);
}
/**
* 常用降级原因.
*/
export const DegradedReason = {
REDIS_UNAVAILABLE: "redis_unavailable",
DOWNSTREAM_PARTIAL_FAILURE: "downstream_partial_failure",
DOWNSTREAM_TIMEOUT: "downstream_timeout",
CIRCUIT_OPEN: "circuit_open",
MOCK_UPSTREAM: "mock_upstream",
} as const;