npm package: @gumlethq/event-router-client
Description: Node.js client library for Event Router Server - Segment.js compatible API
Author: Gumlet Pte. Ltd.
Latest version: 1.0.7

# Event Router Client

A Node.js client library for Event Router Server with a Segment.js-compatible API. Send analytics events with automatic batching, retries, and queue management.

## Installation

```bash
npm install @gumlet/event-router-client
```

## Quick Start

```typescript
import { Analytics } from '@gumlet/event-router-client';

// Initialize the client
const analytics = new Analytics({
  host: 'http://localhost:3000',
  flushAt: 20,           // Flush after 20 events
  flushInterval: 10000   // Flush every 10 seconds
});

// Identify a user
analytics.identify({
  userId: 'user123',
  traits: {
    email: 'user@example.com',
    firstName: 'John',
    lastName: 'Doe'
  }
});

// Track an event
analytics.track({
  userId: 'user123',
  event: 'Button Clicked',
  properties: {
    buttonId: 'signup-cta',
    page: 'homepage'
  }
});

// Gracefully shutdown when your app exits
process.on('SIGTERM', async () => {
  await analytics.shutdown();
  process.exit(0);
});
```

## API Reference

### Constructor

```typescript
const analytics = new Analytics({
  host: string;              // Required: Event router server URL
  flushAt?: number;          // Optional: Flush after N events (default: 20)
  flushInterval?: number;    // Optional: Flush every N ms (default: 10000)
  maxQueueSize?: number;     // Optional: Max queue size (default: 1000)
  timeout?: number;          // Optional: Request timeout (default: 10000)
  retryCount?: number;       // Optional: Retry attempts (default: 3)
  enable?: boolean;          // Optional: Enable/disable tracking (default: true)
});
```

### Methods

#### identify()

Identify a user with traits. You must provide either `userId` or `anonymousId`.

```typescript
analytics.identify(payload: {
  userId?: string;
  anonymousId?: string;
  traits?: Traits;
  context?: Context;
  timestamp?: Date;
  integrations?: Record<string, boolean>;
}, callback?: Callback): void;
```

**Example:**

```typescript
// Identify with userId
analytics.identify({
  userId: 'user123',
  traits: {
    email: 'user@example.com',
    firstName: 'John',
    lastName: 'Doe',
    company: 'Acme Inc',
    phone: '+1234567890',
    createdAt: new Date()
  }
});

// Identify anonymous user
analytics.identify({
  anonymousId: '48d213bb-95c3-4f8d-af97-86b2b404dcfe',
  traits: {
    friends: 42
  }
});

// With context
analytics.identify({
  userId: 'user123',
  traits: { email: 'user@example.com' },
  context: {
    ip: '192.168.1.1',
    userAgent: 'Mozilla/5.0...'
  },
  timestamp: new Date()
});

// With callback
analytics.identify({
  userId: 'user123',
  traits: { email: 'user@example.com' }
}, (err) => {
  if (err) console.error('Failed to identify:', err);
});
```

#### track()

Track a custom event. You must provide either `userId` or `anonymousId`, and an event name.

```typescript
analytics.track(payload: {
  userId?: string;
  anonymousId?: string;
  event: string;
  properties?: Properties;
  context?: Context;
  timestamp?: Date;
  integrations?: Record<string, boolean>;
}, callback?: Callback): void;
```

**Example:**

```typescript
// Track with userId
analytics.track({
  userId: 'user123',
  event: 'Item Purchased',
  properties: {
    revenue: 39.95,
    shippingMethod: '2-day',
    productId: 'prod_123'
  }
});

// Track anonymous event
analytics.track({
  anonymousId: '48d213bb-95c3-4f8d-af97-86b2b404dcfe',
  event: 'Item Purchased',
  properties: {
    revenue: 39.95
  }
});

// With context
analytics.track({
  userId: 'user123',
  event: 'Button Clicked',
  properties: { buttonId: 'signup' },
  context: {
    page: '/landing'
  },
  timestamp: new Date()
});

// With callback
analytics.track({
  userId: 'user123',
  event: 'Video Watched',
  properties: { videoId: 'abc' }
}, (err) => {
  if (err) console.error('Failed to track:', err);
});

// With selective integrations
analytics.track({
  userId: 'user123',
  event: 'Membership Upgraded',
  integrations: {
    'All': false,
    'Vero': true,
    'Google Analytics': false
  }
});
```

