DATIUSDocs

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

Shell
npm install @datius/node

Direct usage

TypeScript
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.

TypeScript
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)

TypeScript
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

TypeScript
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

OptionDefaultDescription
apiKey— (required)Workspace-scoped API key with the signals:emit scope.
endpoint— (required)Base URL of the Datius API.
flushIntervalMs2000Automatic flush interval.
maxBatchSize50Flush as soon as the buffer reaches this size.
maxRetries3Retry attempts per failed batch (exponential backoff + jitter).
debugfalseLog lifecycle events to the console.
handleProcessSignalstrueFlush 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.