Skip to content

Auditing — Causation

See Correlation, identity, and causation for what causation means and why Chronicle tracks it. This page covers the TypeScript-specific API in depth. The causation chain is stored with every event and enables full audit-trail tracing.

TypeRole
CausationTypeA named string wrapper identifying the kind of operation that caused something.
CausationA single node in the chain — a timestamp, a CausationType, and a property bag.
ICausationManagerInterface for reading and mutating the chain in the current call context.
CausationManagerDefault AsyncLocalStorage-backed implementation.
import { CausationType } from '@cratis/chronicle';
// Built-in types
CausationType.root // 'Root' — the process-level root
CausationType.unknown // 'Unknown'
CausationType.appendEvent // 'TypeScriptClient.Append'
CausationType.appendManyEvents // 'TypeScriptClient.AppendMany'
// Custom types
const myType = new CausationType('MyApp.CreateEmployee');
import { Causation, CausationType } from '@cratis/chronicle';
const entry = new Causation(
new Date(), // occurred
new CausationType('MyApp.CreateEmployee'), // type
{ employeeId: '123' } // properties (string→string map)
);
// Factory for a placeholder
const placeholder = Causation.unknown();

The module exports a singleton causationManager that uses Node.js AsyncLocalStorage so the chain is scoped automatically to the active async context.

import { causationManager } from '@cratis/chronicle';
const chain = causationManager.getCurrentChain();
// chain[0] is always the root causation
// chain[n] are additional entries added in this context

Call add() before performing an operation to push a new entry onto the chain:

import { causationManager, CausationType } from '@cratis/chronicle';
causationManager.add(
new CausationType('MyApp.CreateEmployee'),
{ correlatedCommand: 'HireEmployee', tenantId: 'acme' }
);
// Now append an event — the event will carry this entry in its Causation chain
await store.eventLog.append(eventSourceId, new EmployeeHired(...));

By default the root causation is a bare CausationType.root entry. Call defineRoot() once at start-up to attach application-specific properties:

import { causationManager } from '@cratis/chronicle';
causationManager.defineRoot({
application: 'hr-service',
version: '2.1.0'
});
import { causationManager, CausationType } from '@cratis/chronicle';
async function handleCommand(commandName: string, handler: () => Promise<void>) {
causationManager.add(new CausationType(`MyApp.Command.${commandName}`), {});
await handler();
}

When you call eventLog.append() or eventLog.appendMany(), the Chronicle client automatically reads causationManager.getCurrentChain() and sends the full chain as the Causation field of the gRPC request. You do not need to pass it manually.