#### page()

Track a page view. You must provide either `userId` or `anonymousId`.

```typescript
analytics.page(payload: {
  userId?: string;
  anonymousId?: string;
  category?: string;
  name?: string;
  properties?: Properties;
  context?: Context;
  timestamp?: Date;
  integrations?: Record<string, boolean>;
}, callback?: Callback): void;
```

**Example:**

```typescript
// Simple page view
analytics.page({
  userId: 'user123'
});

// With name
analytics.page({
  userId: 'user123',
  name: 'Home'
});

// With category and name
analytics.page({
  userId: 'user123',
  category: 'Docs',
  name: 'Node.js Library',
  properties: {
    url: 'https://segment.com/docs/connections/sources/catalog/libraries/node',
    path: '/docs/connections/sources/catalog/libraries/node/',
    title: 'Node.js Library - Segment',
    referrer: 'https://github.com/segmentio/analytics-node'
  }
});
```

#### screen()

Track a screen view (for mobile apps). You must provide either `userId` or `anonymousId`.

```typescript
analytics.screen(payload: {
  userId?: string;
  anonymousId?: string;
  category?: string;
  name?: string;
  properties?: Properties;
  context?: Context;
  timestamp?: Date;
  integrations?: Record<string, boolean>;
}, callback?: Callback): void;
```

**Example:**

```typescript
analytics.screen({
  userId: 'user123',
  category: 'Main',
  name: 'Home Screen',
  properties: {
    screenWidth: 1920,
    screenHeight: 1080
  }
});
```

#### group()

Associate a user with a group or company. You must provide either `userId` or `anonymousId`, and a `groupId`.

```typescript
analytics.group(payload: {
  userId?: string;
  anonymousId?: string;
  groupId: string;
  traits?: Traits;
  context?: Context;
  timestamp?: Date;
  integrations?: Record<string, boolean>;
}, callback?: Callback): void;
```

**Example:**

```typescript
analytics.group({
  userId: 'user123',
  groupId: '56',
  traits: {
    name: 'Initech',
    description: 'Accounting Software',
    employees: 100,
    plan: 'Enterprise'
  }
});
```

#### alias()

Link two user identities together. This allows you to associate an anonymous user with an identified user.

```typescript
analytics.alias(payload: {
  userId: string;
  previousId: string;
  context?: Context;
  timestamp?: Date;
  integrations?: Record<string, boolean>;
}, callback?: Callback): void;
```

**Example:**

```typescript
// Link anonymous ID to user ID after signup/login
analytics.alias({
  previousId: 'anonymous_user',
  userId: 'identified@example.com'
});
```

#### flush()

Manually flush all queued events.

```typescript
await analytics.flush();
```

**Example:**

```typescript
// Flush before critical operations
await analytics.flush();
```

#### shutdown()

Gracefully shutdown the client (flushes queue and stops timers).

```typescript
await analytics.shutdown();
```

**Example:**

```typescript
// Clean shutdown
process.on('SIGTERM', async () => {
  await analytics.shutdown();
  process.exit(0);
});
```

#### enable() / disable()

Enable or disable event tracking.

```typescript
analytics.disable();  // Stop tracking
analytics.enable();   // Resume tracking
```

**Example:**

```typescript
// Disable in development
if (process.env.NODE_ENV === 'development') {
  analytics.disable();
}
```

## Advanced Usage

### Custom Context

Add custom context to all events:

```typescript
analytics.identify({
  userId: 'user123',
  traits: {
    email: 'user@example.com'
  },
  context: {
    app: {
      name: 'My App',
      version: '1.0.0'
    },
    device: {
      type: 'mobile',
      model: 'iPhone 13'
    },
    ip: '192.168.1.1',
    userAgent: 'Mozilla/5.0...'
  }
});
```

