arvo-event-handler 2.3.3 → 3.0.2

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 (78) hide show
  1. package/dist/AbstractArvoEventHandler/index.d.ts +1 -1
  2. package/dist/ArvoEventHandler/helpers.d.ts +40 -6
  3. package/dist/ArvoEventHandler/helpers.js +40 -6
  4. package/dist/ArvoEventHandler/index.d.ts +78 -49
  5. package/dist/ArvoEventHandler/index.js +152 -83
  6. package/dist/ArvoEventHandler/types.d.ts +25 -2
  7. package/dist/ArvoMachine/createMachine.d.ts +208 -0
  8. package/dist/ArvoMachine/createMachine.js +283 -0
  9. package/dist/ArvoMachine/index.d.ts +93 -0
  10. package/dist/ArvoMachine/index.js +160 -0
  11. package/dist/ArvoMachine/types.d.ts +194 -0
  12. package/dist/ArvoMachine/utils.d.ts +40 -0
  13. package/dist/ArvoMachine/utils.js +70 -0
  14. package/dist/ArvoOrchestrator/error.d.ts +16 -0
  15. package/dist/ArvoOrchestrator/error.js +43 -0
  16. package/dist/ArvoOrchestrator/factory.d.ts +28 -0
  17. package/dist/ArvoOrchestrator/factory.js +56 -0
  18. package/dist/ArvoOrchestrator/index.d.ts +69 -0
  19. package/dist/ArvoOrchestrator/index.js +597 -0
  20. package/dist/ArvoOrchestrator/types.d.ts +98 -0
  21. package/dist/ArvoResumable/factory.d.ts +50 -0
  22. package/dist/ArvoResumable/factory.js +70 -0
  23. package/dist/ArvoResumable/index.d.ts +141 -0
  24. package/dist/ArvoResumable/index.js +694 -0
  25. package/dist/ArvoResumable/types.d.ts +147 -0
  26. package/dist/ArvoResumable/types.js +2 -0
  27. package/dist/MachineExecutionEngine/index.d.ts +29 -0
  28. package/dist/MachineExecutionEngine/index.js +132 -0
  29. package/dist/MachineExecutionEngine/interface.d.ts +14 -0
  30. package/dist/MachineExecutionEngine/interface.js +2 -0
  31. package/dist/MachineExecutionEngine/types.d.ts +14 -0
  32. package/dist/MachineExecutionEngine/types.js +2 -0
  33. package/dist/MachineMemory/Simple.d.ts +51 -0
  34. package/dist/MachineMemory/Simple.js +158 -0
  35. package/dist/MachineMemory/TelemetredSimple.d.ts +51 -0
  36. package/dist/MachineMemory/TelemetredSimple.js +230 -0
  37. package/dist/MachineMemory/interface.d.ts +57 -0
  38. package/dist/MachineMemory/interface.js +2 -0
  39. package/dist/MachineMemory/utils.d.ts +1 -0
  40. package/dist/MachineMemory/utils.js +18 -0
  41. package/dist/MachineRegistry/index.d.ts +37 -0
  42. package/dist/MachineRegistry/index.js +87 -0
  43. package/dist/MachineRegistry/interface.d.ts +21 -0
  44. package/dist/MachineRegistry/interface.js +2 -0
  45. package/dist/SyncEventResource/index.d.ts +110 -0
  46. package/dist/SyncEventResource/index.js +280 -0
  47. package/dist/SyncEventResource/types.d.ts +2 -0
  48. package/dist/SyncEventResource/types.js +2 -0
  49. package/dist/index.d.ts +26 -8
  50. package/dist/index.js +39 -16
  51. package/dist/utils/SimpleEventBroker/helper.d.ts +166 -0
  52. package/dist/utils/SimpleEventBroker/helper.js +276 -0
  53. package/dist/utils/SimpleEventBroker/index.d.ts +96 -0
  54. package/dist/utils/SimpleEventBroker/index.js +259 -0
  55. package/dist/utils/SimpleEventBroker/types.d.ts +6 -0
  56. package/dist/utils/SimpleEventBroker/types.js +2 -0
  57. package/dist/utils/SimpleEventBroker/utils.d.ts +1 -0
  58. package/dist/utils/SimpleEventBroker/utils.js +10 -0
  59. package/dist/{utils.d.ts → utils/index.d.ts} +3 -36
  60. package/dist/utils/index.js +91 -0
  61. package/dist/utils/object/index.d.ts +37 -0
  62. package/dist/utils/object/index.js +63 -0
  63. package/package.json +5 -3
  64. package/dist/ArvoEventRouter/helpers.d.ts +0 -19
  65. package/dist/ArvoEventRouter/helpers.js +0 -22
  66. package/dist/ArvoEventRouter/index.d.ts +0 -89
  67. package/dist/ArvoEventRouter/index.js +0 -268
  68. package/dist/ArvoEventRouter/types.d.ts +0 -36
  69. package/dist/ArvoEventRouter/utils.d.ts +0 -30
  70. package/dist/ArvoEventRouter/utils.js +0 -43
  71. package/dist/MultiArvoEventHandler/helpers.d.ts +0 -48
  72. package/dist/MultiArvoEventHandler/helpers.js +0 -56
  73. package/dist/MultiArvoEventHandler/index.d.ts +0 -68
  74. package/dist/MultiArvoEventHandler/index.js +0 -205
  75. package/dist/MultiArvoEventHandler/types.d.ts +0 -64
  76. package/dist/utils.js +0 -191
  77. /package/dist/{ArvoEventRouter → ArvoMachine}/types.js +0 -0
  78. /package/dist/{MultiArvoEventHandler → ArvoOrchestrator}/types.js +0 -0
