arvo-event-handler
Version:
Type-safe event handler system with versioning, telemetry, and contract validation for distributed Arvo event-driven architectures, featuring routing and multi-handler support.
107 lines (106 loc) • 4.92 kB
TypeScript
import type { Span, SpanOptions } from '@opentelemetry/api';
import type { ArvoContract, ArvoEvent, ArvoSemanticVersion, CreateArvoEvent, InferArvoEvent, VersionedArvoContract } from 'arvo-core';
import type { z } from 'zod';
/**
* 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;
};
/**
* 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>;
/**
* The domain configuration for multi-domain event broadcasting.
*
* When an event is emitted with a `domain` array, Arvo generates a separate ArvoEvent
* for each resolved domain value. This enables parallel routing to multiple contexts
* such as analytics, auditing, human-in-the-loop systems, or external integrations.
*
* **Accepted Values:**
* - A concrete domain string (e.g. `'audit.orders'`)
* - `null` for standard internal routing (no domain)
* - A symbolic value from {@link ArvoDomain}.
*
* **Broadcasting Rules:**
* - Each resolved domain in the array creates a separate ArvoEvent instance
* - Duplicate resolved domains are automatically removed
* - If the field is omitted, Arvo defaults to `[null]`
*
* **Examples:**
* - `['analytics.orders', 'audit.orders']` → Creates two routed events
* - `[ArvoDomain.FROM_TRIGGERING_EVENT, 'human.review', null]` → Mirrors source domain, routes to review, and standard consumer
* - `[null]` → Emits a single event with no domain routing
* - _Omitted_ → Same as `[null]`
*/
domain?: (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 interface IArvoEventHandler<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?: SpanOptions;
/**
* Optional configuration to customize where system error events are emitted.
*
* This overrides the default system error domain fallback of:
* `[event.domain, handler.contract.domain, null]`
*
* Use this to precisely control the set of domains that should receive structured
* `sys.*.error` events when uncaught exceptions occur in the handler.
*
* Symbolic constants from {@link ArvoDomain} are supported.
*
* @default undefined — uses standard fallback broadcast domains
*/
systemErrorDomain?: (string | null)[];
}