diff --git a/apps/desktop-shell/scripts/check-config.mjs b/apps/desktop-shell/scripts/check-config.mjs index 631d9e12e..7f7a8de90 100644 --- a/apps/desktop-shell/scripts/check-config.mjs +++ b/apps/desktop-shell/scripts/check-config.mjs @@ -1780,16 +1780,17 @@ for (const expectedShareSnippet of [ 'DesktopSharePayload::Invalid', '"share target is invalid"', 'log_desktop_share_failure', - 'desktop share failed for {label}: {error}', + 'desktop share failed for {label}', 'share_unavailable_response', '"share unavailable"', 'set_desktop_host_bridge_share_target', 'share_text_from_value(target)', - 'log_desktop_share_failure("target.lock", "share target lock poisoned")', - 'log_desktop_share_failure("target.store", "share target lock poisoned")', + 'log_desktop_share_failure("target.lock")', + 'log_desktop_share_failure("target.store")', 'share_target_payload_must_be_valid_before_cache', 'share_unavailable_response_is_stable', 'share_failures_are_logged_without_exposing_native_detail', + 'share_failures_log_stable_label_only', 'open_desktop_host_bridge_share', 'write_desktop_clipboard_text(app, &share_text)', '"copied_to_clipboard"', @@ -1803,7 +1804,10 @@ for (const expectedShareSnippet of [ if ( desktopHostBridgeShareSource.includes('failed(request.id.clone(), "host_error", "share target lock poisoned")') || - desktopHostBridgeShareSource.includes('failed(request.id.clone(), "host_error", error.to_string())') + desktopHostBridgeShareSource.includes('failed(request.id.clone(), "host_error", error.to_string())') || + desktopHostBridgeShareSource.includes('desktop share failed for {label}: {error}') || + desktopHostBridgeShareSource.includes('log_desktop_share_failure("target.lock", "share target lock poisoned")') || + desktopHostBridgeShareSource.includes('log_desktop_share_failure("target.store", "share target lock poisoned")') ) { throw new Error('desktop shell share module must hide native share errors'); } diff --git a/apps/desktop-shell/src-tauri/src/host_bridge/share.rs b/apps/desktop-shell/src-tauri/src/host_bridge/share.rs index 1f2f2abc7..cb33a0f28 100644 --- a/apps/desktop-shell/src-tauri/src/host_bridge/share.rs +++ b/apps/desktop-shell/src-tauri/src/host_bridge/share.rs @@ -28,11 +28,8 @@ fn payload_string<'a>(value: &'a Value, field: &str) -> Option<&'a str> { .filter(|text| !text.is_empty()) } -fn log_desktop_share_failure(label: &str, error: &str) -> bool { - if !error.is_empty() { - eprintln!("desktop share failed for {label}: {error}"); - } - +fn log_desktop_share_failure(label: &str) -> bool { + eprintln!("desktop share failed for {label}"); false } @@ -124,7 +121,7 @@ pub(crate) fn share_text_from_request( .target .lock() .map_err(|_| { - log_desktop_share_failure("target.lock", "share target lock poisoned"); + log_desktop_share_failure("target.lock"); share_unavailable_response(request) })? .clone(); @@ -180,7 +177,7 @@ pub(crate) fn set_desktop_host_bridge_share_target( ok(request.id.clone(), json!(true)) } Err(_) => { - log_desktop_share_failure("target.store", "share target lock poisoned"); + log_desktop_share_failure("target.store"); share_unavailable_response(request) } }; @@ -378,13 +375,12 @@ mod tests { #[test] fn share_failures_are_logged_without_exposing_native_detail() { - assert!(!log_desktop_share_failure( - "target.lock", - "share target lock poisoned" - )); - assert!(!log_desktop_share_failure( - "target.store", - "share target lock poisoned" - )); + assert!(!log_desktop_share_failure("target.lock")); + assert!(!log_desktop_share_failure("target.store")); + } + + #[test] + fn share_failures_log_stable_label_only() { + assert!(!log_desktop_share_failure("target.lock")); } } diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 6c78daae8..24c6dda28 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -3189,6 +3189,7 @@ - 背景:桌面壳 `share.setTarget` 和 `share.open` 会读写 Rust 侧分享目标缓存;如果缓存锁异常直接返回 `share target lock poisoned`,H5 会看到 Rust 内部同步原语细节,且开发侧没有统一日志标签定位读缓存还是写缓存失败。 - 决策:`apps/desktop-shell/src-tauri/src/host_bridge/share.rs` 必须在分享目标缓存读写失败时分别记录 `desktop share failed for target.lock` 或 `desktop share failed for target.store` 日志。HostBridge 对 H5 仍只返回稳定 `share unavailable`,不透传锁状态、内部缓存状态或 Rust 同步原语细节。 +- 2026-06-21 调整:桌面分享缓存失败日志只记录 `desktop share failed for target.lock` / `desktop share failed for target.store` 固定标签,不输出锁污染说明、内部缓存状态或其它 Rust 同步原语细节;配置检查拒绝 `share.rs` 重新拼接 `: {error}` 或把锁异常字符串传给日志函数。 - 验证方式:`cargo test --manifest-path apps/desktop-shell/src-tauri/Cargo.toml host_bridge::share`、`npm run desktop-shell:typecheck`、`npm run check:native-shells`、`npm run check:encoding`、`git diff --check`。 ## 2026-06-20 移动壳门禁脚本必须自登记自扫描 diff --git a/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md b/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md index 32b6f0f09..b9de539b6 100644 --- a/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md +++ b/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md @@ -360,7 +360,7 @@ GameBridge 禁止: 2026-06-20 追加:桌面壳网络状态查询系统异常必须可观测。Tauri 桌面壳后台解析网络状态任务失败时必须记录 `desktop network failed for status.resolve` 日志;HostBridge 回包仍只暴露稳定 `network status unavailable` 语义,不透传 resolver、线程或系统错误细节。2026-06-21 调整:该日志只记录固定标签,不把后台任务 join 错误或 resolver 异常写入 stderr。 -2026-06-20 追加:桌面壳分享缓存内部异常必须可观测。Tauri 桌面壳读写 `share.setTarget` 缓存失败时必须记录 `desktop share failed for ...` 日志;HostBridge 回包仍只暴露稳定 `share unavailable` 语义,不透传锁状态、内部缓存状态或 Rust 同步原语细节。 +2026-06-20 追加:桌面壳分享缓存内部异常必须可观测。Tauri 桌面壳读写 `share.setTarget` 缓存失败时必须记录 `desktop share failed for ...` 日志;HostBridge 回包仍只暴露稳定 `share unavailable` 语义,不透传锁状态、内部缓存状态或 Rust 同步原语细节。2026-06-21 调整:该日志只记录 `desktop share failed for target.lock` / `desktop share failed for target.store` 固定标签,不把锁异常说明写入 stderr。 2026-06-18 追加:H5 账号状态刷新开始消费 `app.reloadWebView`。用户登录成功、退出登录、其它身份边界变化或登录状态异常页点击重新尝试时,`AuthGate` 会优先请求 Expo 壳刷新当前 WebView;宿主未声明或刷新失败时再回退浏览器刷新,避免在移动壳内绕过受控容器刷新入口。