From 8b50db989362984bc2b8e12bd7da33eee50f80f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Thu, 1 Oct 2026 16:05:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=BD=95=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E5=88=86=E6=B5=81=E6=8A=8A=E7=A9=BA=E6=96=87=E6=A1=88?= =?UTF-8?q?=E7=9A=84=E4=B8=9A=E5=8A=A1=E5=8F=98=E4=BD=93=E8=AF=AF=E5=88=A4?= =?UTF-8?q?=E4=B8=BA=E9=9C=80=E4=B8=8A=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolveClientAuthFailure 改用 clientAuthErrorKind 判分流,不再用 clientAuthErrorNotice 是否为 null 当判据 - 空文案的 input/session 变体改为给兜底提示、不进错误池,保持"预期拒绝永不进池"的约束 - clientAuthErrorNotice 文档注明 null 同时表示 fault 与空文案,不能当分流判据 - clientAuthHost.test.ts 增加空文案业务变体的分流用例 --- .../src/services/clientAuth.ts | 21 +++++++++++++++---- .../src/services/clientAuthError.ts | 5 ++++- .../tests/clientAuthHost.test.ts | 8 +++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apps/ai-game-creator-shell/src/services/clientAuth.ts b/apps/ai-game-creator-shell/src/services/clientAuth.ts index 2af0f6ce7..04c60af19 100644 --- a/apps/ai-game-creator-shell/src/services/clientAuth.ts +++ b/apps/ai-game-creator-shell/src/services/clientAuth.ts @@ -1,6 +1,10 @@ import type { AuthUser } from '../../../../packages/shared/src/contracts/auth'; import { resolveTauriInvoke } from '../app/tauri'; -import { clientAuthErrorNotice, isClientAuthError } from './clientAuthError'; +import { + clientAuthErrorKind, + clientAuthErrorNotice, + isClientAuthError, +} from './clientAuthError'; import { subscribeTauriEvent } from './tauriEventSubscription'; /** Rust 认证态事件:只承载状态投影,不含 token 或 refresh 凭据。 */ @@ -57,7 +61,8 @@ export function getClientAuthErrorMessage(error: unknown, fallback: string) { * 只显示 Rust 文案;`report` 是系统变体 / 未识别变体 / 非结构化拒绝,显示文案之外还要带上下文 * 交给错误池(见 [`captureClientError`](./errorReporting.ts))。 * - * 判定只看类型化的 `type`,不做任何文案匹配;这条规则是"输错一次密码不该被引导上报"的判据。 + * 判定只看类型化的 `type`(`clientAuthErrorKind`),不做任何文案匹配;这条规则是 + * "输错一次密码不该被引导上报"的判据。 */ export type ClientAuthFailureResolution = | { kind: 'notice'; message: string } @@ -68,8 +73,16 @@ export function resolveClientAuthFailure( fallback: string, ): ClientAuthFailureResolution { const structured = isClientAuthError(error); - const notice = structured ? clientAuthErrorNotice(structured) : null; - if (notice !== null) return { kind: 'notice', message: notice }; + // 分流判据是 `clientAuthErrorKind`,不是"有没有提示":`clientAuthErrorNotice` 对空文案也返回 + // `null`,拿它当判据会把"Rust 给了可识别的 input/session 变体、但文案为空"错当成 fault 上报。 + if (structured && clientAuthErrorKind(structured) !== 'fault') { + return { + kind: 'notice', + message: + clientAuthErrorNotice(structured) ?? + getClientAuthErrorMessage(error, fallback), + }; + } return { kind: 'report', message: getClientAuthErrorMessage(error, fallback), diff --git a/apps/ai-game-creator-shell/src/services/clientAuthError.ts b/apps/ai-game-creator-shell/src/services/clientAuthError.ts index 741e1ce6d..94797fd16 100644 --- a/apps/ai-game-creator-shell/src/services/clientAuthError.ts +++ b/apps/ai-game-creator-shell/src/services/clientAuthError.ts @@ -51,7 +51,10 @@ export function clientAuthErrorKind( /** * 用户可读的提示:`input` / `session` 原样使用 Rust 生成的那一份文案;`fault` 返回 `null`, - * 表示"调用方处理不了,交给错误池"。空文案按"没有提示"处理,避免调用方拿空串当提示显示。 + * 表示"调用方处理不了,交给错误池"。空文案也按"没有提示"处理,避免调用方拿空串当提示显示。 + * + * **`null` 同时表示这两件事,所以它不是分流判据**:判定"要不要进错误池"必须用 + * [`clientAuthErrorKind`],只有 `fault` 才上报;否则一个文案为空的可识别变体会被误报。 */ export function clientAuthErrorNotice(error: ClientAuthError): string | null { if (clientAuthErrorKind(error) === 'fault') return null; diff --git a/apps/ai-game-creator-shell/tests/clientAuthHost.test.ts b/apps/ai-game-creator-shell/tests/clientAuthHost.test.ts index 68d8a612a..2d2d51493 100644 --- a/apps/ai-game-creator-shell/tests/clientAuthHost.test.ts +++ b/apps/ai-game-creator-shell/tests/clientAuthHost.test.ts @@ -210,6 +210,14 @@ test('登录失败分流只看类型化变体:业务拒绝给提示,系统 '登录失败', ), ).toEqual({ kind: 'notice', message: '登录已失效,请重新登录' }); + // 文案为空的可识别变体仍按"用户可改"处理:给兜底提示,不进错误池 + // (分流判据是 kind,不是"有没有提示文案")。 + expect( + resolveClientAuthFailure( + { type: 'phoneNumberInvalid', message: ' ' }, + '登录失败', + ), + ).toEqual({ kind: 'notice', message: '登录失败' }); // 系统变体与未识别变体:显示 Rust 文案,同时交给错误池。 expect( resolveClientAuthFailure(