next-app/instrumentation-client.ts
Rama main · réplica de lectura del repositorio original.
// Next 15.3+ client-side instrumentation entry. Runs after the HTML
// document loads but before React hydration, which is the right moment
// to install error / performance hooks so hydration errors and early
// client crashes are captured.
//
// Sentry recommends this filename over `sentry.client.config.ts` for
// turbopack compatibility (the latter is deprecated as of @sentry/nextjs
// 9+). We're on webpack for now, but using the Next-native convention
// future-proofs us when turbopack stabilises.
//
// Env: NEXT_PUBLIC_SENTRY_DSN (must be public-prefixed so it's bundled
// into the client). DSN-missing = SDK no-ops internally; no manual guard.
import * as Sentry from "@sentry/nextjs";
import { DENIED_URL_PATTERNS, IGNORED_ERROR_PATTERNS } from "@/lib/sentryFilters";
// One attempt per page load. See beforeSend.
let replayRequested = false;
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 0.1,
debug: false,
// Errors are reported at 100% — `tracesSampleRate` above governs tracing
// only. Worth stating because the `client_sample_rate: 0.1` that appears in
// every event's trace context reads like an error sample rate and is not
// one; multiplying issue counts by ten gives a number ten times too big.
// Injected third-party scripts, mostly from in-app WebViews. Rationale for
// each pattern lives in lib/sentryFilters.ts, next to the tests that pin
// them to the exact strings Sentry reported.
//
// These matter beyond quota. EventFilters runs as an event processor, which
// @sentry/core resolves BEFORE beforeSend (client.js `_processEvent`), so a
// filtered error never reaches the Replay block below and never triggers its
// download. Before this, an extension's syntax error on someone's phone
// pulled half a megabyte of Replay SDK onto that phone — 88 times.
ignoreErrors: IGNORED_ERROR_PATTERNS,
denyUrls: DENIED_URL_PATTERNS,
// Replay intentionally omitted from init. The full replay SDK (~500 kB
// gzipped) is loaded lazily on first error so it does not bloat the
// landing-page bundle. replaysSessionSampleRate stays 0 (no background
// recording); on-error capture is wired below.
//
// ⚠️ Neither `replaysSessionSampleRate` nor `replaysOnErrorSampleRate` is
// set, and on-error capture needs the latter above 0. Until one is
// configured this download most likely records nothing. Left as-is rather
// than removed or enabled: turning it on starts uploading session
// recordings of real users, which is a privacy and quota decision, not a
// cleanup. Decide, then either set a rate or delete the block.
beforeSend(event) {
// Guarded, and deliberately not reset on failure. lazyLoadIntegration
// fetches from https://browser.sentry-cdn.com, and this site's users are
// overwhelmingly in mainland China, where that origin is not dependable.
// Retrying per error would mean a stream of failing script tags on
// exactly the sessions already going badly.
if (!replayRequested && (event.level === "error" || event.level === "fatal")) {
replayRequested = true;
Sentry.lazyLoadIntegration("replayIntegration")
.then((ReplayIntegration) => {
Sentry.addIntegration(
ReplayIntegration({ maskAllText: false, blockAllMedia: false }),
);
})
.catch(() => {});
}
return event;
},
});
// Required by @sentry/nextjs for App Router navigation spans -- without
// it the SDK logs a warning at startup. Forwards Next's transition events
// to Sentry's app-router routing instrumentation.
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;