From 8b408a21d671d91567dc063a451fcccf9b4677b0 Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 18 Jun 2026 08:12:24 -0400 Subject: [PATCH 1/2] Fix three overnight Sentry issues (Turso 502, slow Prisma spans, SyntaxError noise). Retry Turso 502/503/504 in saferFetch and skip capture when retries exhaust; drop standalone prisma transaction spans and minified-chunk SyntaxError events without app frames. Fixes WEBSITE-31 Fixes WEBSITE-32 Fixes WEBSITE-1T Co-authored-by: Cursor --- src/lib/sentry/policy.ts | 24 ++++++++++++++++++++++++ src/lib/sentry/shared-options.ts | 14 +++++++++++++- src/lib/server/saferFetch.ts | 22 ++++++++++++++++++++-- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/lib/sentry/policy.ts b/src/lib/sentry/policy.ts index 4f0fb687..68fb98a2 100644 --- a/src/lib/sentry/policy.ts +++ b/src/lib/sentry/policy.ts @@ -191,6 +191,17 @@ function isTransientTrpcHtmlError(error: unknown): boolean { return message.includes("Unexpected token '<'") || message.includes(" { return fetch(request, options) } +async function fetchWithRetriableStatuses( + request: RequestInfo | URL, + options?: RequestInit +): Promise { + const response = await fetchWithBodyClone(request, options) + + if (retriableHttpStatuses.has(response.status)) { + throw new Error(`Server returned HTTP status ${response.status}`) + } + + return response +} + export const saferFetch = withRetries( { maxAttempts: 5, backoff: attempt => attempt ** 2 * 5, retryOn: isRetriableFetchError }, - fetchWithBodyClone + fetchWithRetriableStatuses ) From 6402d0584992b02263a8c25db7de379ccee2035b Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 18 Jun 2026 08:16:46 -0400 Subject: [PATCH 2/2] Fix TransactionEvent typing for beforeSendTransaction CI. Co-authored-by: Cursor --- src/lib/sentry/shared-options.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/lib/sentry/shared-options.ts b/src/lib/sentry/shared-options.ts index bcd24950..3c00c3d7 100644 --- a/src/lib/sentry/shared-options.ts +++ b/src/lib/sentry/shared-options.ts @@ -1,15 +1,17 @@ +import type { TransactionEvent } from "@sentry/core" import type { ErrorEvent, EventHint } from "@sentry/nextjs" /** Next.js App Router control-flow signals — not application bugs. */ const NEXTJS_CONTROL_FLOW_ERRORS = ["NEXT_NOT_FOUND", "NEXT_REDIRECT"] as const -type TransactionLike = { - transaction?: string -} - /** Standalone Prisma spans sampled as transactions — Turso latency noise, not app bugs. */ -export function shouldDropSentryTransaction(event: TransactionLike): boolean { - return event.transaction === "prisma:client:operation" +export function shouldDropSentryTransaction(event: TransactionEvent): boolean { + const transaction = + typeof event === "object" && event !== null && "transaction" in event + ? (event as { transaction?: unknown }).transaction + : undefined + + return transaction === "prisma:client:operation" } export function shouldDropSentryEvent(event: ErrorEvent, _hint?: EventHint): boolean { @@ -28,8 +30,14 @@ export const sentrySharedOptions = { beforeSend(event: ErrorEvent, hint: EventHint) { return shouldDropSentryEvent(event, hint) ? null : event }, - beforeSendTransaction(event: TransactionLike): TransactionLike | null { - return shouldDropSentryTransaction(event) ? null : event + beforeSendTransaction(event: TransactionEvent) { + if (shouldDropSentryTransaction(event)) { + return null + } + + // TransactionEvent from @sentry/nextjs is `any` in ESLint; tsc expects the full event back. + // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- Sentry SDK transaction callback + return event }, ignoreErrors: [...NEXTJS_CONTROL_FLOW_ERRORS, "Unexpected token '{'"] }