diff --git a/apps/ai-game-creator-shell/src-tauri/src/auth_error.rs b/apps/ai-game-creator-shell/src-tauri/src/auth_error.rs index 8d3a9f55d..13dd6c794 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/auth_error.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/auth_error.rs @@ -7,8 +7,9 @@ //! 响应契约的 5 种破损各自只占一个变体:前端 `switch (failure.type)` 选到类别后,再用 //! `switch (payload.reason)` 在**类型化**的细分上分流,仍然不碰文案。 //! -//! Rust **不预拼用户可见文案**:载荷只装原始事实(服务端 400 的原文、HTTP 状态码、本机 IO 的 -//! `detail`),服务端没给原文就是 `None`;前缀与句式由前端调用方在自己的 catch 分支按当前操作拼接。 +//! Rust **不预拼用户可见文案**:载荷只装原始事实(服务端 400 的原文、HTTP 状态码),服务端没给原文 +//! 就是 `None`;前缀与句式由前端调用方在自己的 catch 分支按当前操作拼接。本机 IO 的原始错误只写本地 +//! 日志,不进载荷(避免把 AppData 路径带进登录页与上报包),对应变体无字段、前端给固定文案。 use serde::Serialize; use ts_rs::TS; @@ -55,10 +56,10 @@ pub(crate) enum ClientAuthError { UnexpectedRejection(UnexpectedRejection), /// 登录服务响应的契约破损,细分原因见 [`AuthResponseInvalidReason`]。 AuthResponseInvalid(AuthResponseInvalid), - /// 本机登录凭据文件读写失败。 - ClientSessionPersistFailed(ClientSessionPersistFailed), - /// 本机运行时会话安装 / 清理失败。 - RuntimeSessionInstallFailed(RuntimeSessionInstallFailed), + /// 本机登录凭据文件读写失败;原始错误只写本地日志。 + ClientSessionPersistFailed, + /// 本机运行时会话安装 / 清理失败;原始错误只写本地日志。 + RuntimeSessionInstallFailed, /// 认证网络客户端构建失败。 AuthClientInitFailed, } @@ -186,22 +187,6 @@ pub(crate) struct AuthResponseInvalid { pub(crate) server_message: Option, } -/// 本机凭据文件读写的原始错误明细。 -#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/services/generated/"))] -pub(crate) struct ClientSessionPersistFailed { - pub(crate) detail: String, -} - -/// 本机运行时会话安装 / 清理的原始错误明细。 -#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/services/generated/"))] -pub(crate) struct RuntimeSessionInstallFailed { - pub(crate) detail: String, -} - impl ClientAuthError { /// 会话路由的 401/403 是「登录态失效」:调用方据此清会话、按未登录处理, /// 既不给用户报错,也不进错误报告池。 @@ -277,15 +262,11 @@ mod tests { "authResponseInvalid", ), ( - ClientAuthError::ClientSessionPersistFailed(ClientSessionPersistFailed { - detail: "x".to_string(), - }), + ClientAuthError::ClientSessionPersistFailed, "clientSessionPersistFailed", ), ( - ClientAuthError::RuntimeSessionInstallFailed(RuntimeSessionInstallFailed { - detail: "x".to_string(), - }), + ClientAuthError::RuntimeSessionInstallFailed, "runtimeSessionInstallFailed", ), ( @@ -304,9 +285,20 @@ mod tests { #[test] fn unit_variants_serialize_without_payload_fields() { - let value = - serde_json::to_value(ClientAuthError::LoginCodeMissing).expect("serialize auth error"); - assert_eq!(value, serde_json::json!({ "type": "loginCodeMissing" })); + for (error, expected_type) in [ + (ClientAuthError::LoginCodeMissing, "loginCodeMissing"), + ( + ClientAuthError::ClientSessionPersistFailed, + "clientSessionPersistFailed", + ), + ( + ClientAuthError::RuntimeSessionInstallFailed, + "runtimeSessionInstallFailed", + ), + ] { + let value = serde_json::to_value(error).expect("serialize auth error"); + assert_eq!(value, serde_json::json!({ "type": expected_type })); + } } #[test] @@ -354,14 +346,6 @@ mod tests { .expect("serialize auth error"); assert_eq!(invalid["reason"], "serverRejected"); assert_eq!(invalid["serverMessage"], "登录服务请求失败"); - - let persist = serde_json::to_value(ClientAuthError::ClientSessionPersistFailed( - ClientSessionPersistFailed { - detail: "磁盘只读".to_string(), - }, - )) - .expect("serialize auth error"); - assert_eq!(persist["detail"], "磁盘只读"); } #[test] diff --git a/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs b/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs index c65cba3ac..d08e697cb 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs @@ -6,9 +6,8 @@ use crate::auth_error::{ AuthNetworkFailure, AuthNetworkReason, AuthResponseInvalid, AuthResponseInvalidReason, - AuthServiceUnavailable, ClientAuthError, ClientSessionPersistFailed, PasswordLoginRejected, - PhoneCodeLoginRejected, RuntimeSessionInstallFailed, SendCodeRejected, ServerAddressReason, - ServerAddressRejected, UnexpectedRejection, + AuthServiceUnavailable, ClientAuthError, PasswordLoginRejected, PhoneCodeLoginRejected, + SendCodeRejected, ServerAddressReason, ServerAddressRejected, UnexpectedRejection, }; use crate::http_client::agc_main_site_client_builder; use crate::platform_session::{current_platform_session, PlatformSessionSnapshot}; @@ -222,24 +221,21 @@ fn session_file_path(app: &tauri::AppHandle) -> Result .app_data_dir() .map(|root| root.join(SESSION_FILE_NAME)) .map_err(|error| { - ClientAuthError::ClientSessionPersistFailed(ClientSessionPersistFailed { - detail: format!("无法读取 AGC 应用数据目录:{error}"), - }) + app_log!("无法读取 AGC 应用数据目录:{error}"); + ClientAuthError::ClientSessionPersistFailed }) } /// 凭据文件相关的字符串错误统一收口成凭据落盘失败变体。 fn session_persist_error(message: impl Into) -> ClientAuthError { - ClientAuthError::ClientSessionPersistFailed(ClientSessionPersistFailed { - detail: message.into(), - }) + app_log!("{}", message.into()); + ClientAuthError::ClientSessionPersistFailed } /// 本机运行时安装 / 清理失败的字符串错误统一收口。 fn runtime_session_error(message: impl Into) -> ClientAuthError { - ClientAuthError::RuntimeSessionInstallFailed(RuntimeSessionInstallFailed { - detail: message.into(), - }) + app_log!("{}", message.into()); + ClientAuthError::RuntimeSessionInstallFailed } /// 服务地址校验失败统一收口成带类型化原因的变体。 diff --git a/apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx b/apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx index 0eb882bd8..b4bb237b4 100644 --- a/apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx +++ b/apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx @@ -38,10 +38,8 @@ import { import type { AuthNetworkFailure } from '../services/generated/AuthNetworkFailure'; import type { AuthResponseInvalid } from '../services/generated/AuthResponseInvalid'; import type { AuthServiceUnavailable } from '../services/generated/AuthServiceUnavailable'; -import type { ClientSessionPersistFailed } from '../services/generated/ClientSessionPersistFailed'; import type { PasswordLoginRejected } from '../services/generated/PasswordLoginRejected'; import type { PhoneCodeLoginRejected } from '../services/generated/PhoneCodeLoginRejected'; -import type { RuntimeSessionInstallFailed } from '../services/generated/RuntimeSessionInstallFailed'; import type { SendCodeRejected } from '../services/generated/SendCodeRejected'; import type { ServerAddressRejected } from '../services/generated/ServerAddressRejected'; import type { UnexpectedRejection } from '../services/generated/UnexpectedRejection'; @@ -438,15 +436,13 @@ export function AuthenticatedClient({ throw error; } case 'clientSessionPersistFailed': { - const payload = failure as ClientSessionPersistFailed; - const text = `本机登录凭据读写失败:${payload.detail}`; + const text = '本机登录凭据读写失败'; setAuthCheckError(text); setLoginStatus(text); throw error; } case 'runtimeSessionInstallFailed': { - const payload = failure as RuntimeSessionInstallFailed; - const text = `本机运行时会话安装失败:${payload.detail}`; + const text = '本机运行时会话安装失败'; setAuthCheckError(text); setLoginStatus(text); throw error; @@ -708,17 +704,11 @@ export function AuthenticatedClient({ throw error; } case 'clientSessionPersistFailed': { - const payload = failure as ClientSessionPersistFailed; - setLoginStatus( - `发送验证码失败:本机登录凭据读写失败:${payload.detail}`, - ); + setLoginStatus('发送验证码失败:本机登录凭据读写失败'); throw error; } case 'runtimeSessionInstallFailed': { - const payload = failure as RuntimeSessionInstallFailed; - setLoginStatus( - `发送验证码失败:本机运行时会话安装失败:${payload.detail}`, - ); + setLoginStatus('发送验证码失败:本机运行时会话安装失败'); throw error; } case 'authClientInitFailed': { @@ -945,13 +935,11 @@ export function AuthenticatedClient({ throw error; } case 'clientSessionPersistFailed': { - const payload = failure as ClientSessionPersistFailed; - setLoginStatus(`登录失败:本机登录凭据读写失败:${payload.detail}`); + setLoginStatus('登录失败:本机登录凭据读写失败'); throw error; } case 'runtimeSessionInstallFailed': { - const payload = failure as RuntimeSessionInstallFailed; - setLoginStatus(`登录失败:本机运行时会话安装失败:${payload.detail}`); + setLoginStatus('登录失败:本机运行时会话安装失败'); throw error; } case 'authClientInitFailed': { diff --git a/apps/ai-game-creator-shell/src/services/generated/ClientAuthError.ts b/apps/ai-game-creator-shell/src/services/generated/ClientAuthError.ts index 6cb924232..8b402ac56 100644 --- a/apps/ai-game-creator-shell/src/services/generated/ClientAuthError.ts +++ b/apps/ai-game-creator-shell/src/services/generated/ClientAuthError.ts @@ -2,10 +2,8 @@ import type { AuthNetworkFailure } from './AuthNetworkFailure'; import type { AuthResponseInvalid } from './AuthResponseInvalid'; import type { AuthServiceUnavailable } from './AuthServiceUnavailable'; -import type { ClientSessionPersistFailed } from './ClientSessionPersistFailed'; import type { PasswordLoginRejected } from './PasswordLoginRejected'; import type { PhoneCodeLoginRejected } from './PhoneCodeLoginRejected'; -import type { RuntimeSessionInstallFailed } from './RuntimeSessionInstallFailed'; import type { SendCodeRejected } from './SendCodeRejected'; import type { ServerAddressRejected } from './ServerAddressRejected'; import type { UnexpectedRejection } from './UnexpectedRejection'; @@ -30,6 +28,6 @@ export type ClientAuthError = | ({ type: 'authServiceUnavailable' } & AuthServiceUnavailable) | ({ type: 'unexpectedRejection' } & UnexpectedRejection) | ({ type: 'authResponseInvalid' } & AuthResponseInvalid) - | ({ type: 'clientSessionPersistFailed' } & ClientSessionPersistFailed) - | ({ type: 'runtimeSessionInstallFailed' } & RuntimeSessionInstallFailed) + | { type: 'clientSessionPersistFailed' } + | { type: 'runtimeSessionInstallFailed' } | { type: 'authClientInitFailed' }; diff --git a/apps/ai-game-creator-shell/src/services/generated/ClientSessionPersistFailed.ts b/apps/ai-game-creator-shell/src/services/generated/ClientSessionPersistFailed.ts deleted file mode 100644 index 258f43fb0..000000000 --- a/apps/ai-game-creator-shell/src/services/generated/ClientSessionPersistFailed.ts +++ /dev/null @@ -1,6 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. - -/** - * 本机凭据文件读写的原始错误明细。 - */ -export type ClientSessionPersistFailed = { detail: string }; diff --git a/apps/ai-game-creator-shell/src/services/generated/RuntimeSessionInstallFailed.ts b/apps/ai-game-creator-shell/src/services/generated/RuntimeSessionInstallFailed.ts deleted file mode 100644 index df2940b5d..000000000 --- a/apps/ai-game-creator-shell/src/services/generated/RuntimeSessionInstallFailed.ts +++ /dev/null @@ -1,6 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. - -/** - * 本机运行时会话安装 / 清理的原始错误明细。 - */ -export type RuntimeSessionInstallFailed = { detail: string }; diff --git a/apps/ai-game-creator-shell/tests/clientAuthErrorCarrier.test.ts b/apps/ai-game-creator-shell/tests/clientAuthErrorCarrier.test.ts index c343247a6..ed6a5c902 100644 --- a/apps/ai-game-creator-shell/tests/clientAuthErrorCarrier.test.ts +++ b/apps/ai-game-creator-shell/tests/clientAuthErrorCarrier.test.ts @@ -16,10 +16,8 @@ import type { AuthNetworkFailure } from '../src/services/generated/AuthNetworkFa import type { AuthResponseInvalid } from '../src/services/generated/AuthResponseInvalid'; import type { AuthServiceUnavailable } from '../src/services/generated/AuthServiceUnavailable'; import type { ClientAuthError } from '../src/services/generated/ClientAuthError'; -import type { ClientSessionPersistFailed } from '../src/services/generated/ClientSessionPersistFailed'; import type { PasswordLoginRejected } from '../src/services/generated/PasswordLoginRejected'; import type { PhoneCodeLoginRejected } from '../src/services/generated/PhoneCodeLoginRejected'; -import type { RuntimeSessionInstallFailed } from '../src/services/generated/RuntimeSessionInstallFailed'; import type { SendCodeRejected } from '../src/services/generated/SendCodeRejected'; import type { ServerAddressRejected } from '../src/services/generated/ServerAddressRejected'; import type { UnexpectedRejection } from '../src/services/generated/UnexpectedRejection'; @@ -115,9 +113,9 @@ function variantMessage(error: ClientAuthError): string { } } case 'clientSessionPersistFailed': - return (error as ClientSessionPersistFailed).detail; + return '本机登录凭据读写失败'; case 'runtimeSessionInstallFailed': - return (error as RuntimeSessionInstallFailed).detail; + return '本机运行时会话安装失败'; case 'authClientInitFailed': return '网络客户端构建失败'; default: {