@@ -57,7 +57,7 @@ export default abstract class AbstractArvoEventHandler {
57
57
  */
58
58
  abstract execute(event: ArvoEvent, opentelemetry: ArvoEventHandlerOpenTelemetryOptions): Promise<{
59
59
  events: ArvoEvent[];
60
- [key: string]: unknown;
60
+ metadata?: Record<string, any>;
61
61
  }>;
62
62
  /**
63
63
  * Provides the schema for system error events.
@@ -2,21 +2,55 @@ import type { ArvoContract } from 'arvo-core';
2
2
  import ArvoEventHandler from '.';
3
3
  import type { IArvoEventHandler } from './types';
4
4
  /**
5
- * Creates an ArvoEventHandler for processing events defined by a specific contract.
6
- * Each handler manages event validation, processing, and telemetry for its contract.
5
+ * Create the instance of `ArvoEventHandler`
7
6
  *
8
- * @param param Configuration including contract, execution metrics and version handlers
9
- * @returns Configured ArvoEventHandler instance for the specified contract
7
+ * > **Caution:** Don't use domained contracts unless it is fully intentional. Using domained
8
+ * contracts causes implicit domain assignment which can be hard to track and confusing. For 99%
9
+ * of the cases you dont need domained contracts
10
+ *
11
+ * See {@link ArvoEventHandler}
10
12
  *
11
13
  * @example
14
+ * ```typescript
12
15
  * const handler = createArvoEventHandler({
13
16
  * contract: userContract,
14
- * executionunits: 10,
17
+ * executionunits: 1,
15
18
  * handler: {
16
- * '1.0.0': async ({ event }) => {
19
+ * '1.0.0': async ({ event, domain, span }) => {
20
+ * // Access domain context
21
+ * if (event.domain === 'priority.high') {
22
+ * // Handle high-priority processing
23
+ * }
24
+ *
25
+ * if (domain.event !== domain.self) {
26
+ * logToSpan({
27
+ * level: 'WARN',
28
+ * message: 'Domain mismatch detected'
29
+ * }, span)
30
+ * }
31
+ *
32
+ *
17
33
  * // Process event according to contract v1.0.0
34
+ * const result = await processUser(event.data);
35
+ *
36
+ * // Return structured response
37
+ * return {
38
+ * type: 'evt.user.created',
39
+ * data: result,
40
+ * // Optional: override default routing
41
+ * to: 'com.notification.service',
42
+ * // Creates 2 events:
43
+ * // - One for 'analytics.realtime' domain (specialized processing)
44
+ * // - One with no domain (standard processing pipeline)
45
+ * domain: ['analytics.realtime', null]
46
+ * };
47
+ * },
48
+ * '2.0.0': async ({ event, contract, span }) => {
49
+ * // Process event according to contract v2.0.0
50
+ * // Handler must be implemented for all contract versions
18
51
  * }
19
52
  * }
20
53
  * });
54
+ * ```
21
55
  */
22
56
  export declare const createArvoEventHandler: <TContract extends ArvoContract>(param: IArvoEventHandler<TContract>) => ArvoEventHandler<TContract>;
@@ -6,22 +6,56 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createArvoEventHandler = void 0;
7
7
  var _1 = __importDefault(require("."));
8
8
  /**
9
- * Creates an ArvoEventHandler for processing events defined by a specific contract.
10
- * Each handler manages event validation, processing, and telemetry for its contract.
9
+ * Create the instance of `ArvoEventHandler`
11
10
  *
12
- * @param param Configuration including contract, execution metrics and version handlers
13
- * @returns Configured ArvoEventHandler instance for the specified contract
11
+ * > **Caution:** Don't use domained contracts unless it is fully intentional. Using domained
12
+ * contracts causes implicit domain assignment which can be hard to track and confusing. For 99%
13
+ * of the cases you dont need domained contracts
14
+ *
15
+ * See {@link ArvoEventHandler}
14
16
  *
15
17
  * @example
18
+ * ```typescript
16
19
  * const handler = createArvoEventHandler({
17
20
  * contract: userContract,
18
- * executionunits: 10,
21
+ * executionunits: 1,
19
22
  * handler: {
20
- * '1.0.0': async ({ event }) => {
23
+ * '1.0.0': async ({ event, domain, span }) => {
24
+ * // Access domain context
25
+ * if (event.domain === 'priority.high') {
26
+ * // Handle high-priority processing
27
+ * }
28
+ *
29
+ * if (domain.event !== domain.self) {
30
+ * logToSpan({
31
+ * level: 'WARN',
32
+ * message: 'Domain mismatch detected'
33
+ * }, span)
34
+ * }
35
+ *
36
+ *
21
37
  * // Process event according to contract v1.0.0
38
+ * const result = await processUser(event.data);
39
+ *
40
+ * // Return structured response
41
+ * return {
42
+ * type: 'evt.user.created',
43
+ * data: result,
44
+ * // Optional: override default routing
45
+ * to: 'com.notification.service',
46
+ * // Creates 2 events:
47
+ * // - One for 'analytics.realtime' domain (specialized processing)
48
+ * // - One with no domain (standard processing pipeline)
49
+ * domain: ['analytics.realtime', null]
50
+ * };
51
+ * },
52
+ * '2.0.0': async ({ event, contract, span }) => {
53
+ * // Process event according to contract v2.0.0
54
+ * // Handler must be implemented for all contract versions
22
55
  * }
23
56
  * }
24
57
  * });
58
+ * ```
25
59
  */
26
60
  var createArvoEventHandler = function (param) { return new _1.default(param); };
27
61
  exports.createArvoEventHandler = createArvoEventHandler;
@@ -21,29 +21,59 @@ import type { ArvoEventHandlerFunction, IArvoEventHandler } from './types';
21
21
  * This means it not only verifies data formats but also applies default values where needed and
22
22
  * ensures all conditions are met before and after processing.
23
23
  *
24
- * Error handling in the handler divides issues into two categories:
24
+ * ## Event Processing Lifecycle
25
25
  *
26
- * - `Violations` are serious contract breaches that indicate fundamental problems with how services
27
- * are communicating. These errors bubble up to the calling code, allowing developers to handle
28
- * these critical issues explicitly.
26
+ * 1. **Type Validation**: Ensures the incoming event type matches the handler's contract
27
+ * 2. **Contract Resolution**: Extracts version from dataschema and resolves appropriate contract version
28
+ * 3. **Schema Validation**: Validates event data against the contract's accepts schema
29
+ * 4. **Handler Execution**: Invokes the version-specific handler implementation
30
+ * 5. **Response Processing**: Validates and structures handler output into events
31
+ * 6. **Domain Broadcasting**: Creates multiple events for multi-domain distribution if specified
32
+ * 7. **Routing Configuration**: Applies routing logic based on handler output and event context
33
+ * 8. **Telemetry Integration**: Records processing metrics and tracing information
29
34
  *
30
- * - `System Error Events` cover normal runtime errors that occur during event processing. These are
31
- * typically workflow-related issues that need to be reported back to the event's source but don't
32
- * indicate a broken contract.
35
+ * ## Error Handling Strategy
33
36
  *
34
- * * @example
35
- * const handler = createArvoEventHandler({
36
- * contract: userContract,
37
- * executionunits: 1,
38
- * handler: {
39
- * '1.0.0': async ({ event }) => {
40
- * // Process event according to contract v1.0.0
41
- * },
42
- * '2.0.0': async ({ event }) => {
43
- * // Process event according to contract v2.0.0
44
- * }
45
- * }
46
- * });
37
+ * The handler divides issues into two distinct categories:
38
+ *
39
+ * - **Violations** are serious contract breaches that indicate fundamental problems with how services
40
+ * are communicating. These errors bubble up to the calling code, allowing developers to handle
41
+ * these critical issues explicitly. Violations include contract mismatches, schema validation
42
+ * failures, and configuration errors.
43
+ *
44
+ * - **System Error Events** cover normal runtime errors that occur during event processing. These are
45
+ * typically workflow-related issues that need to be reported back to the event's source but don't
46
+ * indicate a broken contract. System errors are converted to structured error events and returned
47
+ * in the response. **Multi-domain error broadcasting** ensures error events reach all relevant
48
+ * processing contexts (source event domain, handler contract domain, and null domain).
49
+ *
50
+ * ## Multi-Domain Event Broadcasting
51
+ *
52
+ * The handler supports sophisticated multi-domain event distribution through array-based domain specification:
53
+ *
54
+ * ### Domain Assignment Rules:
55
+ * 1. **Array Processing**: Each element in the `domain` array creates a separate ArvoEvent
56
+ * 2. **Undefined Resolution**: `undefined` elements resolve to: `event.domain ?? handler.contract.domain ?? null`
57
+ * 3. **Automatic Deduplication**: Duplicate domains are removed to prevent redundant events
58
+ * 4. **Default Behavior**: Omitted/undefined `domain` field defaults to `[null]` (single event, no domain)
59
+ *
60
+ * ### Domain Patterns:
61
+ * - `domain: ['domain1', 'domain2']` → Creates 2 events: one for each domain
62
+ * - `domain: ['analytics', undefined, null]` → Creates up to 3 events:
63
+ * - Event with `domain: 'analytics'`
64
+ * - Event with `domain: event.domain ?? handler.contract.domain ?? null`
65
+ * - Event with `domain: null`
66
+ * - `domain: [null]` → Single event with explicit no-domain routing
67
+ * - `domain: undefined` (or omitted) → Single event with `domain: null`
68
+ *
69
+ * ### Error Broadcasting:
70
+ * System errors are automatically broadcast to all relevant processing contexts:
71
+ * - Source event domain (`event.domain`)
72
+ * - Handler contract domain (`handler.contract.domain`)
73
+ * - No-domain context (`null`)
74
+ *
75
+ * Duplicates are automatically removed, so if `event.domain === handler.contract.domain`,
76
+ * only two error events are created instead of three.
47
77
  */
48
78
  export default class ArvoEventHandler<TContract extends ArvoContract> extends AbstractArvoEventHandler {
49
79
  /** Contract instance that defines the event schema and validation rules */
@@ -56,6 +86,12 @@ export default class ArvoEventHandler<TContract extends ArvoContract> extends Ab
56
86
  readonly handler: ArvoEventHandlerFunction<TContract>;
57
87
  /** The source identifier for events produced by this handler */
58
88
  get source(): TContract['type'];
89
+ /**
90
+ * The contract-defined domain for this handler, used as the default domain for emitted events.
91
+ * Can be overridden by individual handler implementations for cross-domain workflows.
92
+ * Returns null if no domain is specified, indicating standard processing context.
93
+ */
94
+ get domain(): string | null;
59
95
  /**
60
96
  * Initializes a new ArvoEventHandler instance with the specified contract and configuration.
61
97
  * Validates handler implementations against contract versions during initialization.
@@ -69,46 +105,39 @@ export default class ArvoEventHandler<TContract extends ArvoContract> extends Ab
69
105
  constructor(param: IArvoEventHandler<TContract>);
70
106
  /**
71
107
  * Processes an incoming event according to the handler's contract specifications. This method
72
- * handles the complete lifecycle of event processing including validation, execution, and error
73
- * handling, while maintaining detailed telemetry through OpenTelemetry.
74
- *
75
- * The execution follows a careful sequence to ensure reliability:
76
- * First, it validates that the event matches the handler's contract type. Then it extracts
77
- * and validates the event's schema version, defaulting to the latest version if none is specified.
78
- * After validation passes, it executes the version-specific handler function and processes its
79
- * output into new events.
80
- *
81
- * The method handles routing through three distinct paths:
82
- * - For successful execution, events are routed based on handler output or configuration.
83
- * - The 'to' field in the handler's result (if specified)
84
- * - The 'redirectto' field from the source event (if present)
85
- * - Falls back to the source event's 'source' field
86
- * - For violations (mismatched types, invalid data), errors bubble up to the caller
87
- * - For runtime errors, system error events are created and sent back to the source
88
- *
89
- * Throughout execution, comprehensive telemetry is maintained through OpenTelemetry spans,
90
- * tracking the complete event journey including validation steps, processing time, and any
91
- * errors that occur. This enables detailed monitoring and debugging of the event flow.
108
+ * handles the complete lifecycle of event processing including validation, execution, error
109
+ * handling, and multi-domain event broadcasting, while maintaining detailed telemetry through OpenTelemetry.
92
110
  *
93
111
  * @param event - The incoming event to process
94
- * @param opentelemetry - Configuration for OpenTelemetry context inheritance
95
- * @returns Promise resolving to an array of output events or error events
96
- * @throws `ContractViolation` when input or output event data violates the contract
97
- * @throws `ConfigViolation` when event type doesn't match contract type or the
112
+ * @param opentelemetry - Configuration for OpenTelemetry context inheritance, defaults to inheriting from the event
113
+ * @returns Promise resolving to a structured result containing an array of output events
114
+ * @returns Structured response containing:
115
+ * - `events`: Array of events to be emitted (may contain multiple events per handler output due to domain broadcasting)
116
+ *
117
+ * @throws {ContractViolation} when input or output event data violates the contract schema,
118
+ * or when event emission fails due to invalid data
119
+ * @throws {ConfigViolation} when event type doesn't match contract type, when the
98
120
  * contract version expected by the event does not exist
99
- * in handler configuration
100
- * @throws `ExecutionViolation` for explicitly handled runtime errors
121
+ * in handler configuration, or when contract URI mismatch occurs
122
+ * @throws {ExecutionViolation} for explicitly handled runtime errors that should bubble up
101
123
  */
102
124
  execute(event: ArvoEvent, opentelemetry?: ArvoEventHandlerOpenTelemetryOptions): Promise<{
103
125
  events: ArvoEvent[];
104
126
  }>;
105
127
  /**
106
128
  * Provides access to the system error event schema configuration.
129
+ *
107
130
  * The schema defines the structure of error events emitted during execution failures.
131
+ * These events are automatically generated when runtime errors occur and follow a
132
+ * standardized format for consistent error handling across the system.
133
+ *
134
+ * Error events follow the naming convention: `sys.<contract-type>.error`
135
+ *
136
+ * @example
137
+ * For a contract handling 'com.user.create' events, system error events
138
+ * will have the type 'sys.com.user.create.error'
108
139
  *
109
- * Error events follow the naming convention: sys.<contract-type>.error
110
- * For example, a contract handling 'user.created' events will emit error events
111
- * with the type 'sys.user.created.error'.
140
+ * @returns The error event schema containing type and validation rules
112
141
  */
113
142
  get systemErrorSchema(): import("arvo-core").ArvoContractRecord<`sys.${string}.error`, import("zod").ZodObject<{
114
143
  errorName: import("zod").ZodString;
@@ -61,6 +61,17 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
61
61
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
62
62
  }
63
63
  };
64
+ var __rest = (this && this.__rest) || function (s, e) {
65
+ var t = {};
66
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
67
+ t[p] = s[p];
68
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
69
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
70
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
71
+ t[p[i]] = s[p[i]];
72
+ }
73
+ return t;
74
+ };
64
75
  var __importDefault = (this && this.__importDefault) || function (mod) {
65
76
  return (mod && mod.__esModule) ? mod : { "default": mod };
66
77
  };
