UNPKG

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

154 lines (153 loc) 9.44 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.setupArvoMachine = setupArvoMachine; var arvo_core_1 = require("arvo-core"); var xstate_1 = require("xstate"); var _1 = __importDefault(require(".")); var servicesValidation_1 = require("../ArvoOrchestrationUtils/servicesValidation"); var errors_1 = require("../errors"); var object_1 = require("../utils/object"); var utils_1 = require("./utils"); /** * 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) */ function setupArvoMachine(param) { var _a, _b; var createConfigErrorMessage = function (type) { return (0, arvo_core_1.cleanString)("\n Configuration Error: '".concat(type, "' not supported in Arvo machines\n \n Arvo machines do not support XState ").concat(type === 'actor' ? 'actors' : 'delay transitions', " as they introduce asynchronous behavior.\n \n To fix:\n 1. Remove the '").concat(type, "' configuration\n 2. Use Arvo's event-driven patterns instead for asynchronous operations\n ")); }; if (param.actors) { throw new errors_1.ConfigViolation(createConfigErrorMessage('actor')); } if (param.delays) { throw new errors_1.ConfigViolation(createConfigErrorMessage('delays')); } if ((_a = param.actions) === null || _a === void 0 ? void 0 : _a.enqueueArvoEvent) { throw new errors_1.ConfigViolation((0, arvo_core_1.cleanString)("\n Configuration Error: Reserved action name 'enqueueArvoEvent'\n \n 'enqueueArvoEvent' is an internal Arvo system action and cannot be overridden.\n \n To fix: Use a different name for your action, such as:\n - 'queueCustomEvent'\n - 'scheduleEvent'\n - 'dispatchEvent'\n ")); } (0, servicesValidation_1.servicesValidation)(param.contracts, 'machine'); var combinedActions = __assign(__assign({}, ((_b = param.actions) !== null && _b !== void 0 ? _b : {})), { enqueueArvoEvent: (0, xstate_1.assign)(function (_a, param) { var _b, _c, _d, _e, _f; var context = _a.context; return (__assign(__assign({}, (context !== null && context !== void 0 ? context : {})), { arvo$$: __assign(__assign({}, ((_b = context === null || context === void 0 ? void 0 : context.arvo$$) !== null && _b !== void 0 ? _b : {})), { volatile$$: __assign(__assign({}, ((_d = (_c = context === null || context === void 0 ? void 0 : context.arvo$$) === null || _c === void 0 ? void 0 : _c.volatile$$) !== null && _d !== void 0 ? _d : {})), { eventQueue$$: __spreadArray(__spreadArray([], (((_f = (_e = context === null || context === void 0 ? void 0 : context.arvo$$) === null || _e === void 0 ? void 0 : _e.volatile$$) === null || _f === void 0 ? void 0 : _f.eventQueue$$) || []), true), [param], false) }) }) })); }) }); // Call the original setup function with modified parameters var systemSetup = (0, xstate_1.setup)({ schemas: param.schemas, types: param.types, guards: param.guards, actions: combinedActions, }); /** * Creates an Arvo-compatible XState machine. */ var createMachine = function (config) { var _a, _b, _c, _d, _e; var machineVersion = (_a = config.version) !== null && _a !== void 0 ? _a : param.contracts.self.version; if (machineVersion !== param.contracts.self.version) { throw new errors_1.ConfigViolation("Version mismatch: Machine version must be '".concat(param.contracts.self.version, "' or undefined, received '").concat(config.version, "'")); } var createConfigErrorMessage = function (type, path) { var location = path.join(' > '); if (type === 'invoke') { return (0, arvo_core_1.cleanString)("\n Configuration Error: 'invoke' not supported\n \n Location: ".concat(location, "\n \n Arvo machines do not support XState invocations as they introduce asynchronous behavior.\n \n To fix: Replace 'invoke' with Arvo event-driven patterns for asynchronous operations\n ")); } if (type === 'after') { return (0, arvo_core_1.cleanString)("\n Configuration Error: 'after' not supported\n \n Location: ".concat(location, "\n \n Arvo machines do not support delayed transitions as they introduce asynchronous behavior.\n \n To fix: Replace 'after' with Arvo event-driven patterns for time-based operations\n ")); } if (type === 'enqueueArvoEvent') { return (0, arvo_core_1.cleanString)("\n Configuration Error: Reserved action name 'enqueueArvoEvent'\n \n Location: ".concat(location, "\n \n 'enqueueArvoEvent' is an internal Arvo system action and cannot be used in machine configurations.\n \n To fix: Use a different name for your action\n ")); } }; for (var _i = 0, _f = (0, object_1.getAllPaths)((_b = config.states) !== null && _b !== void 0 ? _b : {}); _i < _f.length; _i++) { var item = _f[_i]; if (item.path.includes('invoke')) { throw new errors_1.ConfigViolation((_c = createConfigErrorMessage('invoke', item.path)) !== null && _c !== void 0 ? _c : 'Invoke not allowed'); } if (item.path.includes('after')) { throw new errors_1.ConfigViolation((_d = createConfigErrorMessage('after', item.path)) !== null && _d !== void 0 ? _d : 'After not allowed'); } if (item.path.includes('enqueueArvoEvent')) { throw new errors_1.ConfigViolation((_e = createConfigErrorMessage('enqueueArvoEvent', item.path)) !== null && _e !== void 0 ? _e : 'EnqueueArvoEvent not allowed'); } } var machine = systemSetup.createMachine(__assign({}, config)); var hasParallelStates = (0, utils_1.detectParallelStates)(machine.config); var hasMultipleNonSystemErrorEvents = Object.values(param.contracts.services).some(function (item) { return Object.keys(item.emits).length > 1; }); var requiresLocking = hasParallelStates || hasMultipleNonSystemErrorEvents; return new _1.default(config.id, machineVersion, param.contracts, machine, requiresLocking); }; return { /** * 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: createMachine, }; }