Files
Genarrative/apps/ai-game-creator-shell/src/services/clientAuthError.ts
T
k88936 8b50db9893 修复登录失败分流把空文案的业务变体误判为需上报
- resolveClientAuthFailure 改用 clientAuthErrorKind 判分流,不再用 clientAuthErrorNotice 是否为 null 当判据
- 空文案的 input/session 变体改为给兜底提示、不进错误池,保持"预期拒绝永不进池"的约束
- clientAuthErrorNotice 文档注明 null 同时表示 fault 与空文案,不能当分流判据
- clientAuthHost.test.ts 增加空文案业务变体的分流用例
2026-10-01 16:05:47 +08:00

63 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { ClientAuthError } from './generated/ClientAuthError';
export type { ClientAuthError };
/**
* `invoke` 拒绝时拿到的是 Rust 序列化出来的普通对象(不是 `Error`)。这里只做形状读取:
* `type` 是稳定判别键,`message` 是 Rust 生成的可展示文案,**文案不参与任何判断**。
*
* 不在名单里的 `type` 也算"形状合法":新变体会落到 [`clientAuthErrorKind`] 的 `fault`,
* 由调用方交给错误池——这是故意的,见 ADR 的"未识别变体上调"。
*/
export function isClientAuthError(value: unknown): ClientAuthError | null {
if (!value || typeof value !== 'object') return null;
const candidate = value as { type?: unknown; message?: unknown };
if (typeof candidate.type !== 'string' || !candidate.type) return null;
if (typeof candidate.message !== 'string') return null;
return value as ClientAuthError;
}
/**
* 变体分流的稳定分类,与 Rust `ClientAuthError` 的三段注释一一对应:
*
* - `input`:用户自己能改的输入 / 前置条件(登录 400/401、发码 429 等),调用方给提示后消化掉。
* - `session`:会话路由 401/403,调用方按"未登录"处理,不报错也不进池。
* - `fault`:网络 / 5xx / 写盘 / 运行时 / 响应不合法,以及**未识别变体**,由调用方交给错误池。
*/
export type ClientAuthErrorKind = 'input' | 'session' | 'fault';
export function clientAuthErrorKind(
error: ClientAuthError,
): ClientAuthErrorKind {
switch (error.type) {
case 'serverAddressRejected':
case 'phoneNumberInvalid':
case 'passwordMissing':
case 'loginCodeMissing':
case 'passwordEntryInputRejected':
case 'phoneOrPasswordMismatch':
case 'sendCodeInputRejected':
case 'smsCodeThrottled':
case 'phoneLoginInputRejected':
case 'smsCodeInvalidOrExpired':
return 'input';
case 'sessionAuthorityRejected':
case 'permissionDenied':
return 'session';
default:
return 'fault';
}
}
/**
* 用户可读的提示:`input` / `session` 原样使用 Rust 生成的那一份文案;`fault` 返回 `null`,
* 表示"调用方处理不了,交给错误池"。空文案也按"没有提示"处理,避免调用方拿空串当提示显示。
*
* **`null` 同时表示这两件事,所以它不是分流判据**:判定"要不要进错误池"必须用
* [`clientAuthErrorKind`],只有 `fault` 才上报;否则一个文案为空的可识别变体会被误报。
*/
export function clientAuthErrorNotice(error: ClientAuthError): string | null {
if (clientAuthErrorKind(error) === 'fault') return null;
return error.message.trim() || null;
}