Files
supabase/apps/studio/instrumentation-client.ts
T
Yogeshwaran C 83187d5836 fix: correct grammar in comments and user-facing copy (#42918)
## What kind of change does this PR introduce?

Grammar corrections in comments and user-facing text.

## What is the current behavior?

Several files have minor grammar issues:

- Missing contraction: "it an error" (should be "it's an error")
- Subject-verb disagreement: "a users loads" (should be "a user loads")
- Missing possessive apostrophe: "a users organization" and "a users
language" (should be "a user's")

## What is the new behavior?

All grammar issues are corrected:

- `apps/studio/instrumentation-client.ts` — "it's an error" + "a user
loads"
- `apps/docs/instrumentation-client.ts` — "a user loads"
- `apps/www/data/partners/index.tsx` — "a user's organization"
-
`apps/docs/content/troubleshooting/customizing-emails-by-language-KZ_38Q.mdx`
— "a user's language"
2026-02-19 23:10:41 +08:00

258 lines
11 KiB
TypeScript

// This file configures the initialization of Sentry on the client.
// The config you add here will be used whenever a user loads a page in their browser.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from '@sentry/nextjs'
import { hasConsented } from 'common'
import { IS_PLATFORM } from 'common/constants/environment'
import { MIRRORED_BREADCRUMBS } from 'lib/breadcrumbs'
import { sanitizeArrayOfObjects, sanitizeUrlHashParams } from 'lib/sanitize'
// This is a workaround to ignore hCaptcha related errors.
function isHCaptchaRelatedError(event: Sentry.Event): boolean {
const errors = event.exception?.values ?? []
for (const error of errors) {
if (
error.value?.includes('is not a function') &&
error.stacktrace?.frames?.some((f) => f.filename === 'api.js')
) {
return true
}
}
return false
}
// We want to ignore errors not originating from docs app static files
// (such as errors from browser extensions). Those errors come from files
// not starting with 'app:///_next'.
//
// However, there is a complication because the Sentry code that sends
// the error shows up in the stack trace, and that _does_ start with
// 'app:///_next'. It is always the first frame in the stack trace,
// and has a specific pre_context comment that we can use for filtering.
// Copied from docs app instrumentation-client.ts
function isThirdPartyError(frames: Sentry.StackFrame[] | undefined) {
if (!frames || frames.length === 0) return false
function isSentryFrame(frame: Sentry.StackFrame, index: number) {
return index === 0 && frame.pre_context?.some((line) => line.includes('sentry.javascript'))
}
// Check if any frame is from our app (excluding Sentry's own frame)
const hasAppFrame = frames.some((frame, index) => {
const path = frame.abs_path || frame.filename
return path?.startsWith('app:///_next') && !isSentryFrame(frame, index)
})
// If no app frames found, it's a third-party error
return !hasAppFrame
}
// Filter browser wallet extension errors (e.g., Gate.io wallet)
// These errors come from injected wallet scripts and are not actionable
// Examples: SUPABASE-APP-AFC, SUPABASE-APP-92A
export function isBrowserWalletExtensionError(event: Sentry.Event): boolean {
const frames = event.exception?.values?.flatMap((e) => e.stacktrace?.frames || []) || []
return frames.some((frame) => {
const filename = frame.filename || frame.abs_path || ''
return filename.includes('gt-window-provider') || filename.includes('wallet-provider')
})
}
// Filter user-aborted operations (intentional cancellations)
// These are expected when users cancel requests or navigate away
// Examples: SUPABASE-APP-BG6, SUPABASE-APP-BG7
export function isUserAbortedOperation(error: unknown, event: Sentry.Event): boolean {
const errorMessage = error instanceof Error ? error.message : ''
const eventMessage = event.message || ''
const message = errorMessage || eventMessage
return (
message.includes('operation was aborted') ||
message.includes('signal is aborted') ||
message.includes('manually canceled') ||
message.includes('AbortError')
)
}
// Filter cancellation promise rejections (e.g., from query cancellation)
// These occur when operations are intentionally cancelled by the user
// Example: SUPABASE-APP-353 (~466k events)
export function isCancellationRejection(event: Sentry.Event): boolean {
const serialized = event.extra?.__serialized__ as Record<string, unknown> | undefined
return serialized?.type === 'cancelation'
}
// Filter challenge/captcha expired errors (user timeout)
// These happen when users don't complete captcha in time - expected behavior
// Example: SUPABASE-APP-ACC
export function isChallengeExpiredError(error: unknown, event: Sentry.Event): boolean {
const errorMessage = error instanceof Error ? error.message : ''
const eventMessage = event.message || ''
const message = errorMessage || eventMessage
return message.includes('challenge-expired')
}
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
...(process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT && {
environment: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
}),
// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
// Enable performance monitoring - Next.js routes and API calls are automatically instrumented
tracesSampleRate: 0.001, // Capture 0.1% of transactions for performance monitoring
// [Ali] Filter out browser extensions and user scripts (FE-2094)
// Using denyUrls to block known third-party script patterns
denyUrls: [/userscript/i],
beforeBreadcrumb(breadcrumb, _hint) {
const cleanedBreadcrumb = { ...breadcrumb }
if (cleanedBreadcrumb.category === 'navigation') {
if (typeof cleanedBreadcrumb.data?.from === 'string') {
cleanedBreadcrumb.data.from = sanitizeUrlHashParams(cleanedBreadcrumb.data.from)
}
if (typeof cleanedBreadcrumb.data?.to === 'string') {
cleanedBreadcrumb.data.to = sanitizeUrlHashParams(cleanedBreadcrumb.data.to)
}
}
MIRRORED_BREADCRUMBS.pushBack(cleanedBreadcrumb)
return cleanedBreadcrumb
},
beforeSend(event, hint) {
const consent = hasConsented()
if (!consent) {
return null
}
if (!IS_PLATFORM) {
return null
}
// Ignore invalid URL events for 99% of the time because it's using up a lot of quota.
const isInvalidUrlEvent = (hint.originalException as any)?.message?.includes(
`Failed to construct 'URL': Invalid URL`
)
// [Joshen] Similar behaviour for this error from SessionTimeoutModal to control the quota usage
const isSessionTimeoutEvent = (hint.originalException as any)?.message?.includes(
'Session error detected'
)
if ((isInvalidUrlEvent || isSessionTimeoutEvent) && Math.random() > 0.01) {
return null
}
if (isHCaptchaRelatedError(event)) {
return null
}
const frames = event.exception?.values?.[0].stacktrace?.frames || []
if (isThirdPartyError(frames)) {
return null
}
// Filter out errors like 'e._5BLbSXV[t] is not a function' or anything matching '[t] is not a function'
if (
hint.originalException instanceof Error &&
hint.originalException.message.includes('[t] is not a function')
) {
return null
}
if (isBrowserWalletExtensionError(event)) {
return null
}
if (isUserAbortedOperation(hint.originalException, event)) {
return null
}
if (isCancellationRejection(event)) {
return null
}
if (isChallengeExpiredError(hint.originalException, event)) {
return null
}
if (event.breadcrumbs) {
event.breadcrumbs = sanitizeArrayOfObjects(event.breadcrumbs) as Sentry.Breadcrumb[]
}
return event
},
ignoreErrors: [
// Used exclusively in Monaco Editor.
'ResizeObserver',
's.getModifierState is not a function',
/^Uncaught NetworkError: Failed to execute 'importScripts' on 'WorkerGlobalScope'/,
// Browser wallet extension errors (e.g., Gate.io wallet)
'shouldSetTallyForCurrentProvider is not a function',
// [Joshen] We currently use stripe-js for customers to save their credit card data
// I'm unable to reproduce this error on local, staging nor prod across chrome, safari or firefox
// Based on https://github.com/stripe/stripe-js/issues/26, it seems like this error is safe to ignore,
'Failed to load Stripe.js',
// [Joshen] This event started occurring after our fix in the org dropdown by reading the slug from
// the URL params instead of the store, but we cannot repro locally, staging nor on prod
// Safe to ignore since it's not a user-facing issue + we've not received any user feedback/report about it
// Ref: https://github.com/supabase/supabase/pull/9729
'The provided `href` (/org/[slug]/general) value is missing query values (slug)',
'The provided `href` (/org/[slug]/team) value is missing query values (slug)',
'The provided `href` (/org/[slug]/billing) value is missing query values (slug)',
'The provided `href` (/org/[slug]/invoices) value is missing query values (slug)',
// [Joshen] Seems to be from hcaptcha
"undefined is not an object (evaluating 'n.chat.setReady')",
"undefined is not an object (evaluating 'i.chat.setReady')",
// [Terry] When users paste in an embedded GitHub Gist
// Error thrown by `sql-formatter` lexer when given invalid input
// Original format: new Error(`Parse error: Unexpected "${text}" at line ${line} column ${col}`)
/^Parse error: Unexpected ".+" at line \d+ column \d+$/,
// [Joshen] IMO, should be caught on API if there's anything to handle - FE shouldn't dupe this alert
/504 Gateway Time-out/,
// [Joshen] This is the one caused by Google translate in the browser + 3rd party extensions
'Node.insertBefore: Child to insert before is not a child of this node',
// [Ali] Google Translate / browser extension DOM manipulation errors
'NotFoundError: The object can not be found here.',
// [Joshen] This one sprung up recently and I've no idea where this is coming from
'r.default.setDefaultLevel is not a function',
// [Joshen] Safe to ignore, it's an error from the copyToClipboard
'The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.',
// API/Network errors - should be handled by API layer, not actionable on frontend
/502/,
'upstream request timeout',
/upstream connect error or disconnect\/reset before headers/,
/Failed to fetch/,
// Google Translate / browser extension DOM manipulation errors
/Failed to execute 'removeChild' on 'Node'/,
// Monaco editor errors - already filtering ResizeObserver, adding general monaco errors
/monaco-editor/,
// JWT/Auth errors - expected during session expiry, handled by auth flow
'jwt expired',
/InvalidJWTToken: Invalid value for JWT claim "exp"/,
// User cancellation - intentional user action
'Canceled: Canceled',
// Third-party/extension errors
'html2canvas is not defined',
'[object Event]',
'ConnectorClass.onMessage(extensionPageScript)',
"Cannot destructure property 'address' of '(intermediate value)' as it is undefined.",
// Expected user flow errors
'Profile already exists: User already exists',
// JSON parse errors from invalid responses
'"undefined" is not valid JSON',
'SyntaxError: "undefined" is not valid JSON',
],
})
// This export will instrument router navigations, and is only relevant if you enable tracing.
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart