npm package: @staccats/sdk-js
Description: Official JavaScript/TypeScript SDK for integrating with the Staccats notification infrastructure platform.
Latest version: 0.11.0

# Staccats JavaScript/TypeScript SDK

Official JavaScript/TypeScript SDK for integrating with the Staccats notification infrastructure platform.

## Installation

```bash
npm install @staccats/sdk-js
```

or with yarn:

```bash
yarn add @staccats/sdk-js
```

or with bun:

```bash
bun add @staccats/sdk-js
```

## Quick Start

```typescript
import { Staccats } from '@staccats/sdk-js';

// Initialize the client
const client = new Staccats({
  apiKey: 'your-api-key-here',
  apiUrl: 'https://api.staccats.com' // optional, defaults to production
});

// Send a notification
const result = await client.notifications.send({
  event: 'welcome_email',
  userId: 'user_123',
  data: {
    name: 'John Doe',
    company: 'Acme Inc'
  }
});

console.log('Notification queued:', result.notificationId);
```

## Client-Side Usage

The SDK can be used in client-side applications (Vue, React, Angular, etc.) using **public API keys**. Public keys are safe to expose in frontend code and have restricted permissions.

### Public Keys vs Secret Keys

- **Secret Keys (`sk_...`)**: Full access, server-side only. Use these in Node.js, backend services, or serverless functions.
- **Public Keys (`pk_...`)**: Restricted access, client-side safe. Use these in Vue, React, Angular, or any frontend framework.

### Creating a Public Key

Public keys must be created through the dashboard (not via API). Once created, they can be safely used in client-side code.

### Frontend Framework Examples

#### Vue 3

```javascript
import { Staccats } from '@staccats/sdk-js';

// In your Vue component
const client = new Staccats({
  apiKey: 'pk_your_public_key_here',
  apiUrl: 'https://api.staccats.com'
});

// Send notification
await client.notifications.send({
  event: 'welcome_email',
  userId: 'user_123',
  data: { name: 'John Doe' }
});

// Get user notifications
const notifications = await client.logs.getUserNotifications('user_123');
```

#### React

```javascript
import { Staccats } from '@staccats/sdk-js';
import { useEffect, useState } from 'react';

function NotificationComponent({ userId }) {
  const [client] = useState(() => new Staccats({
    apiKey: 'pk_your_public_key_here',
    apiUrl: 'https://api.staccats.com'
  }));

  useEffect(() => {
    async function loadNotifications() {
      const notifications = await client.logs.getUserNotifications(userId);
      console.log('Notifications:', notifications);
    }
    loadNotifications();
  }, [userId]);

  return (
    <div>
      {/* Your component */}
    </div>
  );
}
```

#### Angular

```typescript
import { Injectable } from '@angular/core';
import { Staccats } from '@staccats/sdk-js';

@Injectable({
  providedIn: 'root'
})
export class NotificationService {
  private client: Staccats;

  constructor() {
    this.client = new Staccats({
      apiKey: 'pk_your_public_key_here',
      apiUrl: 'https://api.staccats.com'
    });
  }

  async sendNotification(event: string, userId: string, data: any) {
    return await this.client.notifications.send({
      event,
      userId,
      data
    });
  }

  async getUserNotifications(userId: string) {
    return await this.client.logs.getUserNotifications(userId);
  }
}
```

### Public Key Permissions

Public keys have restricted access by default:

**Allowed:**
- `POST /notify` - Send notifications
- `GET /logs/users/:userId/notifications` - Get user's notifications
- `GET /logs/notifications/:id` - Get notification details

**Blocked:**
- All management APIs (events, templates, users, providers)
- Analytics endpoints
- Listing all notifications

### Security Best Practices

1. **Never expose secret keys** (`sk_...`) in client-side code
2. **Use public keys** (`pk_...`) for frontend applications
3. **Set appropriate rate limits** when creating public keys
4. **Monitor usage** through the dashboard
5. **Revoke compromised keys** immediately if needed

### Rate Limiting

Public keys are rate-limited by default (60 requests/minute). If you exceed the limit, you'll receive a `429 Too Many Requests` error. Adjust the rate limit when creating the public key based on your application's needs.

