arvo-event-handler 3.0.23 → 3.0.26

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.
@@ -1,4 +1,4 @@
1
- import type { ArvoEvent, VersionedArvoContract } from 'arvo-core';
1
+ import { type ArvoEvent, type VersionedArvoContract } from 'arvo-core';
2
2
  /**
3
3
  * Symbolic constants for domain resolution in Arvo event emission.
4
4
  *
@@ -7,57 +7,75 @@ import type { ArvoEvent, VersionedArvoContract } from 'arvo-core';
7
7
  */
8
8
  export declare const ArvoDomain: {
9
9
  /**
10
- * Resolve the domain from the emitting handlers own contract (`handlerSelfContract.domain`).
10
+ * Resolve domain from the handler's contract.
11
11
  *
12
- * Use this when the handler’s contract defines a stable domain that should apply
13
- * to all emitted events, regardless of the triggering context.
12
+ * Uses `handlerSelfContract.domain` for all emitted events.
14
13
  */
15
14
  readonly FROM_SELF_CONTRACT: "domain.contract.self.inherit";
16
15
  /**
17
- * Resolve the domain from the contract that defines the event being emitted (`eventContract.domain`).
16
+ * Resolve domain from the event's contract.
18
17
  *
19
- * In `ArvoResumable` and `ArvoMachine`, this is typically used when emitting service events
20
- * (not the completion event). In `ArvoEventHandler`, where only the self contract exists,
21
- * this resolves to the same value as `FROM_SELF_CONTRACT`.
22
- *
23
- * For orchestration `complete` events, this behaves identically to `FROM_SELF_CONTRACT`
24
- * since the emitting contract is also the self contract.
18
+ * For orchestrators, uses the service contract's domain.
19
+ * For handlers, behaves the same as FROM_SELF_CONTRACT.
25
20
  */
26
21
  readonly FROM_EVENT_CONTRACT: "domain.contract.inherit";
27
22
  /**
28
- * Resolve the domain from the triggering events `domain` field (`triggeringEvent.domain`).
23
+ * Resolve domain from the triggering event's domain field.
29
24
  *
30
- * Use this when you want to preserve the domain context of the incoming event
31
- * and carry it forward through event emissions.
25
+ * Preserves the domain context of the incoming event.
32
26
  */
33
27
  readonly FROM_TRIGGERING_EVENT: "domain.event.inherit";
34
28
  /**
35
- * Keep the event in the current execution context (null domain).
29
+ * Extract domain from the current event's subject.
30
+ *
31
+ * Parses the subject to retrieve `execution.domain`.
32
+ * Falls back to LOCAL if subject is not a valid ArvoOrchestrationSubject.
33
+ */
34
+ readonly FROM_CURRENT_SUBJECT: "domain.event.current.subject";
35
+ /**
36
+ * Extract domain from the parent orchestration subject.
37
+ *
38
+ * Parses the parent subject to retrieve `execution.domain`.
39
+ * Falls back to LOCAL if subject is not a valid ArvoOrchestrationSubject.
40
+ */
41
+ readonly FROM_PARENT_SUBJECT: "domain.parent.subject";
42
+ /**
43
+ * Resolve domain based on orchestration context.
44
+ *
45
+ * Routes responses and completions back through the orchestration chain:
46
+ * - For handlers: routes back to the orchestration's domain
47
+ * - For child orchestrations: routes to parent's domain if different, LOCAL if same
48
+ * - For root orchestrations: routes to own domain if cross-domain call, LOCAL otherwise
49
+ *
50
+ * This is the recommended default for maintaining domain coherence in orchestration workflows.
51
+ */
52
+ readonly ORCHESTRATION_CONTEXT: "domain.orchestration.context";
53
+ /**
54
+ * Stay in the current execution context (null domain).
36
55
  *
37
- * Use this when the event should remain local to the current domain without
38
- * crossing execution boundaries through the exchange layer.
56
+ * Event remains local without crossing domain boundaries.
39
57
  */
40
58
  readonly LOCAL: null;
41
59
  };
