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
170 lines (169 loc) • 9.05 kB
TypeScript
import { type ArvoOrchestratorEventTypeGen, type CreateArvoEvent, type InferVersionedArvoContract, type VersionedArvoContract } from 'arvo-core';
import { type ActionFunction, type MachineConfig, type MachineContext, type MetaObject, type ParameterizedObject, type SetupTypes } from 'xstate';
import type { z } from 'zod';
import ArvoMachine from '.';
import type { EnqueueArvoEventActionParam, ExtractOrchestratorType, InferServiceContract, ToParameterizedObject, ToProvidedActor } from './types';
import { NonEmptyArray } from '../types';
/**
* Establishes the foundation for creating Arvo-compatible state machines.
*
* Designed for synchronous state machine orchestrations in Arvo's event-driven architecture.
* Builds upon XState with Arvo-specific constraints to enforce predictable state transitions.
*
* @throws {ConfigViolation} When configuration violates Arvo constraints:
* - Using `actors` or `delays` (async behavior not supported)
* - Overriding reserved `enqueueArvoEvent` action name
* - Machine version mismatch with contract version
* - Using `invoke` or `after` in state configurations
* - Service contracts with duplicate URIs (multiple versions of same contract)
* - Circular dependency (self contract URI matches a service contract URI)
*/
export declare function setupArvoMachine<TContext extends MachineContext, TSelfContract extends VersionedArvoContract<any, any>, TServiceContracts extends Record<string, VersionedArvoContract<any, any>>, TActions extends Record<string, ParameterizedObject['params'] | undefined> = {}, TGuards extends Record<string, ParameterizedObject['params'] | undefined> = {}, TTag extends string = string, TMeta extends MetaObject = MetaObject>(param: {
schemas?: unknown;
/**
* Contract definitions for the machine's event interface.
* Defines what events the machine accepts, emits, and exchanges with services.
*/
contracts: {
/**
* Self contract defining the machine's initialization input structure
* and the completion output structure when the machine finishes execution.
*/
self: TSelfContract;
/**
* Service contracts defining the event interfaces for external services.
* Each service specifies the events it accepts and emits, enabling
* type-safe communication between the machine and its dependencies.
*/
services: TServiceContracts;
};
/**
* Type definitions for the machine's internal structure.
* Specifies the shape of context and other variables used throughout
* the machine's lifecycle. These types enable full type inference and safety.
*/
types?: Omit<SetupTypes<TContext, InferServiceContract<TServiceContracts>['events'], {}, TTag, InferVersionedArvoContract<TSelfContract>['accepts']['data'], InferVersionedArvoContract<TSelfContract>['emits'][ReturnType<typeof ArvoOrchestratorEventTypeGen.complete<ExtractOrchestratorType<TSelfContract['accepts']['type']>>>]['data'], InferServiceContract<TServiceContracts>['emitted'], TMeta>, 'input' | 'output' | 'children' | 'emitted'>;
/**
* Named action implementations that can be referenced throughout the machine.
* Actions perform side effects like data transformations, context updates,
* and event emissions. Each action receives the current context and event,
* along with any parameters defined in its type.
*
* For more information, see [xstate action docs](https://stately.ai/docs/actions)
*
* @example
* ```typescript
* actions: {
* updateUser: ({ context, event }, params) => {
* // Transform and update context
* },
* logEvent: ({ event }) => {
* // Log for debugging
* }
* }
* ```
*/
actions?: {
[]: ActionFunction<TContext, InferServiceContract<TServiceContracts>['events'], InferServiceContract<TServiceContracts>['events'], TActions[K], never, ToParameterizedObject<TActions>, ToParameterizedObject<TGuards>, never, InferServiceContract<TServiceContracts>['emitted']>;
};
/**
* Named guard implementations that control conditional state transitions.
* Guards are boolean functions that determine whether a transition should occur
* based on the current context and event. They enable dynamic flow control
* without side effects.
*
* For more information, see [xstate guard docs](https://stately.ai/docs/guards)
*
* @example
* ```typescript
* guards: {
* isAuthorized: ({ context, event }, params) => {
* return context.user.role === 'admin';
* },
* hasRequiredData: ({ context }) => {
* return context.data !== null;
* }
* }
* ```
*/
guards?: {
[]: (args: {
context: TContext;
event: InferServiceContract<TServiceContracts>['events'];
}, params: TGuards[K]) => boolean;
};
}): {
/**
* Creates an Arvo-compatible state machine with the specified configuration.
*
* Constructs a fully-typed state machine that orchestrates event-driven workflows
* using the contracts and types defined in setup. The machine enforces synchronous
* execution and validates configuration against Arvo constraints.
*
* For more information, see [xstate state machine docs](https://stately.ai/docs/states)
* @returns {ArvoMachine} A configured Arvo machine ready for execution
* @throws {ConfigViolation} When configuration violates Arvo constraints (see {@link setupArvoMachine} docs)
*
* @example
* ```typescript
* const machine = setup.createMachine({
* id: 'machineV100',
* initial: 'verifying',
* context: ({ input }) => ({
* userId: input.data.userId,
* verified: false
* }),
* states: {
* verifying: {
* on: {
* 'com.user.verified': {
* target: 'active',
* actions: { type: 'updateUser' }
* }
* }
* },
* active: {
* type: 'final'
* }
* }
* });
* ```
*/
createMachine: <const TConfig extends MachineConfig<TContext, InferServiceContract<TServiceContracts>["events"], ToProvidedActor<{}, {}>, ToParameterizedObject<TActions & {
enqueueArvoEvent: EnqueueArvoEventActionParam;
}>, ToParameterizedObject<TGuards>, never, TTag, InferVersionedArvoContract<TSelfContract>["accepts"], z.input<TSelfContract["emits"][ReturnType<typeof ArvoOrchestratorEventTypeGen.complete<ExtractOrchestratorType<TSelfContract["accepts"]["type"]>>>]> & {
__id?: CreateArvoEvent<Record<string, unknown>, string>["id"];
__executionunits?: CreateArvoEvent<Record<string, unknown>, string>["executionunits"];
__domain?: NonEmptyArray<string | null>;
}, InferServiceContract<TServiceContracts>["emitted"], TMeta>>(config: TConfig & {
id: string;
version?: TSelfContract["version"];
}) => ArvoMachine<string, TSelfContract["version"], TSelfContract, TServiceContracts, import("xstate").StateMachine<TContext, { [K in keyof TServiceContracts]: import("./types").InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>; }[keyof TServiceContracts], {}, never, (TActions & {
enqueueArvoEvent: EnqueueArvoEventActionParam;
} extends infer T extends Record<string, import("xstate").NonReducibleUnknown> ? { [K_1 in keyof T as K_1 & string]: {
type: K_1 & string;
params: T[K_1];
}; } : never)[keyof (TActions & {
enqueueArvoEvent: EnqueueArvoEventActionParam;
} extends infer T_1 extends Record<string, import("xstate").NonReducibleUnknown> ? { [K_1 in keyof T_1 as K_1 & string]: {
type: K_1 & string;
params: T_1[K_1];
}; } : never)], { [K_2 in keyof TGuards as K_2 & string]: {
type: K_2 & string;
params: TGuards[K_2];
}; }[keyof { [K_2 in keyof TGuards as K_2 & string]: {
type: K_2 & string;
params: TGuards[K_2];
}; }], never, {} | {
[]: {} | /*elided*/ any | {
[]: {} | /*elided*/ any | /*elided*/ any;
};
} | {
[]: {} | {
[]: {} | /*elided*/ any | /*elided*/ any;
} | /*elided*/ any;
}, TTag, TSelfContract["accepts"]["schema"]["_output"], { [K_3 in string & keyof TSelfContract["emits"]]: import("arvo-core").InferArvoEvent<import("arvo-core").ArvoEvent<TSelfContract["emits"][K_3]["_output"], Record<string, any>, K_3>>; }[`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]["data"], { [K_4 in keyof TServiceContracts]: EnqueueArvoEventActionParam<z.input<TServiceContracts[K_4]["accepts"]["schema"]>, TServiceContracts[K_4]["accepts"]["type"], Record<string, string | number | boolean | null>>; }[keyof TServiceContracts], TMeta, {
id: any;
states: any;
}>>;
};