### Error Handling

```typescript
analytics.track({
  userId: 'user123',
  event: 'Purchase',
  properties: { amount: 100 }
}, (err) => {
  if (err) {
    console.error('Failed to track purchase:', err);
    // Implement fallback logic
  } else {
    console.log('Purchase tracked successfully');
  }
});
```

### Batching Configuration

```typescript
const analytics = new Analytics({
  host: 'http://localhost:3000',
  flushAt: 50,           // Batch 50 events before sending
  flushInterval: 30000,  // Or flush every 30 seconds
  maxQueueSize: 5000     // Max 5000 events in queue
});
```

### High-Volume Applications

```typescript
const analytics = new Analytics({
  host: 'http://localhost:3000',
  flushAt: 100,          // Larger batches
  flushInterval: 5000,   // Flush more frequently
  timeout: 30000,        // Longer timeout for large batches
  retryCount: 5          // More retries
});
```

### Disable in Tests

```typescript
const analytics = new Analytics({
  host: 'http://localhost:3000',
  enable: process.env.NODE_ENV !== 'test'
});
```

## TypeScript Support

The library is written in TypeScript and provides full type definitions:

```typescript
import { Analytics, Traits, Properties, Options } from '@gumlet/event-router-client';

const traits: Traits = {
  email: 'user@example.com',
  firstName: 'John',
  lastName: 'Doe'
};

const properties: Properties = {
  productId: 'prod_123',
  price: 99.99
};

const options: Options = {
  timestamp: new Date(),
  context: {
    ip: '192.168.1.1'
  }
};
```

## Complete Example

```typescript
import { Analytics } from '@gumlet/event-router-client';

// Initialize
const analytics = new Analytics({
  host: process.env.EVENT_ROUTER_URL || 'http://localhost:3000',
  flushAt: 20,
  flushInterval: 10000
});

// User signup flow
async function handleSignup(user: any) {
  // Identify the user
  analytics.identify({
    userId: user.id,
    traits: {
      email: user.email,
      firstName: user.firstName,
      lastName: user.lastName,
      createdAt: new Date()
    }
  });

  // Track signup event
  analytics.track({
    userId: user.id,
    event: 'User Signed Up',
    properties: {
      method: 'email',
      plan: user.plan
    }
  });

  // Associate with company
  if (user.companyId) {
    analytics.group({
      userId: user.id,
      groupId: user.companyId,
      traits: {
        name: user.companyName,
        plan: user.companyPlan
      }
    });
  }

  // Flush immediately for important events
  await analytics.flush();
}

// User activity tracking
function trackPageView(userId: string, pageName: string) {
  analytics.page({
    userId,
    name: pageName,
    properties: {
      url: window.location.href,
      referrer: document.referrer,
      path: window.location.pathname
    }
  });
}

// Anonymous user tracking
function trackAnonymousEvent(anonymousId: string, event: string, properties: any) {
  analytics.track({
    anonymousId,
    event,
    properties
  });
}

// Alias anonymous user after signup
function linkUserIdentities(anonymousId: string, userId: string) {
  analytics.alias({
    previousId: anonymousId,
    userId
  });
}

// Graceful shutdown
process.on('SIGTERM', async () => {
  console.log('Shutting down...');
  await analytics.shutdown();
  process.exit(0);
});
```

## Comparison with Segment.js

This library provides an API very similar to Segment.js:

| Feature | Segment.js | Event Router Client |
|---------|-----------|---------------------|
| identify() | ✅ | ✅ |
| track() | ✅ | ✅ |
| page() | ✅ | ✅ |
| screen() | ✅ | ✅ |
| group() | ✅ | ✅ |
| alias() | ✅ | ✅ |
| Auto batching | ✅ | ✅ |
| Auto retries | ✅ | ✅ |
| TypeScript | ✅ | ✅ |
| Callbacks | ✅ | ✅ |
| Context | ✅ | ✅ |

## License

MIT