npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@immutablelog/sdk

v0.1.0

Published

Official ImmutableLog SDK for Node.js — audit logging middleware for Express, Fastify, Koa, NestJS, AdonisJS and plain Node.

Downloads

89

Readme

@immutablelog/sdk

SDK oficial do ImmutableLog para Node.js Official ImmutableLog SDK for Node.js

Envie eventos de auditoria para o ledger imutável a partir de Express, Fastify, Koa, NestJS, AdonisJS ou Node.js puro. Ship audit events to the immutable ledger from Express, Fastify, Koa, NestJS, AdonisJS or plain Node.js.

npm types license

🇧🇷 Português · 🇺🇸 English


✨ Highlights / Destaques

| | | | --- | ------------------------------------------------------------------------------------- | | ✅ | Fail-open — uma indisponibilidade do ImmutableLog nunca quebra sua aplicação. | | ⚡ | Não-bloqueante — eventos são entregues em background por padrão. | | 🔒 | Redação de segredos — senhas, tokens, cartões etc. removidos no cliente. | | 🧾 | Grau de auditoria — hash SHA-256 do corpo sem armazenar o corpo. | | 🧩 | Adapters de framework + um client de baixo nível para qualquer caso. | | 🟦 | JS e TS — ESM + CommonJS + tipos .d.ts no mesmo pacote. | | 0️⃣ | Zero dependências de runtime (usa fetch nativo, Node ≥ 18). |

JavaScript e TypeScript: o pacote publica import (ESM), require (CommonJS) e definições de tipos. Funciona sem configuração em qualquer um dos dois. / The package ships ESM, CommonJS and type definitions — works out of the box in both.


🇧🇷 Português

Índice

Instalação

npm install @immutablelog/sdk
# ou
pnpm add @immutablelog/sdk
yarn add @immutablelog/sdk

Requisito: Node.js ≥ 18 (usa o fetch global). Em versões antigas, injete um fetch via configuração (veja Referência de configuração).

Configuração

O client lê estas variáveis de ambiente por padrão:

IMTBL_API_KEY=iml_live_xxxxxxxxxxxx      # obrigatória para enviar
IMTBL_URL=https://api.immutablelog.com   # opcional (este é o padrão)
IMTBL_SERVICE_NAME=orders-api            # opcional
IMTBL_ENV=production                     # opcional

Qualquer valor passado no código sobrescreve o ambiente. Sem IMTBL_API_KEY/IMTBL_URL, o client vira no-op (fail-open): não envia nada e nunca lança erro.

Início rápido (eventos manuais)

TypeScript / ESM

import { imtbl } from '@immutablelog/sdk';

await imtbl.sendEvent({
  eventName: 'payment.approved',
  payload: { paymentId: 'pay_abc123', amount: 299.9 },
  kind: 'success',
  service: 'payments-service',
  immutableTrail: 'order-7782',
});

JavaScript / CommonJS

const { imtbl } = require('@immutablelog/sdk');

imtbl.sendEvent({
  eventName: 'user.deleted',
  payload: { userId: 42 },
  kind: 'audit',
});

O payload é sanitizado (redação de segredos), limitado em tamanho e convertido para string JSON automaticamente. Todos os valores de meta são convertidos para string (exigência da API) e o immutable_trail é sanitizado no cliente (:-, trim, máx. 256).

Para uma instância isolada (ex.: múltiplos serviços/keys):

import { createClient } from '@immutablelog/sdk';

const auditClient = createClient({ apiKey: process.env.AUDIT_KEY, service: 'billing' });
await auditClient.sendEvent({ eventName: 'invoice.issued', payload: { id: 1 } });

Adapters de framework

Cada adapter captura automaticamente: método, rota, status, latência, IP (com X-Forwarded-For), user-agent, usuário autenticado (req.user), erros lançados e corpo da requisição (com hash + redação, apenas em erros). Também propaga/gera X-Request-Id.

Express

import express from 'express';
import { immutableLog } from '@immutablelog/sdk/express';

const app = express();
app.use(express.json());

// audita todas as requisições
app.use(immutableLog({ service: 'orders-api' }));

app.get('/orders/:id', (req, res) => res.json({ id: req.params.id }));

