# SvelteKit

SvelteKit is the tidiest of the meta-frameworks for this: the `$env` modules enforce the key
split at build time — importing `$env/static/private` into client code is a **build error**,
not a silently leaked secret — and the two hook files map one-to-one onto the SDK.

## 1. Install

```bash
npm i bugboard
```

```dotenv
BUGBOARD_KEY_ID=bbk_xxxxxxxx
BUGBOARD_SIGNING_SECRET=bb_sec_xxxxxxxx
PUBLIC_BUGBOARD_API_KEY=bb_pub_xxxxxxxx
```

## 2. Two client modules

```ts
// src/lib/bugboard.server.ts
import { createClient } from 'bugboard';
import { BUGBOARD_KEY_ID, BUGBOARD_SIGNING_SECRET } from '$env/static/private';
import { dev } from '$app/environment';

export default createClient({
    keyId: BUGBOARD_KEY_ID,
    signingSecret: BUGBOARD_SIGNING_SECRET,
    environment: dev ? 'development' : 'production',
});
```

```ts
// src/lib/bugboard.ts (client)
import { createClient } from 'bugboard';
import { PUBLIC_BUGBOARD_API_KEY } from '$env/static/public';
import { dev } from '$app/environment';

export default createClient({
    apiKey: PUBLIC_BUGBOARD_API_KEY,
    environment: dev ? 'development' : 'production',
});
```

The `.server.ts` suffix is the convention worth keeping: an accidental client import fails at
build time rather than shipping your signing secret.

## 3. The hooks

```ts
// src/hooks.server.ts
import type { HandleServerError } from '@sveltejs/kit';
import bugboard from '$lib/bugboard.server';

export const handleError: HandleServerError = async ({
    error,
    event,
    status,
}) => {
    if (status !== 404) {
        bugboard.criticalHigh(
            `Server error: ${event.route.id ?? event.url.pathname}`,
            error,
            ['sveltekit', 'server'],
        );
        await bugboard.flush(); // adapter-vercel / adapter-cloudflare may freeze right after
    }

    return { message: 'Internal Error' };
};
```

```ts
// src/hooks.client.ts
import type { HandleClientError } from '@sveltejs/kit';
import bugboard from '$lib/bugboard';

export const handleClientError: HandleClientError = ({ error, event }) => {
    bugboard.critical(
        `Client error: ${event.route.id ?? event.url.pathname}`,
        error,
        ['sveltekit', 'client'],
    );

    return { message: 'Something went wrong' };
};
```

Two details carry most of the value here:

- **`event.route.id` is the route pattern** (`/products/[id]`), which is what you want in the
  title. `event.url.pathname` is the URL and would create a card per product. See
  **[Deduplication](/docs/api-reference#deduplication-important-for-sdk-design)**.
- **The `status !== 404` guard.** A public site 404s constantly; those are not your bugs and
  they will bury the ones that are.

## 4. Report from anywhere else

In a load function, form action or component:

```ts
import bugboard from '$lib/bugboard.server';

export const actions = {
    checkout: async ({ request }) => {
        try {
            await processCheckout(await request.formData());
        } catch (err) {
            bugboard.criticalHigh('Checkout action failed', err, ['checkout']);
            await bugboard.flush();

            return fail(500, { error: 'Checkout failed' });
        }
    },
};
```

## Delivery by adapter

The `await flush()` in `hooks.server.ts` is what makes this portable across adapters:

- **`adapter-node`** — the automatic `beforeExit` hook covers normal shutdown; add a `SIGTERM`
  handler if you deploy to containers, as in **[the Node guide](/docs/frameworks/node#delivery-and-flushing)**.
- **`adapter-vercel`, `adapter-cloudflare`, `adapter-netlify`** — no lifecycle hook at all; the
  runtime may freeze the instant you return. The explicit flush is the only thing delivering
  your reports. See **[Serverless & edge](/docs/frameworks/serverless)**.
- **The browser** — the SDK flushes on `pagehide` with `keepalive`, so no work needed.

## Next steps

- **[JavaScript SDK](/docs/sdks/javascript)** — the base guide and the full method surface.
- **[Vite SPA](/docs/frameworks/vite-spa)** — the browser-side global handlers.
- **[API Reference](/docs/api-reference)** — every config option and the HTTP contract.
