arvo-event-handler 0.0.4 → 0.0.5

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/CHANGELOG.md CHANGED
@@ -7,3 +7,7 @@
7
7
 
8
8
  - Finalised Event Handler implementation
9
9
 
10
+ ## [0.0.5] - 2024-09-10
11
+
12
+ - Updated routing
13
+
@@ -44,17 +44,46 @@ export default class ArvoEventHandler<TContract extends ArvoContract> {
44
44
  * Executes the event handler for a given event.
45
45
  *
46
46
  * @param event - The event to handle.
47
- * @returns A promise that resolves to the resulting ArvoEvents.
47
+ * @returns A promise that resolves to an array of resulting ArvoEvents.
48
48
  *
49
49
  * @remarks
50
50
  * This method performs the following steps:
51
51
  * 1. Creates an OpenTelemetry span for the execution.
52
52
  * 2. Validates the input event against the contract.
53
53
  * 3. Executes the handler function.
54
- * 4. Creates and returns the result event.
54
+ * 4. Creates and returns the result event(s).
55
55
  * 5. Handles any errors and creates an error event if necessary.
56
56
  *
57
57
  * All telemetry data is properly set and propagated throughout the execution.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const contract = createArvoContract({ ... })
62
+ * const handler = createArvoEventHandler({
63
+ * contract: contract,
64
+ * ...
65
+ * });
66
+ * const inputEvent: ArvoEvent<...> = createArvoEvent({ ... });
67
+ * const resultEvents = await handler.execute(inputEvent);
68
+ * ```
69
+ *
70
+ * @throws All error throw during the execution are returned as a system error event
71
+ *
72
+ * **Routing**
73
+ * The routing of the resulting events is determined as follows:
74
+ * - The `to` field of the output event is set in this priority:
75
+ * 1. The `to` field provided by the handler result
76
+ * 2. The `redirectto` field from the input event
77
+ * 3. The `source` field from the input event (as a form of reply)
78
+ * - For system error events, the `to` field is always set to the `source` of the input event.
79
+ *
80
+ * **Telemetry**
81
+ * - Creates a new span for each execution as per the traceparent and tracestate field
82
+ * of the event. If those are not present, then a brand new span is created and distributed
83
+ * tracing is disabled
84
+ * - Sets span attributes for input and output events
85
+ * - Propagates trace context to output events
86
+ * - Handles error cases and sets appropriate span status
58
87
  */
59
88
  execute(event: ArvoEvent<ResolveArvoContractRecord<TContract['accepts']>, Record<string, any>, TContract['accepts']['type']>): Promise<ArvoEvent[]>;
60
89
  /**
@@ -62,6 +62,7 @@ var arvo_core_1 = require("arvo-core");
62
62
  var schema_1 = require("arvo-core/dist/ArvoEvent/schema");
63
63
  var OpenTelemetry_1 = require("../OpenTelemetry");
64
64
  var api_1 = require("@opentelemetry/api");
65
+ var utils_1 = require("../utils");
65
66
  /**
66
67
  * Represents an event handler for Arvo contracts.
67
68
  *
@@ -109,17 +110,46 @@ var ArvoEventHandler = /** @class */ (function () {
109
110
  * Executes the event handler for a given event.
110
111
  *
111
112
  * @param event - The event to handle.
112
- * @returns A promise that resolves to the resulting ArvoEvents.
113
+ * @returns A promise that resolves to an array of resulting ArvoEvents.
113
114
  *
114
115
  * @remarks
115
116
  * This method performs the following steps:
116
117
  * 1. Creates an OpenTelemetry span for the execution.
117
118
  * 2. Validates the input event against the contract.
118
119
  * 3. Executes the handler function.
119
- * 4. Creates and returns the result event.
120
+ * 4. Creates and returns the result event(s).
120
121
  * 5. Handles any errors and creates an error event if necessary.
121
122
  *
122
123
  * All telemetry data is properly set and propagated throughout the execution.
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const contract = createArvoContract({ ... })
128
+ * const handler = createArvoEventHandler({
129
+ * contract: contract,
130
+ * ...
131
+ * });
132
+ * const inputEvent: ArvoEvent<...> = createArvoEvent({ ... });
133
+ * const resultEvents = await handler.execute(inputEvent);
134
+ * ```
135
+ *
136
+ * @throws All error throw during the execution are returned as a system error event
137
+ *
138
+ * **Routing**
139
+ * The routing of the resulting events is determined as follows:
140
+ * - The `to` field of the output event is set in this priority:
141
+ * 1. The `to` field provided by the handler result
142
+ * 2. The `redirectto` field from the input event
143
+ * 3. The `source` field from the input event (as a form of reply)
144
+ * - For system error events, the `to` field is always set to the `source` of the input event.
145
+ *
146
+ * **Telemetry**
147
+ * - Creates a new span for each execution as per the traceparent and tracestate field
148
+ * of the event. If those are not present, then a brand new span is created and distributed
149
+ * tracing is disabled
150
+ * - Sets span attributes for input and output events
151
+ * - Propagates trace context to output events
152
+ * - Handles error cases and sets appropriate span status
123
153
  */
124
154
  ArvoEventHandler.prototype.execute = function (event) {
125
155
  return __awaiter(this, void 0, void 0, function () {
@@ -178,7 +208,12 @@ var ArvoEventHandler = /** @class */ (function () {
178
208
  }
179
209
  return [2 /*return*/, outputs.map(function (output, index) {
180
210
  var __extensions = output.__extensions, handlerResult = __rest(output, ["__extensions"]);
181
- var result = eventFactory.emits(__assign(__assign({}, handlerResult), { traceparent: otelSpanHeaders.traceparent || undefined, tracestate: otelSpanHeaders.tracestate || undefined, source: _this.source, subject: event.subject, to: handlerResult.to || event.source, executionunits: handlerResult.executionunits || _this.executionunits }), __extensions);
211
+ var result = eventFactory.emits(__assign(__assign({}, handlerResult), { traceparent: otelSpanHeaders.traceparent || undefined, tracestate: otelSpanHeaders.tracestate || undefined, source: _this.source, subject: event.subject,
212
+ // The user should be able to override the `to` field
213
+ // If that is not present then the 'redirectto' field
214
+ // is referred to. Then, after all else, 'source' field
215
+ // is used as a form of reply.
216
+ to: (0, utils_1.coalesceOrDefault)([handlerResult.to, event.redirectto], event.source), executionunits: (0, utils_1.coalesce)(handlerResult.executionunits, _this.executionunits) }), __extensions);
182
217
  Object.entries(result.otelAttributes).forEach(function (_a) {
183
218
  var key = _a[0], value = _a[1];
184
219
  return span.setAttribute("to_emit.".concat(index, ".").concat(key), value);
@@ -195,6 +230,8 @@ var ArvoEventHandler = /** @class */ (function () {
195
230
  result = eventFactory.systemError({
196
231
  source: this.source,
197
232
  subject: event.subject,
233
+ // The system error must always got back to
234
+ // the source
198
235
  to: event.source,
199
236
  error: error_1,
200
237
  executionunits: this.executionunits,
@@ -36,18 +36,43 @@ export default class MultiArvoEventHandler {
36
36
  * Executes the event handler for a given event.
37
37
  *
38
38
  * @param event - The event to handle.
39
- * @returns A promise that resolves to the resulting ArvoEvents.
39
+ * @returns A promise that resolves to an array of resulting ArvoEvents.
40
40
  *
41
41
  * @remarks
42
42
  * This method performs the following steps:
43
43
  * 1. Creates an OpenTelemetry span for the execution.
44
44
  * 2. Executes the handler function.
45
- * 3. Creates and returns the result event.
45
+ * 3. Creates and returns the result event(s).
46
46
  * 4. Handles any errors and creates an error event if necessary.
47
47
  *
48
48
  * All telemetry data is properly set and propagated throughout the execution.
49
- * The method ensures that the resulting event has the correct source, subject,
50
- * and execution units, and includes any necessary tracing information.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const handler = new MultiArvoEventHandler({
53
+ * source: 'com.multi.handler',
54
+ * ...
55
+ * });
56
+ * const inputEvent: ArvoEvent = createArvoEvent({ ... });
57
+ * const resultEvents = await handler.execute(inputEvent);
58
+ * ```
59
+ *
60
+ * @throws All errors thrown during the execution are returned as a system error event
61
+ *
62
+ * **Routing**
63
+ * The routing of the resulting events is determined as follows:
64
+ * - The `to` field of the output event is set in this priority:
65
+ * 1. The `to` field provided by the handler result
66
+ * 2. The `source` field from the input event (as a form of reply)
67
+ * - For system error events, the `to` field is always set to the `source` of the input event.
68
+ *
69
+ * **Telemetry**
70
+ * - Creates a new span for each execution as per the traceparent and tracestate field
71
+ * of the event. If those are not present, then a brand new span is created and distributed
72
+ * tracing is disabled
73
+ * - Sets span attributes for input and output events
74
+ * - Propagates trace context to output events
75
+ * - Handles error cases and sets appropriate span status
51
76
  */
52
77
  execute(event: ArvoEvent): Promise<ArvoEvent[]>;
53
78
  /**
@@ -62,6 +62,7 @@ var api_1 = require("@opentelemetry/api");
62
62
  var arvo_core_1 = require("arvo-core");
63
63
  var schema_1 = require("arvo-core/dist/ArvoEvent/schema");
64
64
  var OpenTelemetry_1 = require("../OpenTelemetry");
65
+ var utils_1 = require("../utils");
65
66
  /**
66
67
  * Represents a Multi ArvoEvent handler that can process multiple event types.
67
68
  *
@@ -100,18 +101,43 @@ var MultiArvoEventHandler = /** @class */ (function () {
100
101
  * Executes the event handler for a given event.
101
102
  *
102
103
  * @param event - The event to handle.
103
- * @returns A promise that resolves to the resulting ArvoEvents.
104
+ * @returns A promise that resolves to an array of resulting ArvoEvents.
104
105
  *
105
106
  * @remarks
106
107
  * This method performs the following steps:
107
108
  * 1. Creates an OpenTelemetry span for the execution.
108
109
  * 2. Executes the handler function.
109
- * 3. Creates and returns the result event.
110
+ * 3. Creates and returns the result event(s).
110
111
  * 4. Handles any errors and creates an error event if necessary.
111
112
  *
112
113
  * All telemetry data is properly set and propagated throughout the execution.
113
- * The method ensures that the resulting event has the correct source, subject,
114
- * and execution units, and includes any necessary tracing information.
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * const handler = new MultiArvoEventHandler({
118
+ * source: 'com.multi.handler',
119
+ * ...
120
+ * });
121
+ * const inputEvent: ArvoEvent = createArvoEvent({ ... });
122
+ * const resultEvents = await handler.execute(inputEvent);
123
+ * ```
124
+ *
125
+ * @throws All errors thrown during the execution are returned as a system error event
126
+ *
127
+ * **Routing**
128
+ * The routing of the resulting events is determined as follows:
129
+ * - The `to` field of the output event is set in this priority:
130
+ * 1. The `to` field provided by the handler result
131
+ * 2. The `source` field from the input event (as a form of reply)
132
+ * - For system error events, the `to` field is always set to the `source` of the input event.
133
+ *
134
+ * **Telemetry**
135
+ * - Creates a new span for each execution as per the traceparent and tracestate field
136
+ * of the event. If those are not present, then a brand new span is created and distributed
137
+ * tracing is disabled
138
+ * - Sets span attributes for input and output events
139
+ * - Propagates trace context to output events
140
+ * - Handles error cases and sets appropriate span status
115
141
  */
116
142
  MultiArvoEventHandler.prototype.execute = function (event) {
117
143
  return __awaiter(this, void 0, void 0, function () {
@@ -165,7 +191,12 @@ var MultiArvoEventHandler = /** @class */ (function () {
165
191
  }
166
192
  return [2 /*return*/, outputs.map(function (output, index) {
167
193
  var __extensions = output.__extensions, handlerResult = __rest(output, ["__extensions"]);
168
- var result = (0, arvo_core_1.createArvoEvent)(__assign(__assign({}, handlerResult), { traceparent: otelSpanHeaders.traceparent || undefined, tracestate: otelSpanHeaders.tracestate || undefined, source: _this.source, subject: event.subject, to: handlerResult.to || event.source, executionunits: handlerResult.executionunits || _this.executionunits }), __extensions);
194
+ var result = (0, arvo_core_1.createArvoEvent)(__assign(__assign({}, handlerResult), { traceparent: otelSpanHeaders.traceparent || undefined, tracestate: otelSpanHeaders.tracestate || undefined, source: _this.source, subject: event.subject,
195
+ // The user should be able to override the `to` field
196
+ // If that is not present then the 'redirectto' field
197
+ // is referred to. Then, after all else, 'source' field
198
+ // is used as a form of reply.
199
+ to: (0, utils_1.coalesceOrDefault)([handlerResult.to, event.redirectto], event.source), executionunits: (0, utils_1.coalesce)(handlerResult.executionunits, _this.executionunits) }), __extensions);
169
200
  Object.entries(result.otelAttributes).forEach(function (_a) {
170
201
  var key = _a[0], value = _a[1];
171
202
  return span.setAttribute("to_emit.".concat(index, ".").concat(key), value);
@@ -183,6 +214,8 @@ var MultiArvoEventHandler = /** @class */ (function () {
183
214
  type: "sys.".concat(this.source, ".error"),
184
215
  source: this.source,
185
216
  subject: event.subject,
217
+ // The system error must always got back to
218
+ // the source
186
219
  to: event.source,
187
220
  executionunits: this.executionunits,
188
221
  traceparent: otelSpanHeaders.traceparent || undefined,
package/dist/index.d.ts CHANGED
@@ -5,4 +5,5 @@ import { PartialExcept } from './types';
5
5
  import MultiArvoEventHandler from './MultiArvoEventHandler';
6
6
  import { MultiArvoEventHandlerFunctionInput, MultiArvoEventHandlerFunctionOutput, MultiArvoEventHandlerFunction, IMultiArvoEventHandler } from './MultiArvoEventHandler/types';
7
7
  import { createMultiArvoEventHandler } from './MultiArvoEventHandler/helpers';
8
- export { ArvoEventHandler, createArvoEventHandler, IArvoEventHandler, ArvoEventHandlerFunctionOutput, ArvoEventHandlerFunctionInput, ArvoEventHandlerFunction, PartialExcept, MultiArvoEventHandler, MultiArvoEventHandlerFunctionInput, MultiArvoEventHandlerFunctionOutput, MultiArvoEventHandlerFunction, IMultiArvoEventHandler, createMultiArvoEventHandler, };
8
+ import { isNullOrUndefined, getValueOrDefault, coalesce, coalesceOrDefault } from './utils';
9
+ export { ArvoEventHandler, createArvoEventHandler, IArvoEventHandler, ArvoEventHandlerFunctionOutput, ArvoEventHandlerFunctionInput, ArvoEventHandlerFunction, PartialExcept, MultiArvoEventHandler, MultiArvoEventHandlerFunctionInput, MultiArvoEventHandlerFunctionOutput, MultiArvoEventHandlerFunction, IMultiArvoEventHandler, createMultiArvoEventHandler, isNullOrUndefined, getValueOrDefault, coalesce, coalesceOrDefault, };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createMultiArvoEventHandler = exports.MultiArvoEventHandler = exports.createArvoEventHandler = exports.ArvoEventHandler = void 0;
6
+ exports.coalesceOrDefault = exports.coalesce = exports.getValueOrDefault = exports.isNullOrUndefined = exports.createMultiArvoEventHandler = exports.MultiArvoEventHandler = exports.createArvoEventHandler = exports.ArvoEventHandler = void 0;
7
7
  var ArvoEventHandler_1 = __importDefault(require("./ArvoEventHandler"));
8
8
  exports.ArvoEventHandler = ArvoEventHandler_1.default;
9
9
  var helpers_1 = require("./ArvoEventHandler/helpers");
@@ -12,3 +12,8 @@ var MultiArvoEventHandler_1 = __importDefault(require("./MultiArvoEventHandler")
12
12
  exports.MultiArvoEventHandler = MultiArvoEventHandler_1.default;
13
13
  var helpers_2 = require("./MultiArvoEventHandler/helpers");
14
14
  Object.defineProperty(exports, "createMultiArvoEventHandler", { enumerable: true, get: function () { return helpers_2.createMultiArvoEventHandler; } });
15
+ var utils_1 = require("./utils");
16
+ Object.defineProperty(exports, "isNullOrUndefined", { enumerable: true, get: function () { return utils_1.isNullOrUndefined; } });
17
+ Object.defineProperty(exports, "getValueOrDefault", { enumerable: true, get: function () { return utils_1.getValueOrDefault; } });
18
+ Object.defineProperty(exports, "coalesce", { enumerable: true, get: function () { return utils_1.coalesce; } });
19
+ Object.defineProperty(exports, "coalesceOrDefault", { enumerable: true, get: function () { return utils_1.coalesceOrDefault; } });
package/dist/utils.d.ts CHANGED
@@ -1 +1,43 @@
1
- export declare function isArray(input: unknown): boolean;
1
+ /**
2
+ * Checks if the item is null or undefined.
3
+ *
4
+ * @param item - The value to check.
5
+ * @returns True if the item is null or undefined, false otherwise.
6
+ */
7
+ export declare function isNullOrUndefined(item: unknown): item is null | undefined;
8
+ /**
9
+ * Returns the provided value if it's not null or undefined; otherwise, returns the default value.
10
+ *
11
+ * @template T - The type of the value and default value.
12
+ * @param value - The value to check.
13
+ * @param defaultValue - The default value to return if the provided value is null or undefined.
14
+ * @returns The provided value if it's not null or undefined; otherwise, the default value.
15
+ */
16
+ export declare function getValueOrDefault<T>(value: T | null | undefined, defaultValue: NonNullable<T>): NonNullable<T>;
17
+ /**
18
+ * Returns the first non-null and non-undefined value from the provided arguments.
19
+ * If all arguments are null or undefined, returns undefined.
20
+ *
21
+ * @template T - The type of the values.
22
+ * @param values - The values to coalesce.
23
+ * @returns The first non-null and non-undefined value, or undefined if all are null or undefined.
24
+ */
25
+ export declare function coalesce<T>(...values: (T | null | undefined)[]): T | undefined;
26
+ /**
27
+ * Returns the first non-null and non-undefined value from the provided array of values.
28
+ * If all values in the array are null or undefined, returns the specified default value.
29
+ *
30
+ * @template T - The type of the values and the default value.
31
+ * @param values - An array of values to coalesce.
32
+ * @param _default - The default value to return if all values in the array are null or undefined.
33
+ * @returns The first non-null and non-undefined value from the array, or the default value if all are null or undefined.
34
+ *
35
+ * @example
36
+ * const result = coalesceOrDefault([null, undefined, 'hello', 'world'], 'default');
37
+ * console.log(result); // Output: 'hello'
38
+ *
39
+ * @example
40
+ * const result = coalesceOrDefault([null, undefined], 'default');
41
+ * console.log(result); // Output: 'default'
42
+ */
43
+ export declare function coalesceOrDefault<T>(values: (T | null | undefined)[], _default: NonNullable<T>): NonNullable<T>;
package/dist/utils.js CHANGED
@@ -1,6 +1,67 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isArray = isArray;
4
- function isArray(input) {
5
- return Array.isArray(input);
3
+ exports.isNullOrUndefined = isNullOrUndefined;
4
+ exports.getValueOrDefault = getValueOrDefault;
5
+ exports.coalesce = coalesce;
6
+ exports.coalesceOrDefault = coalesceOrDefault;
7
+ /**
8
+ * Checks if the item is null or undefined.
9
+ *
10
+ * @param item - The value to check.
11
+ * @returns True if the item is null or undefined, false otherwise.
12
+ */
13
+ function isNullOrUndefined(item) {
14
+ return item === null || item === undefined;
15
+ }
16
+ /**
17
+ * Returns the provided value if it's not null or undefined; otherwise, returns the default value.
18
+ *
19
+ * @template T - The type of the value and default value.
20
+ * @param value - The value to check.
21
+ * @param defaultValue - The default value to return if the provided value is null or undefined.
22
+ * @returns The provided value if it's not null or undefined; otherwise, the default value.
23
+ */
24
+ function getValueOrDefault(value, defaultValue) {
25
+ return isNullOrUndefined(value) ? defaultValue : value;
26
+ }
27
+ /**
28
+ * Returns the first non-null and non-undefined value from the provided arguments.
29
+ * If all arguments are null or undefined, returns undefined.
30
+ *
31
+ * @template T - The type of the values.
32
+ * @param values - The values to coalesce.
33
+ * @returns The first non-null and non-undefined value, or undefined if all are null or undefined.
34
+ */
35
+ function coalesce() {
36
+ var values = [];
37
+ for (var _i = 0; _i < arguments.length; _i++) {
38
+ values[_i] = arguments[_i];
39
+ }
40
+ for (var _a = 0, values_1 = values; _a < values_1.length; _a++) {
41
+ var value = values_1[_a];
42
+ if (!isNullOrUndefined(value)) {
43
+ return value;
44
+ }
45
+ }
46
+ return undefined;
47
+ }
48
+ /**
49
+ * Returns the first non-null and non-undefined value from the provided array of values.
50
+ * If all values in the array are null or undefined, returns the specified default value.
51
+ *
52
+ * @template T - The type of the values and the default value.
53
+ * @param values - An array of values to coalesce.
54
+ * @param _default - The default value to return if all values in the array are null or undefined.
55
+ * @returns The first non-null and non-undefined value from the array, or the default value if all are null or undefined.
56
+ *
57
+ * @example
58
+ * const result = coalesceOrDefault([null, undefined, 'hello', 'world'], 'default');
59
+ * console.log(result); // Output: 'hello'
60
+ *
61
+ * @example
62
+ * const result = coalesceOrDefault([null, undefined], 'default');
63
+ * console.log(result); // Output: 'default'
64
+ */
65
+ function coalesceOrDefault(values, _default) {
66
+ return getValueOrDefault(coalesce.apply(void 0, values), _default);
6
67
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arvo-event-handler",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "This package contains class and function for event handlers in an Arvo Event Driven system",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -43,7 +43,8 @@
43
43
  "ts-node": "^10.9.2",
44
44
  "typedoc": "^0.26.6",
45
45
  "typedoc-plugin-zod": "^1.2.1",
46
- "typescript": "^5.5.4"
46
+ "typescript": "^5.5.4",
47
+ "typedoc-plugin-mermaid": "^1.12.0"
47
48
  },
48
49
  "dependencies": {
49
50
  "@opentelemetry/api": "^1.9.0",