// DEPOIS das rotas: captura exceções com nome/mensagem da exceção
app.use(immutableLog.errorHandler({ service: 'orders-api' }));

Fastify

import Fastify from 'fastify';
import { immutableLog } from '@immutablelog/sdk/fastify';

const app = Fastify();
await app.register(immutableLog, { service: 'orders-api' });

O plugin é registrado sem encapsulamento (skip-override), então vale para toda a aplicação.

Koa

import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
import { immutableLog } from '@immutablelog/sdk/koa';

const app = new Koa();
app.use(bodyParser());
app.use(immutableLog({ service: 'orders-api' }));

NestJS

Funciona tanto na plataforma Express quanto Fastify.

// main.ts
import { ImmutableLogInterceptor } from '@immutablelog/sdk/nestjs';

app.useGlobalInterceptors(new ImmutableLogInterceptor({ service: 'orders-api' }));

Ou via injeção de dependência (global):

import { APP_INTERCEPTOR } from '@nestjs/core';
import { ImmutableLogInterceptor } from '@immutablelog/sdk/nestjs';

@Module({
  providers: [
    { provide: APP_INTERCEPTOR, useValue: new ImmutableLogInterceptor({ service: 'orders-api' }) },
  ],
})
export class AppModule {}

O nome do evento é derivado de http.{MÉTODO}.{Controller}.{handler} automaticamente.

AdonisJS v6

// app/middleware/imtbl_middleware.ts
import { immutableLog } from '@immutablelog/sdk/adonis';

export default class ImmutableLogMiddleware {
  handle = immutableLog({ service: 'orders-api' });
}

Registre como middleware global em start/kernel.ts:

import server from '@adonisjs/core/services/server';
server.use([() => import('#middleware/imtbl_middleware')]);

Node.js puro

import http from 'node:http';
import { withImmutableLog } from '@immutablelog/sdk/node';

const server = http.createServer(
  withImmutableLog(async (req, res) => {
    res.writeHead(200, { 'content-type': 'application/json' });
    res.end(JSON.stringify({ ok: true }));
  }, { service: 'edge-gateway' }),
);

server.listen(3000);

Para frameworks baseados em http não listados, use o helper de baixo nível:

import { instrument } from '@immutablelog/sdk/node';

function handler(req, res) {
  const done = instrument(req, res, { service: 'custom' });
  try {
    // ...sua lógica...
  } catch (err) {
    done(err); // registra o erro (o evento sai sozinho ao finalizar a resposta)
    throw err;
  }
}

Controles por requisição

Os adapters leem estas propriedades convencionais quando presentes:

| Propriedade / Header | Efeito | | ---------------------- | ------------------------------------------------------------------ | | req.imtblTrail | Define o immutable_trail desta requisição | | req.imtblEventName | Sobrescreve o nome do evento gerado | | req.user | Adiciona { id, email, username } ao contexto do evento | | header X-Request-Id | Reutilizado para correlação (senão, um UUID é gerado) | | header X-Imtbl-Trail | Trail propagada por um chamador upstream |

Em Koa/Adonis use ctx.state.imtblTrail / ctx.imtblTrail. A ordem de resolução da trail é: imtblTrail → header X-Imtbl-Trail → fallback user-<username>.

Formato do evento enviado

O SDK faz POST {IMTBL_URL}/v1/events com este corpo:

{
  // payload é SEMPRE uma string JSON (limitada a ~16KB; o SDK reduz se passar)
  "payload": "{\"id\":\"...\",\"kind\":\"success\",\"message\":\"...\",\"timestamp\":\"...\",\"context\":{...},\"request\":{...},\"metrics\":{\"latency_ms\":12,\"status_code\":200},\"severity\":\"low\"}",
  // todos os valores de meta são strings
  "meta": {
    "type": "success",            // error | warning | info | success | audit | debug
    "event_name": "http.GET /orders",
    "service": "orders-api",
    "request_id": "uuid",
    "env": "production",
    "immutable_trail": "order-7782" // opcional
  }
}

Headers enviados:

