Plattform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Modelle Tools & Services
Lösungen
Organisationen Entwickler Internet Service Provider Managed Service Provider AI-in-a-Box
Ressourcen
Support Documentation Blog Downloads
Unternehmen
Über uns Forschung Karriere Investieren Kontakt
Anmelden

TypeScript SDK

The TypeScript SDK (@scailabs/scailog) is the Node.js emit side of ScaiLog: createLogger plus pi() give you GDPR-native structured logging that ships entries over a Unix socket to the local scailog-agent. It is wire-compatible with the Python, Go, and .NET SDKs — a TS-emitted entry is encrypted at ingest and decrypts correctly through DSAR.

Install#

bash
1
npm install @scailabs/scailog

The package is distributed as Node ESM with bundled type definitions, and has no runtime dependencies.

Emit a log entry#

Create a logger with your tenant and service, then call a level method with a call_site_id, a constant message, and an options object. Wrap any personal-information value in pi():

ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import { createLogger, pi } from '@scailabs/scailog';

const log = createLogger({ tenant: 'acme', service: 'checkout' });

const eventId = log.info('SCAI-CHECKOUT-PAID-001', 'order paid', {
  subject: 'usr_8842', // required whenever a pi() field is present
  fields: {
    method: 'card',
    email: pi('jan@example.nl', 'direct_identifier'),
    ip: pi('203.0.113.7', 'online_identifier'),
  },
});

The call returns the entry's ULID eventId. Plain fields (method) are stored in cleartext and must stay PI-free; pi() fields are encrypted at ingest and never enter the plaintext full-text index. Keep variable data in fields, not in the message.

Log levels#

Six methods with the same signature level(site, message, opts?), where opts is { subject?, fields?, traceId?, requestId? }:

ts
1
2
3
4
5
6
log.trace('SCAI-CACHE-MISS-001', 'cache miss');
log.debug('SCAI-CACHE-EVICT-001', 'evicted key');
log.info('SCAI-USER-LOGIN-001', 'user logged in', { subject: 'usr_8842' });
log.warn('SCAI-RATE-NEAR-001', 'approaching rate limit');
log.error('SCAI-DB-TXN-FAIL-001', 'transaction rolled back');
log.fatal('SCAI-BOOT-CONFIG-001', 'missing required config');

Contract rules#

The SDK enforces the shared ScaiLog contract before an entry leaves the process, throwing an Error on a violation:

  • call_site_id (first arg) must match ^[A-Z0-9]+(-[A-Z0-9]+){2,}$. The AUTO- / SCAILOG- prefixes are reserved.
  • pi(value, type) marks a field as personal information; markers attach to fields only, never to the message.
  • A pi() field requires subject — enforced client-side (SUBJECT_REQUIRED) and again at the server.
  • Reserved field names (event_id, tenant, msg, …) are rejected.

Context propagation#

withContext() — backed by Node's AsyncLocalStorage — propagates subject, traceId, and requestId across await boundaries, so request handlers don't thread them through every call. The logger uses the ambient context as defaults; explicit options on a call override it, and nested scopes inherit and can override:

ts
1
2
3
4
5
6
import { withContext } from '@scailabs/scailog';

await withContext({ requestId: req.id, subject: user.id }, async () => {
  // picks up requestId + subject from the ambient context
  log.info('SCAI-API-HANDLED-001', 'handled');
});

Configuration#

createLogger({ tenant, service, environment?, socketPath? }) constructs a logger explicitly. environment defaults to prod, and socketPath defaults to $SCAILOG_SOCKET or /run/scailog/agent.sock.

defaultLogger() builds one from the environment instead, reading SCAILOG_TENANT (default default), SCAILOG_SERVICE (default unknown), SCAILOG_ENV (default prod), and SCAILOG_SOCKET.

Flush before exit#

Entries are queued and sent by a background sender as NDJSON over the socket. If the queue is full or the socket is unavailable, the entry is written to stderr in the same NDJSON shape (with PI values redacted) rather than being silently dropped. Before a short-lived process exits, drain the queue:

ts
1
2
await log.flush(); // best-effort drain
log.close();
Updated 2026-07-13 09:41:43 View source (.md) rev 2