Correlation
See Correlation, identity, and causation for what a correlation ID is and why Chronicle tracks it. This page covers the TypeScript-specific API in depth. A CorrelationId is sent with every event append as the CorrelationId field.
CorrelationId
Section titled “CorrelationId”import { CorrelationId } from '@cratis/chronicle';
// Generate a new unique correlation IDconst id = CorrelationId.create();
// Wrap an existing string (e.g. from an incoming X-Correlation-Id header)const fromHeader = new CorrelationId('d4e5f6a7-...');
// Well-known sentinel for an unset IDconst empty = CorrelationId.notSet;
console.log(id.toString()); // 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'Managing the correlation ID for a call context
Section titled “Managing the correlation ID for a call context”The module exports a singleton correlationIdManager backed by Node.js AsyncLocalStorage. The ID is scoped automatically to the active async context — no need to pass it through every function call.
Reading the current ID
Section titled “Reading the current ID”import { correlationIdManager } from '@cratis/chronicle';
const id = correlationIdManager.current;// If nothing has been set in this context, a new GUID is generated on each access.Setting a fixed ID
Section titled “Setting a fixed ID”import { correlationIdManager, CorrelationId } from '@cratis/chronicle';
correlationIdManager.setCurrent(new CorrelationId('d4e5f6a7-...'));Resetting to a new ID
Section titled “Resetting to a new ID”correlationIdManager.clear(); // replaces the stored ID with a fresh GUIDExpress middleware example
Section titled “Express middleware example”import express from 'express';import { correlationIdManager, CorrelationId } from '@cratis/chronicle';
app.use((req, res, next) => { const header = req.headers['x-correlation-id']; const id = header ? new CorrelationId(String(header)) : CorrelationId.create();
correlationIdManager.setCurrent(id); res.setHeader('x-correlation-id', id.toString()); res.on('finish', () => correlationIdManager.clear()); next();});Interface segregation
Section titled “Interface segregation”CorrelationIdManager implements two separate interfaces, following the same pattern as the .NET client:
| Interface | Purpose |
|---|---|
ICorrelationIdAccessor | Read-only access — exposes current. Inject this where you only need to read the ID. |
ICorrelationIdSetter | Write access — exposes setCurrent() and clear(). Inject this where you need to set or reset the ID. |
import { ICorrelationIdAccessor, ICorrelationIdSetter, CorrelationIdManager } from '@cratis/chronicle';
// Narrow the type for read-only consumersfunction logCorrelation(accessor: ICorrelationIdAccessor) { console.log('Correlation:', accessor.current.toString());}
// Narrow the type for writers (e.g. middleware, test setup)function resetForTest(setter: ICorrelationIdSetter) { setter.clear();}
const manager = new CorrelationIdManager();logCorrelation(manager);resetForTest(manager);How correlation flows into events
Section titled “How correlation flows into events”When you call eventLog.append() or eventLog.appendMany(), the Chronicle client automatically uses correlationIdManager.current as the CorrelationId for the gRPC request unless you provide an explicit correlationId in AppendOptions:
import { CorrelationId } from '@cratis/chronicle';
// Uses correlationIdManager.current automaticallyawait store.eventLog.append(eventSourceId, new EmployeeHired(...));
// Override for this single appendawait store.eventLog.append(eventSourceId, new EmployeeHired(...), { correlationId: CorrelationId.create()});