Skip to content

Release v2.2.0

Choose a tag to compare

@github-actions github-actions released this 06 Aug 06:53
6c8058d

Summary

Brings the Kotlin/Java Chronicle client to parity with the other Chronicle clients across two phases of work:

  1. 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.
  2. This phase: three confirmed bug fixes, full IEventSequence/IEventLog completeness (redact, concurrency scopes, bookmarked reads, stream completion, a live append feed), IEventStore interface completeness, a richer UnitOfWork, 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 + IWebhookDefiner class 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/EventTypeMigration base class plus an EventTypeMigrationBuilder DSL (renamedFrom, defaultValue, split, combine) for upcasting/downcasting between event type generations, discovered alongside @EventType classes at register().
  • 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 new EventForEventSourceId wrapper, and it's auto-appended as a side effect — same-stream or cross-stream.
  • ComplianceService.deleteEncryptionKey for 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 ConcurrencyScope support via AppendOptions.concurrencyScope and ConcurrencyScopeBuilder, and appendMany now commits the whole batch through a single atomic RPC instead of one Append call 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 hot Flow that emits after every completed append made through a specific IEventSequence instance.

IEventStore / IChronicleClient completeness (this phase)

  • compliance, eventTypes, namespaces, externalServices, jobs, eventStoreSubscriptions, webhooks, and identities are now all on the IEventStore interface itself (previously only on the concrete EventStore class), plus getEventSequence(id) for non-default event sequences.
  • IChronicleClient.getEventStores() / evictEventStores() — list every event store known to the kernel, and clear this client's cached EventStore instances 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 through parse().

Transactions, constraints, seeding, read models (this phase)

  • Richer IUnitOfWork: isSuccess, getConstraintViolations/getConcurrencyViolations/getAppendErrors, onCompleted, tryGetLastCommittedEventSequenceNumber. Richer IUnitOfWorkManager: 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; typed forEventType() 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; releaseMany decrypts @Pii properties 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 typed watch().
  • 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 to watch/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.current now throws NoUnitOfWorkHasBeenStarted when no unit of work has been begun on the current thread, rather than any prior placeholder behavior. Since this entire UnitOfWork surface 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, and ReactorsService'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