| Header | Valor | | -------------------------- | -------------------------------------- | | Authorization | Bearer <IMTBL_API_KEY> | | Content-Type | application/json | | Idempotency-Key | {eventName}-{requestId} | | Request-Id | UUID de correlação | | X-Client-TZ | America/Sao_Paulo (configurável) | | X-Client-Offset-Minutes | -180 (configurável) |

Resposta (202 Accepted):

{ "ok": true, "tx_id": "uuid", "payload_hash": "sha256-hex", "status": "accepted", "duplicate": false, "request_id": "uuid" }

sendEvent() / emitFromHttp() resolvem para um SendResult: { ok, status, txId, payloadHash, duplicate, requestId, error }.

Regras do immutable_trail

A trail agrupa eventos relacionados em uma única linha do tempo auditável.

  • Não pode ser vazia após trim.
  • Máximo de 256 caracteres (o SDK trunca e emite um aviso).
  • Não pode conter : — o SDK substitui por -.
  • Use -, _, . ou / como separadores.
  • Case-sensitive (Order-1order-1).

Códigos de status da API

| Status | Significado | Ação do SDK | | ------ | -------------------------------------- | --------------------------------- | | 202 | Evento enfileirado (novo) | sucesso | | 200 | Duplicado (mesma Idempotency-Key) | sucesso, duplicate: true | | 400 | Trail inválida / sem Idempotency-Key | logado como warning | | 403 | Assinatura inativa/expirada | logado como warning | | 413 | Payload acima de 16KB | mitigado pelo clamp de payload | | 429 | Limite mensal excedido | não faz retry | | 503 | Mempool cheia | faz retry (configurável) |

Amostragem (sampling)

Eventos error, warning, audit e debug são sempre enviados. Para reduzir ruído/custo em volume alto, amostre success/info:

createClient({ sampleSuccess: 0.1, sampleInfo: 0 }); // 10% dos success, 0% dos info

Redação de dados sensíveis

Chaves comuns (password, token, secret, authorization, credit_card, cpf, cvv, ...) têm o valor substituído por ***REDACTED*** recursivamente, em query, body e payload. Adicione chaves extras:

createClient({ redactKeys: ['national_id', 'session'] });

Em erros, o SDK inclui o hash SHA-256 do corpo (prova sem guardar o conteúdo) e um trecho sanitizado (desligável com includeBodyOnError: false).

Encerramento gracioso (flush)

Como a entrega é em background, aguarde os envios pendentes antes de sair:

import { imtbl } from '@immutablelog/sdk';

process.on('SIGTERM', async () => {
  await imtbl.flush();
  process.exit(0);
});

Referência de configuração

| Opção | Env | Padrão | Descrição | | -------------------- | -------------------- | ------------------------------- | ----------------------------------------------- | | apiKey | IMTBL_API_KEY | — | Chave secreta (necessária para enviar) | | url | IMTBL_URL | https://api.immutablelog.com | URL base da API | | service | IMTBL_SERVICE_NAME | node-service | Nome lógico do serviço | | env | IMTBL_ENV | production | Ambiente de deploy | | headers | — | {} | Headers estáticos extras | | timeoutMs | — | 400 | Timeout por requisição | | retries | — | 1 | Retries em erros transitórios/transporte | | sampleSuccess | — | 1 | Taxa de amostragem de success (0..1) | | sampleInfo | — | 1 | Taxa de amostragem de info (0..1) | | ignorePaths | — | [] | Prefixos de path a ignorar (health, metrics) | | maxPayloadBytes | — | 12000 | Limite para reduzir o payload | | includeBodyOnError | — | true | Anexa corpo sanitizado + hash em erros | | redactKeys | — | conjunto interno | Chaves sensíveis extras | | clientTz | — | America/Sao_Paulo | Header X-Client-TZ | | clientOffsetMinutes| — | -180 | Header X-Client-Offset-Minutes | | awaitDelivery | — | false | Aguarda a entrega em vez de fire-and-forget | | logger | — | silencioso | Passe console para depurar | | fetch | — | fetch global | Implementação de fetch customizada | | skip | — | — | ({ method, path }) => boolean para pular | | client | — | — | Reutiliza um client já criado (nos adapters) |

Referência da API pública