## Configuration

### Using Environment Variables

You can configure the SDK using environment variables:

```bash
STACCATS_API_KEY=your-api-key-here
STACCATS_API_URL=https://api.staccats.com  # optional
```

```typescript
import { Staccats } from '@staccats/sdk-js';

// API key will be read from STACCATS_API_KEY environment variable
const client = new Staccats({
  apiUrl: 'https://api.staccats.com' // optional
});
```

### Configuration Options

```typescript
interface StaccatsConfig {
  apiKey: string;           // Your Staccats API key (required)
  apiUrl?: string;           // Base URL (default: 'https://api.staccats.com')
  timeout?: number;          // Request timeout in ms (default: 30000)
  maxRetries?: number;       // Max retry attempts (default: 3)
}
```

## API Reference

### Notifications

#### Send Notification

Send a notification to a user.

```typescript
const result = await client.notifications.send({
  event: 'welcome_email',        // Event key (required)
  userId: 'user_123',            // User ID (optional if email provided)
  email: 'user@example.com',      // Email (optional if userId provided)
  data: {                         // Template variables (optional)
    name: 'John Doe',
    company: 'Acme Inc'
  }
});

// Returns: { notificationId: string, status: 'queued' }
```

### Events

Events define the types of notifications your app can send.

#### List Events

```typescript
const { events } = await client.events.list();
```

#### Get Event

```typescript
const { event } = await client.events.get('event-id');
```

#### Create Event

```typescript
const { event } = await client.events.create({
  key: 'password_reset',
  name: 'Password Reset'
});
```

#### Update Event

```typescript
const { event } = await client.events.update('event-id', {
  name: 'Updated Name'
});
```

#### Delete Event

```typescript
await client.events.delete('event-id');
```

### Templates

Templates define the email content for each event.

#### List Templates

```typescript
// List all templates
const { templates } = await client.templates.list();

// Filter by event
const { templates } = await client.templates.list({
  event_id: 'event-id'
});
```

#### Get Template

```typescript
const { template } = await client.templates.get('template-id');
```

#### Create Template

```typescript
const { template } = await client.templates.create({
  event_id: 'event-id',
  channel: 'email',
  locale: 'en-US',
  subject: 'Welcome {{name}}!',
  body: '<h1>Hello {{name}}</h1><p>Thanks for joining!</p>',
  is_active: true
});
```

#### Update Template

```typescript
const { template } = await client.templates.update('template-id', {
  subject: 'Updated Subject',
  body: 'Updated body',
  is_active: false
});
```

#### Delete Template

```typescript
await client.templates.delete('template-id');
```

### Users

Users are the recipients of notifications.

#### List Users

```typescript
const { users } = await client.users.list();
```

#### Get User

```typescript
const { user } = await client.users.get('user-id');
```

#### Create User

```typescript
const { user } = await client.users.create({
  external_user_id: 'user_123',
  email: 'user@example.com',
  metadata: {
    name: 'John Doe',
    company: 'Acme Inc'
  }
});
```

#### Update User

```typescript
const { user } = await client.users.update('user-id', {
  email: 'newemail@example.com',
  metadata: {
    name: 'Jane Doe'
  }
});
```

#### Delete User

```typescript
await client.users.delete('user-id');
```

### Providers

Providers configure email delivery services (Brevo, SendGrid, etc.).

#### List Providers

```typescript
// List all providers
const { providers } = await client.providers.list();

// Filter by channel
const { providers } = await client.providers.list({
  channel: 'email'
});
```

#### Get Provider

```typescript
const { provider } = await client.providers.get('provider-id');
```

#### Create Provider

```typescript
const { provider } = await client.providers.create({
  channel: 'email',
  provider_type: 'brevo',
  config: {
    api_key: 'your-api-key',
    from_email: 'noreply@yourdomain.com'
  },
  is_primary: true
});
```

#### Update Provider

```typescript
const { provider } = await client.providers.update('provider-id', {
  config: {
    api_key: 'new-api-key'
  },
  is_primary: false
});
```