@@ -88,29 +99,59 @@ var utils_1 = require("../utils");
88
99
  * This means it not only verifies data formats but also applies default values where needed and
89
100
  * ensures all conditions are met before and after processing.
90
101
  *
91
- * Error handling in the handler divides issues into two categories:
102
+ * ## Event Processing Lifecycle
103
+ *
104
+ * 1. **Type Validation**: Ensures the incoming event type matches the handler's contract
105
+ * 2. **Contract Resolution**: Extracts version from dataschema and resolves appropriate contract version
106
+ * 3. **Schema Validation**: Validates event data against the contract's accepts schema
107
+ * 4. **Handler Execution**: Invokes the version-specific handler implementation
108
+ * 5. **Response Processing**: Validates and structures handler output into events
109
+ * 6. **Domain Broadcasting**: Creates multiple events for multi-domain distribution if specified
110
+ * 7. **Routing Configuration**: Applies routing logic based on handler output and event context
111
+ * 8. **Telemetry Integration**: Records processing metrics and tracing information
112
+ *
113
+ * ## Error Handling Strategy
114
+ *
115
+ * The handler divides issues into two distinct categories:
116
+ *
117
+ * - **Violations** are serious contract breaches that indicate fundamental problems with how services
118
+ * are communicating. These errors bubble up to the calling code, allowing developers to handle
119
+ * these critical issues explicitly. Violations include contract mismatches, schema validation
120
+ * failures, and configuration errors.
121
+ *
122
+ * - **System Error Events** cover normal runtime errors that occur during event processing. These are
123
+ * typically workflow-related issues that need to be reported back to the event's source but don't
124
+ * indicate a broken contract. System errors are converted to structured error events and returned
125
+ * in the response. **Multi-domain error broadcasting** ensures error events reach all relevant
126
+ * processing contexts (source event domain, handler contract domain, and null domain).
127
+ *
128
+ * ## Multi-Domain Event Broadcasting
92
129
  *