import {
  createClient,        // factory: createClient(config) => ImmutableLogClient
  ImmutableLogClient,  // classe
  imtbl,               // client padrão dirigido por variáveis de ambiente
  // utilitários (também usados internamente)
  redact, safeBody, sanitizeTrail, clampPayload, hashBody, severityFrom, severityLevel,
} from '@immutablelog/sdk';

Métodos do client:

  • sendEvent(input): Promise<SendResult> — evento manual de alto nível.
  • emitFromHttp(input): Promise<SendResult> — a partir de uma troca HTTP normalizada (usado pelos adapters).
  • flush(): Promise<void> — aguarda entregas em background.
  • get enabled(): boolean — se está configurado para enviar.

TypeScript

Os tipos acompanham o pacote. Os principais:

import type {
  EventKind, SeverityLevel, Logger, FetchLike,
  ImmutableLogConfig, SendEventInput, HttpEventInput, SendResult, AdapterOptions,
} from '@immutablelog/sdk';

Solução de problemas

  • Nada é enviado → verifique IMTBL_API_KEY/IMTBL_URL. Sem eles o client é no-op. Use logger: console para confirmar.
  • require is not defined / fetch ausente → Node < 18. Atualize ou passe fetch na config.
  • 400 invalid_immutable_trail → a trail tem caractere inválido ou está vazia; revise as regras.
  • Eventos somem ao encerrar o processo → chame await imtbl.flush() antes de sair.

🇺🇸 English

Table of contents

Installation

npm install @immutablelog/sdk
# or
pnpm add @immutablelog/sdk
yarn add @immutablelog/sdk

Requires Node.js ≥ 18 (uses the global fetch). On older runtimes, inject a fetch via config (see Configuration reference).

Configuration

The client reads these environment variables by default:

IMTBL_API_KEY=iml_live_xxxxxxxxxxxx      # required to send
IMTBL_URL=https://api.immutablelog.com   # optional (this is the default)
IMTBL_SERVICE_NAME=orders-api            # optional
IMTBL_ENV=production                     # optional

Anything passed in code overrides the environment. Without IMTBL_API_KEY/IMTBL_URL the client becomes a no-op (fail-open): it sends nothing and never throws.

Quick start (manual events)

TypeScript / ESM

import { imtbl } from '@immutablelog/sdk';

await imtbl.sendEvent({
  eventName: 'payment.approved',
  payload: { paymentId: 'pay_abc123', amount: 299.9 },
  kind: 'success',
  service: 'payments-service',
  immutableTrail: 'order-7782',
});

JavaScript / CommonJS

const { imtbl } = require('@immutablelog/sdk');

imtbl.sendEvent({
  eventName: 'user.deleted',
  payload: { userId: 42 },
  kind: 'audit',
});

payload is sanitized (secret redaction), size-clamped and JSON-stringified for you. All meta values are coerced to strings (an API requirement) and immutable_trail is sanitized client-side (:-, trimmed, max 256).

For an isolated instance (e.g. multiple services/keys):

import { createClient } from '@immutablelog/sdk';

const auditClient = createClient({ apiKey: process.env.AUDIT_KEY, service: 'billing' });
await auditClient.sendEvent({ eventName: 'invoice.issued', payload: { id: 1 } });

Framework adapters

Each adapter captures automatically: method, route, status, latency, IP (honouring X-Forwarded-For), user-agent, authenticated user (req.user), thrown errors and the request body (hashed + redacted, on errors only). It also propagates/generates X-Request-Id.

Express

import express from 'express';
import { immutableLog } from '@immutablelog/sdk/express';

const app = express();
app.use(express.json());

// audit every request
app.use(immutableLog({ service: 'orders-api' }));

app.get('/orders/:id', (req, res) => res.json({ id: req.params.id }));

// AFTER your routes: capture thrown errors with exception name/message
app.use(immutableLog.errorHandler({ service: 'orders-api' }));

Fastify

import Fastify from 'fastify';
import { immutableLog } from '@immutablelog/sdk/fastify';

const app = Fastify();
await app.register(immutableLog, { service: 'orders-api' });

The plugin registers without encapsulation (skip-override) so it applies app-wide.

Koa

import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
import { immutableLog } from '@immutablelog/sdk/koa';