#### Delete Provider

```typescript
await client.providers.delete('provider-id');
```

### Logs

Query notification history and delivery status.

#### Get User Notifications

```typescript
const { notifications } = await client.logs.getUserNotifications('user_123');
```

#### Get Notification Detail

```typescript
const detail = await client.logs.getNotificationDetail('notification-id');
// Returns: { notification: Notification, attempts: NotificationAttempt[] }
```

#### List Notifications

```typescript
// List all notifications
const { notifications } = await client.logs.list();

// Filter by event and status
const { notifications } = await client.logs.list({
  event: 'welcome_email',
  status: 'completed',
  limit: 50,
  offset: 0
});
```

## Error Handling

The SDK provides custom error classes for better error handling:

```typescript
import {
  StaccatsError,
  StaccatsAPIError,
  StaccatsAuthenticationError,
  StaccatsNotFoundError
} from '@staccats/sdk-js';

try {
  await client.notifications.send({ event: 'test', userId: 'user_123' });
} catch (error) {
  if (error instanceof StaccatsAuthenticationError) {
    console.error('Invalid API key');
  } else if (error instanceof StaccatsNotFoundError) {
    console.error('Resource not found');
  } else if (error instanceof StaccatsAPIError) {
    console.error(`API Error: ${error.message} (${error.status})`);
  } else {
    console.error('Unknown error:', error);
  }
}
```

### Error Types

- **StaccatsError** - Base error class for all SDK errors
- **StaccatsAPIError** - API request failed (includes `status`, `statusText`, `response`)
- **StaccatsAuthenticationError** - Authentication failed (401)
- **StaccatsNotFoundError** - Resource not found (404)

## Retry Logic

The SDK automatically retries failed requests with exponential backoff:

- **Server errors (5xx)**: Retried up to `maxRetries` times
- **Rate limits (429)**: Retried with exponential backoff
- **Client errors (4xx)**: Not retried (except 429)

## Examples

### Node.js / Bun

```typescript
import { Staccats } from '@staccats/sdk-js';

const client = new Staccats({
  apiKey: process.env.STACCATS_API_KEY!,
  apiUrl: process.env.STACCATS_API_URL || 'https://api.staccats.com'
});

// Send welcome email
async function sendWelcomeEmail(userId: string, userName: string) {
  try {
    const result = await client.notifications.send({
      event: 'welcome_email',
      userId,
      data: { name: userName }
    });
    console.log('Welcome email queued:', result.notificationId);
  } catch (error) {
    console.error('Failed to send welcome email:', error);
  }
}
```

### TypeScript with Type Safety

```typescript
import { Staccats, type Event, type Notification } from '@staccats/sdk-js';

const client = new Staccats({ apiKey: 'your-key' });

// Full type safety
const events: Event[] = (await client.events.list()).events;
const notifications: Notification[] = (await client.logs.getUserNotifications('user_123')).notifications;
```

### Error Handling Example

```typescript
import { Staccats, StaccatsAPIError } from '@staccats/sdk-js';

const client = new Staccats({ apiKey: 'your-key' });

async function sendNotificationSafely() {
  try {
    const result = await client.notifications.send({
      event: 'test_event',
      userId: 'user_123'
    });
    return result;
  } catch (error) {
    if (error instanceof StaccatsAPIError) {
      console.error(`API Error ${error.status}: ${error.message}`);
      if (error.response) {
        console.error('Response:', error.response);
      }
    }
    throw error;
  }
}
```

## Runtime Compatibility

The SDK works with:

- **Node.js** 18+ (using native `fetch`)
- **Bun** (using native `fetch`)
- **Deno** (using native `fetch`)
- **Edge runtimes** (Cloudflare Workers, Vercel Edge Functions, etc.)

## TypeScript Support

Full TypeScript support is included. All types are exported:

```typescript
import type {
  Event,
  Template,
  User,
  Provider,
  Notification,
  NotificationDetail,
  SendNotificationRequest,
  CreateEventRequest,
  // ... and more
} from '@staccats/sdk-js';
```

## License

MIT

## Support

For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/staccats/staccats).