Files
vyndr/web/src/components/SentryInit.tsx
T

50 lines
1.5 KiB
TypeScript

'use client';
import { useEffect } from 'react';
/**
* Client-side Sentry init (Session 10).
*
* Manual init rather than the @sentry/nextjs `withSentryConfig`
* wrapper because that plugin conflicts with standalone output mode
* (the Coolify production build). Manual init keeps the bundle
* simple: nothing imported when DSN is unset, lazy import via
* dynamic import() when it is.
*
* Mount once at the root layout — repeated mounts get the
* Sentry-internal idempotency guard, but we keep the layout single-
* mount to avoid unnecessary work.
*/
export default function SentryInit() {
useEffect(() => {
const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN;
if (!dsn) return;
let cancelled = false;
(async () => {
try {
const Sentry = await import('@sentry/nextjs');
if (cancelled) return;
Sentry.init({
dsn,
tracesSampleRate: 0.1,
// PII posture: don't sweep up IPs / cookies automatically.
sendDefaultPii: false,
// Trim heavy integrations we don't need for free-tier volume.
integrations: (defaults) => defaults.filter((i) => i.name !== 'Replay'),
beforeSend(event) {
if (event.user) {
delete event.user.ip_address;
delete event.user.email;
}
return event;
},
});
} catch {
// Sentry init failure is never user-facing — degrade silently.
}
})();
return () => { cancelled = true; };
}, []);
return null;
}