arvo-event-handler 3.0.2 → 3.0.4

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.
@@ -73,6 +73,7 @@ var error_1 = require("./error");
73
73
  var SyncEventResource_1 = require("../SyncEventResource");
74
74
  var AbstractArvoEventHandler_1 = __importDefault(require("../AbstractArvoEventHandler"));
75
75
  var errors_1 = require("../errors");
76
+ var ArvoDomain_1 = require("../ArvoDomain");
76
77
  /**
77
78
  * Orchestrates state machine execution and lifecycle management.
78
79
  * Handles machine resolution, state management, event processing and error handling.
@@ -85,8 +86,9 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
85
86
  * @throws Error if machines in registry have different sources
86
87
  */
87
88
  function ArvoOrchestrator(_a) {
88
- var executionunits = _a.executionunits, memory = _a.memory, registry = _a.registry, executionEngine = _a.executionEngine, requiresResourceLocking = _a.requiresResourceLocking;
89
+ var executionunits = _a.executionunits, memory = _a.memory, registry = _a.registry, executionEngine = _a.executionEngine, requiresResourceLocking = _a.requiresResourceLocking, systemErrorDomain = _a.systemErrorDomain;
89
90
  var _this = _super.call(this) || this;
91
+ _this.systemErrorDomain = [];
90
92
  _this.executionunits = executionunits;
91
93
  var representativeMachine = registry.machines[0];
92
94
  var lastSeenVersions = [];
@@ -103,6 +105,7 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
103
105
  _this.registry = registry;
104
106
  _this.executionEngine = executionEngine;
105
107
  _this.syncEventResource = new SyncEventResource_1.SyncEventResource(memory, requiresResourceLocking);
108
+ _this.systemErrorDomain = systemErrorDomain;
106
109
  return _this;
107
110
  }
