arvo-event-handler
Version:
A complete set of orthogonal event handler and orchestration primitives for Arvo based applications, featuring declarative state machines (XState), imperative resumables for agentic workflows, contract-based routing, OpenTelemetry observability, and in-me
110 lines (109 loc) • 4.92 kB
TypeScript
import type { Span } from '@opentelemetry/api';
import type { ArvoContract, ArvoEvent, ArvoSemanticVersion, CreateArvoEvent, InferArvoEvent, OpenTelemetryHeaders, VersionedArvoContract } from 'arvo-core';
import type { z } from 'zod';
import type { ArvoEventHandlerOtelSpanOptions, NonEmptyArray } from '../types';
/**
* Represents the input for an ArvoEvent handler function.
*/
export type ArvoEventHandlerFunctionInput<TContract extends VersionedArvoContract<any, any>> = {
/** The ArvoEvent object. */
event: InferArvoEvent<ArvoEvent<z.infer<TContract['accepts']['schema']>, Record<string, any>, TContract['accepts']['type']>>;
/** The source field data of the handler */
source: string;
/** The domain information for handling the event */
domain: {
self: string | null;
event: string | null;
};
/** The contract used in the processing */
contract: TContract;
/** The OpenTelemetry span */
span: Span;
/** The span headers */
spanHeaders: OpenTelemetryHeaders;
};
/**
* Represents the output of an ArvoEvent handler function.
*/
export type ArvoEventHandlerFunctionOutput<TContract extends VersionedArvoContract<any, any>> = {
[K in keyof TContract['emits']]: Pick<CreateArvoEvent<z.infer<TContract['emits'][K]>, K & string>, 'id' | 'time' | 'type' | 'data' | 'to' | 'accesscontrol' | 'redirectto'> & {
/**
* An optional override for the execution units of this specific event.
*
* @remarks
* Execution units represent the computational cost or resources required to process this event.
* If not provided, the default value defined in the handler's constructor will be used.
*/
executionunits?: number;
/** Optional extensions for the event. */
__extensions?: Record<string, string | number | boolean>;
/**
* Specifies which execution contexts should receive this event. Each domain value creates a separate routed event.
* Defaults to the domain encoded in the triggering event's subject with fallback to ArvoDomain.LOCAL (null) to
* maintain execution context continuity.
*
* @default [ArvoDomain.FROM_PARENT_SUBJECT]
*
* **Examples:**
* - `['human.interaction', 'audit.reporting']` → Creates two routed events
* - `[ArvoDomain.FROM_TRIGGERING_EVENT, 'human.review']` → Mirrors source domain and routes to review
* - `[ArvoDomain.LOCAL]` → Stays in current execution context
*/
domain?: NonEmptyArray<string | null>;
};
}[keyof TContract['emits']];
/**
* Defines the structure of an ArvoEvent handler function.
*/
export type ArvoEventHandlerFunction<TContract extends ArvoContract> = {
[V in ArvoSemanticVersion & keyof TContract['versions']]: (params: ArvoEventHandlerFunctionInput<VersionedArvoContract<TContract, V>>) => Promise<Array<ArvoEventHandlerFunctionOutput<VersionedArvoContract<TContract, V>>> | ArvoEventHandlerFunctionOutput<VersionedArvoContract<TContract, V>> | void>;
};
/**
* Interface for an ArvoEvent handler.
*/
export type ArvoEventHandlerParam<TContract extends ArvoContract> = {
/**
* The contract for the handler defining its input and outputs as well as the description.
*/
contract: TContract;
/**
* The default execution cost of the function.
* This can represent a dollar value or some other number with a rate card.
*/
executionunits?: number;
/**
* The functional handler of the event which takes the input, performs an action, and returns the result.
* @param params - The input parameters for the handler function.
* @returns A promise of object containing the created ArvoEvent and optional extensions.
*/
handler: ArvoEventHandlerFunction<TContract>;
/**
* The OpenTelemetry span options
*/
spanOptions?: ArvoEventHandlerOtelSpanOptions;
/**
* Optional default domains for the events emitted
* by the event handler.
*/
defaultEventEmissionDomains?: {
/**
* Default domains for system error events emitted by this handler.
*
* System errors are routed through these domains when the handler encounters
* unhandled exceptions or critical failures.
*
* @default [ArvoDomain.ORCHESTRATION_CONTEXT]
*/
systemError?: NonEmptyArray<string | null>;
/**
* Default domains for response events emitted by this handler.
*
* Response events are routed through these domains when the handler successfully
* processes an incoming event. Individual handler implementations can override
* this default on a per-event basis.
*
* @default [ArvoDomain.ORCHESTRATION_CONTEXT]
*/
emits?: NonEmptyArray<string | null>;
};
};