8b50db9893
- resolveClientAuthFailure 改用 clientAuthErrorKind 判分流,不再用 clientAuthErrorNotice 是否为 null 当判据 - 空文案的 input/session 变体改为给兜底提示、不进错误池,保持"预期拒绝永不进池"的约束 - clientAuthErrorNotice 文档注明 null 同时表示 fault 与空文案,不能当分流判据 - clientAuthHost.test.ts 增加空文案业务变体的分流用例
63 lines
2.6 KiB
TypeScript
63 lines
2.6 KiB
TypeScript
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;
|
||
}
|