93
- * - `Violations` are serious contract breaches that indicate fundamental problems with how services
94
- * are communicating. These errors bubble up to the calling code, allowing developers to handle
95
- * these critical issues explicitly.
130
+ * The handler supports sophisticated multi-domain event distribution through array-based domain specification:
96
131
  *
97
- * - `System Error Events` cover normal runtime errors that occur during event processing. These are
98
- * typically workflow-related issues that need to be reported back to the event's source but don't
99
- * indicate a broken contract.
132
+ * ### Domain Assignment Rules:
133
+ * 1. **Array Processing**: Each element in the `domain` array creates a separate ArvoEvent
134
+ * 2. **Undefined Resolution**: `undefined` elements resolve to: `event.domain ?? handler.contract.domain ?? null`
135
+ * 3. **Automatic Deduplication**: Duplicate domains are removed to prevent redundant events
136
+ * 4. **Default Behavior**: Omitted/undefined `domain` field defaults to `[null]` (single event, no domain)
100
137
  *
101
- * * @example
102
- * const handler = createArvoEventHandler({
103
- * contract: userContract,
104
- * executionunits: 1,
105
- * handler: {
106
- * '1.0.0': async ({ event }) => {
107
- * // Process event according to contract v1.0.0
108
- * },
109
- * '2.0.0': async ({ event }) => {
110
- * // Process event according to contract v2.0.0
111
- * }
112
- * }
113
- * });
138
+ * ### Domain Patterns:
139
+ * - `domain: ['domain1', 'domain2']` → Creates 2 events: one for each domain
140
+ * - `domain: ['analytics', undefined, null]` → Creates up to 3 events:
141
+ * - Event with `domain: 'analytics'`
142
+ * - Event with `domain: event.domain ?? handler.contract.domain ?? null`
143
+ * - Event with `domain: null`
144
+ * - `domain: [null]` → Single event with explicit no-domain routing
145
+ * - `domain: undefined` (or omitted) → Single event with `domain: null`
146
+ *
147
+ * ### Error Broadcasting:
148
+ * System errors are automatically broadcast to all relevant processing contexts:
149
+ * - Source event domain (`event.domain`)
150
+ * - Handler contract domain (`handler.contract.domain`)
151
+ * - No-domain context (`null`)
152
+ *
153
+ * Duplicates are automatically removed, so if `event.domain === handler.contract.domain`,
154
+ * only two error events are created instead of three.
114
155
  */
