npm package: @helpgrid/sveltekit
Description: HelpGrid Signals SDK for SvelteKit - Error tracking and observability
Author: HelpGrid Team
Latest version: 0.1.2

# @helpgrid/sveltekit

HelpGrid Signals SDK for SvelteKit - Error tracking and observability for your SvelteKit applications.

## Installation

```bash
npm install @helpgrid/sveltekit
# or
pnpm add @helpgrid/sveltekit
```

## Setup

### 1. Initialize in `hooks.server.ts`

```typescript
// src/hooks.server.ts
import { signalsHandle, handleError } from '@helpgrid/sveltekit';
import { sequence } from '@sveltejs/kit/hooks';

export const handle = sequence(
  // ... other hooks
  signalsHandle({
    apiKey: import.meta.env.VITE_HELPGRID_API_KEY,
    environment: import.meta.env.MODE,
    ignoreRoutes: ['/health', '/api/signals/ingest']
  })
);

export { handleError };
```

### 2. Configure Environment Variables

```bash
# .env.local or .env
VITE_HELPGRID_API_KEY=your-api-key-here
```

## Usage

### Automatic Error Capture

Server-side errors are automatically captured via the `handleError` hook:

```typescript
// src/routes/api/users/+server.ts
export const GET: RequestHandler = async () => {
  throw new Error('Database connection failed');
  // ↑ Automatically captured and sent to Signals
};
```

### Manual Error Capture

```typescript
// src/routes/+page.server.ts
import { captureException, withScope } from '@helpgrid/sveltekit';

export const load: PageServerLoad = async ({ locals }) => {
  try {
    const user = await db.getUser(locals.user.id);
    return { user };
  } catch (error) {
    withScope((scope) => {
      scope.setTag('action', 'load');
      scope.setUser({ id: locals.user.id });
      captureException(error);
    });

    throw error;
  }
};
```

### Manual Message Capture

```typescript
import { captureMessage } from '@helpgrid/sveltekit';

export const load: PageServerLoad = async () => {
  captureMessage('Page loaded successfully', 'info', {
    tags: { page: 'dashboard' }
  });
};
```

### Scope Management

Scopes allow you to add context to errors:

```typescript
import { withScope } from '@helpgrid/sveltekit';

withScope((scope) => {
  scope.setTag('feature', 'checkout');
  scope.setTag('status', 'in_progress');
  scope.setExtra('cart_id', '12345');
  scope.setUser({ id: 'user_123', email: 'user@example.com' });

  captureException(new Error('Payment failed'));
});
```

### Breadcrumbs

Track user actions leading up to errors:

```typescript
import { addBreadcrumb, captureException } from '@helpgrid/sveltekit';

export const actions = {
  checkout: async ({ request, locals }) => {
    try {
      const data = await request.formData();

      addBreadcrumb('User initiated checkout', 'action');

      // Validate data
      addBreadcrumb('Cart validation passed', 'validation');

      // Process payment
      const payment = await processPayment(data);

      addBreadcrumb('Payment processed', 'payment');

      return { success: true };
    } catch (error) {
      captureException(error);
      // Breadcrumbs automatically included with error
      throw error;
    }
  }
};
```

## Configuration

### signalsHandle Options

```typescript
signalsHandle({
  // Required
  apiKey: 'your-api-key',

  // Optional
  endpoint: 'https://helpgrid.dev/api/signals/ingest',
  environment: 'production',
  release: '1.0.0',
  sampleRate: 0.1, // 10% sampling
  maxBreadcrumbs: 100,

  // Ignore specific routes
  ignoreRoutes: [
    '/health',
    '/api/signals/ingest',
    '/api/cron/*'
  ],

  // Modify events before sending
  beforeSend: (event, { locals, request, url }) => {
    // Skip sensitive routes
    if (url.pathname.includes('/admin')) {
      return null;
    }

    // Add user context
    if (locals.user) {
      event.user = {
        id: locals.user.id,
        email: locals.user.email
      };
    }

    // Scrub sensitive headers
    if (event.request?.headers) {
      delete event.request.headers.authorization;
      delete event.request.headers.cookie;
    }

    return event;
  }
});
```

## Features

- ✅ Automatic error capture via `handleError`
- ✅ Request context tracking (method, URL, route)
- ✅ User context tracking
- ✅ Breadcrumb trail
- ✅ Manual error/message capture
- ✅ Scope management for adding context
- ✅ Route filtering to ignore specific paths
- ✅ Event filtering and sampling
- ✅ Event modification via `beforeSend` hook

## User Context

Automatically capture user information with errors:

```typescript
// In your hooks.server.ts load function
if (event.locals.user) {
  const scope = getScope();
  scope.setUser({
    id: event.locals.user.id,
    email: event.locals.user.email,
    username: event.locals.user.username
  });
}
```

## Request Context

Request information is automatically captured:

- HTTP method
- Request URL and pathname
- Route ID
- Response status code
- Query parameters (for non-GET requests)

## Error Filtering

Ignore specific error patterns:

```typescript
signalsHandle({
  apiKey: 'your-api-key',
  ignoreErrors: [
    'NetworkError',
    /^Cannot find module/,
    'AbortError'
  ]
});
```

## Performance Monitoring

Track slow requests with logging:

```typescript
// src/lib/server/logger.ts
export function createLogger(context = {}) {
  return {
    info: (msg, extra) => {
      console.log(JSON.stringify({
        level: 'info',
        message: msg,
        timestamp: new Date().toISOString(),
        ...context,
        ...extra
      }));
    }
  };
}

// src/hooks.server.ts
const logger = createLogger();

export const handle = sequence(
  async ({ event, resolve }) => {
    const startTime = Date.now();

    try {
      const response = await resolve(event);
      const duration = Date.now() - startTime;

      if (duration > 1000) {
        logger.info('Slow request', {
          route: event.route.id,
          duration,
          method: event.request.method
        });
      }

      return response;
    } catch (error) {
      const duration = Date.now() - startTime;
      logger.info('Request error', {
        route: event.route.id,
        duration,
        error: error instanceof Error ? error.message : String(error)
      });

      throw error;
    }
  },

  signalsHandle({ apiKey: import.meta.env.VITE_HELPGRID_API_KEY })
);
```

## Development

```bash
pnpm install
pnpm build
pnpm test
```

## Compatibility

- SvelteKit 2.0+
- Cloudflare Workers compatible

## License

MIT