# Node.js SDK

`@cohorly/node` is the server-side Node.js SDK. The API mirrors the official `mixpanel` npm library: stateless, `distinct_id` passed explicitly on every call, optional Node-style callbacks plus first-class promises. Node 18+, zero runtime dependencies.

## Install

```bash
pnpm add @cohorly/node
```

## Initialize

```typescript
import Cohorly from "@cohorly/node";

const cohorly = Cohorly.init("YOUR_PROJECT_TOKEN", {
  host: "https://cohorly-service.velloalabs.com", // your Cohorly server
});

// distinct_id is required (server-side style)
cohorly.track("signed_up", { distinct_id: "user-13793", plan: "premium" });

// Profile updates (sent immediately via /engage)
cohorly.people.set("user-13793", { $email: "ada@example.com", plan: "free" });

// Link ids after signup
cohorly.alias("user-13793", "anonymous-abc");

// Before process exit: stop the timer + final flush (never throws)
process.on("SIGTERM", async () => {
  await cohorly.shutdown();
  process.exit(0);
});
```

Events are queued in memory and delivered in batches: auto-flush every
5s, or as soon as 20 events accumulate (server cap 500 per request).
The flush timer is `unref`'d, so it never keeps your process alive.

## API

| Member                                                    | Notes                                                                                                          |
| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `Cohorly.init(token, config)`                             | Config: `host`, `flushIntervalMs` (5000), `batchSize` (20), `debug`, `maxQueueSize` (1000), `maxRetryDelayMs`. |
| `track(event, properties, callback?)`                     | Queue an event. Stamps `time`, `$insert_id`, `$lib`, `$lib_version`; your values win.                          |
| `trackBatch(events)` / `import(event, time, props)`       | Bulk queueing / historical events with an explicit timestamp (Date or unix ms). `importBatch` for arrays.      |
| `people.set / set_once / increment / unset / delete_user` | Mirror mixpanel-node people API, mapped to /engage ops. camelCase aliases (`setOnce`, `deleteUser`) exist.     |
| `alias(distinctId, alias)`                                | POST /alias.                                                                                                   |
| `flush()` / `shutdown()`                                  | Force-drain now / stop the timer and final-flush (never rejects).                                              |

## Delivery and retries

The queue survives transient failures: 429/5xx/network errors are
retried with exponential backoff (2s base, doubling, 10 min cap,
+/-20% jitter) honoring `Retry-After`; a 413 halves the
batch size; a 400 drops the rejected batch; a 401 keeps the queue at
max backoff. The queue holds at most 1000 events (oldest dropped
first). The project token travels as the `X-Cohorly-Token`
header.

Building with NestJS? Use `@cohorly/nest`, a dynamic module
wrapping this SDK.