115
156
  var ArvoEventHandler = /** @class */ (function (_super) {
116
157
  __extends(ArvoEventHandler, _super);
@@ -148,37 +189,35 @@ var ArvoEventHandler = /** @class */ (function (_super) {
148
189
  enumerable: false,
149
190
  configurable: true
150
191
  });
192
+ Object.defineProperty(ArvoEventHandler.prototype, "domain", {
193
+ /**
194
+ * The contract-defined domain for this handler, used as the default domain for emitted events.
195
+ * Can be overridden by individual handler implementations for cross-domain workflows.
196
+ * Returns null if no domain is specified, indicating standard processing context.
197
+ */
198
+ get: function () {
199
+ return this.contract.domain;
200
+ },
201
+ enumerable: false,
202
+ configurable: true
203
+ });
151
204
  /**
152
205
  * Processes an incoming event according to the handler's contract specifications. This method
153
- * handles the complete lifecycle of event processing including validation, execution, and error
154
- * handling, while maintaining detailed telemetry through OpenTelemetry.
155
- *
156
- * The execution follows a careful sequence to ensure reliability:
157
- * First, it validates that the event matches the handler's contract type. Then it extracts
158
- * and validates the event's schema version, defaulting to the latest version if none is specified.
159
- * After validation passes, it executes the version-specific handler function and processes its
160
- * output into new events.
161
- *
162
- * The method handles routing through three distinct paths:
163
- * - For successful execution, events are routed based on handler output or configuration.
164
- * - The 'to' field in the handler's result (if specified)
165
- * - The 'redirectto' field from the source event (if present)
166
- * - Falls back to the source event's 'source' field
167
- * - For violations (mismatched types, invalid data), errors bubble up to the caller
168
- * - For runtime errors, system error events are created and sent back to the source
169
- *
170
- * Throughout execution, comprehensive telemetry is maintained through OpenTelemetry spans,
171
- * tracking the complete event journey including validation steps, processing time, and any
172
- * errors that occur. This enables detailed monitoring and debugging of the event flow.
206
+ * handles the complete lifecycle of event processing including validation, execution, error
207
+ * handling, and multi-domain event broadcasting, while maintaining detailed telemetry through OpenTelemetry.
173
208
  *
174
209
  * @param event - The incoming event to process
175
- * @param opentelemetry - Configuration for OpenTelemetry context inheritance
176
- * @returns Promise resolving to an array of output events or error events
177
- * @throws `ContractViolation` when input or output event data violates the contract
178
- * @throws `ConfigViolation` when event type doesn't match contract type or the
210
+ * @param opentelemetry - Configuration for OpenTelemetry context inheritance, defaults to inheriting from the event
211
+ * @returns Promise resolving to a structured result containing an array of output events
212
+ * @returns Structured response containing:
213
+ * - `events`: Array of events to be emitted (may contain multiple events per handler output due to domain broadcasting)
214
+ *
215
+ * @throws {ContractViolation} when input or output event data violates the contract schema,
216
+ * or when event emission fails due to invalid data
217
+ * @throws {ConfigViolation} when event type doesn't match contract type, when the
179
218
  * contract version expected by the event does not exist
180
- * in handler configuration
181
- * @throws `ExecutionViolation` for explicitly handled runtime errors
219
+ * in handler configuration, or when contract URI mismatch occurs
220
+ * @throws {ExecutionViolation} for explicitly handled runtime errors that should bubble up
182
221
  */
183
222
  ArvoEventHandler.prototype.execute = function (event_1) {
184
223
  return __awaiter(this, arguments, void 0, function (event, opentelemetry) {
@@ -192,15 +231,16 @@ var ArvoEventHandler = /** @class */ (function (_super) {
192
231
  case 0:
193
232
  otelConfig = (0, utils_1.createEventHandlerTelemetryConfig)("ArvoEventHandler<".concat(this.contract.uri, ">"), this.spanOptions, opentelemetry, event);
194
233
  return [4 /*yield*/, arvo_core_1.ArvoOpenTelemetry.getInstance().startActiveSpan(__assign(__assign({}, otelConfig), { fn: function (span) { return __awaiter(_this, void 0, void 0, function () {
195
- var otelSpanHeaders, _i, _a, _b, key, value, parsedDataSchema, handlerContract, inputEventValidation, _handleOutput, outputs, eventFactory_1, result, error_1, eventFactory, result, _c, _d, _e, key, value;
196
- var _f, _g, _h, _j, _k;
197
- return __generator(this, function (_l) {
198
- switch (_l.label) {
234
+ var otelSpanHeaders, _i, _a, _b, key, value, parsedDataSchema, handlerContract, inputEventValidation, _handleOutput, outputs, result, _c, outputs_1, item, __extensions, handlerResult, domains, _d, _e, _dom, _f, _g, _h, key, value, error_1, result, _j, _k, _dom, _l, _m, _o, key, value;
235
+ var _this = this;
236
+ var _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
237
+ return __generator(this, function (_z) {
238
+ switch (_z.label) {
199
239
  case 0:
200
240
  otelSpanHeaders = (0, arvo_core_1.currentOpenTelemetryHeaders)();
201
- _l.label = 1;
241
+ _z.label = 1;
202
242
  case 1:
203
- _l.trys.push([1, 3, 4, 5]);
243
+ _z.trys.push([1, 3, 4, 5]);
204
244
  span.setStatus({ code: api_1.SpanStatusCode.OK });
205
245
  for (_i = 0, _a = Object.entries(event.otelAttributes); _i < _a.length; _i++) {
206
246
  _b = _a[_i], key = _b[0], value = _b[1];
@@ -228,9 +268,9 @@ var ArvoEventHandler = /** @class */ (function (_super) {
228
268
  }
229
269
  handlerContract = void 0;
230
270
  try {
231
- handlerContract = this.contract.version((_f = parsedDataSchema === null || parsedDataSchema === void 0 ? void 0 : parsedDataSchema.version) !== null && _f !== void 0 ? _f : 'latest');
271
+ handlerContract = this.contract.version((_p = parsedDataSchema === null || parsedDataSchema === void 0 ? void 0 : parsedDataSchema.version) !== null && _p !== void 0 ? _p : 'latest');
232
272
  }
233
- catch (error) {
273
+ catch (_0) {
234
274
  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(', ')));
235
275
  }
236
276
  (0, arvo_core_1.logToSpan)({
@@ -250,12 +290,17 @@ var ArvoEventHandler = /** @class */ (function (_super) {
250
290
  message: "Executing handler for event type '".concat(event.type, "'"),
251
291
  });
252
292
  return [4 /*yield*/, this.handler[handlerContract.version]({
253
- event: event,
293
+ event: event.toJSON(),
254
294
  source: this.source,
295
+ contract: handlerContract,
296
+ domain: {
297
+ self: this.domain,
298
+ event: event.domain,
299
+ },
255
300
  span: span,
256
301
  })];
257
302
  case 2:
258
- _handleOutput = _l.sent();
303
+ _handleOutput = _z.sent();
259
304
  if (!_handleOutput)
260
305
  return [2 /*return*/, {
261
306
  events: [],
@@ -267,15 +312,28 @@ var ArvoEventHandler = /** @class */ (function (_super) {
267
312
  else {
268
313
  outputs = [_handleOutput];
269
314
  }
270
- eventFactory_1 = (0, arvo_core_1.createArvoEventFactory)(handlerContract);
271
- result = (0, utils_1.eventHandlerOutputEventCreator)(outputs, otelSpanHeaders, this.source, event, this.executionunits, function (param, extensions) {
315
+ result = [];
316
+ for (_c = 0, outputs_1 = outputs; _c < outputs_1.length; _c++) {
317
+ item = outputs_1[_c];
272
318
  try {
273
- return eventFactory_1.emits(param, extensions);
319
+ __extensions = item.__extensions, handlerResult = __rest(item, ["__extensions"]);
320
+ domains = (_r = (_q = handlerResult.domain) === null || _q === void 0 ? void 0 : _q.map(function (item) { var _a, _b; return item === undefined ? ((_b = (_a = event.domain) !== null && _a !== void 0 ? _a : _this.domain) !== null && _b !== void 0 ? _b : null) : item; })) !== null && _r !== void 0 ? _r : [null];
321
+ for (_d = 0, _e = Array.from(new Set(domains)); _d < _e.length; _d++) {
322
+ _dom = _e[_d];
323
+ result.push((0, arvo_core_1.createArvoEventFactory)(handlerContract).emits(__assign(__assign({}, handlerResult), { traceparent: otelSpanHeaders.traceparent || undefined, tracestate: otelSpanHeaders.tracestate || undefined, source: this.source, subject: event.subject,
324
+ // 'source'
325
+ // prioritise returned 'to', 'redirectto' and then
326
+ 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));
327
+ for (_f = 0, _g = Object.entries(result[result.length - 1].otelAttributes); _f < _g.length; _f++) {
328
+ _h = _g[_f], key = _h[0], value = _h[1];
329
+ span.setAttribute("to_emit.".concat(result.length - 1, ".").concat(key), value);
330
+ }
331
+ }
274
332
  }
275
333
  catch (e) {
276
- throw new errors_1.ContractViolation(e.message);
334
+ throw new errors_1.ContractViolation((_u = e === null || e === void 0 ? void 0 : e.message) !== null && _u !== void 0 ? _u : 'Invalid data');
277
335
  }
278
- });
336
+ }
279
337
  (0, arvo_core_1.logToSpan)({
280
338
  level: 'INFO',
281
339
  message: "Event processing completed successfully. Generated ".concat(result.length, " event(s)"),
@@ -288,7 +346,7 @@ var ArvoEventHandler = /** @class */ (function (_super) {
288
346
  events: result,
289
347
  }];
290
348
  case 3:
291
- error_1 = _l.sent();
349
+ error_1 = _z.sent();
292
350
  (0, arvo_core_1.exceptionToSpan)(error_1);
293
351
  span.setStatus({
294
352
  code: api_1.SpanStatusCode.ERROR,
@@ -297,26 +355,30 @@ var ArvoEventHandler = /** @class */ (function (_super) {
297
355
  if (error_1.name.includes('ViolationError')) {
298
356
  throw error_1;
299
357
  }
300
- eventFactory = (0, arvo_core_1.createArvoEventFactory)(this.contract.version('latest'));
301
- result = eventFactory.systemError({
302
- source: this.source,
303
- subject: event.subject,
304
- // The system error must always got back to
305
- // the source
306
- to: event.source,
307
- error: error_1,
308
- executionunits: this.executionunits,
309
- traceparent: (_g = otelSpanHeaders.traceparent) !== null && _g !== void 0 ? _g : undefined,
310
- tracestate: (_h = otelSpanHeaders.tracestate) !== null && _h !== void 0 ? _h : undefined,
311
- accesscontrol: (_j = event.accesscontrol) !== null && _j !== void 0 ? _j : undefined,
312
- parentid: (_k = event.id) !== null && _k !== void 0 ? _k : undefined,
313
- }, {});
314
- for (_c = 0, _d = Object.entries(result.otelAttributes); _c < _d.length; _c++) {
315
- _e = _d[_c], key = _e[0], value = _e[1];
316
- span.setAttribute("to_emit.0.".concat(key), value);
358
+ result = [];
359
+ for (_j = 0, _k = Array.from(new Set([event.domain, this.domain, null])); _j < _k.length; _j++) {
360
+ _dom = _k[_j];
361
+ result.push((0, arvo_core_1.createArvoEventFactory)(this.contract.version('latest')).systemError({
362
+ source: this.source,
363
+ subject: event.subject,
364
+ // The system error must always got back to
365
+ // the source
366
+ to: event.source,
367
+ error: error_1,
368
+ executionunits: this.executionunits,
369
+ traceparent: (_v = otelSpanHeaders.traceparent) !== null && _v !== void 0 ? _v : undefined,
370
+ tracestate: (_w = otelSpanHeaders.tracestate) !== null && _w !== void 0 ? _w : undefined,
371
+ accesscontrol: (_x = event.accesscontrol) !== null && _x !== void 0 ? _x : undefined,
372
+ parentid: (_y = event.id) !== null && _y !== void 0 ? _y : undefined,
373
+ domain: _dom,
374
+ }));
375
+ for (_l = 0, _m = Object.entries(result[result.length - 1].otelAttributes); _l < _m.length; _l++) {
376
+ _o = _m[_l], key = _o[0], value = _o[1];
377
+ span.setAttribute("to_emit.".concat(result.length - 1, ".").concat(key), value);
378
+ }
317
379
  }
318
380
  return [2 /*return*/, {
319
- events: [result],
381
+ events: result,
320
382
  }];
321
383
  case 4:
322
384
  span.end();
@@ -333,11 +395,18 @@ var ArvoEventHandler = /** @class */ (function (_super) {
333
395
  Object.defineProperty(ArvoEventHandler.prototype, "systemErrorSchema", {
334
396
  /**
335
397
  * Provides access to the system error event schema configuration.
398
+ *
336
399
  * The schema defines the structure of error events emitted during execution failures.
400
+ * These events are automatically generated when runtime errors occur and follow a
401
+ * standardized format for consistent error handling across the system.
402
+ *
403
+ * Error events follow the naming convention: `sys.<contract-type>.error`
404
+ *
405
+ * @example
406
+ * For a contract handling 'com.user.create' events, system error events
407
+ * will have the type 'sys.com.user.create.error'
337
408
  *
338
- * Error events follow the naming convention: sys.<contract-type>.error
339
- * For example, a contract handling 'user.created' events will emit error events
340
- * with the type 'sys.user.created.error'.
409
+ * @returns The error event schema containing type and validation rules
341
410
  */
342
411
  get: function () {
343
412
  return this.contract.systemError;