42
60
  /**
43
- * Resolves a symbolic or static domain value into a concrete domain string or `null`.
61
+ * Resolves symbolic domain constants to concrete domain values.
44
62
  *
45
- * Used internally in the Arvo execution model to interpret symbolic domain constants
46
- * at the moment an event is emitted. Supports resolution from:
47
- * - the emitting handler's own contract
48
- * - the emitted event’s associated contract
49
- * - the triggering event’s `domain` field
63
+ * Interprets domain resolution symbols and returns the appropriate domain string or null.
64
+ * Static domain strings pass through unchanged.
50
65
  *
51
- * @param param - Parameters for resolving the domain.
52
- * @param param.domainToResolve - Either a static domain string, symbolic value, or null.
53
- * @param param.handlerSelfContract - The contract of the handler currently emitting the event.
54
- * @param param.eventContract - The contract of the event being emitted (optional).
55
- * @param param.triggeringEvent - The triggering event that caused this emission.
66
+ * @param param.domainToResolve - Domain string or symbolic constant to resolve
67
+ * @param param.parentSubject - Parent orchestration subject (null for root orchestrations or handlers)
68
+ * @param param.currentSubject - Current event subject
69
+ * @param param.handlerSelfContract - Contract of the handler emitting the event
70
+ * @param param.eventContract - Contract of the event being emitted (optional)
71
+ * @param param.triggeringEvent - Event that triggered this emission
56
72
  *
57
- * @returns A resolved domain string, or `null` if no valid domain is found.
73
+ * @returns Resolved domain string or null
58
74
  */
