<br>
<p align="center">
  <img src="https://cdn.xreos.co/webasset/images/grain_logomark_dark.svg" alt="Grain" width="150"/>
</p>

<h1 align="center">Grain Analytics Web SDK</h1>

<p align="center">
  Lightweight TypeScript SDK for event tracking and remote configuration via <a href="https://grainql.com">Grain</a>.<br/>
  Works in browsers, Node.js, and any JavaScript runtime.
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/@grainql/analytics-web"><img src="https://img.shields.io/npm/v/@grainql/analytics-web" alt="npm version" /></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" /></a>
</p>

---

> **For browser analytics with heatmaps, snapshots, and consent management, use [`@grainql/tag`](https://www.npmjs.com/package/@grainql/tag) instead.**
> This SDK is the right choice when you need **remote configuration** or need to **send events from servers and non-browser environments**.

## Installation

```bash
npm install @grainql/analytics-web
```

## Quick Start

### Server-Side / Node.js

```typescript
import { createGrainAnalytics } from '@grainql/analytics-web';

const grain = createGrainAnalytics({
  tenantId: 'your-tenant-id',
  authStrategy: 'SERVER_SIDE',
  secretKey: 'your-secret-key',
});

// Track server-side events
grain.track('order_completed', {
  order_id: 'ORD-123',
  total: 149.99,
  currency: 'USD',
});

// Track with an explicit user ID
grain.trackForUser('user-456', 'subscription_renewed', {
  plan: 'pro',
  period: 'annual',
});

// Flush before process exit
await grain.flush();
```

### Remote Configuration

```typescript
import { createGrainAnalytics } from '@grainql/analytics-web';

const grain = createGrainAnalytics({ tenantId: 'your-tenant-id' });

// Fetch remote config from Grain dashboard
await grain.fetchConfig();

// Read values
const heroText = grain.getConfig('hero_text');
const featureEnabled = grain.getConfig('new_feature') === 'true';

// Get all configs with fallback defaults
const allConfigs = grain.getAllConfigs();

// Listen for config changes
grain.onConfigChange((configs) => {
  console.log('Config updated:', configs);
});
```

### React (Remote Config Hooks)

```typescript
import { GrainProvider, useConfig, useTrack } from '@grainql/analytics-web/react';

function App() {
  return (
    <GrainProvider config={{ tenantId: 'your-tenant-id' }}>
      <HomePage />
    </GrainProvider>
  );
}

function HomePage() {
  const { value: heroText } = useConfig('hero_text');
  const track = useTrack();

  return (
    <div>
      <h1>{heroText || 'Welcome!'}</h1>
      <button onClick={() => track('cta_clicked')}>Get Started</button>
    </div>
  );
}
```

## Configuration

```typescript
createGrainAnalytics({
  tenantId: 'your-tenant-id',             // Required
  apiUrl: 'https://clientapis.grainql.com', // Default
  debug: false,                            // Enable debug logging
  // Authentication
  authStrategy: 'NONE',                   // 'NONE' | 'SERVER_SIDE' | 'JWT'
  secretKey: undefined,                    // For SERVER_SIDE auth
  authProvider: undefined,                 // For JWT auth
  // Batching
  batchSize: 50,                           // Events per batch
  flushInterval: 5000,                     // Flush interval in ms
  retryAttempts: 3,                        // Retry attempts on failure
  // Remote Config
  defaultConfigurations: {},               // Fallback values
  configRefreshInterval: 300000,           // Auto-refresh (5 min default)
  enableConfigCache: true,                 // Cache configs locally
  // Privacy
  consentMode: 'cookieless',              // 'cookieless' | 'gdpr-strict' | 'gdpr-opt-out'
});
```

## API Reference

### Event Tracking

```typescript
grain.track(eventName, properties?)                // Track with current user
grain.trackForUser(userId, eventName, properties?) // Track with explicit user
grain.flush()                                      // Flush pending events
```

### Identity

```typescript
grain.setUserId(userId)              // Set user identity
grain.getUserId()                    // Get current user ID
grain.getDeviceId()                  // Get device ID
grain.getSessionId()                 // Get session ID
```

### Remote Configuration

```typescript
grain.fetchConfig(options?)          // Fetch configs from API
grain.getConfig(key)                 // Get a single config value
grain.getAllConfigs()                 // Get all configs with defaults
grain.onConfigChange(callback)       // Listen for config changes
```

### Consent

```typescript
grain.grantConsent(categories?)      // Grant consent
grain.revokeConsent()                // Revoke consent
grain.hasConsent()                   // Check consent status
```

### Lifecycle

```typescript
grain.destroy()                      // Flush and cleanup
```

## When to Use Which SDK

| Use Case | SDK |
|----------|-----|
| Browser analytics, heatmaps, snapshots | [`@grainql/tag`](https://www.npmjs.com/package/@grainql/tag) |
| Script tag delivery (Cloudflare Workers) | [`@grainql/tag`](https://www.npmjs.com/package/@grainql/tag) |
| Remote configuration | `@grainql/analytics-web` |
| Server-side event tracking (Node.js) | `@grainql/analytics-web` |
| React config hooks (`useConfig`) | `@grainql/analytics-web/react` |
| Non-browser runtimes | `@grainql/analytics-web` |

## License

[MIT](LICENSE)
