npm package: @notify.partners/web-sdk
Description: Notify Partners Web SDK for browser push notifications
Latest version: 1.0.0

# Notify Partners Web SDK

Push notification SDK for browsers with Web Push and Service Worker support.

## Features

- **Automatic lifecycle tracking** — no manual foreground/background calls needed
- **Debounced updates** — rapid `setExternalId`/`setTags` calls coalesce into one request
- **Exponential backoff retry** — 3 policies (INIT / UPDATE / EVENT) for reliability
- **Input validation** — catches configuration errors early
- **Structured errors** — `SdkError` with typed error discrimination
- **Tree-shakeable ESM** + UMD bundle for CDN usage
- **TypeScript-first** — full type definitions included

## Requirements

- Modern browser with Service Worker and Push API support
- HTTPS (required for Service Workers)
- VAPID key pair from the Notify Partners dashboard

## Installation

### npm

```bash
npm install @notify.partners/web-sdk
```

### CDN

```html
<script src="https://cdn.jsdelivr.net/npm/@notify.partners/web-sdk/dist/notify-partners-sdk.umd.js"></script>
```

## Quick Start

### 1. Copy the Service Worker

Copy `node_modules/@notify.partners/web-sdk/dist/notify-partners-sw.js` to the root of your website (so it's accessible at `/notify-partners-sw.js`).

### 2. Initialize the SDK

```typescript
import { NotifyPartnersSDK } from '@notify.partners/web-sdk';

NotifyPartnersSDK.initialize({
  appId: 'your-app-id',
  vapidKey: 'your-vapid-public-key',
});
```

**That's it.** The SDK automatically handles:
- Notification permission request
- Service Worker registration and push subscription
- Lifecycle tracking (page visible / hidden / closed)
- Periodic device info updates

### 3. Set user properties (optional)

```typescript
NotifyPartnersSDK.setExternalId('user-123');
NotifyPartnersSDK.setTags({ plan: 'premium', locale: 'en' });
```

## Advanced Configuration

```typescript
import { NotifyPartnersSDK } from '@notify.partners/web-sdk';

NotifyPartnersSDK.initialize({
  appId: 'your-app-id',
  vapidKey: 'your-vapid-public-key',
  externalId: 'user-123',
  tags: { plan: 'premium' },
  baseUrl: 'https://custom-api.example.com/api/v3',
  serviceWorkerPath: '/custom-sw.js',
  debug: true,
  listener: {
    onInitialized(instanceId) {
      console.log('SDK ready:', instanceId);
    },
    onInitializationFailed(error) {
      console.error('SDK failed:', error.type, error.message);
    },
    onMessageReceived(msgId, title, body, data) {
      console.log('Push received:', title, body);
    },
  },
});
```

## API Reference

### `NotifyPartnersSDK`

| Method | Description |
|--------|-------------|
| `initialize(config)` | Initialize the SDK. Fire-and-forget — errors go to the listener. |
| `shutdown()` | Release all resources. Allows re-initialization. |
| `setExternalId(id)` | Set external user ID (max 256 chars). Debounced. |
| `setTags(tags)` | Set tags for segmentation (max 50). Debounced. |
| `isInitialized()` | Returns `true` if the SDK is ready. |
| `getInstanceId()` | Returns the server-assigned instance ID. |
| `setListener(listener)` | Replace the lifecycle listener. |

### `NotifyPartnersConfig`

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `appId` | `string` | *required* | Application ID from the dashboard |
| `vapidKey` | `string` | *required* | VAPID public key |
| `externalId` | `string?` | — | External user ID (max 256 chars) |
| `tags` | `Record<string,string>?` | — | User tags (max 50, key ≤128, value ≤256) |
| `baseUrl` | `string?` | `https://api.notify.partners/api/v3` | API base URL |
| `serviceWorkerPath` | `string?` | `/notify-partners-sw.js` | Path to the SW file |
| `debug` | `boolean?` | `false` | Enable debug logging |
| `listener` | `NotifyPartnersListener?` | — | Lifecycle callbacks |

### `SdkError`

Structured error with a `type` discriminant for `switch`-based handling:

```typescript
import { SdkError } from '@notify.partners/web-sdk';

// In your listener:
onInitializationFailed(error) {
  switch (error.type) {
    case 'ConfigurationError':
      console.error('Bad config:', error.message);
      break;
    case 'NetworkError':
    case 'TimeoutError':
      console.error('Network issue, will retry');
      break;
    case 'ServerError':
      console.error('Server error:', error.httpCode);
      break;
    case 'ClientError':
      console.error('Client error:', error.httpCode, error.body);
      break;
  }
}
```

### CDN / Script Tag

```html
<script src="https://cdn.jsdelivr.net/npm/@notify.partners/web-sdk/dist/notify-partners-sdk.umd.js"></script>
<script>
  NotifyPartners.NotifyPartnersSDK.initialize({
    appId: 'your-app-id',
    vapidKey: 'your-vapid-public-key',
  });
</script>
```

## Service Worker Setup

The service worker file must be served from the root of your domain (or the scope you want to cover). It handles:

- Showing push notifications
- Reporting delivery and click events to the backend
- Opening URLs when notifications are clicked
- Forwarding push payloads to the main thread

If using a bundler, copy the file during your build:

```bash
# Example with cp
cp node_modules/@notify.partners/web-sdk/dist/notify-partners-sw.js public/
```

## License

[MIT](LICENSE)