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.
Concepts
Section titled “Concepts”| Type | Role |
|---|---|
CausationType | A named string wrapper identifying the kind of operation that caused something. |
Causation | A single node in the chain — a timestamp, a CausationType, and a property bag. |
ICausationManager | Interface for reading and mutating the chain in the current call context. |
CausationManager | Default AsyncLocalStorage-backed implementation. |
CausationType
Section titled “CausationType”import { CausationType } from '@cratis/chronicle';
// Built-in typesCausationType.root // 'Root' — the process-level rootCausationType.unknown // 'Unknown'CausationType.appendEvent // 'TypeScriptClient.Append'CausationType.appendManyEvents // 'TypeScriptClient.AppendMany'
// Custom typesconst myType = new CausationType('MyApp.CreateEmployee');Causation
Section titled “Causation”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 placeholderconst placeholder = Causation.unknown();Managing the causation chain
Section titled “Managing the causation chain”The module exports a singleton causationManager that uses Node.js AsyncLocalStorage so the chain is scoped automatically to the active async context.
Reading the current chain
Section titled “Reading the current chain”import { causationManager } from '@cratis/chronicle';
const chain = causationManager.getCurrentChain();// chain[0] is always the root causation// chain[n] are additional entries added in this contextAdding causation
Section titled “Adding causation”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 chainawait store.eventLog.append(eventSourceId, new EmployeeHired(...));Defining the process root
Section titled “Defining the process root”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'});Command-handler middleware example
Section titled “Command-handler middleware example”import { causationManager, CausationType } from '@cratis/chronicle';
async function handleCommand(commandName: string, handler: () => Promise<void>) { causationManager.add(new CausationType(`MyApp.Command.${commandName}`), {}); await handler();}How causation flows into events
Section titled “How causation flows into events”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.