SDKs & Code Examples
@datius/node is a zero-dependency Node.js/TypeScript SDK for emitting signals without calling the Ingestion API directly. It buffers events in memory and dispatches them as batched HTTP requests, with automatic retries, backoff, and a graceful shutdown drain — none of it ever blocks or throws in the host application.
Install
npm install @datius/node
Direct usage
import { Datius } from "@datius/node";const datius = new Datius({apiKey: process.env.DATIUS_API_KEY!,endpoint: process.env.DATIUS_INGEST_ENDPOINT!,});datius.emit("order_completed", {value: 149.99,tags: { currency: "USD", customerTier: "gold" },});
Decorator usage (NestJS, Express controllers, service classes)
Requires experimentalDecorators: true in tsconfig.json. Emits a signal automatically after the decorated method resolves, derived from its arguments and return value.
import { DatiusEmit } from "@datius/node";export class CheckoutService {@DatiusEmit("daily_arr", ([request]: [CheckoutRequest], result) => ({value: request.order.total,tags: { orderId: result.orderId, paymentMethod: request.order.paymentMethod },}))async processCheckout(request: CheckoutRequest) {return { orderId: "ord_9921" };}}
Route handler usage (Next.js App Router, Fastify, Lambda)
import { NextResponse } from "next/server";import { withDatius } from "@datius/node";export const POST = withDatius("daily_arr",async (req: Request) => {const body = await req.json();return { value: body.order.total, tags: { orderId: body.order.id } };},async (req: Request) => {const body = await req.json();return NextResponse.json({ success: true, orderId: body.order.id });},);
The extract function receives a clone of the request, so it and the handler can each independently read the body.
Signal shape
datius.emit(signalKey: string, {value: number,tags?: Record<string, string | number | boolean>,timestamp?: string,});
This mirrors the Ingestion API's payload exactly — see Ingestion API for the full field reference.
Resolving the default client
@DatiusEmit and withDatius both fall back to the first Datius instance constructed in the process, unless a client is passed explicitly via { client }. Call Datius.setDefault(instance) to override, or construct multiple clients and pass { client } per call site for multi-tenant or multi-endpoint setups.
Configuration
| Option | Default | Description |
|---|---|---|
apiKey | — (required) | Workspace-scoped API key with the signals:emit scope. |
endpoint | — (required) | Base URL of the Datius API. |
flushIntervalMs | 2000 | Automatic flush interval. |
maxBatchSize | 50 | Flush as soon as the buffer reaches this size. |
maxRetries | 3 | Retry attempts per failed batch (exponential backoff + jitter). |
debug | false | Log lifecycle events to the console. |
handleProcessSignals | true | Flush and detach on SIGINT/SIGTERM. |
The buffer caps out at 5,000 queued events; beyond that, the oldest events are dropped (FIFO) to protect memory during extended outages. A batch that exhausts its retries is dropped rather than retried indefinitely.
Other languages
Only the ingestion payload shape matters to talk to Datius — any HTTP client can call POST /api/v1/ingest directly. Additional language SDKs may follow the Node.js SDK in the future. Already instrumenting with OpenTelemetry instead? See OpenTelemetry — no Datius SDK needed at all, any language's standard OTel exporter works.