TypeScript SDK
@tickr.gg/sdk is an isomorphic TypeScript client for the Tickr ingestion API. It works in Node 18+ and the browser with no Node-only imports; it relies on globalThis.fetch and globalThis.crypto. It’s the same client the Minecraft plugin bridge uses.
Install
npm install @tickr.gg/sdk
# or: pnpm add @tickr.gg/sdk
Quick start
import { TickrClient } from '@tickr.gg/sdk'
const tickr = new TickrClient({
serverKey: process.env.TICKR_SERVER_KEY!, // tickr_sk_…
})
// Events are queued and flushed in batches every 5s
// (idempotencyKey + ts are auto-filled when missing).
tickr.track({ name: 'boss_kill', category: 'pve', playerId: 'uuid-123', value: 1 })
tickr.track({
name: 'shop_purchase',
category: 'economy',
playerId: 'uuid-123',
value: 250,
properties: { item: 'diamond_sword', currency: 'coins' },
})
// Join/leave sessions.
tickr.session({ playerId: 'uuid-123', username: 'Steve', type: 'join', sessionId: 'sess-1' })
// Graceful exit: stops the flush timer and drains the queues.
process.on('SIGTERM', () => void tickr.shutdown())
Bridge usage (game server loop)
const tickr = new TickrClient({
serverKey: config.serverKey,
flushIntervalMs: 5000, // batch window
maxBatchSize: 50, // items per request
maxQueueSize: 10_000, // bound memory; oldest items dropped beyond this
})
// Heartbeat every 30s — immediate POST, not batched.
setInterval(() => void tickr.heartbeat({ tps: server.currentTps() }), 30_000)
server.on('playerJoin', (p) =>
tickr.session({ playerId: p.uuid, username: p.name, type: 'join', sessionId: p.sessionId, world: p.world })
)
server.on('playerQuit', (p) =>
tickr.session({ playerId: p.uuid, type: 'leave', sessionId: p.sessionId, ts: Date.now() })
)
// Gate premium features on the org's plan.
const { premium, plan } = await tickr.checkLicense()
// On graceful stop: tell Tickr it's a clean shutdown
// (absence of this before a drop ⇒ counted as a crash), then flush.
server.on('stop', async () => {
await tickr.heartbeat({ cleanShutdown: true })
await tickr.shutdown()
})
Options
| Option | Default | Description |
|---|---|---|
serverKey | none (required) | Server API key, sent as Authorization: Bearer <key>. |
baseUrl | https://api.tickr.gg | API origin (point at your own deployment if self-hosted). |
flushIntervalMs | 5000 | Background flush cadence. |
maxBatchSize | 50 | Max items per ingest request. |
maxQueueSize | 10000 | Per-queue memory bound (drop-oldest beyond it). |
maxRetries | 5 | Retries per batch for retryable failures. |
fetch | globalThis.fetch | Injectable fetch (tests, polyfills). |
Methods
track(input): queue a custom event (idempotencyKey/tsauto-generated when missing).session(input): queue ajoin/leavesession item.heartbeat({ tps?, cleanShutdown? }): immediatePOST /v1/ingest/heartbeat; throwsTickrApiErroron non-2xx.checkLicense():GET /v1/ingest/license→{ premium, plan }.flush(): drain queues now; concurrent calls share one in-flight flush.shutdown(): stop the timer and run a final flush.
Reliability semantics
- Events and sessions sit in separate in-memory FIFO queues, bounded by
maxQueueSize(oldest items dropped, with a singleconsole.warn). - Failed requests are retried with exponential backoff + jitter (500 ms base, ×2, capped at 30 s) up to
maxRetries, but only for network errors,429and5xx. Other4xxresponses drop the batch (logged once). - After retries are exhausted the batch goes back to the front of the queue (order preserved) and is retried on the next flush.
- Auto-generated
idempotencyKeys mean retried event batches never double-count. See idempotency in the API reference.