arvo-event-handler 3.0.14 → 3.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/ArvoEventHandler/index.d.ts +20 -123
  2. package/dist/ArvoEventHandler/index.js +5 -112
  3. package/dist/ArvoMachine/createMachine.d.ts +103 -158
  4. package/dist/ArvoMachine/createMachine.js +59 -181
  5. package/dist/ArvoMachine/index.d.ts +5 -57
  6. package/dist/ArvoMachine/index.js +8 -117
  7. package/dist/ArvoMachine/types.d.ts +0 -82
  8. package/dist/ArvoMachine/utils.d.ts +0 -15
  9. package/dist/ArvoMachine/utils.js +0 -15
  10. package/dist/ArvoOrchestrationUtils/createEmitableEvent.d.ts +31 -0
  11. package/dist/ArvoOrchestrationUtils/createEmitableEvent.js +18 -0
  12. package/dist/ArvoOrchestrationUtils/error.d.ts +22 -0
  13. package/dist/ArvoOrchestrationUtils/error.js +21 -0
  14. package/dist/ArvoOrchestrationUtils/handlerErrors.d.ts +30 -2
  15. package/dist/ArvoOrchestrationUtils/handlerErrors.js +19 -2
  16. package/dist/ArvoOrchestrationUtils/inputValidation.d.ts +47 -0
  17. package/dist/ArvoOrchestrationUtils/inputValidation.js +120 -0
  18. package/dist/ArvoOrchestrationUtils/orchestrationExecutionState.d.ts +24 -1
  19. package/dist/ArvoOrchestrationUtils/orchestrationExecutionState.js +9 -1
  20. package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/acquireLockWithValidation.d.ts +5 -1
  21. package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/acquireLockWithValidation.js +5 -1
  22. package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/index.d.ts +44 -5
  23. package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/index.js +17 -5
  24. package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/validateAndParseSubject.d.ts +6 -1
  25. package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/validateAndParseSubject.js +6 -1
  26. package/dist/ArvoOrchestrationUtils/servicesValidation.d.ts +14 -6
  27. package/dist/ArvoOrchestrationUtils/servicesValidation.js +14 -6
  28. package/dist/ArvoOrchestrator/factory.d.ts +18 -15
  29. package/dist/ArvoOrchestrator/factory.js +19 -16
  30. package/dist/ArvoOrchestrator/index.d.ts +51 -19
  31. package/dist/ArvoOrchestrator/index.js +29 -17
  32. package/dist/ArvoOrchestrator/types.d.ts +74 -49
  33. package/dist/ArvoResumable/factory.d.ts +31 -36
  34. package/dist/ArvoResumable/factory.js +29 -18
  35. package/dist/ArvoResumable/index.d.ts +69 -65
  36. package/dist/ArvoResumable/index.js +49 -92
  37. package/dist/ArvoResumable/types.d.ts +177 -72
  38. package/dist/IArvoEventHandler/index.d.ts +29 -15
  39. package/package.json +2 -2
@@ -46,59 +46,31 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
46
46
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
47
  }
48
48
  };
49
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
50
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
51
- if (ar || !(i in from)) {
52
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
53
- ar[i] = from[i];
54
- }
55
- }
56
- return to.concat(ar || Array.prototype.slice.call(from));
57
- };
58
49
  Object.defineProperty(exports, "__esModule", { value: true });
59
50
  exports.ArvoResumable = void 0;
60
51
  var api_1 = require("@opentelemetry/api");
61
52
  var arvo_core_1 = require("arvo-core");
62
53
  var createEmitableEvent_1 = require("../ArvoOrchestrationUtils/createEmitableEvent");
54
+ var inputValidation_1 = require("../ArvoOrchestrationUtils/inputValidation");
63
55
  var orchestrationExecutionWrapper_1 = require("../ArvoOrchestrationUtils/orchestrationExecutionWrapper");
64
56
  var index_1 = require("../SyncEventResource/index");
65
57
  var errors_1 = require("../errors");
