arvo-event-handler 2.3.3 → 3.0.1
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.
- package/dist/AbstractArvoEventHandler/index.d.ts +1 -1
- package/dist/ArvoEventHandler/helpers.d.ts +40 -6
- package/dist/ArvoEventHandler/helpers.js +40 -6
- package/dist/ArvoEventHandler/index.d.ts +78 -49
- package/dist/ArvoEventHandler/index.js +151 -82
- package/dist/ArvoEventHandler/types.d.ts +25 -2
- package/dist/ArvoMachine/createMachine.d.ts +208 -0
- package/dist/ArvoMachine/createMachine.js +283 -0
- package/dist/ArvoMachine/index.d.ts +93 -0
- package/dist/ArvoMachine/index.js +160 -0
- package/dist/ArvoMachine/types.d.ts +194 -0
- package/dist/ArvoMachine/utils.d.ts +40 -0
- package/dist/ArvoMachine/utils.js +70 -0
- package/dist/ArvoOrchestrator/error.d.ts +16 -0
- package/dist/ArvoOrchestrator/error.js +43 -0
- package/dist/ArvoOrchestrator/factory.d.ts +28 -0
- package/dist/ArvoOrchestrator/factory.js +56 -0
- package/dist/ArvoOrchestrator/index.d.ts +69 -0
- package/dist/ArvoOrchestrator/index.js +597 -0
- package/dist/ArvoOrchestrator/types.d.ts +98 -0
- package/dist/ArvoResumable/factory.d.ts +50 -0
- package/dist/ArvoResumable/factory.js +70 -0
- package/dist/ArvoResumable/index.d.ts +141 -0
- package/dist/ArvoResumable/index.js +694 -0
- package/dist/ArvoResumable/types.d.ts +147 -0
- package/dist/ArvoResumable/types.js +2 -0
- package/dist/MachineExecutionEngine/index.d.ts +29 -0
- package/dist/MachineExecutionEngine/index.js +132 -0
- package/dist/MachineExecutionEngine/interface.d.ts +14 -0
- package/dist/MachineExecutionEngine/interface.js +2 -0
- package/dist/MachineExecutionEngine/types.d.ts +14 -0
- package/dist/MachineExecutionEngine/types.js +2 -0
- package/dist/MachineMemory/Simple.d.ts +51 -0
- package/dist/MachineMemory/Simple.js +158 -0
- package/dist/MachineMemory/TelemetredSimple.d.ts +51 -0
- package/dist/MachineMemory/TelemetredSimple.js +230 -0
- package/dist/MachineMemory/interface.d.ts +57 -0
- package/dist/MachineMemory/interface.js +2 -0
- package/dist/MachineMemory/utils.d.ts +1 -0
- package/dist/MachineMemory/utils.js +18 -0
- package/dist/MachineRegistry/index.d.ts +37 -0
- package/dist/MachineRegistry/index.js +87 -0
- package/dist/MachineRegistry/interface.d.ts +21 -0
- package/dist/MachineRegistry/interface.js +2 -0
- package/dist/SyncEventResource/index.d.ts +110 -0
- package/dist/SyncEventResource/index.js +280 -0
- package/dist/SyncEventResource/types.d.ts +2 -0
- package/dist/SyncEventResource/types.js +2 -0
- package/dist/index.d.ts +26 -8
- package/dist/index.js +39 -16
- package/dist/utils/SimpleEventBroker/helper.d.ts +166 -0
- package/dist/utils/SimpleEventBroker/helper.js +276 -0
- package/dist/utils/SimpleEventBroker/index.d.ts +96 -0
- package/dist/utils/SimpleEventBroker/index.js +259 -0
- package/dist/utils/SimpleEventBroker/types.d.ts +6 -0
- package/dist/utils/SimpleEventBroker/types.js +2 -0
- package/dist/utils/SimpleEventBroker/utils.d.ts +1 -0
- package/dist/utils/SimpleEventBroker/utils.js +10 -0
- package/dist/{utils.d.ts → utils/index.d.ts} +3 -36
- package/dist/utils/index.js +91 -0
- package/dist/utils/object/index.d.ts +37 -0
- package/dist/utils/object/index.js +63 -0
- package/package.json +5 -3
- package/dist/ArvoEventRouter/helpers.d.ts +0 -19
- package/dist/ArvoEventRouter/helpers.js +0 -22
- package/dist/ArvoEventRouter/index.d.ts +0 -89
- package/dist/ArvoEventRouter/index.js +0 -268
- package/dist/ArvoEventRouter/types.d.ts +0 -36
- package/dist/ArvoEventRouter/utils.d.ts +0 -30
- package/dist/ArvoEventRouter/utils.js +0 -43
- package/dist/MultiArvoEventHandler/helpers.d.ts +0 -48
- package/dist/MultiArvoEventHandler/helpers.js +0 -56
- package/dist/MultiArvoEventHandler/index.d.ts +0 -68
- package/dist/MultiArvoEventHandler/index.js +0 -205
- package/dist/MultiArvoEventHandler/types.d.ts +0 -64
- package/dist/utils.js +0 -191
- /package/dist/{ArvoEventRouter → ArvoMachine}/types.js +0 -0
- /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
|
-
|
|
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
|
-
*
|
|
6
|
-
* Each handler manages event validation, processing, and telemetry for its contract.
|
|
5
|
+
* Create the instance of `ArvoEventHandler`
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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:
|
|
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
|
-
*
|
|
10
|
-
* Each handler manages event validation, processing, and telemetry for its contract.
|
|
9
|
+
* Create the instance of `ArvoEventHandler`
|
|
11
10
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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:
|
|
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
|
-
*
|
|
24
|
+
* ## Event Processing Lifecycle
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
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,
|
|
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
|
|
96
|
-
* @
|
|
97
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
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
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
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,
|
|
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
|
|
177
|
-
* @
|
|
178
|
-
*
|
|
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
|
|
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,
|
|
196
|
-
var
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
241
|
+
_z.label = 1;
|
|
202
242
|
case 1:
|
|
203
|
-
|
|
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,7 +268,7 @@ var ArvoEventHandler = /** @class */ (function (_super) {
|
|
|
228
268
|
}
|
|
229
269
|
handlerContract = void 0;
|
|
230
270
|
try {
|
|
231
|
-
handlerContract = this.contract.version((
|
|
271
|
+
handlerContract = this.contract.version((_p = parsedDataSchema === null || parsedDataSchema === void 0 ? void 0 : parsedDataSchema.version) !== null && _p !== void 0 ? _p : 'latest');
|
|
232
272
|
}
|
|
233
273
|
catch (error) {
|
|
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(', ')));
|
|
@@ -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 =
|
|
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
|
-
|
|
271
|
-
|
|
315
|
+
result = [];
|
|
316
|
+
for (_c = 0, outputs_1 = outputs; _c < outputs_1.length; _c++) {
|
|
317
|
+
item = outputs_1[_c];
|
|
272
318
|
try {
|
|
273
|
-
|
|
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 =
|
|
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
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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:
|
|
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
|
-
*
|
|
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;
|