Skip to content

Chronicle registration options

withChronicle connects an Arc application to one Chronicle event store. This page lists what it accepts and what it does with each value. Add event sourcing walks through a first registration against a local kernel.

main.ts (excerpt)
import '@cratis/arc.chronicle';
builder.withChronicle({ connectionString: 'chronicle://localhost:35000', eventStore: 'MyArcApp' });

Importing @cratis/arc.chronicle adds the withChronicle method to the Node builder and to the Fetch API builder from @cratis/arc.core/fetch. The package also exports the function withChronicle(builder, options), which does the same; the Library sample uses that form.

The integration records the event types, projections, reducers, reactors, and constraints Arc discovers. A class with Arc metadata is recorded whether discover(...) runs before or after withChronicle. A Chronicle-only class, one without an Arc decorator, is picked up only when withChronicle runs first, so call it before discover(...). The same goes for add(...), which otherwise rejects such a class. With activateArtifactsInScopes on, Chronicle-only classes discovered earlier are picked up too. Arc-owned clients pass the registered artifacts to the SDK and set discoveryPatterns: [], so they do not depend on SDK file scanning. For a caller-owned client, import and register your artifacts explicitly or configure its discoveryPatterns. Since SDK 6.10.0, compiled JavaScript entry points no longer scan .ts files by default; explicit patterns still apply.

Each recorded reactor and reducer also gets a scoped service registration in Arc, but only when nothing else registers that class. A registration in builder.services (before or after withChronicle), an entry in options.services, or an Arc lifetime decorator such as @singleton() always wins, and discovering an artifact twice does not add a second registration. With a caller-supplied ServiceRegistry in options.services, Arc adds no such registrations; register the artifacts yourself. By default Arc does not construct reactors or reducers through these registrations; the Chronicle SDK creates them. To opt in, see Scoped activation.

OptionTypeRequiredMeaning
eventStorestringYesThe event store every append and read uses. Chronicle creates it on first use
connectionStringstringOne of connectionString and clientArc creates, connects, and disposes the SDK client
clientIChronicleClient from @cratis/chronicleOne of connectionString and clientYou own the client; see Choose who owns the client
completionTimeoutMspositive integer, millisecondsNo; no wait by defaultAfter each successful append, wait until Chronicle’s observers have processed it before the command answers. See Choose Chronicle read consistency
readModelNamingPolicy(identifier, readModelType?) => stringNoOnly with connectionString. Names the container each read model is stored in. Defaults to Arc’s MongoDB collection name when withMongoDB is configured, otherwise to the read model identifier. See Choose where read models are stored
activateArtifactsInScopesbooleanNo; off by defaultPreview. Resolve reactors and reducers from Arc’s container, one scope per delivery. With client, registration verifies only that the client was created with chronicleArtifactActivator; passing reactorCommandResultHandler as reactorResultHandler is up to you. See Scoped activation

Registration throws Chronicle requires eventStore and exactly one of connectionString or client when the event store is missing, or when neither or both of a connection string and a client are set.

Every append and read uses the current execution’s tenant as the Chronicle namespace, or the Default namespace when no tenant is resolved. Tenancy you configure for Arc therefore also isolates events and read models. See Tenancy.

withChronicle reads Cratis:Chronicle from the application’s configuration: the appsettings.json in the working directory, its environment variant, and Cratis__... environment variables, as Arc does for its own configuration.

appsettings.json
{
"Cratis": {
"Chronicle": {
"connectionString": "chronicle://localhost:35000",
"eventStore": "MyArcApp"
}
}
}

With that file, call builder.withChronicle({}). Keys are case-insensitive. To override the file in a deployment, set Cratis__Chronicle__ConnectionString and Cratis__Chronicle__EventStore. Only these two keys are read from configuration; client, completionTimeoutMs, and readModelNamingPolicy are set in code.

Values follow this precedence:

  1. Options passed in code win over configuration.
  2. Environment variables win over appsettings.json.
  3. A client passed in code replaces a configured connection string, so the two never collide.
RegistrationOwnership
{ connectionString, eventStore }Arc creates the SDK client with an artifact catalog for this application, and closes it when the application is disposed
{ client, eventStore }You pass a caller-owned IChronicleClient. Arc never disposes it; your host calls client.dispose(). The client must already have an artifact provider that registers the event types, projections, reducers, and reactors you use

An Arc-owned client is also wired so that reactors can return Arc commands. A caller-owned client needs that handler passed to the SDK before it connects; the reactor page shows how. To use scoped activation with a caller-owned client, also pass chronicleArtifactActivator as its artifactActivator. Dispose the Arc application before the client, so deliveries still running finish while the connection is open.

A projected read model is stored in a container, which is a MongoDB collection by default. The Chronicle SDK names it after the read model identifier unless it is given a readModelNamingPolicy, a function of the identifier and, when the SDK knows it, the read model class. It changes only the container name.

  • With withMongoDB. An Arc-owned client gets a policy that returns the collection Arc’s MongoDB integration reads for a class listed in readModels, so a projected read model lands where your queries look with no configuration. A class outside that list, and a read model known only by identifier, keep the identifier. This holds whichever of withMongoDB and withChronicle you call first. See Naming policies for the rule and for upgrading.
  • With your own readModelNamingPolicy. It replaces the automatic policy. Return the identifier when readModelType is undefined.
  • Without withMongoDB. Arc adds no policy, and the SDK default, the identifier, applies.
  • With a caller-owned client. Arc never changes the client, so it sets no policy, and withChronicle throws if you also pass readModelNamingPolicy. Set the policy in the ChronicleOptions you create the client with.

The option needs @cratis/chronicle 6.29.0 or later.