import { SchemaBase } from './dsl.js'; import type { DtoField } from './dto.js'; import type { FlowSchema } from './flow.js'; /** * Domain event declaration: a fact that has happened ("OrderCancelled"), * carrying a data snapshot (not references). Declared as a first-class schema * so the flow `publish` action can be compile-time checked against it (event * name exists, payload fields match) and the outbox table + handler wiring can * be generated. * * Command vs event: a command says "do something" (future tense, one receiver, * caller senses failure); an event says "something happened" (past tense, zero * to many subscribers, publisher does not care who handles it). */ export interface DomainEventSchema extends SchemaBase { type: 'domain-event'; /** Payload fields: data snapshot, not references. */ fields: Record; } export function defineDomainEvent(options: { name: string; fields: Record; description?: string; }): DomainEventSchema { if (Object.keys(options.fields).length === 0) { throw new Error(`domain event '${options.name}': fields must not be empty`); } return { type: 'domain-event', name: options.name, description: options.description, fields: options.fields, }; } /** * Event subscription: declares that a handler processes a domain event. * The processing logic is a flow (the flow model is the execution model — a * handler flow receives the event payload as its input slot). A plain async * function is accepted as the runtime path until a flow executor exists; the * declared flow is then compile-time checked (payload fields match the event) * and drives generation. */ export interface EventHandlerSchema extends SchemaBase { type: 'event-handler'; /** Subscribed event name (must match a defineDomainEvent name). */ event: string; /** Processing flow — receives the event payload as its input slot. */ flow?: FlowSchema; /** Runtime handler function (used directly when no flow executor exists). */ handler?: (payload: Record) => Promise | void; } export function defineEventHandler(options: { name: string; event: string; flow?: FlowSchema; handler?: (payload: Record) => Promise | void; description?: string; }): EventHandlerSchema { if (options.flow === undefined && options.handler === undefined) { throw new Error(`event handler '${options.name}': at least one of flow or handler is required`); } return { type: 'event-handler', name: options.name, description: options.description, event: options.event, flow: options.flow, handler: options.handler, }; }