Repository: supabase/supabase
File: apps/studio/instrumentation-client.ts (TypeScript)

Code before:
  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?.[0]?.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
}

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  // Setting this option to true will print useful information to the console while you're setting up Sentry.
  debug: false,
  // [Ali] Filter out browser extensions and user scripts (FE-2094)
  // Using denyUrls to block known third-party script patterns
  denyUrls: [
    /extensions?\//i,
    /^chrome:\/\//i,
    /^chrome-extension:\/\//i,
    /^moz-extension:\/\//i,
    /^safari-extension:\/\//i,
    /^safari-web-extension:\/\//i,

Review comment (bug):
```suggestion
    return index === 0 && frame.pre_context?.some(line => line.includes('sentry.javascript'))
```

we have a bug here actually, the latest user scripting alerts would've been caught with this

Code after:
  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
}

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  // Setting this option to true will print useful information to the console while you're setting up Sentry.
  debug: false,
  // [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)