108
111
  Object.defineProperty(ArvoOrchestrator.prototype, "source", {
@@ -147,7 +150,7 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
147
150
  * @throws {ExecutionViolation} On invalid parentSubject$$ format
148
151
  */
149
152
  ArvoOrchestrator.prototype.createEmittableEvent = function (event, machine, otelHeaders, orchestrationParentSubject, sourceEvent, initEventId, _domain) {
150
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
153
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
151
154
  (0, arvo_core_1.logToSpan)({
152
155
  level: 'INFO',
153
156
  message: "Creating emittable event: ".concat(event.type),
@@ -158,7 +161,12 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
158
161
  var contract = null;
159
162
  var subject = sourceEvent.subject;
160
163
  var parentId = sourceEvent.id;
161
- var domain = _domain === undefined ? ((_b = (_a = sourceEvent.domain) !== null && _a !== void 0 ? _a : this.domain) !== null && _b !== void 0 ? _b : null) : _domain;
164
+ var domain = (0, ArvoDomain_1.resolveEventDomain)({
165
+ domainToResolve: _domain,
166
+ handlerSelfContract: selfContract,
167
+ eventContract: null,
168
+ triggeringEvent: sourceEvent,
169
+ });
162
170
  if (event.type === selfContract.metadata.completeEventType) {
163
171
  (0, arvo_core_1.logToSpan)({
164
172
  level: 'INFO',
@@ -168,7 +176,12 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
168
176
  schema = selfContract.emits[selfContract.metadata.completeEventType];
169
177
  subject = orchestrationParentSubject !== null && orchestrationParentSubject !== void 0 ? orchestrationParentSubject : sourceEvent.subject;
170
178
  parentId = initEventId;
171
- domain = _domain === undefined ? ((_e = (_d = (_c = selfContract.domain) !== null && _c !== void 0 ? _c : sourceEvent.domain) !== null && _d !== void 0 ? _d : this.domain) !== null && _e !== void 0 ? _e : null) : _domain;
179
+ domain = (0, ArvoDomain_1.resolveEventDomain)({
180
+ domainToResolve: _domain,
181
+ handlerSelfContract: selfContract,
182
+ eventContract: selfContract,
183
+ triggeringEvent: sourceEvent,
184
+ });
172
185
  }
173
186
  else if (serviceContract[event.type]) {
174
187
  (0, arvo_core_1.logToSpan)({
@@ -177,7 +190,12 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
177
190
  });
178
191
  contract = serviceContract[event.type];
179
192
  schema = serviceContract[event.type].accepts.schema;
180
- domain = _domain === undefined ? ((_h = (_g = (_f = contract === null || contract === void 0 ? void 0 : contract.domain) !== null && _f !== void 0 ? _f : sourceEvent.domain) !== null && _g !== void 0 ? _g : this.domain) !== null && _h !== void 0 ? _h : null) : _domain;
193
+ domain = (0, ArvoDomain_1.resolveEventDomain)({
194
+ domainToResolve: _domain,
195
+ handlerSelfContract: selfContract,
196
+ eventContract: contract,
197
+ triggeringEvent: sourceEvent,
198
+ });
181
199
  // If the event is to call another orchestrator then, extract the parent subject
182
200
  // passed to it and then form an new subject. This allows for event chaining
183
201
  // between orchestrators
@@ -186,8 +204,8 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
186
204
  try {
187
205
  arvo_core_1.ArvoOrchestrationSubject.parse(event.data.parentSubject$$);
188
206
  }
189
- catch (_v) {
190
- throw new errors_1.ExecutionViolation("Invalid parentSubject$$ for the event(type='".concat(event.type, "', uri='").concat((_j = event.dataschema) !== null && _j !== void 0 ? _j : arvo_core_1.EventDataschemaUtil.create(contract), "').It must be follow the ArvoOrchestrationSubject schema. The easiest way is to use the current orchestration subject by storing the subject via the context block in the machine definition."));
207
+ catch (_m) {
208
+ throw new errors_1.ExecutionViolation("Invalid parentSubject$$ for the event(type='".concat(event.type, "', uri='").concat((_a = event.dataschema) !== null && _a !== void 0 ? _a : arvo_core_1.EventDataschemaUtil.create(contract), "').It must be follow the ArvoOrchestrationSubject schema. The easiest way is to use the current orchestration subject by storing the subject via the context block in the machine definition."));
191
209
  }
192
210
  }
193
211
  try {
@@ -198,7 +216,7 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
198
216
  subject: event.data.parentSubject$$,
199
217
  domain: domain !== null && domain !== void 0 ? domain : null,
200
218
  meta: {
201
- redirectto: (_k = event.redirectto) !== null && _k !== void 0 ? _k : this.source,
219
+ redirectto: (_b = event.redirectto) !== null && _b !== void 0 ? _b : this.source,
202
220
  },
203
221
  });
204
222
  }
@@ -209,7 +227,7 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
209
227
  initiator: this.source,
210
228
  domain: domain !== null && domain !== void 0 ? domain : undefined,
211
229
  meta: {
212
- redirectto: (_l = event.redirectto) !== null && _l !== void 0 ? _l : this.source,
230
+ redirectto: (_c = event.redirectto) !== null && _c !== void 0 ? _c : this.source,
213
231
  },
214
232
  });
215
233
  }
@@ -244,16 +262,16 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
244
262
  subject: subject,
245
263
  dataschema: finalDataschema !== null && finalDataschema !== void 0 ? finalDataschema : undefined,
246
264
  data: finalData,
247
- to: (_m = event.to) !== null && _m !== void 0 ? _m : event.type,
248
- accesscontrol: (_p = (_o = event.accesscontrol) !== null && _o !== void 0 ? _o : sourceEvent.accesscontrol) !== null && _p !== void 0 ? _p : undefined,
265
+ to: (_d = event.to) !== null && _d !== void 0 ? _d : event.type,
266
+ accesscontrol: (_f = (_e = event.accesscontrol) !== null && _e !== void 0 ? _e : sourceEvent.accesscontrol) !== null && _f !== void 0 ? _f : undefined,
249
267
  // The orchestrator does not respect redirectto from the source event
250
- redirectto: (_q = event.redirectto) !== null && _q !== void 0 ? _q : this.source,
251
- executionunits: (_r = event.executionunits) !== null && _r !== void 0 ? _r : this.executionunits,
252
- traceparent: (_s = otelHeaders.traceparent) !== null && _s !== void 0 ? _s : undefined,
253
- tracestate: (_t = otelHeaders.tracestate) !== null && _t !== void 0 ? _t : undefined,
268
+ redirectto: (_g = event.redirectto) !== null && _g !== void 0 ? _g : this.source,
269
+ executionunits: (_h = event.executionunits) !== null && _h !== void 0 ? _h : this.executionunits,
270
+ traceparent: (_j = otelHeaders.traceparent) !== null && _j !== void 0 ? _j : undefined,
271
+ tracestate: (_k = otelHeaders.tracestate) !== null && _k !== void 0 ? _k : undefined,
254
272
  parentid: parentId,
255
273
  domain: domain !== null && domain !== void 0 ? domain : undefined,
256
- }, (_u = event.__extensions) !== null && _u !== void 0 ? _u : {});
274
+ }, (_l = event.__extensions) !== null && _l !== void 0 ? _l : {});
257
275
  (0, arvo_core_1.logToSpan)({
258
276
  level: 'INFO',
259
277
  message: "Event created successfully: ".concat(emittableEvent.type),
@@ -262,12 +280,6 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
262
280
  };
263
281
  /**
264
282
  * Core orchestration method that executes state machines in response to events.
265
- * Manages the complete event lifecycle:
266
- * 1. Acquires lock and state
267
- * 2. Validates events and contracts
268
- * 3. Executes state machine
269
- * 4. Persists new state
270
- * 5. Generates response events with domain-based segregation
271
283
  *
272
284
  * @param event - Event triggering the execution
273
285
  * @param opentelemetry - OpenTelemetry configuration
@@ -310,7 +322,8 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
310
322
  },
311
323
  disableSpanManagement: true,
312
324
  fn: function (span) { return __awaiter(_this, void 0, void 0, function () {
313
- var otelHeaders, orchestrationParentSubject, initEventId, acquiredLock, parsedEventSubject, machine, _a, name_1, version, inputValidation, state, executionResult, rawMachineEmittedEvents, emittables, _i, rawMachineEmittedEvents_1, item, domains, _b, _c, _dom, evt, _d, _e, _f, key, value, error_2, e, parsedEventSubject, result, _g, _h, _dom, _j, _k, _l, key, value;
325
+ var otelHeaders, orchestrationParentSubject, initEventId, acquiredLock, parsedEventSubject, machine, _a, name_1, version, inputValidation, state, executionResult, rawMachineEmittedEvents, emittables, _i, rawMachineEmittedEvents_1, item, createdDomain, _b, _c, _dom, evt, _d, _e, _f, key, value, error_2, e, parsedEventSubject, result, _g, _h, _dom, _j, _k, _l, key, value;
326
+ var _this = this;
314
327
  var _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
315
328
  return __generator(this, function (_0) {
316
329
  switch (_0.label) {
@@ -450,16 +463,22 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
450
463
  to: (_t = (_s = parsedEventSubject.meta) === null || _s === void 0 ? void 0 : _s.redirectto) !== null && _t !== void 0 ? _t : parsedEventSubject.execution.initiator,
451
464
  domain: orchestrationParentSubject
452
465
  ? [arvo_core_1.ArvoOrchestrationSubject.parse(orchestrationParentSubject).execution.domain]
453
- : [undefined],
466
+ : [null],
454
467
  });
455
468
  }
456
469
  emittables = [];
457
470
  for (_i = 0, rawMachineEmittedEvents_1 = rawMachineEmittedEvents; _i < rawMachineEmittedEvents_1.length; _i++) {
458
471
  item = rawMachineEmittedEvents_1[_i];
459
- domains = (_u = item.domain) !== null && _u !== void 0 ? _u : [null];
460
- for (_b = 0, _c = Array.from(new Set(domains)); _b < _c.length; _b++) {
472
+ createdDomain = new Set();
473
+ for (_b = 0, _c = Array.from(new Set((_u = item.domain) !== null && _u !== void 0 ? _u : [null])); _b < _c.length; _b++) {
461
474
  _dom = _c[_b];
462
475
  evt = this.createEmittableEvent(item, machine, otelHeaders, orchestrationParentSubject, event, initEventId, _dom);
476
+ // Making sure the raw event broadcast is actually unique as the
477
+ // domain resolution (especially for symbolic) can only happen
478
+ // in the createEmittableEvent
479
+ if (createdDomain.has(evt.domain))
480
+ continue;
481
+ createdDomain.add(evt.domain);
463
482
  emittables.push(evt);
464
483
  for (_d = 0, _e = Object.entries(emittables[emittables.length - 1].otelAttributes); _d < _e.length; _d++) {
465
484
  _f = _e[_d], key = _f[0], value = _f[1];
@@ -532,7 +551,16 @@ var ArvoOrchestrator = /** @class */ (function (_super) {
532
551
  });
533
552
  }
