UNPKG

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
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; }; }