修复 Tauri 错误报告事件订阅拒绝
错误报告桥在浏览器和未初始化 WebView 中安全降级 优先复用全局 Tauri 事件桥并收口订阅拒绝 新增无 Tauri 环境回归测试 补充事件桥 fail-safe 排障记忆
This commit is contained in:
@@ -143,9 +143,15 @@ export function subscribeClientErrorEvents(listener: () => void) {
|
||||
let unlisten: (() => void) | undefined;
|
||||
void subscribeErrorReportUpdates(() => {
|
||||
if (!disposed) listener();
|
||||
}).then((stop) => {
|
||||
})
|
||||
.then((stop) => {
|
||||
if (disposed) stop();
|
||||
else unlisten = stop;
|
||||
})
|
||||
.catch(() => {
|
||||
// Browser previews and partially initialized native webviews do not have
|
||||
// an event bridge; snapshots and focus/visibility refreshes remain the
|
||||
// source of truth in those environments.
|
||||
});
|
||||
return () => {
|
||||
disposed = true;
|
||||
|
||||
@@ -31,8 +31,33 @@ export function ackErrorReports(eventIds: string[]) {
|
||||
export function subscribeErrorReportUpdates(
|
||||
listener: () => void,
|
||||
): Promise<UnlistenFn> {
|
||||
return listen<ErrorReportUpdate>('error-report-updated', (event) => {
|
||||
const handleUpdate = (event: { payload: ErrorReportUpdate }) => {
|
||||
void event.payload;
|
||||
listener();
|
||||
});
|
||||
};
|
||||
|
||||
// 客户端也会运行在浏览器预览和 Vitest 的 jsdom 中。Tauri API 模块默认
|
||||
// `__TAURI_INTERNALS__` 已存在,缺失时会拒绝,因此原生 WebView 之外保持
|
||||
// 桥接为空操作。启用 `withGlobalTauri` 时优先使用全局桥接,让测试替身与
|
||||
// 客户端其它事件订阅复用同一入口。
|
||||
if (typeof window !== 'undefined') {
|
||||
const globalListen = window.__TAURI__?.event?.listen;
|
||||
if (globalListen) {
|
||||
return globalListen('error-report-updated', handleUpdate).catch(
|
||||
() => () => {},
|
||||
);
|
||||
}
|
||||
|
||||
const internals = (window as Window & { __TAURI_INTERNALS__?: unknown })
|
||||
.__TAURI_INTERNALS__;
|
||||
if (!internals) {
|
||||
return Promise.resolve(() => {});
|
||||
}
|
||||
} else {
|
||||
return Promise.resolve(() => {});
|
||||
}
|
||||
|
||||
return listen<ErrorReportUpdate>('error-report-updated', handleUpdate).catch(
|
||||
() => () => {},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ import {
|
||||
resetClientErrorEventsForTests,
|
||||
shouldCaptureClientError,
|
||||
submitErrorReportBatch,
|
||||
subscribeClientErrorEvents,
|
||||
} from '../src/services/errorReporting';
|
||||
|
||||
describe('客户端错误报告池', () => {
|
||||
@@ -184,4 +185,12 @@ describe('客户端错误报告池', () => {
|
||||
uninstall();
|
||||
consoleInfo.mockRestore();
|
||||
});
|
||||
|
||||
it('浏览器预览中订阅错误事件不会产生未处理拒绝', async () => {
|
||||
delete window.__TAURI__;
|
||||
|
||||
const unsubscribe = subscribeClientErrorEvents(vi.fn());
|
||||
unsubscribe();
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
> 当前口径:本文件保留可复用的排障经验;历史条目的旧路由、旧版本和已删除文档仅作根因背景,不得据此恢复退役入口。当前命令、路由和 schema 以代码与 `docs/README.md` 为准。
|
||||
|
||||
## 2026-09-02 Tauri 事件桥在浏览器预览中必须 fail-safe
|
||||
|
||||
- **现象**:Vitest/jsdom 挂载 AGC 客户端时,错误报告通知调用 `@tauri-apps/api/event.listen`,因缺少 `window.__TAURI_INTERNALS__` 产生未处理拒绝;测试断言虽通过,CI 仍以 unhandled errors 失败。
|
||||
- **原因**:错误报告订阅是非阻塞唤醒通道,不能假定所有渲染环境都已初始化 Tauri IPC;模块级 `listen` 在 API 调用前就会访问 `transformCallback`,仅在调用方包一层 `.then` 无法消除该环境差异。
|
||||
- **处理**:订阅桥先复用 `window.__TAURI__.event.listen`(含 globalTauri/native shim),其次仅在 `__TAURI_INTERNALS__` 存在时调用模块 API;浏览器预览或订阅失败统一返回 no-op,并在消费层收口 rejection。错误快照读取、焦点和可见性刷新仍是权威路径。
|
||||
- **验证**:`errorReporting.test.ts` 覆盖无 Tauri 环境无未处理拒绝;`appSurface.test.ts` 全部 385 条用例通过且无 Vitest unhandled errors。
|
||||
|
||||
## 2026-08-27 Provider 成功 handoff 失败时需要保留本地私有原始响应
|
||||
|
||||
- **现象**:Provider 已返回响应,但 tool-plan handoff 因绝对路径或其它内容安全校验失败,Runtime 只留下 `failureKind`、哈希和被压平的 JSON pointer;排障时无法确认实际工具名和完整 arguments。
|
||||
|
||||
Reference in New Issue
Block a user