534
553
  result = [];
535
- for (_g = 0, _h = Array.from(new Set([event.domain, this.domain, null])); _g < _h.length; _g++) {
554
+ for (_g = 0, _h = Array.from(new Set(this.systemErrorDomain
555
+ ? this.systemErrorDomain.map(function (item) {
556
+ return (0, ArvoDomain_1.resolveEventDomain)({
557
+ domainToResolve: item,
558
+ triggeringEvent: event,
559
+ handlerSelfContract: _this.registry.machines[0].contracts.self,
560
+ eventContract: _this.registry.machines[0].contracts.self,
561
+ });
562
+ })
563
+ : [event.domain, this.domain, null])); _g < _h.length; _g++) {
536
564
  _dom = _h[_g];
537
565
  result.push((0, arvo_core_1.createArvoOrchestratorEventFactory)(this.registry.machines[0].contracts.self).systemError({
538
566
  source: this.source,
@@ -81,6 +81,10 @@ export interface IArvoOrchestrator {
81
81
  /** Engine responsible for machine execution */
82
82
  executionEngine: IMachineExectionEngine;
83
83
  requiresResourceLocking: boolean;
84
+ /**
85
+ * Optional configuration to customize where system error events are emitted.
86
+ */
87
+ systemErrorDomain?: (string | null)[];
84
88
  }
85
89
  /**
86
90
  * Configuration interface for creating an Arvo orchestrator instance.
@@ -95,4 +99,18 @@ export interface ICreateArvoOrchestrator {
95
99
  * All machines must have the same source identifier.
96
100
  */
97
101
  machines: ArvoMachine<any, any, any, any, any>[];
102
+ /**
103
+ * Optional configuration to customize where system error events are emitted.
104
+ *
105
+ * This overrides the default system error domain fallback of:
106
+ * `[event.domain, self.contract.domain, null]`
107
+ *
108
+ * Use this to precisely control the set of domains that should receive structured
109
+ * `sys.*.error` events when uncaught exceptions occur in the handler.
110
+ *
111
+ * Symbolic constants from {@link ArvoDomain} are supported.
112
+ *
113
+ * @default undefined — uses standard fallback broadcast domains
114
+ */
115
+ systemErrorDomain?: (string | null)[];
98
116
  }
@@ -19,21 +19,12 @@ import { ArvoResumable } from '.';
19
19
  * @param param.handler - Versioned orchestration logic handlers mapped by semantic version
20
20
  * @param param.executionunits - Resource allocation cost for this orchestrator's execution (default: 0)
21
21
  * @param param.requiresResourceLocking - Enable distributed locking for concurrent safety (default: auto-determined by service count)
22
+ * @param param.systemErrorDomain - The domain override of the system error events. (default [event.domain, self.contract.domain, null])
22
23
  *
23
24
  * @returns A new ArvoResumable orchestrator instance configured with the provided parameters
24
25
  *
25
26
  * @throws {Error} Service contracts have duplicate URIs - Multiple versions of the same contract are not allowed
26
27
  * @throws {Error} Circular dependency detected - Self contract is registered as a service, creating execution loops
27
- *
28
- * @remarks
29
- * **Resource Locking:**
30
- * When `requiresResourceLocking` is not specified, it defaults to `true` when multiple
31
- * services are configured (indicating potential concurrent operations) and `false` for
32
- * single-service orchestrations.
33
- *
34
- * **Contract Validation:**
35
- * The factory validates that all service contracts have unique URIs and prevents
36
- * circular dependencies where the orchestrator's own contract is registered as a service.
37
28
  */
38
29
  export declare const createArvoResumable: <TMemory extends Record<string, any>, TSelfContract extends ArvoOrchestratorContract = ArvoOrchestratorContract, TServiceContract extends Record<string, VersionedArvoContract<any, any>> = Record<string, VersionedArvoContract<any, any>>>(param: {
39
30
  types?: {
@@ -47,4 +38,5 @@ export declare const createArvoResumable: <TMemory extends Record<string, any>,
47
38
  handler: ArvoResumableHandler<ArvoResumableState<TMemory>, TSelfContract, TServiceContract>;
48
39
  executionunits?: number;
49
40
  requiresResourceLocking?: boolean;
41
+ systemErrorDomain?: (string | null)[];
50
42
  }) => ArvoResumable<TMemory, TSelfContract, TServiceContract>;
@@ -32,21 +32,12 @@ var uuid_1 = require("uuid");
32
32
  * @param param.handler - Versioned orchestration logic handlers mapped by semantic version
33
33
  * @param param.executionunits - Resource allocation cost for this orchestrator's execution (default: 0)
34
34
  * @param param.requiresResourceLocking - Enable distributed locking for concurrent safety (default: auto-determined by service count)
35
+ * @param param.systemErrorDomain - The domain override of the system error events. (default [event.domain, self.contract.domain, null])
35
36
  *
36
37
  * @returns A new ArvoResumable orchestrator instance configured with the provided parameters
37
38
  *
38
39
  * @throws {Error} Service contracts have duplicate URIs - Multiple versions of the same contract are not allowed
39
40
  * @throws {Error} Circular dependency detected - Self contract is registered as a service, creating execution loops
40
- *
41
- * @remarks
42
- * **Resource Locking:**
43
- * When `requiresResourceLocking` is not specified, it defaults to `true` when multiple
44
- * services are configured (indicating potential concurrent operations) and `false` for
45
- * single-service orchestrations.
46
- *
47
- * **Contract Validation:**
48
- * The factory validates that all service contracts have unique URIs and prevents
49
- * circular dependencies where the orchestrator's own contract is registered as a service.
50
41
  */
51
42
  var createArvoResumable = function (param) {
52
43
  var _a;
@@ -65,6 +56,7 @@ var createArvoResumable = function (param) {
65
56
  handler: param.handler,
66
57
  executionunits: (_b = param.executionunits) !== null && _b !== void 0 ? _b : 0,
67
58
  requiresResourceLocking: (_c = param.requiresResourceLocking) !== null && _c !== void 0 ? _c : Object.keys(param.contracts.services).length > 1,
59
+ systemErrorDomain: param.systemErrorDomain,
68
60
  });
69
61
  };
70
62
  exports.createArvoResumable = createArvoResumable;
@@ -42,6 +42,7 @@ export declare class ArvoResumable<TMemory extends Record<string, any> = Record<
42
42
  readonly syncEventResource: SyncEventResource<ArvoResumableState<TMemory>>;
43
43
  readonly source: string;
44
44
  readonly handler: ArvoResumableHandler<ArvoResumableState<TMemory>, TSelfContract, TServiceContract>;
45
+ readonly systemErrorDomain?: (string | null)[];
45
46
  readonly contracts: {
46
47
  self: TSelfContract;
47
48
  services: TServiceContract;
@@ -58,6 +59,7 @@ export declare class ArvoResumable<TMemory extends Record<string, any> = Record<
58
59
  memory: IMachineMemory<ArvoResumableState<TMemory>>;
59
60
  requiresResourceLocking?: boolean;
60
61
  handler: ArvoResumableHandler<ArvoResumableState<TMemory>, TSelfContract, TServiceContract>;
62
+ systemErrorDomain?: (string | null)[];
61
63
  });
62
64
  protected validateInput(event: ArvoEvent): {
63
65
  contractType: 'self' | 'service';
@@ -75,23 +77,10 @@ export declare class ArvoResumable<TMemory extends Record<string, any> = Record<
75
77
  * @throws {ContractViolation} On schema/contract mismatch
76
78
  * @throws {ExecutionViolation} On invalid parentSubject$$ format
77
79
  */
78
- protected createEmittableEvent(event: EnqueueArvoEventActionParam, otelHeaders: OpenTelemetryHeaders, orchestrationParentSubject: string | null, sourceEvent: ArvoEvent, selfVersionedContract: VersionedArvoContract<TSelfContract, ArvoSemanticVersion>, initEventId: string, _domain: string | null | undefined): ArvoEvent;
80
+ protected createEmittableEvent(event: EnqueueArvoEventActionParam, otelHeaders: OpenTelemetryHeaders, orchestrationParentSubject: string | null, sourceEvent: ArvoEvent, selfVersionedContract: VersionedArvoContract<TSelfContract, ArvoSemanticVersion>, initEventId: string, _domain: string | null): ArvoEvent;
79
81
  /**
80
82
  * Executes the orchestration workflow for an incoming event
81
83
  *
82
- * This is the main orchestration entry point that coordinates the complete event
83
- * processing lifecycle. It implements the core workflow execution pattern including
84
- * validation, locking, state management, handler invocation, event creation, and
85
- * persistence with comprehensive error handling and observability.
86
- *
87
- * The execution process follows these phases:
88
- * 1. **Validation & Setup** - Subject parsing, handler resolution, contract validation
89
- * 2. **Resource Management** - Distributed lock acquisition and state loading
90
- * 3. **Handler Execution** - Context preparation and user handler invocation
91
- * 4. **Event Processing** - Result transformation and emittable event creation
92
- * 5. **State Persistence** - Atomic state updates and event tracking
93
- * 6. **Cleanup & Return** - Resource release and structured result return
94
- *
95
84
  * @param event - The triggering event to process
96
85
  * @param opentelemetry - OpenTelemetry configuration for trace inheritance
97
86
  *
@@ -101,26 +90,6 @@ export declare class ArvoResumable<TMemory extends Record<string, any> = Record<
101
90
  * @throws {ConfigViolation} When handler resolution or contract validation fails
102
91
  * @throws {ContractViolation} When event schema validation fails
103
92
  * @throws {ExecutionViolation} When workflow execution encounters critical errors
104
- *
105
- * @remarks
106
- * **Execution Safety:**
107
- * The method implements comprehensive error recovery with proper resource cleanup
108
- * in all execution paths. ViolationErrors are rethrown for system handling while
109
- * workflow errors become system error events for graceful degradation.
110
- *
111
- * **State Management:**
112
- * Workflow state is managed atomically with optimistic concurrency control.
113
- * Status transitions from 'active' to 'done' occur only when completion events
114
- * are generated, ensuring proper workflow lifecycle management.
115
- *
116
- * **Observability:**
117
- * Complete execution is traced using OpenTelemetry with detailed span attributes
118
- * for debugging and monitoring. Event metadata includes processing context and
119
- * routing information for operational visibility.
120
- *
121
- * **Terminal State Handling:**
122
- * Workflows in 'done' status ignore additional events to prevent state corruption
123
- * while preserving audit trails for completed workflow executions.
124
93
  */
125
94
  execute(event: ArvoEvent, opentelemetry: ArvoEventHandlerOpenTelemetryOptions): Promise<{
126
95
  events: ArvoEvent[];
@@ -82,6 +82,7 @@ var index_1 = require("../SyncEventResource/index");
82
82
  var index_2 = require("../utils/index");
83
83
  var AbstractArvoEventHandler_1 = __importDefault(require("../AbstractArvoEventHandler"));
84
84
  var errors_1 = require("../errors");
85
+ var ArvoDomain_1 = require("../ArvoDomain");
85
86
  /**
86
87
  * ArvoResumable - A stateful orchestration handler for managing distributed workflows
87
88
  *
@@ -118,11 +119,13 @@ var ArvoResumable = /** @class */ (function (_super) {
118
119
  function ArvoResumable(param) {
119
120
  var _a;
120
121
  var _this = _super.call(this) || this;
122
+ _this.systemErrorDomain = [];
121
123
  _this.executionunits = param.executionunits;
122
124
  _this.source = param.contracts.self.type;
123
125
  _this.syncEventResource = new index_1.SyncEventResource(param.memory, (_a = param.requiresResourceLocking) !== null && _a !== void 0 ? _a : true);
124
126
  _this.contracts = param.contracts;
125
127
  _this.handler = param.handler;
128
+ _this.systemErrorDomain = param.systemErrorDomain;
126
129
  return _this;
127
130
  }
128
131
  Object.defineProperty(ArvoResumable.prototype, "requiresResourceLocking", {
@@ -208,7 +211,7 @@ var ArvoResumable = /** @class */ (function (_super) {
208
211
  * @throws {ExecutionViolation} On invalid parentSubject$$ format
209
212
  */
210
213
  ArvoResumable.prototype.createEmittableEvent = function (event, otelHeaders, orchestrationParentSubject, sourceEvent, selfVersionedContract, initEventId, _domain) {
211
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
214
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
212
215
  (0, arvo_core_1.logToSpan)({
213
216
  level: 'INFO',
214
217
  message: "Creating emittable event: ".concat(event.type),
@@ -218,7 +221,12 @@ var ArvoResumable = /** @class */ (function (_super) {
218
221
  var contract = null;
219
222
  var subject = sourceEvent.subject;
220
223
  var parentId = sourceEvent.id;
221
- var domain = _domain === undefined ? ((_b = (_a = sourceEvent.domain) !== null && _a !== void 0 ? _a : this.domain) !== null && _b !== void 0 ? _b : null) : _domain;
224
+ var domain = (0, ArvoDomain_1.resolveEventDomain)({
225
+ domainToResolve: _domain,
226
+ handlerSelfContract: selfVersionedContract,
227
+ eventContract: null,
228
+ triggeringEvent: sourceEvent,
229
+ });
222
230
  if (event.type === selfVersionedContract.metadata.completeEventType) {
223
231
  (0, arvo_core_1.logToSpan)({
224
232
  level: 'INFO',
@@ -228,8 +236,12 @@ var ArvoResumable = /** @class */ (function (_super) {
228
236
  schema = selfVersionedContract.emits[selfVersionedContract.metadata.completeEventType];
229
237
  subject = orchestrationParentSubject !== null && orchestrationParentSubject !== void 0 ? orchestrationParentSubject : sourceEvent.subject;
230
238
  parentId = initEventId;
231
- domain =
232
- _domain === undefined ? ((_e = (_d = (_c = selfVersionedContract.domain) !== null && _c !== void 0 ? _c : sourceEvent.domain) !== null && _d !== void 0 ? _d : this.domain) !== null && _e !== void 0 ? _e : null) : _domain;
239
+ domain = (0, ArvoDomain_1.resolveEventDomain)({
240
+ domainToResolve: _domain,
241
+ handlerSelfContract: selfVersionedContract,
242
+ eventContract: selfVersionedContract,
243
+ triggeringEvent: sourceEvent,
244
+ });
233
245
  }
234
246
  else if (serviceContract[event.type]) {
235
247
  (0, arvo_core_1.logToSpan)({
@@ -238,7 +250,12 @@ var ArvoResumable = /** @class */ (function (_super) {
238
250
  });
239
251
  contract = serviceContract[event.type];
240
252
  schema = serviceContract[event.type].accepts.schema;
241
- domain = _domain === undefined ? ((_h = (_g = (_f = contract === null || contract === void 0 ? void 0 : contract.domain) !== null && _f !== void 0 ? _f : sourceEvent.domain) !== null && _g !== void 0 ? _g : this.domain) !== null && _h !== void 0 ? _h : null) : _domain;
253
+ domain = (0, ArvoDomain_1.resolveEventDomain)({
254
+ domainToResolve: _domain,
255
+ handlerSelfContract: selfVersionedContract,
256
+ eventContract: contract,
257
+ triggeringEvent: sourceEvent,
258
+ });
242
259
  // If the event is to call another orchestrator then, extract the parent subject
243
260
  // passed to it and then form an new subject. This allows for event chaining
244
261
  // between orchestrators
@@ -247,8 +264,8 @@ var ArvoResumable = /** @class */ (function (_super) {
247
264
  try {
248
265
  arvo_core_1.ArvoOrchestrationSubject.parse(event.data.parentSubject$$);
249
266
  }
250
- catch (_v) {
251
- throw new errors_1.ExecutionViolation("Invalid parentSubject$$ for the event(type='".concat(event.type, "', uri='").concat((_j = event.dataschema) !== null && _j !== void 0 ? _j : arvo_core_1.EventDataschemaUtil.create(contract), "').It must be follow the ArvoOrchestrationSubject schema. The easiest way is to use the current orchestration subject by storing the subject via the context block in the machine definition."));
267
+ catch (_m) {
268
+ throw new errors_1.ExecutionViolation("Invalid parentSubject$$ for the event(type='".concat(event.type, "', uri='").concat((_a = event.dataschema) !== null && _a !== void 0 ? _a : arvo_core_1.EventDataschemaUtil.create(contract), "').It must be follow the ArvoOrchestrationSubject schema. The easiest way is to use the current orchestration subject by storing the subject via the context block in the machine definition."));
252
269
  }
253
270
  }
254
271
  try {
@@ -259,7 +276,7 @@ var ArvoResumable = /** @class */ (function (_super) {
259
276
  subject: event.data.parentSubject$$,
260
277
  domain: domain !== null && domain !== void 0 ? domain : null,
261
278
  meta: {
262
- redirectto: (_k = event.redirectto) !== null && _k !== void 0 ? _k : this.source,
279
+ redirectto: (_b = event.redirectto) !== null && _b !== void 0 ? _b : this.source,
263
280
  },
264
281
  });
265
282
  }
@@ -270,7 +287,7 @@ var ArvoResumable = /** @class */ (function (_super) {
270
287
  initiator: this.source,
271
288
  domain: domain !== null && domain !== void 0 ? domain : undefined,
272
289
  meta: {
273
- redirectto: (_l = event.redirectto) !== null && _l !== void 0 ? _l : this.source,
290
+ redirectto: (_c = event.redirectto) !== null && _c !== void 0 ? _c : this.source,
274
291
  },
275
292
  });
276
293
  }
@@ -305,16 +322,16 @@ var ArvoResumable = /** @class */ (function (_super) {
305
322
  subject: subject,
306
323
  dataschema: finalDataschema !== null && finalDataschema !== void 0 ? finalDataschema : undefined,
307
324
  data: finalData,
308
- to: (_m = event.to) !== null && _m !== void 0 ? _m : event.type,
309
- accesscontrol: (_p = (_o = event.accesscontrol) !== null && _o !== void 0 ? _o : sourceEvent.accesscontrol) !== null && _p !== void 0 ? _p : undefined,
325
+ to: (_d = event.to) !== null && _d !== void 0 ? _d : event.type,
326
+ accesscontrol: (_f = (_e = event.accesscontrol) !== null && _e !== void 0 ? _e : sourceEvent.accesscontrol) !== null && _f !== void 0 ? _f : undefined,
310
327
  // The orchestrator/ resumable does not respect redirectto from the source event
311
- redirectto: (_q = event.redirectto) !== null && _q !== void 0 ? _q : this.source,
312
- executionunits: (_r = event.executionunits) !== null && _r !== void 0 ? _r : this.executionunits,
313
- traceparent: (_s = otelHeaders.traceparent) !== null && _s !== void 0 ? _s : undefined,
314
- tracestate: (_t = otelHeaders.tracestate) !== null && _t !== void 0 ? _t : undefined,
328
+ redirectto: (_g = event.redirectto) !== null && _g !== void 0 ? _g : this.source,
329
+ executionunits: (_h = event.executionunits) !== null && _h !== void 0 ? _h : this.executionunits,
330
+ traceparent: (_j = otelHeaders.traceparent) !== null && _j !== void 0 ? _j : undefined,
331
+ tracestate: (_k = otelHeaders.tracestate) !== null && _k !== void 0 ? _k : undefined,
315
332
  parentid: parentId,
316
333
  domain: domain !== null && domain !== void 0 ? domain : undefined,
317
- }, (_u = event.__extensions) !== null && _u !== void 0 ? _u : {});
334
+ }, (_l = event.__extensions) !== null && _l !== void 0 ? _l : {});
318
335
  (0, arvo_core_1.logToSpan)({
319
336
  level: 'INFO',
320
337
  message: "Event created successfully: ".concat(emittableEvent.type),
@@ -324,19 +341,6 @@ var ArvoResumable = /** @class */ (function (_super) {
324
341
  /**
325
342
  * Executes the orchestration workflow for an incoming event
326
343
  *
327
- * This is the main orchestration entry point that coordinates the complete event
328
- * processing lifecycle. It implements the core workflow execution pattern including
329
- * validation, locking, state management, handler invocation, event creation, and
330
- * persistence with comprehensive error handling and observability.
331
- *
332
- * The execution process follows these phases:
333
- * 1. **Validation & Setup** - Subject parsing, handler resolution, contract validation
334
- * 2. **Resource Management** - Distributed lock acquisition and state loading
335
- * 3. **Handler Execution** - Context preparation and user handler invocation
336
- * 4. **Event Processing** - Result transformation and emittable event creation
337
- * 5. **State Persistence** - Atomic state updates and event tracking
338
- * 6. **Cleanup & Return** - Resource release and structured result return
339
- *
340
344
  * @param event - The triggering event to process
341
345
  * @param opentelemetry - OpenTelemetry configuration for trace inheritance
342
346
  *
@@ -346,26 +350,6 @@ var ArvoResumable = /** @class */ (function (_super) {
346
350
  * @throws {ConfigViolation} When handler resolution or contract validation fails
347
351
  * @throws {ContractViolation} When event schema validation fails
348
352
  * @throws {ExecutionViolation} When workflow execution encounters critical errors
349
- *
350
- * @remarks
351
- * **Execution Safety:**
352
- * The method implements comprehensive error recovery with proper resource cleanup
353
- * in all execution paths. ViolationErrors are rethrown for system handling while
354
- * workflow errors become system error events for graceful degradation.
355
- *
356
- * **State Management:**
357
- * Workflow state is managed atomically with optimistic concurrency control.
358
- * Status transitions from 'active' to 'done' occur only when completion events
359
- * are generated, ensuring proper workflow lifecycle management.
360
- *
361
- * **Observability:**
362
- * Complete execution is traced using OpenTelemetry with detailed span attributes
363
- * for debugging and monitoring. Event metadata includes processing context and
364
- * routing information for operational visibility.
365
- *
366
- * **Terminal State Handling:**
367
- * Workflows in 'done' status ignore additional events to prevent state corruption
368
- * while preserving audit trails for completed workflow executions.
369
353
  */
370
354
  ArvoResumable.prototype.execute = function (event, opentelemetry) {
371
355
  return __awaiter(this, void 0, void 0, function () {
@@ -373,7 +357,7 @@ var ArvoResumable = /** @class */ (function (_super) {
373
357
  var _this = this;
374
358
  return __generator(this, function (_b) {
375
359
  return [2 /*return*/, arvo_core_1.ArvoOpenTelemetry.getInstance().startActiveSpan({
376
- name: "ArvoResumable<".concat(this.contracts.self.uri, ">@<").concat(event.type, ">"),
360
+ name: "Resumable<".concat(this.contracts.self.uri, ">@<").concat(event.type, ">"),
377
361
  spanOptions: {
378
362
  kind: api_1.SpanKind.PRODUCER,
379
363
  attributes: __assign((_a = {}, _a[arvo_core_1.ArvoExecution.ATTR_SPAN_KIND] = arvo_core_1.ArvoExecutionSpanKind.ORCHESTRATOR, _a[arvo_core_1.OpenInference.ATTR_SPAN_KIND] = arvo_core_1.OpenInferenceSpanKind.CHAIN, _a), Object.fromEntries(Object.entries(event.otelAttributes).map(function (_a) {
@@ -395,7 +379,8 @@ var ArvoResumable = /** @class */ (function (_super) {
395
379
  },
396
380
  disableSpanManagement: true,
397
381
  fn: function (span) { return __awaiter(_this, void 0, void 0, function () {
398
- var otelHeaders, orchestrationParentSubject, acquiredLock, initEventId, parsedEventSubject, contractType, state, eventTypeToExpectedEvent, _i, _a, _b, _, eventList, _c, eventList_1, _evt, handler, executionResult, emittables, _d, _e, item, domains, _f, _g, _dom, evt, _h, _j, _k, key, value, eventTrackingState, error_2, e, parsedEventSubject, result, _l, _m, _dom, _o, _p, _q, key, value;
382
+ var otelHeaders, orchestrationParentSubject, acquiredLock, initEventId, parsedEventSubject, contractType, state, eventTypeToExpectedEvent, _i, _a, _b, _, eventList, _c, eventList_1, _evt, handler, executionResult, emittables, _d, _e, item, createdDomain, _f, _g, _dom, evt, _h, _j, _k, key, value, eventTrackingState, error_2, e, parsedEventSubject, result, _l, _m, _dom, _o, _p, _q, key, value;
383
+ var _this = this;
399
384
  var _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12;
400
385
  return __generator(this, function (_13) {
401
386
  switch (_13.label) {
@@ -536,6 +521,10 @@ var ArvoResumable = /** @class */ (function (_super) {
536
521
  context: (_1 = state === null || state === void 0 ? void 0 : state.state$$) !== null && _1 !== void 0 ? _1 : null,
537
522
  metadata: state !== null && state !== void 0 ? state : null,
538
523
  collectedEvents: eventTypeToExpectedEvent,
524
+ domain: {
525
+ event: event.domain,
526
+ self: this.contracts.self.domain,
527
+ },
539
528
  input: contractType === 'self' ? event.toJSON() : null,
540
529
  service: contractType === 'service' ? event.toJSON() : null,
541
530
  contracts: {
@@ -554,15 +543,21 @@ var ArvoResumable = /** @class */ (function (_super) {
554
543
  to: (_3 = (_2 = parsedEventSubject.meta) === null || _2 === void 0 ? void 0 : _2.redirectto) !== null && _3 !== void 0 ? _3 : parsedEventSubject.execution.initiator,
555
544
  domain: orchestrationParentSubject
556
545
  ? [arvo_core_1.ArvoOrchestrationSubject.parse(orchestrationParentSubject).execution.domain]
557
- : [undefined],
546
+ : [null],
558
547
  },
559
548
  ]
560
549
  : []), true), ((_4 = executionResult === null || executionResult === void 0 ? void 0 : executionResult.services) !== null && _4 !== void 0 ? _4 : []), true); _d < _e.length; _d++) {
561
550
  item = _e[_d];
562
- domains = (_5 = item.domain) !== null && _5 !== void 0 ? _5 : [null];
563
- for (_f = 0, _g = Array.from(new Set(domains)); _f < _g.length; _f++) {
551
+ createdDomain = new Set(null);
552
+ for (_f = 0, _g = Array.from(new Set((_5 = item.domain) !== null && _5 !== void 0 ? _5 : [null])); _f < _g.length; _f++) {
564
553
  _dom = _g[_f];
565
554
  evt = this.createEmittableEvent(item, otelHeaders, orchestrationParentSubject, event, this.contracts.self.version(parsedEventSubject.orchestrator.version), initEventId, _dom);
555
+ // Making sure the raw event broadcast is actually unique as the
556
+ // domain resolution (especially for symbolic) can only happen
557
+ // in the createEmittableEvent
558
+ if (createdDomain.has(evt.domain))
559
+ continue;
560
+ createdDomain.add(evt.domain);
566
561
  emittables.push(evt);
567
562
  for (_h = 0, _j = Object.entries(emittables[emittables.length - 1].otelAttributes); _h < _j.length; _h++) {
568
563
  _k = _j[_h], key = _k[0], value = _k[1];
@@ -637,9 +632,18 @@ var ArvoResumable = /** @class */ (function (_super) {
637
632
  });
638
633
  }
639
634
  result = [];
640
- for (_l = 0, _m = Array.from(new Set([event.domain, this.domain, null])); _l < _m.length; _l++) {
635
+ for (_l = 0, _m = Array.from(new Set(this.systemErrorDomain
636
+ ? this.systemErrorDomain.map(function (item) {
637
+ return (0, ArvoDomain_1.resolveEventDomain)({
638
+ domainToResolve: item,
639
+ handlerSelfContract: _this.contracts.self.version('latest'),
640
+ eventContract: _this.contracts.self.version('latest'),
641
+ triggeringEvent: event,
642
+ });
643
+ })
644
+ : [event.domain, this.domain, null])); _l < _m.length; _l++) {
641
645
  _dom = _m[_l];
642
- result.push((0, arvo_core_1.createArvoOrchestratorEventFactory)(this.contracts.self.version('any')).systemError({
646
+ result.push((0, arvo_core_1.createArvoOrchestratorEventFactory)(this.contracts.self.version('latest')).systemError({
643
647
  source: this.source,
644
648
  // If the initiator of the workflow exist then match the
645
649
  // subject so that it can incorporate it in its state. If
@@ -22,6 +22,10 @@ type Handler<TState extends ArvoResumableState<Record<string, any>>, TSelfContra
22
22
  collectedEvents: Partial<{
23
23
  [K in AllServiceEventTypes<TServiceContract>]: ServiceEventTypeMap<TServiceContract>[K][];
24
24
  }>;
25
+ domain: {
26
+ event: string | null;
27
+ self: string | null;
28
+ };
25
29
  context: TState['state$$'] | null;
26
30
  input: InferVersionedArvoContract<TSelfContract>['accepts'] | null;
27
31
  service: {
package/dist/index.d.ts CHANGED
@@ -26,8 +26,9 @@ import { createSimpleEventBroker } from './utils/SimpleEventBroker/helper';
26
26
  import { ArvoResumable } from './ArvoResumable';
27
27
  import { createArvoResumable } from './ArvoResumable/factory';
28
28
  import { ArvoResumableHandler, ArvoResumableState } from './ArvoResumable/types';
29
+ import { ArvoDomain, resolveEventDomain } from './ArvoDomain';
29
30
  declare const xstate: {
30
31
  emit: typeof emit;
31
32
  assign: typeof assign;
32
33
  };
33
- export { ArvoEventHandler, createArvoEventHandler, IArvoEventHandler, ArvoEventHandlerFunctionOutput, ArvoEventHandlerFunctionInput, ArvoEventHandlerFunction, PartialExcept, isNullOrUndefined, getValueOrDefault, coalesce, coalesceOrDefault, AbstractArvoEventHandler, ArvoEventHandlerOpenTelemetryOptions, EventHandlerFactory, ContractViolation, ConfigViolation, ExecutionViolation, ArvoMachine, setupArvoMachine, ArvoMachineContext, EnqueueArvoEventActionParam, IMachineRegistry, MachineRegistry, MachineExecutionEngine, IMachineExectionEngine, ExecuteMachineInput, ExecuteMachineOutput, IMachineMemory, SimpleMachineMemory, MachineMemoryRecord, IArvoOrchestrator, TransactionViolation, TransactionViolationCause, ArvoOrchestrator, createArvoOrchestrator, SimpleEventBroker, createSimpleEventBroker, TelemetredSimpleMachineMemory, xstate, ArvoResumable, createArvoResumable, ArvoResumableHandler, ArvoResumableState, };
34
+ export { ArvoEventHandler, createArvoEventHandler, IArvoEventHandler, ArvoEventHandlerFunctionOutput, ArvoEventHandlerFunctionInput, ArvoEventHandlerFunction, PartialExcept, isNullOrUndefined, getValueOrDefault, coalesce, coalesceOrDefault, AbstractArvoEventHandler, ArvoEventHandlerOpenTelemetryOptions, EventHandlerFactory, ContractViolation, ConfigViolation, ExecutionViolation, ArvoMachine, setupArvoMachine, ArvoMachineContext, EnqueueArvoEventActionParam, IMachineRegistry, MachineRegistry, MachineExecutionEngine, IMachineExectionEngine, ExecuteMachineInput, ExecuteMachineOutput, IMachineMemory, SimpleMachineMemory, MachineMemoryRecord, IArvoOrchestrator, TransactionViolation, TransactionViolationCause, ArvoOrchestrator, createArvoOrchestrator, SimpleEventBroker, createSimpleEventBroker, TelemetredSimpleMachineMemory, xstate, ArvoResumable, createArvoResumable, ArvoResumableHandler, ArvoResumableState, ArvoDomain, resolveEventDomain, };