Releases: Cratis/Chronicle.Kotlin
Release list
Release v2.10.0
Summary
A Spring Boot starter reduces setting Chronicle up to adding a dependency: a
connected client, artifacts registered before the first request is served, and
an IEventStore ready to inject.
Stacked on #46 — that PR carries the artifact discovery and registration this
starter builds on, and should merge first.
Added
io.cratis:chronicle-spring-boot-starter— a connected client, artifacts registered before the first request is served, and anIEventStoreready to inject, configured undercratis.chronicle.- Spring Boot multi-tenancy: the injected
IEventStoreroutes to the namespace the current work belongs to, resolved from a fixed value, an HTTP header, the request subdomain, or a claim on the authenticated principal. - Spring Boot gives each request an identity taken from the authenticated principal, a causation trail describing the call, and a unit of work that commits on success and rolls back on failure. Each can be switched off on its own.
Chronicle— the Java-facing Spring bean exposing the everyday operations without coroutines, for Java callers and blocking MVC handlers.IEventStoreNamespaceResolverfor hosts that decide the namespace themselves.- Spring Boot samples for Kotlin and Java, each with a walkthrough.
- A guide for Spring Boot support.
Changed
- The README is rewritten around what the client does for you, with Kotlin and Java shown side by side throughout.
Release v2.9.0
Summary
Artifacts register themselves, and the twelve open issues in this repository are
closed alongside — most of them parity gaps with the .NET client, several of
them things a JVM application simply could not express before.
Added
- Artifacts are discovered and registered with the kernel automatically when the client connects, in the order the kernel needs them, and again on every reconnect. Manual registration is unchanged and still fully supported.
IEventStore.registerAll()registers every artifact in one call, andawaitRegistration()waits for the automatic pass so the first append is deterministic.ChronicleOptions.withoutAutoRegistration()turns discovery off, andwithArtifactsFrom(vararg packages)narrows it to the packages you own.KnownClientArtifactstakes an explicit list where classpath scanning is unwanted.IArtifactActivatorlets a dependency injection container create artifacts, so a reactor or reducer can take its dependencies through its constructor.- Reactor, reducer and read model reactor handlers may be
suspend, so a handler that awaits an HTTP call or the event log no longer blocks the thread the observation runs on. (#16) IReactorMiddlewarewraps every reactor handler invocation, keeping tracing, logging and metrics out of reactor code. Java implementsBlockingReactorMiddlewareinstead. (#11)- A reactor handler may take parameters beyond the event — a read model resolved for the event's event source out of the box, or anything an
IReactorMethodArgumentResolversupplies. (#27) ICanBeNotifiedAboutReplaytells a reactor when a replay begins and ends, per partition. (#13)store.failedPartitionssurfaces the partitions an observer is stuck on, with the history of attempts, and retries one once the cause is fixed. (#13)ConceptAs<T>gives a domain value a type of its own, so the compiler can tell a book's identifier from a member's. Concepts serialize as the value they wrap, so adopting one for a property already in production changes neither the JSON nor the schema. (#15)AppendOptions.causationandEventForEventSourceId.causationattribute an append to a chain other than the ambient one — an imported event, or a side effect that belongs to a chain of its own. (#43)- Chronicle work is reported as OpenTelemetry spans: appends, batches, reactor observations and reducer folds. Nothing to turn on. (#18)
IProjectionsService.query(declaration)runs a Projection Declaration Language declaration and returns what it projected, without registering anything. (#19)- Captures — sources outside Chronicle, pulled in and appended as events. Declare an
ICaptureand discovery saves and starts it on connect, or drivestore.capturesdirectly. (#10) io.cratis:chronicle-testing—EventScenarioandReadModelScenariospecify what a slice appends and what a reducer folds, in-process, with no kernel, container or database. (#25)- Guides for artifact registration, strongly-typed identifiers, tracing, captures and testing.
Changed
ChronicleOptionsgainsautoDiscoverAndRegister(on by default),artifacts,artifactActivatorandopenTelemetry.- Both console samples now opt out of automatic registration, so they keep working as a tour of the registration API.
IConstraintBuilder.uniqueForandIWebhookDefinitionBuilder.withEventTypetake a JavaClassas well as aKClass, andCausation.of(...)builds one without naming a value class — all three were unreachable from Java before. (#36)
Fixed
- A reactor, reducer or read model reactor with no handlers at all now fails at registration instead of registering successfully and observing nothing. (#17)
- A reactor or reducer declared
internalor private failed on every event it was given, because reflection refused to invoke a handler on a non-public class. - The client's public ABI is checked in and validated on every build, and a Java conformance fixture compiles every public entry point from Java — Java had broken twice while CI stayed green. (#36)
Release v2.8.0
Summary
Events can be appended across several event sources as one atomic batch, and composed before committing.
Added
appendManyaccepting events that each carry their own event source id, stream, tags and subject, committed as one atomic operation with an optional concurrency scope per event source. (#14)- Compose a batch across call sites with
eventSequence.forEventSourceId(id) { ... }, inspect it, and commit it withperform(). (#14)
Release v2.7.0
Summary
Geospatial values can be modelled from Kotlin and Java.
Added
Point,LineStringandPolygontypes that serialize as GeoJSON, so Chronicle recognizes them as geospatial and the sink can index and query them. (#28)- Generated schemas mark geospatial properties with the
point,linestringandpolygonformats, matching the .NET client. (#28) ChronicleGson.chronicleGsonexposes the client's own serializer, for callers producing event content themselves.
Release v2.6.0
Summary
Reactors can now respond to read model changes, not just events.
Added
IReadModelReactor— react to read model instances being added, modified or removed by writingadded,modifiedorremovedmethods, with no watch loop to maintain. (#12)- Read model reactor handlers can return events to be appended as side effects, using the changed instance's key as the event source id. (#12)
Release v2.5.0
Summary
Reactors and reducers can be labelled and can narrow which events they observe.
Added
Release v2.4.0
Summary
Appends can now be shaped by the caller instead of using fixed values.
Added
AppendOptionstakeseventSourceType,eventStreamType,eventStreamId,subject,tagsandoccurred, so an append can target a non-default stream, carry tags, be backdated, or name the compliance subject. (#23)AppendOptionsBuilderfor constructing options from Java, where Kotlin's default arguments are unavailable. (#23)
Fixed
- The compliance
subjectwas fixed to the event source id with no way to override it, so PII for a subject other than the event source could not be modeled from Kotlin or Java. (#23)
Release v2.3.1
Summary
The repository could not be checked out or built on macOS or Windows.
Fixed
IdentityProvider.ktandidentityProvider.ktdiffered only by case, so only one could exist in the working tree on a case-insensitive filesystem and the build failed with an unresolved reference. (#29)
Release v2.3.0
Summary
Kotlin and Java reactors and reducers reach parity with the C# client on observation behavior.
Added
@Reactorand@Reducertake aneventSequence, for observing a sequence other than the event log.@ReducertakesisActive, for a reducer the kernel does not actively run.@OnceOnlyexcludes a reactor from replay on the class, or a single handler on a method.@Replaymarks the handler that takes over while an observer is being replayed.- Reducer handlers can take an
EventContextafter the state. EventContextcarries the observation state, event source type, event stream type and id, event store, namespace, causation, tags, and hash.
Changed
- Handler shapes the client cannot invoke now fail at
register()instead of on every event. (#17)
Fixed
EventContext.correlationIdwas a random value andcausedBywas alwaysIdentity.unknown; both are now read from the kernel.
Release v2.2.0
Summary
Brings the Kotlin/Java Chronicle client to parity with the other Chronicle clients across two phases of work:
- Earlier phase: four new service modules (ExternalServices, Webhooks, Jobs, EventStoreSubscriptions), event type migrations, 15 new model-bound projection attributes, a richer declarative projection builder, a richer ReadModels API, reactor side-effect events, and PII encryption key deletion.
- This phase: three confirmed bug fixes, full
IEventSequence/IEventLogcompleteness (redact, concurrency scopes, bookmarked reads, stream completion, a live append feed),IEventStoreinterface completeness, a richerUnitOfWork, constraint scoping, and typed read-model observation.
Fully additive — nothing existing changes behavior, except one safe, pre-release-only behavior change noted below.
Added
Service modules, migrations, projections, read models (earlier phase)
ExternalServices— register named HTTP or database (MS SQL / PostgreSQL) endpoints with basic/bearer/OAuth authentication, addressable by name from other Chronicle integrations.Webhooks— register webhooks either via a discoverable@Webhook+IWebhookDefinerclass or imperatively, with authentication, header, event-type filtering, and replay/activation options; list and remove webhooks.Jobs— list jobs and their steps, get a single job, and stop/resume/delete a job.EventStoreSubscriptions— subscribe an event store to another event store's outbox with optional event-type filtering, list, and unsubscribe. Now defaults to every event type this client has registered when a subscription isn't narrowed explicitly, instead of subscribing to nothing.- Event type migrations —
IEventTypeMigration/EventTypeMigrationbase class plus anEventTypeMigrationBuilderDSL (renamedFrom,defaultValue,split,combine) for upcasting/downcasting between event type generations, discovered alongside@EventTypeclasses atregister(). - 15 new model-bound projection attributes:
@Join,@ChildrenFrom,@Nested,@ClearWith,@Count,@Increment,@Decrement,@AddFrom,@SubtractFrom,@FromAll,@FromEvery,@NotRewindable,@RemovedWith,@RemovedWithJoin,@NoAutoMap. - Declarative projection builder methods:
.join(),.fromEvery()/.fromAll(),.removedWith()/.removedWithJoin(),.children(),.nested(),.notRewindable(), plus composite/constant keys. - Reactor handlers can now return a follow-up event, a
List<Any>, or the newEventForEventSourceIdwrapper, and it's auto-appended as a side effect — same-stream or cross-stream. ComplianceService.deleteEncryptionKeyfor permanently erasing a subject's PII ("right to be forgotten").
IEventSequence / IEventLog completeness (this phase)
redact/redactForEventSource— permanently rewrites one event's content, or every event's content for an event source (optionally narrowed to specific event types). Destructive and irreversible; the single most significant addition in this phase.- Real
ConcurrencyScopesupport viaAppendOptions.concurrencyScopeandConcurrencyScopeBuilder, andappendManynow commits the whole batch through a single atomic RPC instead of oneAppendcall per event. getTailSequenceNumber,getNextSequenceNumber,getTailSequenceNumberForObserver— the current/next position in the sequence, including relative to the event types a specific reactor/reducer handles.getForEventSourceIdAndEventTypes,getFromSequenceNumber— reading events back for one event source (narrowed by type/stream) or forward from a bookmarked position.completeStream— closes an event stream type/id pair so it can no longer be appended to.appendOperations— a hotFlowthat emits after every completed append made through a specificIEventSequenceinstance.
IEventStore / IChronicleClient completeness (this phase)
compliance,eventTypes,namespaces,externalServices,jobs,eventStoreSubscriptions,webhooks, andidentitiesare now all on theIEventStoreinterface itself (previously only on the concreteEventStoreclass), plusgetEventSequence(id)for non-default event sequences.IChronicleClient.getEventStores()/evictEventStores()— list every event store known to the kernel, and clear this client's cachedEventStoreinstances without disposing the client.IIdentityManagerService.rename— renames the human-readable name the kernel has stored for an identity.INamespacesService.getAll()— lists every namespace in the event store.ChronicleConnectionString.toString()— renders a parsed connection string back to its textual form; round-trips throughparse().
Transactions, constraints, seeding, read models (this phase)
- Richer
IUnitOfWork:isSuccess,getConstraintViolations/getConcurrencyViolations/getAppendErrors,onCompleted,tryGetLastCommittedEventSequenceNumber. RicherIUnitOfWorkManager:tryGetFor,setCurrent. - Constraint scoping —
IConstraintBuilder.perEventSourceType()/.perEventStreamType()/.perEventStreamId()narrow a constraint's uniqueness check to a dimension instead of checking globally across the whole event store. IEventSeedingBuilder.forNamespace()— a scoped builder for seed data targeting a namespace other than the event store's own; typedforEventType()for both the top-level and namespace-scoped builders.watch()/getSnapshotsById()now deserialize straight into the caller's read model type instead of raw JSON;releaseManydecrypts@Piiproperties for a batch of instances in one call.
Samples, docs, and Java interop (both phases)
- Both Kotlin and Java console samples demonstrate every feature above end-to-end, wired into the existing interactive command loop — including, this phase, a single-event redact, a bulk "GDPR erase everything for this customer" redact, constraint scoping,
IdentityManager.rename, read-model snapshot history, and a live background watcher using typedwatch(). - Java bridge parity for all of the above via
io.cratis.chronicle.java.*JavaBridge, including new bridges for the value-class-typed members Java cannot call directly (redact, the event-lookup methods,completeStream,ConcurrencyScopeBuilder.withSequenceNumber, and a callback-based subscription towatch/appendOperations). - New and expanded guide/reference pages (Webhooks, Jobs, Event Type Migrations, Event Store Subscriptions, External Services, EventStore API, Seeding, Configuration, Constraints, Transactions, Read Models, Annotations), with matching validated snippets in both the Kotlin and Java client-snippet trees.
Fixed
UniqueConstraintBuilder.on()was silently ignoring the property actually passed to it and always keying the constraint on the first declared property instead.- Event type and read model registration sent an empty
"{}"schema to the kernel instead of a real JSON schema reflecting the type's properties; PII compliance metadata is now wired into that generated schema too.
Behavior change (safe — pre-release, within this same unreleased PR)
IUnitOfWorkManager.currentnow throwsNoUnitOfWorkHasBeenStartedwhen no unit of work has been begun on the current thread, rather than any prior placeholder behavior. Since this entireUnitOfWorksurface is new in this unreleased PR, there is no released behavior to break.
Known follow-up
EventTypesService's migration-building path,ProjectionsService's new reflection/wire-building paths, andReactorsService's side-effect appending don't have dedicated unit tests yet — there's no established gRPC-stub-mocking pattern in this codebase for those specific paths, only pure-logic builders (EventTypeMigrationBuilder,ProjectionBuilderFor) are covered. Flagging as a follow-up rather than blocking this PR.- The event type migration builder DSL (
renamedFrom/defaultValue/split/combine) has no Java bridge yet, since it relies on Kotlin property references (KProperty1) that Java can't produce directly. The Java client-snippet for migrations is left as an honest "not supported" placeholder rather than a misleading example.
Test plan
-
./gradlew clean build test— zero errors, 224 tests passing (up from 133 at the start of this PR) -
python3 Documentation/validate-client-snippets.py— all Kotlin and Java client snippets compile -
bash Documentation/verify-markdown.sh— markdown lint and link checks pass - Both samples (
Samples/Kotlin/Console,Samples/Java/Console) build cleanly