66
58
  /**
67
- * ArvoResumable - A stateful orchestration handler for managing distributed workflows
68
- *
69
- * ArvoResumable provides a handler-based approach to workflow orchestration that prioritizes
70
- * explicit control and simplicity over declarative abstractions. It excels at straightforward
71
- * request-response patterns and linear workflows while maintaining full type safety and
72
- * contract validation throughout the execution lifecycle.
73
- *
74
- * This class addresses fundamental issues in event-driven architecture including:
75
- * - Contract management with runtime validation and type safety
76
- * - Graduated complexity allowing simple workflows to remain simple
77
- * - Unified event handling across initialization and service responses
78
- * - Explicit state management without hidden abstractions
79
- *
80
- * Key capabilities:
81
- * - Handler-based workflow orchestration with explicit state control
82
- * - Contract-driven event validation with runtime schema enforcement
83
- * - Distributed resource locking for transaction safety
84
- * - Comprehensive OpenTelemetry integration for observability
85
- * - Automatic error handling with system error event generation
86
- * - Support for orchestrator chaining and nested workflow patterns
87
- * - Domain-based event routing and organization
59
+ * ArvoResumable complements {@link ArvoOrchestrator} by providing imperative
60
+ * handler functions for orchestration logic instead of declarative state machines.
61
+ * While ArvoOrchestrator excels at complex static workflows with deterministic
62
+ * branching, ArvoResumable handles dynamic orchestrations where branching logic
63
+ * depends on runtime context and event data.
88
64
  *
89
- * Unlike state machine approaches, ArvoResumable uses imperative handler functions
90
- * that provide direct control over workflow logic. This makes debugging easier and
91
- * reduces the learning curve for teams familiar with traditional programming patterns.
92
- *
93
- * @see {@link createArvoResumable} Factory function for creating instances
94
- * @see {@link ArvoResumableHandler} Handler interface documentation
95
- * @see {@link ArvoResumableState} State structure documentation
65
+ * Use this for dynamic orchestrations with context-dependent branching
66
+ * or when preferring imperative programming patterns over state machines.
96
67
  */
