fix(telemetry): surface AI sidecar and DOMException failure reasons in Sentry (#612)

AI sidecar failures reached Sentry as 'Error: Error': the scrubber type-onlys plain Errors and the tool wrappers threw them from result.error. The bridge now exports toSidecarError(), wrapping the sidecar reason in a SafeError (memory-allocation text classifies as operational, the rest as bug); all 14 wrappers use it, plus the dispatcher crash/stdin/spawn rejection paths and parseStdoutJson. toBgRemovalError from #535 delegates to the shared helper.

On the web side, DOMExceptions report their specific name via err.name, so the NATIVE_ERRORS allowlist dropped the whole family's browser-authored messages. It now carries the full WebIDL DOMException name table; messages still pass through url/path redaction.

Bridge-mocking test files switched to importOriginal passthrough mocks.
This commit is contained in:
SnapOtter
2026-07-21 23:18:50 +08:00
committed by GitHub
parent 82f5708193
commit 6a0768b39d
35 changed files with 502 additions and 73 deletions
@@ -6,10 +6,14 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
// `./bridge.js` import receives these stubs.
const runPythonWithProgress = vi.fn();
const parseStdoutJson = vi.fn();
vi.mock("../../../packages/ai/src/bridge.js", () => ({
runPythonWithProgress: (...args: unknown[]) => runPythonWithProgress(...args),
parseStdoutJson: (...args: unknown[]) => parseStdoutJson(...args),
}));
vi.mock("../../../packages/ai/src/bridge.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../../packages/ai/src/bridge.js")>();
return {
...actual,
runPythonWithProgress: (...args: unknown[]) => runPythonWithProgress(...args),
parseStdoutJson: (...args: unknown[]) => parseStdoutJson(...args),
};
});
import { isSafeMessageError, SafeError } from "@snapotter/shared";
import { removeBackground } from "../../../packages/ai/src/background-removal.js";