# SDKs by framework

Bucker's JavaScript framework support is **entry points of the two platform SDKs**, not a package per framework: nothing new to install, nothing new to publish, and a page pays only for the entry it imports. The browser half lives in `@bucker/browser`, the server half in `@bucker/node`. For what `npx create-bucker` writes for you, see [framework guides](frameworks.md).

| Framework | Browser | Server |
| --- | --- | --- |
| React | `@bucker/browser/react`: `ErrorBoundary`, `withErrorBoundary`, `reactErrorHandler`, `useRouteBreadcrumb` | |
| React Router / Remix | `@bucker/browser/react`: `useRouteBreadcrumb`, `captureRouteError` | `@bucker/node/remix`: `remixHandleError` |
| Vue | `@bucker/browser/vue`: `buckerVue`, `attachVueErrorHandler`, `instrumentVueRouter` | |
| Nuxt | `@bucker/browser/nuxt`: `installNuxt` | `@bucker/node/nuxt`: `nitroErrorHook` |
| SvelteKit | `@bucker/browser/svelte`: `buckerHandleError` | `@bucker/node/sveltekit`: `sveltekitHandle`, `sveltekitHandleError` |
| Angular | `@bucker/browser/angular`: `createErrorHandler` | |
| Next.js | see [`@bucker/node`](sdk-node.md#nextjs) | |

For Lambda, Workers, Vercel Edge, Deno, Bun, Hono, Koa and NestJS see [Serverless, edge and more frameworks](sdk-node.md#serverless-edge-and-more-frameworks).

**Tested against what, honestly.** React is tested against the real React 19 and Testing Library. Vue, Nuxt, SvelteKit, Angular, Remix and Nitro are not installed in this repository, so their entries are typed against the host object **structurally** (they import none of them) and tested with fakes of exactly the shape they read. They have not yet been run inside a real Vue, Nuxt, SvelteKit or Angular app; if one misbehaves, that is the first place to look.

**Handled, not crashed.** A framework-level handler (an error boundary, Vue's `errorHandler`, SvelteKit's `handleError`, Angular's `ErrorHandler`) catches the error and the page keeps running, so it is captured `handled: true`: it counts as an error in release health, not as a crash of the session. `handled: false` stays with `window.onerror` and `unhandledrejection`. Server hooks use `request.<framework>` mechanisms for the same reason: a failed request is not a dead process.

**Client errors are not defects.** A 4xx (`HttpErrorResponse`, a SvelteKit 404, an h3 404, a thrown `Response` with a client status) is not captured, and one error object is captured once even when two hooks see it.

## React

```tsx
import { init } from '@bucker/browser'
import { ErrorBoundary } from '@bucker/browser/react'

init({ dsn, release })

<ErrorBoundary fallback={({ error, eventId, resetError }) => <Oops onRetry={resetError} />}>
  <App />
</ErrorBoundary>
```

`fallback` is a node or a function of `{ error, componentStack, eventId, resetError }`; `eventId` is what you hand to `captureFeedback`. `beforeCapture(scope, error, componentStack)` edits the scope for that one event. The component stack rides along as `extra.componentStack` (bounded). `react` is an optional peer dependency (`>=18`).

React 19 reports errors an error boundary does not see through `createRoot` options:

```ts
createRoot(el, {
  onUncaughtError: reactErrorHandler(),
  onCaughtError: reactErrorHandler({ handled: true }),
  onRecoverableError: reactErrorHandler({ handled: true }),
})
```

## React Router and Remix

```tsx
// root.tsx / any route
const { pathname } = useLocation()
useRouteBreadcrumb(pathname, { transactionName: matches.at(-1)?.pathname })

export function ErrorBoundary() {
  const error = useRouteError()
  captureRouteError(error)
  return <Oops />
}
```

```ts
// entry.server.tsx
import { remixHandleError } from '@bucker/node/remix'
export const handleError = remixHandleError(client)
```

## Vue

```ts
const app = createApp(App)
app.use(buckerVue)          // sets app.config.errorHandler; logs and chains the previous one
instrumentVueRouter(router) // navigation breadcrumbs + the route pattern as the transaction
```

## Nuxt

```ts
// plugins/bucker.client.ts
export default defineNuxtPlugin((nuxtApp) => {
  init({ dsn: useRuntimeConfig().public.buckerDsn })
  installNuxt(nuxtApp)
})

// server/plugins/bucker.ts
import { nitroErrorHook } from '@bucker/node/nuxt'
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('error', nitroErrorHook(client))
})
```

## SvelteKit

```ts
// src/hooks.client.ts
export const handleError = buckerHandleError()

// src/hooks.server.ts
import { sveltekitHandle, sveltekitHandleError } from '@bucker/node/sveltekit'
export const handle = sequence(sveltekitHandle(client), yourHandle)
export const handleError = sveltekitHandleError(client)
```

Both `handleError` helpers take your own handler as an argument and return its result, so the error shape your pages show is unchanged.

## Angular

```ts
// app.config.ts
providers: [{ provide: ErrorHandler, useValue: createErrorHandler() }]
```

Angular's default handler logs to the console and providing your own replaces it, so this logs too (`logErrors: false` to stop). Zone.js `{ rejection }` and `{ originalError }` wrappers are unwrapped before capture; a thrown string or object is wrapped so the event has a type and a value to group on.