97
68
  var ArvoResumable = /** @class */ (function () {
98
69
  function ArvoResumable(param) {
99
70
  var _a;
100
71
  var _b, _c, _d;
101
- this.systemErrorDomain = [];
72
+ /** Optional domains for routing system error events */
73
+ this.systemErrorDomain = undefined;
102
74
  this.executionunits = param.executionunits;
103
75
  this.source = param.contracts.self.type;
104
76
  this.syncEventResource = new index_1.SyncEventResource(param.memory, (_b = param.requiresResourceLocking) !== null && _b !== void 0 ? _b : true);
@@ -108,6 +80,7 @@ var ArvoResumable = /** @class */ (function () {
108
80
  this.spanOptions = __assign(__assign({ kind: api_1.SpanKind.PRODUCER }, param.spanOptions), { attributes: __assign(__assign((_a = {}, _a[arvo_core_1.ArvoExecution.ATTR_SPAN_KIND] = arvo_core_1.ArvoExecutionSpanKind.RESUMABLE, _a[arvo_core_1.OpenInference.ATTR_SPAN_KIND] = arvo_core_1.OpenInferenceSpanKind.CHAIN, _a), ((_d = (_c = param.spanOptions) === null || _c === void 0 ? void 0 : _c.attributes) !== null && _d !== void 0 ? _d : {})), { 'arvo.handler.source': this.source, 'arvo.contract.uri': this.contracts.self.uri }) });
109
81
  }
110
82
  Object.defineProperty(ArvoResumable.prototype, "requiresResourceLocking", {
83
+ /** Whether this resumable requires resource locking for concurrent safety */
111
84
  get: function () {
112
85
  return this.syncEventResource.requiresResourceLocking;
113
86
  },
@@ -115,6 +88,7 @@ var ArvoResumable = /** @class */ (function () {
115
88
  configurable: true
116
89
  });
117
90
  Object.defineProperty(ArvoResumable.prototype, "memory", {
91
+ /** Memory interface for state persistence and retrieval */
118
92
  get: function () {
119
93
  return this.syncEventResource.memory;
120
94
  },
@@ -122,72 +96,48 @@ var ArvoResumable = /** @class */ (function () {
122
96
  configurable: true
123
97
  });
124
98
  Object.defineProperty(ArvoResumable.prototype, "domain", {
99
+ /** The contract-defined domain for the handler */
125
100
  get: function () {
126
101
  return this.contracts.self.domain;
127
102
  },
128
103
  enumerable: false,
129
104
  configurable: true
130
105
  });
106
+ /**
107
+ * Validates incoming event against self or service contracts.
108
+ *
109
+ * Resolves the appropriate contract (self for initialization, service for responses),
110
+ * validates schema compatibility, and ensures event data matches contract requirements.
111
+ *
112
+ * See {@link validateInputEvent} for more infromation
113
+ */
131
114
  ArvoResumable.prototype.validateInput = function (event, span) {
132
- var _a;
133
- var resolvedContract = null;
134
- var contractType;
135
- var parsedEventDataSchema = arvo_core_1.EventDataschemaUtil.parse(event);
136
- if (!parsedEventDataSchema) {
137
- throw new errors_1.ExecutionViolation("Event dataschema resolution failed: Unable to parse dataschema='".concat(event.dataschema, "' for event(id='").concat(event.id, "', type='").concat(event.type, "'). This makes the event opaque and does not allow contract resolution"));
138
- }
139
- if (event.type === this.contracts.self.type) {
140
- contractType = 'self';
141
- resolvedContract = this.contracts.self.version(parsedEventDataSchema.version);
142
- }
143
- else {
144
- contractType = 'service';
145
- for (var _i = 0, _b = Object.values(this.contracts.services); _i < _b.length; _i++) {
146
- var contract = _b[_i];
147
- if (resolvedContract)
148
- break;
149
- for (var _c = 0, _d = __spreadArray(__spreadArray([], contract.emitList, true), [contract.systemError], false); _c < _d.length; _c++) {
150
- var emitType = _d[_c];
151
- if (resolvedContract)
152
- break;
153
- if (event.type === emitType.type) {
154
- resolvedContract = contract;
155
- }
156
- }
157
- }
158
- }
159
- if (!resolvedContract) {
160
- throw new errors_1.ConfigViolation("Contract resolution failed: No matching contract found for event (id='".concat(event.id, "', type='").concat(event.type, "')"));
161
- }
162
- (0, arvo_core_1.logToSpan)({
163
- level: 'INFO',
164
- message: "Dataschema resolved: ".concat(event.dataschema, " matches contract(uri='").concat(resolvedContract.uri, "', version='").concat(resolvedContract.version, "')"),
165
- }, span);
166
- if (parsedEventDataSchema.uri !== resolvedContract.uri) {
167
- throw new Error("Contract URI mismatch: ".concat(contractType, " Contract(uri='").concat(resolvedContract.uri, "', type='").concat(resolvedContract.accepts.type, "') does not match Event(dataschema='").concat(event.dataschema, "', type='").concat(event.type, "')"));
168
- }
169
- if (!(0, arvo_core_1.isWildCardArvoSematicVersion)(parsedEventDataSchema.version) &&
170
- parsedEventDataSchema.version !== resolvedContract.version) {
171
- throw new Error("Contract version mismatch: ".concat(contractType, " Contract(version='").concat(resolvedContract.version, "', type='").concat(resolvedContract.accepts.type, "', uri=").concat(resolvedContract.uri, ") does not match Event(dataschema='").concat(event.dataschema, "', type='").concat(event.type, "')"));
172
- }
173
- var validationSchema = contractType === 'self'
174
- ? resolvedContract.accepts.schema
175
- : ((_a = resolvedContract.emits[event.type]) !== null && _a !== void 0 ? _a : resolvedContract.systemError.schema);
176
- validationSchema.parse(event.data);
177
- return { contractType: contractType };
115
+ return (0, inputValidation_1.validateInputEvent)({
116
+ event: event,
117
+ selfContract: this.contracts.self,
118
+ serviceContracts: this.contracts.services,
119
+ span: span,
120
+ });
178
121
  };
179
122
  /**
180
- * Executes the orchestration workflow for an incoming event
123
+ * Executes the workflow handler for an incoming event.
181
124
  *
182
- * @param event - The triggering event to process
183
- * @param opentelemetry - OpenTelemetry configuration for trace inheritance
125
+ * Processes initialization events or service responses through the versioned handler,
126
+ * manages state persistence, tracks expected events, and generates output events.
127
+ * Workflows in 'done' status ignore subsequent events without processing.
184
128
  *
185
- * @returns Object containing domained events
129
+ * For violation errors (transaction, config, contract), the error is thrown to enable
130
+ * retry mechanisms. For non-violation errors, system error events are emitted to the
131
+ * workflow initiator, and the workflow enters a terminal failure state.
132
+ *
133
+ * @param event - The incoming event triggering handler execution
134
+ * @param opentelemetry - Optional OpenTelemetry configuration for tracing
135
+ * @returns Object containing emitted events from the handler or system errors
186
136
  *
187
137
  * @throws {TransactionViolation} When distributed lock acquisition fails
188
138
  * @throws {ConfigViolation} When handler resolution or contract validation fails
189
139
  * @throws {ContractViolation} When event schema validation fails
190
- * @throws {ExecutionViolation} When workflow execution encounters critical errors
140
+ * @throws {ExecutionViolation} When workflow execution encounters critical errors defined by the handler developer
191
141
  */
192
142
  ArvoResumable.prototype.execute = function (event, opentelemetry) {
193
143
  return __awaiter(this, void 0, void 0, function () {
@@ -209,7 +159,7 @@ var ArvoResumable = /** @class */ (function () {
209
159
  selfContract: this.contracts.self.version('latest'),
210
160
  domain: this.domain,
211
161
  }, function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
212
- var contractType, eventTypeToExpectedEvent, _i, _c, _d, _, eventList, _e, eventList_1, _evt, handler, versionedSelfContract, executionResult, rawEvents, emittables, eventTrackingState, newState;
162
+ var inputValidation, contractType, eventTypeToExpectedEvent, _i, _c, _d, _, eventList, _e, eventList_1, _evt, handler, versionedSelfContract, executionResult, rawEvents, emittables, eventTrackingState, newState;
213
163
  var _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
214
164
  var span = _b.span, otelHeaders = _b.otelHeaders, orchestrationParentSubject = _b.orchestrationParentSubject, initEventId = _b.initEventId, parsedEventSubject = _b.parsedEventSubject, state = _b.state;
215
165
  return __generator(this, function (_v) {
@@ -226,7 +176,14 @@ var ArvoResumable = /** @class */ (function () {
226
176
  level: 'INFO',
227
177
  message: "Input validation started for event ".concat(event.type),
228
178
  });
229
- contractType = this.validateInput(event, span).contractType;
179
+ inputValidation = this.validateInput(event, span);
180
+ if (inputValidation.type === 'CONTRACT_UNRESOLVED') {
181
+ throw new errors_1.ConfigViolation('Contract validation failed - Event does not match any registered contract schemas in the resumable');
182
+ }
183
+ if (inputValidation.type === 'INVALID_DATA' || inputValidation.type === 'INVALID') {
184
+ throw new errors_1.ContractViolation("Input validation failed - Event data does not meet contract requirements: ".concat(inputValidation.error.message));
185
+ }
186
+ contractType = inputValidation.contractType;
230
187
  if ((state === null || state === void 0 ? void 0 : state.status) === 'done') {
231
188
  (0, arvo_core_1.logToSpan)({
232
189
  level: 'INFO',
@@ -328,7 +285,7 @@ var ArvoResumable = /** @class */ (function () {
328
285
  };
329
286
  Object.defineProperty(ArvoResumable.prototype, "systemErrorSchema", {
330
287
  get: function () {
331
- return this.contracts.self.systemError;
288
+ return __assign(__assign({}, this.contracts.self.systemError), { domain: this.systemErrorDomain });
332
289
  },
333
290
  enumerable: false,
334
291
  configurable: true
@@ -1,7 +1,12 @@
1
1
  import type { Span } from '@opentelemetry/api';
2
- import type { ArvoContract, ArvoEvent, ArvoSemanticVersion, CreateArvoEvent, InferArvoEvent, InferVersionedArvoContract, VersionedArvoContract } from 'arvo-core';
2
+ import type { ArvoContract, ArvoEvent, ArvoOrchestratorContract, ArvoSemanticVersion, CreateArvoEvent, InferArvoEvent, InferVersionedArvoContract, VersionedArvoContract } from 'arvo-core';
3
3
  import type { EnqueueArvoEventActionParam } from '../ArvoMachine/types';
4
4
  import type { OrchestrationExecutionMemoryRecord } from '../ArvoOrchestrationUtils/orchestrationExecutionState';
5
+ import type { IMachineMemory } from '../MachineMemory/interface';
6
+ import type { ArvoEventHandlerOtelSpanOptions } from '../types';
7
+ /**
8
+ * Extracts all possible event types (including system errors) from service contracts.
9
+ */
5
10
  type ExtractServiceEventTypes<TServiceContract extends Record<string, VersionedArvoContract<any, any>>> = {
6
11
  [K in keyof TServiceContract]: {
7
12
  [L in keyof InferVersionedArvoContract<TServiceContract[K]>['emits']]: {
@@ -13,142 +18,242 @@ type ExtractServiceEventTypes<TServiceContract extends Record<string, VersionedA
13
18
  event: InferVersionedArvoContract<TServiceContract[K]>['systemError'];
14
19
  };
15
20
  }[keyof TServiceContract];
21
+ /**
22
+ * Union of all service event type strings.
23
+ */
16
24
  type AllServiceEventTypes<TServiceContract extends Record<string, VersionedArvoContract<any, any>>> = ExtractServiceEventTypes<TServiceContract>['type'];
25
+ /**
26
+ * Maps event type strings to their corresponding event schemas.
27
+ */
17
28
  type ServiceEventTypeMap<TServiceContract extends Record<string, VersionedArvoContract<any, any>>> = {
18
29
  [T in ExtractServiceEventTypes<TServiceContract> as T['type']]: T['event'];
19
30
  };
31
+ /**
32
+ * Handler function signature for processing events in ArvoResumable workflows.
33
+ *
34
+ * Handlers are invoked for each incoming event (initialization or service response)
35
+ * and must be deterministic and idempotent to ensure reliable execution across retries.
36
+ */
20
37
  type Handler<TState extends ArvoResumableState<Record<string, any>>, TSelfContract extends VersionedArvoContract<any, any>, TServiceContract extends Record<string, VersionedArvoContract<any, any>>> = (param: {
38
+ /** OpenTelemetry span for distributed tracing and observability */
21
39
  span: Span;
40
+ /**
41
+ * Complete workflow metadata including subject, parent info, and event history.
42
+ * Null for new workflow initialization.
43
+ */
22
44
  metadata: Omit<TState, 'state$$'> | null;
45
+ /**
46
+ * Map of collected service response events grouped by event type.
47
+ * Enables type-safe access to accumulated responses from external services.
48
+ * Events are collected based on matching parent IDs with emitted service calls.
49
+ */
23
50
  collectedEvents: Partial<{
24
51
  [K in AllServiceEventTypes<TServiceContract>]: ServiceEventTypeMap<TServiceContract>[K][];
25
52
  }>;
53
+ /** Domain information for routing events */
26
54
  domain: {
55
+ /** Domain from the triggering event */
27
56
  event: string | null;
57
+ /** Domain from the resumable's self contract */
28
58
  self: string | null;
29
59
  };
60
+ /**
61
+ * Current workflow state persisted from previous execution.
62
+ * Null for new workflows or when no state has been saved yet.
63
+ */
30
64
  context: TState['state$$'] | null;
65
+ /**
66
+ * Initialization event data for workflow start.
67
+ * Only present when handler is processing the initialization event that starts the workflow.
68
+ * Null for service response events.
69
+ */
31
70
  input: InferVersionedArvoContract<TSelfContract>['accepts'] | null;
71
+ /**
72
+ * Service response event data.
73
+ * Only present when handler is processing a response from an external service.
74
+ * Null for initialization events.
75
+ */
32
76
  service: {
33
77
  [K in keyof TServiceContract]: {
34
78
  [L in keyof InferVersionedArvoContract<TServiceContract[K]>['emits']]: InferVersionedArvoContract<TServiceContract[K]>['emits'][L];
35
79
  }[keyof InferVersionedArvoContract<TServiceContract[K]>['emits']] | InferVersionedArvoContract<TServiceContract[K]>['systemError'];
36
80
  }[keyof TServiceContract] | null;
81
+ /** Contract definitions available to the handler */
37
82
  contracts: {
83
+ /** The resumable's self contract for validation */
38
84
  self: TSelfContract;
85
+ /** Service contracts for emitting compliant events to external systems */
39
86
  services: TServiceContract;
40
87
  };
41
88
  }) => Promise<{
89
+ /** Updated workflow state to persist for next invocation */
42
90
  context?: TState['state$$'];
91
+ /**
92
+ * Workflow completion data.
93
+ * Returning this signals workflow completion and emits the final output event.
94
+ * The workflow status becomes 'done' and no further events are processed.
95
+ */
43
96
  output?: {
44
97
  [L in keyof InferVersionedArvoContract<TSelfContract>['emits']]: EnqueueArvoEventActionParam<InferVersionedArvoContract<TSelfContract>['emits'][L]['data'], InferVersionedArvoContract<TSelfContract>['emits'][L]['type']>['data'];
45
98
  }[keyof InferVersionedArvoContract<TSelfContract>['emits']] & {
46
99
  __id?: CreateArvoEvent<Record<string, unknown>, string>['id'];
47
100
  };
101
+ /**
102
+ * Service call events to emit.
103
+ * Each event triggers an external service and awaits its response in future invocations.
104
+ * Responses are collected in `collectedEvents` based on parent ID matching.
105
+ */
48
106
  services?: Array<{
49
107
  [K in keyof TServiceContract]: EnqueueArvoEventActionParam<InferVersionedArvoContract<TServiceContract[K]>['accepts']['data'], InferVersionedArvoContract<TServiceContract[K]>['accepts']['type']>;
50
108
  }[keyof TServiceContract]>;
51
109
  } | void>;
52
110
  /**
53
- * The versioned orchestration handlers in ArvoResumable workflows
54
- *
55
- * It maps each version of an orchestrator contract to its corresponding handler function.
56
- * Each handler receives workflow context (state, events, contracts) and returns execution results
57
- * that can update state, complete the workflow, or invoke external services.
58
- *
59
- * The handler is called for each event that matches the orchestrator's contract, whether it's
60
- * an initialization event or a service response. The handler must be deterministic and
61
- * idempotent to ensure reliable workflow execution across potential retries.
62
- *
63
- * @param param - Handler execution context
64
- * @param param.span - OpenTelemetry span for distributed tracing
65
- * @param param.metadata - Complete workflow metadata (null for new workflows)
66
- * @param param.collectedEvents - Type-safe map of event types to their corresponding typed event arrays,
67
- * enabling strongly-typed access with full IntelliSense support.
68
- * @param param.context - Current workflow state (null for new workflows)
69
- * @param param.init - Initialization event data (only present for workflow start events)
70
- * @param param.service - Service response event data (only present for service callbacks)
71
- * @param param.contracts - Available contracts for type validation and event creation
72
- * @param param.contracts.self - The orchestrator's own versioned contract
73
- * @param param.contracts.services - External service contracts for invocation
111
+ * Versioned handler map for ArvoResumable workflows.
74
112
  *
75
- * @returns Promise resolving to execution result or void
76
- * @returns result.context - Updated workflow state to persist
77
- * @returns result.complete - Workflow completion event to emit (ends the workflow)
78
- * @returns result.services - Array of service invocation events to emit
113
+ * Maps contract versions to their corresponding handler implementations.
114
+ * Each version can have different business logic while maintaining backward compatibility.
79
115
  *
80
- * @remarks
81
- * - Each version key must match a valid semantic version in the self contract
82
- * - Handlers should be pure functions without side effects beyond the returned actions
83
- * - State updates are atomic - either all changes persist or none do
84
- * - Only one of `init` or `service` will be non-null for any given invocation
85
- * - Returning void or an empty object indicates no state changes or events to emit
86
- * - Service events are supposed to queued for execution and may trigger callback events
87
- * - Completion events terminate the workflow and route to the parent orchestrator
116
+ * Handlers are invoked for initialization events and service responses matching the
117
+ * resumable's contract. They must be deterministic and idempotent to ensure reliable
118
+ * workflow execution across retries and failures.
88
119
  */
89
120
  export type ArvoResumableHandler<TState extends ArvoResumableState<Record<string, any>>, TSelfContract extends ArvoContract, TServiceContract extends Record<string, VersionedArvoContract<any, any>>> = {
90
121
  [V in ArvoSemanticVersion & keyof TSelfContract['versions']]: Handler<TState, VersionedArvoContract<TSelfContract, V>, TServiceContract>;
91
122
  };
123
+ /**
124
+ * State structure persisted in memory for ArvoResumable workflows.
125
+ *
126
+ * Extends base orchestration state with resumable-specific fields including
127
+ * event collection, workflow status tracking, and custom state management.
128
+ */
92
129
  export type ArvoResumableState<T extends Record<string, any>> = OrchestrationExecutionMemoryRecord<{
93
130
  /**
94
- * Current execution status of the orchestration workflow
95
- *
96
- * This field tracks the lifecycle state of the workflow instance to determine
97
- * whether it can accept new events and continue processing or has reached
98
- * its terminal state.
131
+ * Current workflow status.
99
132
  *
100
- * @remarks
101
- * - **active**: The workflow is running and can accept events for processing.
102
- * It may be waiting for service responses, processing initialization events,
103
- * or handling intermediate workflow steps. The orchestrator will continue
104
- * to route events to active workflows.
105
- *
106
- * - **done**: The workflow has completed its execution lifecycle. This status
107
- * is set when the handler returns a `complete` event, indicating the workflow
108
- * has finished successfully. Done workflows will not process additional events
109
- * and their state is preserved for audit/debugging purposes.
133
+ * Determines whether the workflow can process additional events:
134
+ * - `'active'`: Workflow is running and accepts new events for processing
135
+ * - `'done'`: Workflow has completed (handler returned `output`). No further events are processed.
110
136
  */
111
137
  status: 'active' | 'done';
112
- /** Unique identifier for the machine instance */
138
+ /**
139
+ * Unique identifier for the workflow instance.
140
+ * Serves as the key for state persistence in the memory store.
141
+ */
113
142
  subject: string;
114
143
  /**
115
- * Reference to the parent orchestration's subject when orchestrations are nested or chained.
116
- * This enables hierarchical orchestration patterns where one orchestration can spawn
117
- * sub-orchestrations. When the current orchestration completes, its completion event
118
- * is routed back to this parent subject rather than staying within the current context.
144
+ * Parent orchestration subject for nested workflows.
145
+ *
146
+ * Enables hierarchical orchestration where one workflow spawns sub-workflows.
147
+ * Completion events route back to this parent subject.
119
148
  *
120
- * - For root orchestrations: null
121
- * - For nested orchestrations: contains the subject of the parent orchestration
122
- * - Extracted from the `parentSubject$$` field in initialization events
149
+ * - Root workflows: `null`
150
+ * - Nested workflows: parent's subject identifier
151
+ * - Source: `parentSubject$$` in initialization events
123
152
  */
124
153
  parentSubject: string | null;
125
154
  /**
126
- * The unique identifier of the event that originally initiated this entire orchestration workflow.
127
- * This serves as the root identifier for tracking the complete execution chain from start to finish.
155
+ * ID of the event that initiated this workflow.
128
156
  *
129
- * - For new orchestrations: set to the current event's ID
130
- * - For resumed orchestrations: retrieved from the stored state
131
- * - Used as the `parentid` for completion events to create a direct lineage back to the workflow's origin
157
+ * Root identifier for tracing the complete execution chain.
158
+ * Used as `parentid` for completion events to maintain lineage.
132
159
  *
133
- * This enables tracing the entire execution path and ensures completion events reference
134
- * the original triggering event rather than just the immediate previous step.
160
+ * - New workflows: current event's ID
161
+ * - Resumed workflows: retrieved from stored state
135
162
  */
136
163
  initEventId: string;
164
+ /**
165
+ * Event history for the current invocation.
166
+ * Transient collection tracking events consumed, produced, and expected.
167
+ */
137
168
  events: {
138
- /** The event consumed by the machine in the last session */
169
+ /** Event consumed in the last handler invocation */
139
170
  consumed: InferArvoEvent<ArvoEvent> | null;
140
- /**
141
- * The domained events produced by the machine in the last session
142
- */
171
+ /** Events produced (with domain resolution) in the last invocation */
143
172
  produced: InferArvoEvent<ArvoEvent>[];
144
173
  /**
145
- * The events expected by the resumable. These events are collected on each execution
146
- * as long as the event parent id and the expected key matches. The expected key is the
147
- * event.id of the produced event.
174
+ * Service response events awaiting collection.
175
+ *
176
+ * Keyed by the emitted event's ID (parent ID of responses).
177
+ * Responses are collected when their `parentid` matches a produced event's `id`.
178
+ * Collected events are passed to the handler via `collectedEvents` parameter.
148
179
  */
149
180
  expected: Record<string, InferArvoEvent<ArvoEvent>[]> | null;
150
181
  };
151
- /** The state used by the resumable */
182
+ /**
183
+ * Custom workflow state managed by the handler.
184
+ * Accessible via the `context` parameter in handlers and persisted between invocations.
185
+ */
152
186
  state$$: T | null;
153
187
  }>;
188
+ /**
189
+ * Configuration parameters for creating an ArvoResumable instance.
190
+ *
191
+ * Defines all required components for a resumable workflow orchestrator including
192
+ * contracts, handlers, memory, and execution settings.
193
+ */
194
+ export type ArvoResumableParam<TMemory extends Record<string, any>, TSelfContract extends ArvoOrchestratorContract, TServiceContract extends Record<string, VersionedArvoContract<any, any>>> = {
195
+ /**
196
+ * Contract definitions for the resumable's event interface.
197
+ * Defines accepted events, emitted events, and service integrations.
198
+ */
199
+ contracts: {
200
+ /**
201
+ * Self contract defining initialization input and completion output structures.
202
+ */
203
+ self: TSelfContract;
204
+ /**
205
+ * Service contracts defining external service interfaces.
206
+ * Enables type-safe event emission and response handling for external systems.
207
+ */
208
+ services: TServiceContract;
209
+ };
210
+ /** Computational cost metric for workflow operations */
211
+ executionunits: number;
212
+ /** Memory interface for state persistence and retrieval */
213
+ memory: IMachineMemory<ArvoResumableState<TMemory>>;
214
+ /** Whether to enforce resource locking for concurrent execution safety */
215
+ requiresResourceLocking: boolean;
216
+ /**
217
+ * Versioned handler map for processing workflow events.
218
+ * Each contract version maps to its corresponding handler implementation.
219
+ */
220
+ handler: ArvoResumableHandler<ArvoResumableState<TMemory>, TSelfContract, TServiceContract>;
221
+ /** Optional domains for system error event routing */
222
+ systemErrorDomain?: (string | null)[];
223
+ /** OpenTelemetry span configuration for distributed tracing */
224
+ spanOptions?: ArvoEventHandlerOtelSpanOptions;
225
+ };
226
+ /**
227
+ * Configuration parameters for creating an ArvoResumable instance.
228
+ */
229
+ export type CreateArvoResumableParam<TMemory extends Record<string, any>, TSelfContract extends ArvoOrchestratorContract, TServiceContract extends Record<string, VersionedArvoContract<any, any>> = Record<string, VersionedArvoContract<any, any>>> = {
230
+ /** Optional type hints for TypeScript inference (not used at runtime) */
231
+ types?: {
232
+ context?: Partial<TMemory>;
233
+ };
234
+ /** Contract definitions for event interface validation */
235
+ contracts: {
236
+ /** Self contract defining initialization and completion events */
237
+ self: TSelfContract;
238
+ /** Service contracts for external system integrations */
239
+ services: TServiceContract;
240
+ };
241
+ /** Memory interface for state persistence */
242
+ memory: IMachineMemory<Record<string, any>>;
243
+ /** Versioned handler map for processing events */
244
+ handler: ArvoResumableHandler<ArvoResumableState<TMemory>, TSelfContract, TServiceContract>;
245
+ /**
246
+ * Computational cost metric for operations.
247
+ */
248
+ executionunits?: number;
249
+ /**
250
+ * Whether to enforce resource locking for concurrent safety.
251
+ * @default true if multiple service contracts, false otherwise
252
+ */
253
+ requiresResourceLocking?: boolean;
254
+ /** Optional domains for system error event routing */
255
+ systemErrorDomain?: (string | null)[];
256
+ /** OpenTelemetry span configuration for distributed tracing */
257
+ spanOptions?: ArvoEventHandlerOtelSpanOptions;
258
+ };
154
259
  export {};
@@ -1,36 +1,50 @@
1
1
  import type { ArvoContractRecord, ArvoEvent } from 'arvo-core';
2
2
  import type { ArvoEventHandlerOpenTelemetryOptions } from '../types';
3
3
  /**
4
- * The interface for Arvo event handlers.
4
+ * Interface for Arvo event handlers.
5
5
  *
6
- * This class defines the basic structure for all Arvo event handlers.
7
- * It provides an abstract method for executing events, which must be
8
- * implemented by any concrete subclass.
6
+ * Defines the contract for all event handlers in the Arvo system, including
7
+ * orchestrators, resumable handlers, and custom handlers. Each handler must
8
+ * implement event execution logic and provide system error schema configuration.
9
9
  */
10
10
  export default interface IArvoEventHandler {
11
11
  /**
12
- * Unique identifier for the event handler source system
12
+ * Unique identifier for the event handler's source system.
13
+ * Used for event routing and tracing throughout the system.
13
14
  */
14
15
  source: string;
15
16
  /**
16
- * Executes the event handling logic for a given Arvo event.
17
+ * Executes the event handling logic for an incoming Arvo event.
17
18
  *
18
- * @param event - The Arvo event to be processed.
19
- * @param opentelemetry - Configuration for OpenTelemetry integration
19
+ * Processes the event according to the handler's business logic and returns
20
+ * resulting events to be emitted. The handler may emit multiple events as
21
+ * outcomes of processing a single input event.
20
22
  *
21
- * @returns A promise that resolves to an array of resulting Arvo events.
22
- * These events represent the outcome of processing the input event.
23
+ * For violation errors (transaction, execution, contract, config), implementations
24
+ * typically throw the error to enable retry mechanisms. For non-violation errors,
25
+ * implementations typically emit system error events to the workflow initiator.
26
+ *
27
+ * @param event - The Arvo event to be processed
28
+ * @param opentelemetry - Optional configuration for distributed tracing integration
29
+ * @returns Promise resolving to an object containing emitted events
30
+ *
31
+ * @throws {ViolationError} When retriable errors occur (lock failures, validation errors, etc.)
23
32
  */
24
33
  execute(event: ArvoEvent, opentelemetry?: ArvoEventHandlerOpenTelemetryOptions): Promise<{
25
34
  events: ArvoEvent[];
26
35
  }>;
27
36
  /**
28
- * Provides the schema for system error events.
37
+ * Schema configuration for system error events.
29
38
  *
30
- * @returns An object containing the error event type and schema.
39
+ * Defines the structure and routing for error events emitted when unexpected
40
+ * errors occur during event handling. System errors are sent to the workflow
41
+ * initiator to signal terminal failures that cannot be automatically recovered.
31
42
  *
32
- * This defines the structure for system error events that may be emitted
33
- * when an unexpected error occurs during event handling.
43
+ * @property type - The error event type identifier
44
+ * @property schema - Zod schema defining the error event data structure
45
+ * @property domain - Optional domains for error event routing and distribution
34
46
  */
35
- systemErrorSchema: ArvoContractRecord;
47
+ systemErrorSchema: ArvoContractRecord & {
48
+ domain?: (string | null)[];
49
+ };
36
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arvo-event-handler",
3
- "version": "3.0.14",
3
+ "version": "3.0.15",
4
4
  "description": "Type-safe event handler system with versioning, telemetry, and contract validation for distributed Arvo event-driven architectures, featuring routing and multi-handler support.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -46,7 +46,7 @@
46
46
  "dependencies": {
47
47
  "@opentelemetry/api": "^1.9.0",
48
48
  "@opentelemetry/core": "^1.30.1",
49
- "arvo-core": "^3.0.14",
49
+ "arvo-core": "^3.0.15",
50
50
  "uuid": "^11.1.0",
51
51
  "xstate": "^5.23.0",
52
52
  "zod": "^3.25.74",