feat(errors): fallback handlers for unhandled rejections and errors
Sentry's global integrations natively capture window.onerror / unhandledrejection (renderer) and uncaughtException / unhandledRejection (main). When a DSN is configured we let Sentry own those paths to avoid double-capturing. When it isn't (dev, unconfigured prod), we attach minimal listeners that route through reportError so stray promise rejections and uncaught errors at least hit the console and the facade. This closes the one gap where a bare click-handler promise rejection (no try/catch, not a useMutation) would otherwise be invisible.
This commit is contained in:
+31
-18
@@ -1,28 +1,41 @@
|
||||
import * as Sentry from "@sentry/electron/renderer";
|
||||
import { appConfig } from "@/config/env";
|
||||
import { installErrorSinks } from "@/lib/errors";
|
||||
import { installErrorSinks, reportError } from "@/lib/errors";
|
||||
|
||||
/**
|
||||
* Initialise Sentry for a renderer process. No-ops when `sentryDsn` is empty
|
||||
* so dev builds and unconfigured envs stay quiet.
|
||||
* Initialise renderer error handling. When a DSN is configured, Sentry's
|
||||
* own global handlers capture uncaught exceptions and unhandled promise
|
||||
* rejections. Otherwise we install a minimal fallback so stray rejections
|
||||
* aren't silent in dev / unconfigured envs.
|
||||
*/
|
||||
export function initSentryRenderer(): void {
|
||||
if (!appConfig.sentryDsn) return;
|
||||
if (appConfig.sentryDsn) {
|
||||
Sentry.init({
|
||||
dsn: appConfig.sentryDsn,
|
||||
tracesSampleRate: 0,
|
||||
});
|
||||
|
||||
Sentry.init({
|
||||
dsn: appConfig.sentryDsn,
|
||||
tracesSampleRate: 0,
|
||||
installErrorSinks({
|
||||
capture: (err, context) =>
|
||||
Sentry.captureException(err, { extra: context }),
|
||||
breadcrumb: (err, context) =>
|
||||
Sentry.addBreadcrumb({
|
||||
category: "error",
|
||||
level: "error",
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
data: context,
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener("unhandledrejection", (event) => {
|
||||
reportError(event.reason, { scope: "unhandledrejection" });
|
||||
});
|
||||
|
||||
installErrorSinks({
|
||||
capture: (err, context) =>
|
||||
Sentry.captureException(err, { extra: context }),
|
||||
breadcrumb: (err, context) =>
|
||||
Sentry.addBreadcrumb({
|
||||
category: "error",
|
||||
level: "error",
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
data: context,
|
||||
}),
|
||||
window.addEventListener("error", (event) => {
|
||||
reportError(event.error ?? new Error(event.message), {
|
||||
scope: "window.error",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+28
-19
@@ -1,30 +1,39 @@
|
||||
import { app } from "electron";
|
||||
import * as Sentry from "@sentry/electron/main";
|
||||
import { appConfig } from "@/config/env";
|
||||
import { installErrorSinks } from "@/lib/errors";
|
||||
import { installErrorSinks, reportError } from "@/lib/errors";
|
||||
|
||||
/**
|
||||
* Initialise Sentry for the main process. Captures uncaught exceptions from
|
||||
* the Node side and the crash reporter. Safe to call before `app.whenReady`.
|
||||
* Initialise main-process error handling. Sentry owns uncaught-exception
|
||||
* capture when a DSN is configured; otherwise we install a minimal Node
|
||||
* fallback so rejections aren't silent. Safe to call before `app.whenReady`.
|
||||
*/
|
||||
export function initSentryMain(): void {
|
||||
if (!appConfig.sentryDsn) return;
|
||||
if (appConfig.sentryDsn) {
|
||||
Sentry.init({
|
||||
dsn: appConfig.sentryDsn,
|
||||
tracesSampleRate: 0,
|
||||
release: app.getVersion(),
|
||||
});
|
||||
|
||||
Sentry.init({
|
||||
dsn: appConfig.sentryDsn,
|
||||
tracesSampleRate: 0,
|
||||
release: app.getVersion(),
|
||||
installErrorSinks({
|
||||
capture: (err, context) =>
|
||||
Sentry.captureException(err, { extra: context }),
|
||||
breadcrumb: (err, context) =>
|
||||
Sentry.addBreadcrumb({
|
||||
category: "error",
|
||||
level: "error",
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
data: context,
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
process.on("uncaughtException", (err) => {
|
||||
reportError(err, { scope: "uncaughtException" });
|
||||
});
|
||||
|
||||
installErrorSinks({
|
||||
capture: (err, context) =>
|
||||
Sentry.captureException(err, { extra: context }),
|
||||
breadcrumb: (err, context) =>
|
||||
Sentry.addBreadcrumb({
|
||||
category: "error",
|
||||
level: "error",
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
data: context,
|
||||
}),
|
||||
process.on("unhandledRejection", (reason) => {
|
||||
reportError(reason, { scope: "unhandledRejection" });
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user