const app = new Koa();
app.use(bodyParser());
app.use(immutableLog({ service: 'orders-api' }));

NestJS

Works on both the Express and Fastify platforms.

// main.ts
import { ImmutableLogInterceptor } from '@immutablelog/sdk/nestjs';

app.useGlobalInterceptors(new ImmutableLogInterceptor({ service: 'orders-api' }));

Or via dependency injection (global):

import { APP_INTERCEPTOR } from '@nestjs/core';
import { ImmutableLogInterceptor } from '@immutablelog/sdk/nestjs';

@Module({
  providers: [
    { provide: APP_INTERCEPTOR, useValue: new ImmutableLogInterceptor({ service: 'orders-api' }) },
  ],
})
export class AppModule {}

The event name is derived as http.{METHOD}.{Controller}.{handler} automatically.

AdonisJS v6

// app/middleware/imtbl_middleware.ts
import { immutableLog } from '@immutablelog/sdk/adonis';

export default class ImmutableLogMiddleware {
  handle = immutableLog({ service: 'orders-api' });
}

Register it as a global middleware in start/kernel.ts:

import server from '@adonisjs/core/services/server';
server.use([() => import('#middleware/imtbl_middleware')]);

Plain Node.js

import http from 'node:http';
import { withImmutableLog } from '@immutablelog/sdk/node';

const server = http.createServer(
  withImmutableLog(async (req, res) => {
    res.writeHead(200, { 'content-type': 'application/json' });
    res.end(JSON.stringify({ ok: true }));
  }, { service: 'edge-gateway' }),
);

server.listen(3000);

For http-based frameworks not listed, use the low-level helper:

import { instrument } from '@immutablelog/sdk/node';

function handler(req, res) {
  const done = instrument(req, res, { service: 'custom' });
  try {
    // ...your logic...
  } catch (err) {
    done(err); // record the error (the event is emitted on response finish)
    throw err;
  }
}

Per-request controls

Adapters read these conventional properties when present:

| Property / Header | Effect | | ---------------------- | ------------------------------------------------------------ | | req.imtblTrail | Sets immutable_trail for this request | | req.imtblEventName | Overrides the generated event name | | req.user | Adds { id, email, username } to the event context | | header X-Request-Id | Reused for correlation (otherwise a UUID is generated) | | header X-Imtbl-Trail | Trail propagated from an upstream caller |

On Koa/Adonis use ctx.state.imtblTrail / ctx.imtblTrail. Trail resolution order is: imtblTrailX-Imtbl-Trail header → user-<username> fallback.

Event payload format

The SDK does POST {IMTBL_URL}/v1/events with this body:

{
  // payload is ALWAYS a JSON string (capped at ~16KB; the SDK shrinks it if needed)
  "payload": "{\"id\":\"...\",\"kind\":\"success\",\"message\":\"...\",\"timestamp\":\"...\",\"context\":{...},\"request\":{...},\"metrics\":{\"latency_ms\":12,\"status_code\":200},\"severity\":\"low\"}",
  // all meta values are strings
  "meta": {
    "type": "success",            // error | warning | info | success | audit | debug
    "event_name": "http.GET /orders",
    "service": "orders-api",
    "request_id": "uuid",
    "env": "production",
    "immutable_trail": "order-7782" // optional
  }
}

Headers sent:

| Header | Value | | -------------------------- | -------------------------------------- | | Authorization | Bearer <IMTBL_API_KEY> | | Content-Type | application/json | | Idempotency-Key | {eventName}-{requestId} | | Request-Id | correlation UUID | | X-Client-TZ | America/Sao_Paulo (configurable) | | X-Client-Offset-Minutes | -180 (configurable) |

Response (202 Accepted):

{ "ok": true, "tx_id": "uuid", "payload_hash": "sha256-hex", "status": "accepted", "duplicate": false, "request_id": "uuid" }

sendEvent() / emitFromHttp() resolve to a SendResult: { ok, status, txId, payloadHash, duplicate, requestId, error }.

immutable_trail rules

The trail groups related events into a single auditable timeline.

  • Cannot be empty after trim.
  • Maximum 256 characters (the SDK truncates and warns).
  • Cannot contain : — the SDK replaces it with -.
  • Use -, _, . or / as separators.
  • Case-sensitive (Order-1order-1).

