timonier-sdk
v0.1.0
Published
TypeScript/JavaScript SDK for Timonier CDP
Downloads
100
Readme
timonier-sdk
TypeScript/JavaScript SDK for Timonier CDP. Track customer events, identify users, and record page views with a simple, type-safe API.
Features
- TypeScript-first with full type definitions
- Automatic retry with exponential backoff (5xx and network errors)
- Rate limit handling with
retry-afterheader support - Configurable request timeout (default 10s)
- Auto-generated
message_id(UUID v4) for event deduplication - Batch helper with auto-flush (size threshold + interval)
- Zero external dependencies (uses native
fetch) - ESM and CJS dual output
Requirements
- Node.js 18+ (or any runtime with global
fetchandcrypto.randomUUID)
Installation
npm install timonier-sdkQuick Start
import { Timonier } from "timonier-sdk";
const client = new Timonier({
apiKey: "your-api-key",
});
// Identify a customer
await client.identify({
customerId: "user-123",
traits: { email: "[email protected]", name: "Jane Doe" },
});
// Track an event
await client.track({
customerId: "user-123",
event: "Button Clicked",
properties: { button: "signup", page: "/pricing" },
});
// Track a page view
await client.page({
customerId: "user-123",
url: "https://example.com/pricing",
title: "Pricing",
referrer: "https://google.com",
});Configuration
const client = new Timonier({
// Required
apiKey: "your-api-key",
// Optional
host: "https://cdp.timonier.eu", // API base URL
timeout: 10_000, // Request timeout in ms
maxRetries: 3, // Max retries on 5xx/network errors
flushAt: 100, // Auto-flush batch queue at N items
flushInterval: 5_000, // Auto-flush interval in ms
fetchFn: fetch, // Custom fetch implementation
});API
client.identify(params)
Create or update a customer profile.
await client.identify({
customerId: "user-123",
traits: {
email: "[email protected]",
name: "Jane Doe",
plan: "pro",
},
});Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| customerId | string | Yes | Unique customer ID (max 255 chars) |
| traits | Record<string, unknown> | No | Customer attributes |
client.track(params)
Track a custom event.
await client.track({
customerId: "user-123",
event: "Purchase Completed",
properties: { amount: 49.99, currency: "USD" },
timestamp: new Date("2026-01-15T10:30:00Z"),
});Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| customerId | string | One of customerId or anonymousId | Known customer ID |
| anonymousId | string | One of customerId or anonymousId | Anonymous visitor ID |
| event | string | Yes | Event name (max 100 chars) |
| properties | Record<string, unknown> | No | Event properties |
| context | Record<string, unknown> | No | Contextual data (user agent, IP, etc.) |
| timestamp | Date | No | Event time (defaults to server time) |
| messageId | string | No | Deduplication ID (auto-generated if omitted) |
client.page(params)
Track a page view.
await client.page({
anonymousId: "anon-456",
url: "https://example.com/blog/post-1",
title: "Blog Post 1",
referrer: "https://google.com",
});Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| customerId | string | One of customerId or anonymousId | Known customer ID |
| anonymousId | string | One of customerId or anonymousId | Anonymous visitor ID |
| url | string | Yes | Page URL (max 2048 chars) |
| title | string | No | Page title (max 500 chars) |
| referrer | string | No | Referrer URL (max 2048 chars) |
| properties | Record<string, unknown> | No | Additional properties |
| context | Record<string, unknown> | No | Contextual data |
| timestamp | Date | No | Event time |
| messageId | string | No | Deduplication ID (auto-generated if omitted) |
client.batch(items)
Send multiple operations in a single request (max 100 items).
const result = await client.batch([
{ type: "identify", customer_id: "user-1", traits: { name: "Jane" } },
{ type: "track", customer_id: "user-1", event: "Signup" },
{ type: "page", customer_id: "user-1", url: "https://example.com" },
]);
console.log(result.accepted); // number of accepted items
console.log(result.rejected); // number of rejected itemsAuto-Batching
Queue items for automatic batching:
// Items are queued and auto-flushed when reaching flushAt (default 100)
// or every flushInterval (default 5s)
client.enqueue({ type: "track", customer_id: "user-1", event: "Click" });
client.enqueue({ type: "track", customer_id: "user-2", event: "Click" });
// Manually flush the queue
await client.flush();
// Flush remaining items and stop the timer (call before process exit)
await client.shutdown();Error Handling
The SDK throws typed errors for different failure scenarios:
import {
AuthenticationError,
InputValidationError,
RateLimitError,
ServerError,
ValidationError,
} from "timonier-sdk";
try {
await client.track({ customerId: "user-1", event: "test" });
} catch (err) {
if (err instanceof InputValidationError) {
// Client-side validation failed (before network call)
console.error(err.field, err.message);
} else if (err instanceof ValidationError) {
// Server returned 400
console.error(err.body);
} else if (err instanceof AuthenticationError) {
// Server returned 401 - invalid API key
console.error(err.body);
} else if (err instanceof RateLimitError) {
// Server returned 429
console.error("Retry after", err.retryAfter, "seconds");
} else if (err instanceof ServerError) {
// Server returned 5xx (after all retries exhausted)
console.error(err.status, err.body);
}
}Examples
Express Middleware
import { Timonier } from "timonier-sdk";
const client = new Timonier({ apiKey: process.env.TIMONIER_API_KEY! });
app.post("/api/checkout", async (req, res) => {
await client.track({
customerId: req.user.id,
event: "Checkout Completed",
properties: { total: req.body.total },
});
res.json({ ok: true });
});
process.on("SIGTERM", async () => {
await client.shutdown();
process.exit(0);
});Next.js Server Action
"use server";
import { Timonier } from "timonier-sdk";
const client = new Timonier({ apiKey: process.env.TIMONIER_API_KEY! });
export async function trackSignup(userId: string) {
await client.identify({
customerId: userId,
traits: { signedUpAt: new Date().toISOString() },
});
await client.track({
customerId: userId,
event: "Signup Completed",
});
}License
MIT