59
75
  export declare const resolveEventDomain: (param: {
60
76
  domainToResolve: string | null;
77
+ parentSubject: string | null;
78
+ currentSubject: string;
61
79
  handlerSelfContract: VersionedArvoContract<any, any>;
62
80
  eventContract: VersionedArvoContract<any, any> | null;
63
81
  triggeringEvent: ArvoEvent;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveEventDomain = exports.ArvoDomain = void 0;
4
+ var arvo_core_1 = require("arvo-core");
4
5
  /**
5
6
  * Symbolic constants for domain resolution in Arvo event emission.
6
7
  *
@@ -9,70 +10,138 @@ exports.resolveEventDomain = exports.ArvoDomain = void 0;
9
10
  */
10
11
  exports.ArvoDomain = {
11
12
  /**
12
- * Resolve the domain from the emitting handlers own contract (`handlerSelfContract.domain`).
13
+ * Resolve domain from the handler's contract.
13
14
  *
14
- * Use this when the handler’s contract defines a stable domain that should apply
15
- * to all emitted events, regardless of the triggering context.
15
+ * Uses `handlerSelfContract.domain` for all emitted events.
16
16
  */
17
17
  FROM_SELF_CONTRACT: 'domain.contract.self.inherit',
18
18
  /**
19
- * Resolve the domain from the contract that defines the event being emitted (`eventContract.domain`).
19
+ * Resolve domain from the event's contract.
20
20
  *
21
- * In `ArvoResumable` and `ArvoMachine`, this is typically used when emitting service events
22
- * (not the completion event). In `ArvoEventHandler`, where only the self contract exists,
23
- * this resolves to the same value as `FROM_SELF_CONTRACT`.
24
- *
25
- * For orchestration `complete` events, this behaves identically to `FROM_SELF_CONTRACT`
26
- * since the emitting contract is also the self contract.
21
+ * For orchestrators, uses the service contract's domain.
22
+ * For handlers, behaves the same as FROM_SELF_CONTRACT.
27
23
  */
28
24
  FROM_EVENT_CONTRACT: 'domain.contract.inherit',
29
25
  /**
30
- * Resolve the domain from the triggering events `domain` field (`triggeringEvent.domain`).
26
+ * Resolve domain from the triggering event's domain field.
31
27
  *
32
- * Use this when you want to preserve the domain context of the incoming event
33
- * and carry it forward through event emissions.
28
+ * Preserves the domain context of the incoming event.
34
29
  */
35
30
  FROM_TRIGGERING_EVENT: 'domain.event.inherit',
36
31
  /**
37
- * Keep the event in the current execution context (null domain).
32
+ * Extract domain from the current event's subject.
33
+ *
34
+ * Parses the subject to retrieve `execution.domain`.
35
+ * Falls back to LOCAL if subject is not a valid ArvoOrchestrationSubject.
36
+ */
37
+ FROM_CURRENT_SUBJECT: 'domain.event.current.subject',
38
+ /**
39
+ * Extract domain from the parent orchestration subject.
38
40
  *
39
- * Use this when the event should remain local to the current domain without
40
- * crossing execution boundaries through the exchange layer.
41
+ * Parses the parent subject to retrieve `execution.domain`.
42
+ * Falls back to LOCAL if subject is not a valid ArvoOrchestrationSubject.
41
43
  */
42
- LOCAL: null
44
+ FROM_PARENT_SUBJECT: 'domain.parent.subject',
45
+ /**
46
+ * Resolve domain based on orchestration context.
47
+ *
48
+ * Routes responses and completions back through the orchestration chain:
49
+ * - For handlers: routes back to the orchestration's domain
50
+ * - For child orchestrations: routes to parent's domain if different, LOCAL if same
51
+ * - For root orchestrations: routes to own domain if cross-domain call, LOCAL otherwise
52
+ *
53
+ * This is the recommended default for maintaining domain coherence in orchestration workflows.
54
+ */
55
+ ORCHESTRATION_CONTEXT: 'domain.orchestration.context',
56
+ /**
57
+ * Stay in the current execution context (null domain).
58
+ *
59
+ * Event remains local without crossing domain boundaries.
60
+ */
61
+ LOCAL: null,
43
62
  };
44
63
  /**
45
- * Resolves a symbolic or static domain value into a concrete domain string or `null`.
64
+ * Extracts the domain from an ArvoOrchestrationSubject string.
46
65
  *
47
- * Used internally in the Arvo execution model to interpret symbolic domain constants
48
- * at the moment an event is emitted. Supports resolution from:
49
- * - the emitting handler's own contract
50
- * - the emitted event’s associated contract
51
- * - the triggering event’s `domain` field
66
+ * @param subject - Orchestration subject string or null
67
+ * @returns Domain from subject's execution context, or null if parsing fails
68
+ */
69
+ var getDomainFromArvoSubject = function (subject) {
70
+ if (subject === null)
71
+ return null;
72
+ try {
73
+ var parsedSubject = arvo_core_1.ArvoOrchestrationSubject.parse(subject);
74
+ return parsedSubject.execution.domain;
75
+ }
76
+ catch (e) {
77
+ (0, arvo_core_1.exceptionToSpan)(new Error("Unable to parse the provided subject. Falling back to ArvoDomain.LOCAL. Error: ".concat(e.message)));
78
+ }
79
+ return null;
80
+ };
81
+ /**
82
+ * Resolves symbolic domain constants to concrete domain values.
52
83
  *
53
- * @param param - Parameters for resolving the domain.
54
- * @param param.domainToResolve - Either a static domain string, symbolic value, or null.
55
- * @param param.handlerSelfContract - The contract of the handler currently emitting the event.
56
- * @param param.eventContract - The contract of the event being emitted (optional).
57
- * @param param.triggeringEvent - The triggering event that caused this emission.
84
+ * Interprets domain resolution symbols and returns the appropriate domain string or null.
85
+ * Static domain strings pass through unchanged.
58
86
  *
59
- * @returns A resolved domain string, or `null` if no valid domain is found.
87
+ * @param param.domainToResolve - Domain string or symbolic constant to resolve
88
+ * @param param.parentSubject - Parent orchestration subject (null for root orchestrations or handlers)
89
+ * @param param.currentSubject - Current event subject
90
+ * @param param.handlerSelfContract - Contract of the handler emitting the event
91
+ * @param param.eventContract - Contract of the event being emitted (optional)
92
+ * @param param.triggeringEvent - Event that triggered this emission
93
+ *
94
+ * @returns Resolved domain string or null
60
95
  */
61
96
  var resolveEventDomain = function (param) {
62
97
  var _a, _b;
63
- var ArvoDomainValues = Object.values(exports.ArvoDomain);
64
- if (param.domainToResolve && ArvoDomainValues.includes(param.domainToResolve)) {
65
- var domainToResolve = param.domainToResolve;
66
- if (domainToResolve === exports.ArvoDomain.FROM_EVENT_CONTRACT) {
67
- return (_b = (_a = param.eventContract) === null || _a === void 0 ? void 0 : _a.domain) !== null && _b !== void 0 ? _b : null;
68
- }
69
- if (domainToResolve === exports.ArvoDomain.FROM_SELF_CONTRACT) {
70
- return param.handlerSelfContract.domain;
98
+ if (!param.domainToResolve) {
99
+ return null;
100
+ }
101
+ if (param.domainToResolve === exports.ArvoDomain.LOCAL) {
102
+ return null;
103
+ }
104
+ if (param.domainToResolve === exports.ArvoDomain.FROM_EVENT_CONTRACT) {
105
+ return (_b = (_a = param.eventContract) === null || _a === void 0 ? void 0 : _a.domain) !== null && _b !== void 0 ? _b : null;
106
+ }
107
+ if (param.domainToResolve === exports.ArvoDomain.FROM_SELF_CONTRACT) {
108
+ return param.handlerSelfContract.domain;
109
+ }
110
+ if (param.domainToResolve === exports.ArvoDomain.FROM_TRIGGERING_EVENT) {
111
+ return param.triggeringEvent.domain;
112
+ }
113
+ if (param.domainToResolve === exports.ArvoDomain.FROM_CURRENT_SUBJECT) {
114
+ return getDomainFromArvoSubject(param.currentSubject);
115
+ }
116
+ if (param.domainToResolve === exports.ArvoDomain.FROM_PARENT_SUBJECT) {
117
+ return getDomainFromArvoSubject(param.parentSubject);
118
+ }
119
+ if (param.domainToResolve === exports.ArvoDomain.ORCHESTRATION_CONTEXT) {
120
+ var currentDomain = getDomainFromArvoSubject(param.currentSubject);
121
+ var parentDomain = getDomainFromArvoSubject(param.parentSubject);
122
+ var triggeringDomain = param.triggeringEvent.domain;
123
+ // No parent orchestration (root orchestration or handler)
124
+ if (param.parentSubject === null) {
125
+ // Triggering event is local
126
+ if (triggeringDomain === null) {
127
+ return null;
128
+ }
129
+ // Current and triggering domains match
130
+ if (currentDomain === triggeringDomain) {
131
+ return null;
132
+ }
133
+ // Cross-domain call - route back to orchestration's domain
134
+ return currentDomain;
71
135
  }
72
- if (domainToResolve === exports.ArvoDomain.FROM_TRIGGERING_EVENT) {
73
- return param.triggeringEvent.domain;
136
+ // Has parent orchestration
137
+ // Child and parent in same domain
138
+ if (currentDomain === parentDomain) {
139
+ return null;
74
140
  }
141
+ // Child in different domain - route to parent's domain
142
+ return parentDomain;
75
143
  }
144
+ // Static domain string
76
145
  return param.domainToResolve;
77
146
  };
78
147
  exports.resolveEventDomain = resolveEventDomain;
@@ -14,7 +14,6 @@ import type { ArvoEventHandlerParam } from './types';
14
14
  * ```ts
15
15
  * const handler = createArvoEventHandler({
16
16
  * contract: userContract,
17
- * executionunits: 1,
18
17
  * handler: {
19
18
  * '1.0.0': async ({ event, domain, span }) => {
20
19
  * if (domain.event !== domain.self) {
@@ -18,7 +18,6 @@ var _1 = __importDefault(require("."));
18
18
  * ```ts
19
19
  * const handler = createArvoEventHandler({
20
20
  * contract: userContract,
21
- * executionunits: 1,
22
21
  * handler: {
23
22
  * '1.0.0': async ({ event, domain, span }) => {
24
23
  * if (domain.event !== domain.self) {
@@ -17,8 +17,8 @@ export default class ArvoEventHandler<TContract extends ArvoContract> implements
17
17
  readonly handler: ArvoEventHandlerFunction<TContract>;
18
18
  /** The source identifier for events produced by this handler */
19
19
  get source(): TContract['type'];
20
- /** Optional domains for routing system error events */
21
- readonly systemErrorDomain?: (string | null)[];
20
+ /** Domains for routing events */
21
+ readonly defaultEventEmissionDomains: Required<NonNullable<ArvoEventHandlerParam<TContract>['defaultEventEmissionDomains']>>;
22
22
  /** The contract-defined domain for the handler */
23
23
  get domain(): string | null;
24
24
  constructor(param: ArvoEventHandlerParam<TContract>);
@@ -40,21 +40,17 @@ export default class ArvoEventHandler<TContract extends ArvoContract> implements
40
40
  /**
41
41
  * Provides access to the system error event schema configuration.
42
42
  */
43
- get systemErrorSchema(): {
44
- domain: (string | null)[] | undefined;
45
- type: `sys.${string}.error`;
46
- schema: import("zod").ZodObject<{
47
- errorName: import("zod").ZodString;
48
- errorMessage: import("zod").ZodString;
49
- errorStack: import("zod").ZodNullable<import("zod").ZodString>;
50
- }, "strip", import("zod").ZodTypeAny, {
51
- errorName: string;
52
- errorMessage: string;
53
- errorStack: string | null;
54
- }, {
55
- errorName: string;
56
- errorMessage: string;
57
- errorStack: string | null;
58
- }>;
59
- };
43
+ get systemErrorSchema(): import("arvo-core").ArvoContractRecord<`sys.${string}.error`, import("zod").ZodObject<{
44
+ errorName: import("zod").ZodString;
45
+ errorMessage: import("zod").ZodString;
46
+ errorStack: import("zod").ZodNullable<import("zod").ZodString>;
47
+ }, "strip", import("zod").ZodTypeAny, {
48
+ errorName: string;
49
+ errorMessage: string;
50
+ errorStack: string | null;
51
+ }, {
52
+ errorName: string;
53
+ errorMessage: string;
54
+ errorStack: string | null;
55
+ }>>;
60
56
  }
@@ -72,20 +72,18 @@ var utils_1 = require("../utils");
72
72
  var ArvoEventHandler = /** @class */ (function () {
73
73
  function ArvoEventHandler(param) {
74
74
  var _a;
75
- var _b, _c;
76
- /** Optional domains for routing system error events */
77
- this.systemErrorDomain = undefined;
75
+ var _b, _c, _d, _e;
78
76
  this.contract = param.contract;
79
- this.executionunits = param.executionunits;
77
+ this.executionunits = (_b = param.executionunits) !== null && _b !== void 0 ? _b : 0;
80
78
  this.handler = param.handler;
81
- this.systemErrorDomain = param.systemErrorDomain;
82
- for (var _i = 0, _d = Object.keys(this.contract.versions); _i < _d.length; _i++) {
83
- var contractVersions = _d[_i];
79
+ this.defaultEventEmissionDomains = __assign({ systemError: [ArvoDomain_1.ArvoDomain.ORCHESTRATION_CONTEXT], emits: [ArvoDomain_1.ArvoDomain.ORCHESTRATION_CONTEXT] }, ((_c = param.defaultEventEmissionDomains) !== null && _c !== void 0 ? _c : {}));
80
+ for (var _i = 0, _f = Object.keys(this.contract.versions); _i < _f.length; _i++) {
81
+ var contractVersions = _f[_i];
84
82
  if (!this.handler[contractVersions]) {
85
83
  throw new Error("Contract ".concat(this.contract.uri, " requires handler implementation for version ").concat(contractVersions));
86
84
  }
87
85
  }
88
- this.spanOptions = __assign(__assign({ kind: api_1.SpanKind.CONSUMER }, param.spanOptions), { attributes: __assign(__assign((_a = {}, _a[arvo_core_1.ArvoExecution.ATTR_SPAN_KIND] = arvo_core_1.ArvoExecutionSpanKind.EVENT_HANDLER, _a[arvo_core_1.OpenInference.ATTR_SPAN_KIND] = arvo_core_1.OpenInferenceSpanKind.CHAIN, _a), ((_c = (_b = param.spanOptions) === null || _b === void 0 ? void 0 : _b.attributes) !== null && _c !== void 0 ? _c : {})), { 'arvo.handler.source': this.source, 'arvo.contract.uri': this.contract.uri }) });
86
+ this.spanOptions = __assign(__assign({ kind: api_1.SpanKind.CONSUMER }, param.spanOptions), { attributes: __assign(__assign((_a = {}, _a[arvo_core_1.ArvoExecution.ATTR_SPAN_KIND] = arvo_core_1.ArvoExecutionSpanKind.EVENT_HANDLER, _a[arvo_core_1.OpenInference.ATTR_SPAN_KIND] = arvo_core_1.OpenInferenceSpanKind.CHAIN, _a), ((_e = (_d = param.spanOptions) === null || _d === void 0 ? void 0 : _d.attributes) !== null && _e !== void 0 ? _e : {})), { 'arvo.handler.source': this.source, 'arvo.contract.uri': this.contract.uri }) });
89
87
  }
90
88
  Object.defineProperty(ArvoEventHandler.prototype, "source", {
91
89
  /** The source identifier for events produced by this handler */
@@ -127,14 +125,14 @@ var ArvoEventHandler = /** @class */ (function () {
127
125
  "Handler<".concat(this.contract.uri, ">"), this.spanOptions, opentelemetry !== null && opentelemetry !== void 0 ? opentelemetry : { inheritFrom: 'EVENT' }, event);
128
126
  return [4 /*yield*/, arvo_core_1.ArvoOpenTelemetry.getInstance().startActiveSpan(__assign(__assign({}, otelConfig), { fn: function (span) { return __awaiter(_this, void 0, void 0, function () {
129
127
  var otelSpanHeaders, _i, _a, _b, key, value, parsedDataSchema, handlerContract_1, inputEventValidation, _handleOutput, outputs, result, _c, outputs_1, item, __extensions, handlerResult, domains, _d, _e, _dom, _f, _g, _h, key, value, error_1, errorEvents, _j, _k, _l, errEvtIdx, errEvt, _m, _o, _p, key, value;
130
- var _q, _r, _s, _t, _u, _v;
131
- return __generator(this, function (_w) {
132
- switch (_w.label) {
128
+ var _q, _r, _s, _t, _u;
129
+ return __generator(this, function (_v) {
130
+ switch (_v.label) {
133
131
  case 0:
134
132
  otelSpanHeaders = (0, arvo_core_1.currentOpenTelemetryHeaders)();
135
- _w.label = 1;
133
+ _v.label = 1;
136
134
  case 1:
137
- _w.trys.push([1, 3, 4, 5]);
135
+ _v.trys.push([1, 3, 4, 5]);
138
136
  span.setAttribute('arvo.handler.execution.status', 'normal');
139
137
  span.setAttribute('arvo.handler.execution.type', 'handler');
140
138
  span.setStatus({ code: api_1.SpanStatusCode.OK });
@@ -165,7 +163,7 @@ var ArvoEventHandler = /** @class */ (function () {
165
163
  try {
166
164
  handlerContract_1 = this.contract.version((_q = parsedDataSchema === null || parsedDataSchema === void 0 ? void 0 : parsedDataSchema.version) !== null && _q !== void 0 ? _q : 'latest');
167
165
  }
168
- catch (_x) {
166
+ catch (_w) {
169
167
  throw new errors_1.ConfigViolation("Invalid contract version: ".concat(parsedDataSchema === null || parsedDataSchema === void 0 ? void 0 : parsedDataSchema.version, ". Available versions: ").concat(Object.keys(this.contract.versions).join(', ')));
170
168
  }
171
169
  (0, arvo_core_1.logToSpan)({
@@ -196,7 +194,7 @@ var ArvoEventHandler = /** @class */ (function () {
196
194
  spanHeaders: otelSpanHeaders,
197
195
  })];
198
196
  case 2:
199
- _handleOutput = _w.sent();
197
+ _handleOutput = _v.sent();
200
198
  if (!_handleOutput)
201
199
  return [2 /*return*/, {
202
200
  events: [],
@@ -213,20 +211,22 @@ var ArvoEventHandler = /** @class */ (function () {
213
211
  item = outputs_1[_c];
214
212
  try {
215
213
  __extensions = item.__extensions, handlerResult = __rest(item, ["__extensions"]);
216
- domains = (_s = (_r = handlerResult.domain) === null || _r === void 0 ? void 0 : _r.map(function (item) {
214
+ domains = ((_r = handlerResult.domain) !== null && _r !== void 0 ? _r : this.defaultEventEmissionDomains.emits).map(function (item) {
217
215
  return (0, ArvoDomain_1.resolveEventDomain)({
216
+ parentSubject: null,
217
+ currentSubject: event.subject,
218
218
  domainToResolve: item,
219
219
  handlerSelfContract: handlerContract_1,
220
220
  eventContract: handlerContract_1,
221
221
  triggeringEvent: event,
222
222
  });
223
- })) !== null && _s !== void 0 ? _s : [event.domain];
223
+ });
224
224
  for (_d = 0, _e = Array.from(new Set(domains)); _d < _e.length; _d++) {
225
225
  _dom = _e[_d];
226
226
  result.push((0, arvo_core_1.createArvoEventFactory)(handlerContract_1).emits(__assign(__assign({}, handlerResult), { traceparent: otelSpanHeaders.traceparent || undefined, tracestate: otelSpanHeaders.tracestate || undefined, source: this.source, subject: event.subject,
227
227
  // 'source'
228
228
  // prioritise returned 'to', 'redirectto' and then
229
- to: (0, utils_1.coalesceOrDefault)([handlerResult.to, event.redirectto], event.source), executionunits: (0, utils_1.coalesce)(handlerResult.executionunits, this.executionunits), accesscontrol: (_u = (_t = handlerResult.accesscontrol) !== null && _t !== void 0 ? _t : event.accesscontrol) !== null && _u !== void 0 ? _u : undefined, parentid: event.id, domain: _dom }), __extensions));
229
+ to: (0, utils_1.coalesceOrDefault)([handlerResult.to, event.redirectto], event.source), executionunits: (0, utils_1.coalesce)(handlerResult.executionunits, this.executionunits), accesscontrol: (_t = (_s = handlerResult.accesscontrol) !== null && _s !== void 0 ? _s : event.accesscontrol) !== null && _t !== void 0 ? _t : undefined, parentid: event.id, domain: _dom }), __extensions));
230
230
  for (_f = 0, _g = Object.entries(result[result.length - 1].otelAttributes); _f < _g.length; _f++) {
231
231
  _h = _g[_f], key = _h[0], value = _h[1];
232
232
  span.setAttribute("emittables.".concat(result.length - 1, ".").concat(key), value);
@@ -234,12 +234,12 @@ var ArvoEventHandler = /** @class */ (function () {
234
234
  }
235
235
  }
236
236
  catch (e) {
237
- throw new errors_1.ContractViolation((_v = e === null || e === void 0 ? void 0 : e.message) !== null && _v !== void 0 ? _v : 'Invalid data');
237
+ throw new errors_1.ContractViolation((_u = e === null || e === void 0 ? void 0 : e.message) !== null && _u !== void 0 ? _u : 'Invalid data');
238
238
  }
239
239
  }
240
240
  return [2 /*return*/, (0, orchestrationExecutionWrapper_1.returnEventsWithLogging)({ events: result }, span)];
241
241
  case 3:
242
- error_1 = _w.sent();
242
+ error_1 = _v.sent();
243
243
  span.setAttribute('arvo.handler.execution.status', 'failure');
244
244
  (0, arvo_core_1.exceptionToSpan)(error_1);
245
245
  span.setStatus({
@@ -256,10 +256,9 @@ var ArvoEventHandler = /** @class */ (function () {
256
256
  orchestrationParentSubject: null,
257
257
  initEventId: event.id,
258
258
  selfContract: this.contract.version('any'),
259
- systemErrorDomain: this.systemErrorDomain,
259
+ systemErrorDomain: this.defaultEventEmissionDomains.systemError,
260
260
  executionunits: this.executionunits,
261
261
  source: this.source,
262
- domain: this.domain,
263
262
  handlerType: 'handler',
264
263
  });
265
264
  for (_j = 0, _k = Object.entries(errorEvents); _j < _k.length; _j++) {
@@ -289,7 +288,7 @@ var ArvoEventHandler = /** @class */ (function () {
289
288
  * Provides access to the system error event schema configuration.
290
289
  */
291
290
  get: function () {
292
- return __assign(__assign({}, this.contract.systemError), { domain: this.systemErrorDomain });
291
+ return this.contract.systemError;
293
292
  },
294
293
  enumerable: false,
295
294
  configurable: true
@@ -1,7 +1,7 @@
1
1
  import type { Span } from '@opentelemetry/api';
2
2
  import type { ArvoContract, ArvoEvent, ArvoSemanticVersion, CreateArvoEvent, InferArvoEvent, OpenTelemetryHeaders, VersionedArvoContract } from 'arvo-core';
3
3
  import type { z } from 'zod';
4
- import type { ArvoEventHandlerOtelSpanOptions } from '../types';
4
+ import type { ArvoEventHandlerOtelSpanOptions, NonEmptyArray } from '../types';
5
5
  /**
6
6
  * Represents the input for an ArvoEvent handler function.
7
7
  */
@@ -38,29 +38,18 @@ export type ArvoEventHandlerFunctionOutput<TContract extends VersionedArvoContra
38
38
  /** Optional extensions for the event. */
39
39
  __extensions?: Record<string, string | number | boolean>;
40
40
  /**
41
- * The domain configuration for multi-domain event broadcasting.
41
+ * Specifies which execution contexts should receive this event. Each domain value creates a separate routed event.
42
+ * Defaults to the domain encoded in the triggering event's subject with fallback to ArvoDomain.LOCAL (null) to
43
+ * maintain execution context continuity.
42
44
  *
43
- * When an event is emitted with a `domain` array, Arvo generates a separate ArvoEvent
44
- * for each resolved domain value. This enables parallel routing to multiple contexts
45
- * such as analytics, auditing, human-in-the-loop systems, or external integrations.
46
- *
47
- * **Accepted Values:**
48
- * - A concrete domain string (e.g. `'audit.orders'`)
49
- * - `null` for standard internal routing (no domain)
50
- * - A symbolic value from {@link ArvoDomain}.
51
- *
52
- * **Broadcasting Rules:**
53
- * - Each resolved domain in the array creates a separate ArvoEvent instance
54
- * - Duplicate resolved domains are automatically removed
55
- * - If the field is omitted, Arvo defaults to `[null]`
45
+ * @default [ArvoDomain.FROM_PARENT_SUBJECT]
56
46
  *
57
47
  * **Examples:**
58
- * - `['analytics.orders', 'audit.orders']` → Creates two routed events
59
- * - `[ArvoDomain.FROM_TRIGGERING_EVENT, 'human.review', null]` → Mirrors source domain, routes to review, and standard consumer
60
- * - `[null]` → Emits a single event with no domain routing
61
- * - _Omitted_ → Same as `[null]`
48
+ * - `['human.interaction', 'audit.reporting']` → Creates two routed events
49
+ * - `[ArvoDomain.FROM_TRIGGERING_EVENT, 'human.review']` → Mirrors source domain and routes to review
50
+ * - `[ArvoDomain.LOCAL]` → Stays in current execution context
62
51
  */
63
- domain?: (string | null)[];
52
+ domain?: NonEmptyArray<string | null>;
64
53
  };
65
54
  }[keyof TContract['emits']];
66
55
  /**
@@ -81,7 +70,7 @@ export type ArvoEventHandlerParam<TContract extends ArvoContract> = {
81
70
  * The default execution cost of the function.
82
71
  * This can represent a dollar value or some other number with a rate card.
83
72
  */
84
- executionunits: number;
73
+ executionunits?: number;
85
74
  /**
86
75
  * The functional handler of the event which takes the input, performs an action, and returns the result.
87
76
  * @param params - The input parameters for the handler function.
@@ -93,17 +82,28 @@ export type ArvoEventHandlerParam<TContract extends ArvoContract> = {
93
82
  */
94
83
  spanOptions?: ArvoEventHandlerOtelSpanOptions;
95
84
  /**
96
- * Optional configuration to customize where system error events are emitted.
97
- *
98
- * This overrides the default system error domain fallback of:
99
- * `[event.domain, handler.contract.domain, null]`
100
- *
101
- * Use this to precisely control the set of domains that should receive structured
102
- * `sys.*.error` events when uncaught exceptions occur in the handler.
103
- *
104
- * Symbolic constants from {@link ArvoDomain} are supported.
105
- *
106
- * @default undefined — uses standard fallback broadcast domains
85
+ * Optional default domains for the events emitted
86
+ * by the event handler.
107
87
  */
108
- systemErrorDomain?: (string | null)[];
88
+ defaultEventEmissionDomains?: {
89
+ /**
90
+ * Default domains for system error events emitted by this handler.
91
+ *
92
+ * System errors are routed through these domains when the handler encounters
93
+ * unhandled exceptions or critical failures.
94
+ *
95
+ * @default [ArvoDomain.ORCHESTRATION_CONTEXT]
96
+ */
97
+ systemError?: NonEmptyArray<string | null>;
98
+ /**
99
+ * Default domains for response events emitted by this handler.
100
+ *
101
+ * Response events are routed through these domains when the handler successfully
102
+ * processes an incoming event. Individual handler implementations can override
103
+ * this default on a per-event basis.
104
+ *
105
+ * @default [ArvoDomain.ORCHESTRATION_CONTEXT]
106
+ */
107
+ emits?: NonEmptyArray<string | null>;
108
+ };
109
109
  };