API status codes

| Status | Meaning | SDK behaviour | | ------ | -------------------------------------- | --------------------------------- | | 202 | Event queued (new) | success | | 200 | Duplicate (same Idempotency-Key) | success, duplicate: true | | 400 | Invalid trail / missing idempotency | logged as warning | | 403 | Inactive/expired subscription | logged as warning | | 413 | Payload over 16KB | mitigated by payload clamping | | 429 | Monthly limit exceeded | not retried | | 503 | Mempool full | retried (configurable) |

Sampling

error, warning, audit and debug events are always sent. To cut noise/cost at high volume, sample success/info:

createClient({ sampleSuccess: 0.1, sampleInfo: 0 }); // 10% of success, 0% of info

Secret redaction

Common keys (password, token, secret, authorization, credit_card, cpf, cvv, ...) are recursively replaced with ***REDACTED*** in query, body and payload. Add extras:

createClient({ redactKeys: ['national_id', 'session'] });

On errors, the SDK includes the body's SHA-256 hash (proof without storing content) plus a sanitized snippet (disable with includeBodyOnError: false).

Graceful shutdown

Because delivery is fire-and-forget, flush pending events before exit:

import { imtbl } from '@immutablelog/sdk';

process.on('SIGTERM', async () => {
  await imtbl.flush();
  process.exit(0);
});

Configuration reference

| Option | Env | Default | Description | | -------------------- | -------------------- | ------------------------------- | -------------------------------------------- | | apiKey | IMTBL_API_KEY | — | Secret API key (required to send) | | url | IMTBL_URL | https://api.immutablelog.com | API base URL | | service | IMTBL_SERVICE_NAME | node-service | Logical service name | | env | IMTBL_ENV | production | Deployment environment | | headers | — | {} | Extra static headers | | timeoutMs | — | 400 | Per-request timeout | | retries | — | 1 | Retries on transient/transport errors | | sampleSuccess | — | 1 | Sampling rate for success (0..1) | | sampleInfo | — | 1 | Sampling rate for info (0..1) | | ignorePaths | — | [] | Path prefixes to skip (health, metrics) | | maxPayloadBytes | — | 12000 | Clamp threshold for the payload | | includeBodyOnError | — | true | Attach sanitized body + hash on errors | | redactKeys | — | built-in set | Extra sensitive keys | | clientTz | — | America/Sao_Paulo | X-Client-TZ header | | clientOffsetMinutes| — | -180 | X-Client-Offset-Minutes header | | awaitDelivery | — | false | Await delivery instead of fire-and-forget | | logger | — | silent | Pass console to debug | | fetch | — | global fetch | Custom fetch implementation | | skip | — | — | ({ method, path }) => boolean to skip | | client | — | — | Reuse an existing client (in adapters) |

Public API reference

import {
  createClient,        // factory: createClient(config) => ImmutableLogClient
  ImmutableLogClient,  // class
  imtbl,               // env-driven default client
  // utilities (also used internally)
  redact, safeBody, sanitizeTrail, clampPayload, hashBody, severityFrom, severityLevel,
} from '@immutablelog/sdk';

Client methods:

  • sendEvent(input): Promise<SendResult> — high-level manual event.
  • emitFromHttp(input): Promise<SendResult> — from a normalized HTTP exchange (used by adapters).
  • flush(): Promise<void> — await background deliveries.
  • get enabled(): boolean — whether it is configured to send.

TypeScript

Types ship with the package. The main ones:

import type {
  EventKind, SeverityLevel, Logger, FetchLike,
  ImmutableLogConfig, SendEventInput, HttpEventInput, SendResult, AdapterOptions,
} from '@immutablelog/sdk';

Troubleshooting

  • Nothing is sent → check IMTBL_API_KEY/IMTBL_URL. Without them the client is a no-op. Use logger: console to confirm.
  • require is not defined / missing fetch → Node < 18. Upgrade or pass fetch in the config.
  • 400 invalid_immutable_trail → the trail has an invalid character or is empty; review the rules.
  • Events lost on process exit → call await imtbl.flush() before exiting.

Made with care for ImmutableLog · MIT License