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.
94 lines (93 loc) • 4.16 kB
TypeScript
import { type ArvoContract, type ArvoEvent, type ArvoOrchestratorContract, type ArvoSemanticVersion, type VersionedArvoContract } from 'arvo-core';
import type { AnyActorLogic } from 'xstate';
import type { z } from 'zod';
/**
* Represents an ArvoMachine object that can be consumed by an Arvo orchestrator.
* ArvoMachine encapsulates the logic and metadata required for an Arvo-compatible
* state machine. It combines XState's actor logic with Arvo-specific contracts
* and versioning information.
*
* @remarks
* It is strongly recommended to use `setupArvoMachine(...).createMachine(...)`
* instead of creating this object directly. The setup function provides additional
* type safety and validation that helps prevent runtime errors.
*/
export default class ArvoMachine<TId extends string, TVersion extends ArvoSemanticVersion, TSelfContract extends VersionedArvoContract<ArvoOrchestratorContract, TVersion>, TServiceContract extends Record<string, VersionedArvoContract<ArvoContract, ArvoSemanticVersion>>, TLogic extends AnyActorLogic> {
readonly id: TId;
readonly version: TVersion;
readonly contracts: {
self: TSelfContract;
services: TServiceContract;
};
readonly logic: TLogic;
readonly requiresResourceLocking: boolean;
/**
* Creates a new ArvoMachine instance.
*
* @param id - A unique identifier for the machine. This ID must be unique within
* the scope of an orchestrator and is used for routing and logging.
*
* @param version - The semantic version of the machine. Must follow semver format
* and match the version specified in the contract.
*
* @param contracts - Configuration object containing contract definitions
* @param contracts.self - The contract defining this machine's interface and capabilities
* @param contracts.services - Record of contracts for services this machine can interact with
*
* @param logic - The XState actor logic that defines the machine's behavior,
* including states, transitions, and actions.
* @param [requiresResourceLocking] - Optional flag indicating if the machine needs distributed locks.
* False when machine has no parallel states and executes sequentially.
* Defaults to true.
*
* @throws {Error} When contracts are invalid or incompatible with the specified version
*/
constructor(id: TId, version: TVersion, contracts: {
self: TSelfContract;
services: TServiceContract;
}, logic: TLogic, requiresResourceLocking?: boolean);
/**
* Gets the event type that this machine accepts, as defined in its contract.
*/
get source(): TSelfContract['accepts']['type'];
/**
* Validates an event against the machine's contracts and data schemas.
* Performs validation for both self-contract events and service contract events.
*
* @param event - The event to validate
* @returns A validation result object:
* - "VALID" - Event is valid and can be processed
* - "CONTRACT_UNRESOLVED" - No matching contract found for the event
* - "INVALID" - Event dataschema conflict with contract
* - "INVALID_DATA" - Event data conflicts with contract
*
* @example
* ```typescript
* const result = machine.validateInput(event);
* if (result.type === "VALID") {
* // Process the event
* } else if (result.type === "INVALID") {
* console.error(result.error);
* } else {
* // Handle unresolved contract
* }
* ```
*
* @remarks
* The validation process includes:
* - Finding a matching contract (self or service)
* - Validating dataschema URI and version if present
* - Validating event data against the contract schema
*/
validateInput(event: ArvoEvent): {
type: 'VALID';
} | {
type: 'CONTRACT_UNRESOLVED';
} | {
type: 'INVALID';
error: Error;
} | {
type: 'INVALID_DATA';
error: z.ZodError;
};
}