Skip to content

Returning events

A command decides what happened; the integration appends it. Return the event from handle(), and Arc appends it only after authorization, validation, and provide() have passed.

This excerpt is from the compiled kernel suite, in the shape you would write it in your application:

import { field } from '@cratis/fundamentals';
import { eventType } from '@cratis/chronicle/events';
import { command, key } from '@cratis/arc.core';
@eventType()
export class TaskCreated {
@field(String) title: string;
constructor(title: string) { this.title = title; }
}
@command()
export class CreateTask {
@field(String) @key() id = '';
@field(String) title = '';
handle(): TaskCreated {
return new TaskCreated(this.title);
}
}

With Chronicle registered, POST /api/create-task appends one TaskCreated to the event source named by the command’s @key() field, in the tenant’s namespace. The command result carries no response, because the event was consumed on the server.

handle() returnsResult
A registered eventAppended to the command’s event source
An array of registered eventsAppended in one SDK batch
An array of ordinary objectsAn ordinary response, not events
tuple(event, 'message')The event is appended to the command key, and 'message' is the response
tuple(eventSourceIdResponse(id), event)The event is appended to id, and id is returned to the caller
eventForEventSourceId({ eventSourceId, event, ... })Appended to that event source with explicit routing
eventsWithConcurrencyScopes(events, scopes)Appended with exact concurrency scopes; see Concurrency

The integration is a response value handler: it recognizes registered event instances and branded values, and everything else keeps its ordinary meaning. A command can return Chronicle events together with command operations in a tuple(...): the operations run first, and the event batch decides whether they are compensated; see Events and command operations. An event or operation can’t be the command’s client response.

The event source, routing decorators, and explicit targets are covered in Resolving the event source ID. Everything else an appended event carries, such as its subject, causation, and correlation ID, is listed in Event metadata.

The older defineChronicleCommand remains. It takes a client, an event store, a tenant namespace resolver, and produce() returning { events, response }, and appends immediately with its own rejection mapping. Use the model-bound path for new commands. Neither route makes the SDK’s observer completion synchronous with an append acknowledgment.