arvo-event-handler 1.0.9 → 1.1.0

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
@@ -19,3 +19,7 @@
19
19
  ## [1.0.2] - 2024-09-10
20
20
 
21
21
  - Added ArvoEventRouter as a mechanism to group ArvoEventHandlers
22
+ ## [1.1.0] - 2024-09-30
23
+
24
+ - Added Abstract handler class and bound all handlers to it
25
+
@@ -0,0 +1,62 @@
1
+ import { ArvoContractRecord, ArvoEvent } from "arvo-core";
2
+ /**
3
+ * Abstract base class for Arvo event handlers.
4
+ *
5
+ * @abstract
6
+ * @description
7
+ * This class defines the basic structure for all Arvo event handlers.
8
+ * It provides an abstract method for executing events, which must be
9
+ * implemented by any concrete subclass.
10
+ * ```
11
+ */
12
+ export default abstract class AbstractArvoEventHandler {
13
+ /**
14
+ * Executes the event handling logic for a given Arvo event.
15
+ *
16
+ * @abstract
17
+ * @param {ArvoEvent} event - The Arvo event to be processed.
18
+ * @returns {Promise<ArvoEvent[]>} A promise that resolves to an array of resulting Arvo events.
19
+ *
20
+ * @description
21
+ * This method should contain the core logic for processing an Arvo event.
22
+ * Implementations should handle the event according to their specific requirements
23
+ * and return any resulting events.
24
+ *
25
+ * @throws {Error} Implementations may throw errors for invalid inputs or processing failures.
26
+ *
27
+ * @remarks
28
+ * - The method is asynchronous to allow for potentially time-consuming operations.
29
+ * - The returned array may be empty if no new events are generated as a result of processing.
30
+ * - Implementations should ensure proper error handling and event validation.
31
+ */
32
+ abstract execute(event: ArvoEvent): Promise<ArvoEvent[]>;
33
+ /**
34
+ * Provides the schema for system error events.
35
+ *
36
+ * @abstract
37
+ * @returns {ArvoContractRecord} An object containing the error event type and schema.
38
+ *
39
+ * @description
40
+ * This getter should define the structure for system error events that may be emitted
41
+ * when an unexpected error occurs during event handling.
42
+ *
43
+ * @remarks
44
+ * - The returned ArvoContractRecord typically includes:
45
+ * - `type`: A string representing the error event type.
46
+ * - `schema`: The schema definition for the error event.
47
+ * - Implementations should ensure that the error schema is consistent with the
48
+ * overall system's error handling strategy.
49
+ * - The error event type often follows a pattern like 'sys.[eventType].error'.
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * public get systemErrorSchema(): ArvoContractRecord {
54
+ * return {
55
+ * type: 'sys.myEvent.error',
56
+ * schema: MyCustomErrorSchema
57
+ * };
58
+ * }
59
+ * ```
60
+ */
61
+ abstract get systemErrorSchema(): ArvoContractRecord;
62
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Abstract base class for Arvo event handlers.
5
+ *
6
+ * @abstract
7
+ * @description
8
+ * This class defines the basic structure for all Arvo event handlers.
9
+ * It provides an abstract method for executing events, which must be
10
+ * implemented by any concrete subclass.
11
+ * ```
12
+ */
13
+ var AbstractArvoEventHandler = /** @class */ (function () {
14
+ function AbstractArvoEventHandler() {
15
+ }
16
+ return AbstractArvoEventHandler;
17
+ }());
18
+ exports.default = AbstractArvoEventHandler;
@@ -1,6 +1,7 @@
1
1
  import { ArvoContract, ArvoEvent, ArvoExecutionSpanKind, OpenInferenceSpanKind, ResolveArvoContractRecord } from 'arvo-core';
2
2
  import { IArvoEventHandler } from './types';
3
3
  import { SpanKind } from '@opentelemetry/api';
4
+ import AbstractArvoEventHandler from '../AbstractArvoEventHandler';
4
5
  /**
5
6
  * Represents an event handler for Arvo contracts.
6
7
  *
@@ -11,7 +12,7 @@ import { SpanKind } from '@opentelemetry/api';
11
12
  * for executing event handlers, managing telemetry, and ensuring proper contract validation.
12
13
  * It's designed to be flexible and reusable across different Arvo contract implementations.
13
14
  */
14
- export default class ArvoEventHandler<TContract extends ArvoContract> {
15
+ export default class ArvoEventHandler<TContract extends ArvoContract> extends AbstractArvoEventHandler {
15
16
  /** The contract of the handler to which it is bound */
16
17
  readonly contract: TContract;
17
18
  /** The default execution cost associated with this handler */
@@ -103,20 +104,17 @@ export default class ArvoEventHandler<TContract extends ArvoContract> {
103
104
  * // If the contract's accepted event type is 'user.created'
104
105
  * // The system error event type would be 'sys.user.created.error'
105
106
  */
106
- get systemErrorSchema(): {
107
- type: string;
108
- schema: import("zod").ZodObject<{
109
- errorName: import("zod").ZodString;
110
- errorMessage: import("zod").ZodString;
111
- errorStack: import("zod").ZodNullable<import("zod").ZodString>;
112
- }, "strip", import("zod").ZodTypeAny, {
113
- errorMessage: string;
114
- errorName: string;
115
- errorStack: string | null;
116
- }, {
117
- errorMessage: string;
118
- errorName: string;
119
- errorStack: string | null;
120
- }>;
121
- };
107
+ get systemErrorSchema(): import("arvo-core").ArvoContractRecord<`sys.${string}.error`, import("zod").ZodObject<{
108
+ errorName: import("zod").ZodString;
109
+ errorMessage: import("zod").ZodString;
110
+ errorStack: import("zod").ZodNullable<import("zod").ZodString>;
111
+ }, "strip", import("zod").ZodTypeAny, {
112
+ errorMessage: string;
113
+ errorName: string;
114
+ errorStack: string | null;
115
+ }, {
116
+ errorMessage: string;
117
+ errorName: string;
118
+ errorStack: string | null;
119
+ }>>;
122
120
  }
@@ -1,4 +1,19 @@
1
1
  "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
2
17
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
18
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
19
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -35,12 +50,16 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
50
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
51
  }
37
52
  };
53
+ var __importDefault = (this && this.__importDefault) || function (mod) {
54
+ return (mod && mod.__esModule) ? mod : { "default": mod };
55
+ };
38
56
  Object.defineProperty(exports, "__esModule", { value: true });
39
57
  var arvo_core_1 = require("arvo-core");
40
58
  var schema_1 = require("arvo-core/dist/ArvoEvent/schema");
41
59
  var api_1 = require("@opentelemetry/api");
42
60
  var utils_1 = require("../utils");
43
61
  var utils_2 = require("../OpenTelemetry/utils");
62
+ var AbstractArvoEventHandler_1 = __importDefault(require("../AbstractArvoEventHandler"));
44
63
  /**
45
64
  * Represents an event handler for Arvo contracts.
46
65
  *
@@ -51,7 +70,8 @@ var utils_2 = require("../OpenTelemetry/utils");
51
70
  * for executing event handlers, managing telemetry, and ensuring proper contract validation.
52
71
  * It's designed to be flexible and reusable across different Arvo contract implementations.
53
72
  */
54
- var ArvoEventHandler = /** @class */ (function () {
73
+ var ArvoEventHandler = /** @class */ (function (_super) {
74
+ __extends(ArvoEventHandler, _super);
55
75
  /**
56
76
  * Creates an instance of ArvoEventHandler.
57
77
  *
@@ -65,12 +85,13 @@ var ArvoEventHandler = /** @class */ (function () {
65
85
  */
66
86
  function ArvoEventHandler(param) {
67
87
  var _a, _b, _c, _d, _e, _f, _g;
68
- this.openInferenceSpanKind = arvo_core_1.OpenInferenceSpanKind.CHAIN;
69
- this.arvoExecutionSpanKind = arvo_core_1.ArvoExecutionSpanKind.EVENT_HANDLER;
70
- this.openTelemetrySpanKind = api_1.SpanKind.INTERNAL;
71
- this.contract = param.contract;
72
- this.executionunits = param.executionunits;
73
- this._handler = param.handler;
88
+ var _this = _super.call(this) || this;
89
+ _this.openInferenceSpanKind = arvo_core_1.OpenInferenceSpanKind.CHAIN;
90
+ _this.arvoExecutionSpanKind = arvo_core_1.ArvoExecutionSpanKind.EVENT_HANDLER;
91
+ _this.openTelemetrySpanKind = api_1.SpanKind.INTERNAL;
92
+ _this.contract = param.contract;
93
+ _this.executionunits = param.executionunits;
94
+ _this._handler = param.handler;
74
95
  if (param.source) {
75
96
  var error = schema_1.CloudEventContextSchema.pick({
76
97
  source: true,
@@ -79,13 +100,14 @@ var ArvoEventHandler = /** @class */ (function () {
79
100
  throw new Error("The provided 'source' is not a valid string. Error: ".concat(error.message));
80
101
  }
81
102
  }
82
- this.source = (_a = param.source) !== null && _a !== void 0 ? _a : this.contract.accepts.type;
83
- this.arvoExecutionSpanKind =
84
- (_c = (_b = param.spanKind) === null || _b === void 0 ? void 0 : _b.arvoExecution) !== null && _c !== void 0 ? _c : this.arvoExecutionSpanKind;
85
- this.openInferenceSpanKind =
86
- (_e = (_d = param.spanKind) === null || _d === void 0 ? void 0 : _d.openInference) !== null && _e !== void 0 ? _e : this.openInferenceSpanKind;
87
- this.openTelemetrySpanKind =
88
- (_g = (_f = param.spanKind) === null || _f === void 0 ? void 0 : _f.openTelemetry) !== null && _g !== void 0 ? _g : this.openTelemetrySpanKind;
103
+ _this.source = (_a = param.source) !== null && _a !== void 0 ? _a : _this.contract.accepts.type;
104
+ _this.arvoExecutionSpanKind =
105
+ (_c = (_b = param.spanKind) === null || _b === void 0 ? void 0 : _b.arvoExecution) !== null && _c !== void 0 ? _c : _this.arvoExecutionSpanKind;
106
+ _this.openInferenceSpanKind =
107
+ (_e = (_d = param.spanKind) === null || _d === void 0 ? void 0 : _d.openInference) !== null && _e !== void 0 ? _e : _this.openInferenceSpanKind;
108
+ _this.openTelemetrySpanKind =
109
+ (_g = (_f = param.spanKind) === null || _f === void 0 ? void 0 : _f.openTelemetry) !== null && _g !== void 0 ? _g : _this.openTelemetrySpanKind;
110
+ return _this;
89
111
  }
90
112
  /**
91
113
  * Executes the event handler for a given event.
@@ -149,13 +171,14 @@ var ArvoEventHandler = /** @class */ (function () {
149
171
  eventFactory = (0, arvo_core_1.createArvoEventFactory)(this.contract);
150
172
  return [4 /*yield*/, api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), function () { return __awaiter(_this, void 0, void 0, function () {
151
173
  var otelSpanHeaders, inputEventValidation, _handleOutput, outputs, error_1, result;
152
- return __generator(this, function (_a) {
153
- switch (_a.label) {
174
+ var _a, _b, _c;
175
+ return __generator(this, function (_d) {
176
+ switch (_d.label) {
154
177
  case 0:
155
178
  otelSpanHeaders = (0, arvo_core_1.currentOpenTelemetryHeaders)();
156
- _a.label = 1;
179
+ _d.label = 1;
157
180
  case 1:
158
- _a.trys.push([1, 3, 4, 5]);
181
+ _d.trys.push([1, 3, 4, 5]);
159
182
  span.setStatus({ code: api_1.SpanStatusCode.OK });
160
183
  Object.entries(event.otelAttributes).forEach(function (_a) {
161
184
  var key = _a[0], value = _a[1];
@@ -170,7 +193,7 @@ var ArvoEventHandler = /** @class */ (function () {
170
193
  source: this.source,
171
194
  })];
172
195
  case 2:
173
- _handleOutput = _a.sent();
196
+ _handleOutput = _d.sent();
174
197
  if (!_handleOutput)
175
198
  return [2 /*return*/, []];
176
199
  outputs = [];
@@ -188,7 +211,7 @@ var ArvoEventHandler = /** @class */ (function () {
188
211
  return eventFactory.emits.apply(eventFactory, args);
189
212
  })];
190
213
  case 3:
191
- error_1 = _a.sent();
214
+ error_1 = _d.sent();
192
215
  (0, arvo_core_1.exceptionToSpan)(error_1);
193
216
  span.setStatus({
194
217
  code: api_1.SpanStatusCode.ERROR,
@@ -202,8 +225,9 @@ var ArvoEventHandler = /** @class */ (function () {
202
225
  to: event.source,
203
226
  error: error_1,
204
227
  executionunits: this.executionunits,
205
- traceparent: otelSpanHeaders.traceparent || undefined,
206
- tracestate: otelSpanHeaders.tracestate || undefined,
228
+ traceparent: (_a = otelSpanHeaders.traceparent) !== null && _a !== void 0 ? _a : undefined,
229
+ tracestate: (_b = otelSpanHeaders.tracestate) !== null && _b !== void 0 ? _b : undefined,
230
+ accesscontrol: (_c = event.accesscontrol) !== null && _c !== void 0 ? _c : undefined,
207
231
  }, {});
208
232
  Object.entries(result.otelAttributes).forEach(function (_a) {
209
233
  var key = _a[0], value = _a[1];
@@ -239,14 +263,11 @@ var ArvoEventHandler = /** @class */ (function () {
239
263
  * // The system error event type would be 'sys.user.created.error'
240
264
  */
241
265
  get: function () {
242
- return {
243
- type: "sys.".concat(this.contract.accepts.type, ".error"),
244
- schema: arvo_core_1.ArvoErrorSchema,
245
- };
266
+ return this.contract.systemError;
246
267
  },
247
268
  enumerable: false,
248
269
  configurable: true
249
270
  });
250
271
  return ArvoEventHandler;
251
- }());
272
+ }(AbstractArvoEventHandler_1.default));
252
273
  exports.default = ArvoEventHandler;
@@ -2,16 +2,24 @@ import { ArvoContract, ArvoEvent, ArvoExecutionSpanKind, OpenInferenceSpanKind }
2
2
  import ArvoEventHandler from '../ArvoEventHandler';
3
3
  import { IArvoEventRouter } from './types';
4
4
  import { SpanKind } from '@opentelemetry/api';
5
+ import AbstractArvoEventHandler from '../AbstractArvoEventHandler';
5
6
  /**
6
7
  * ArvoEventRouter class handles routing of ArvoEvents to appropriate event handlers.
7
8
  */
8
- export declare class ArvoEventRouter {
9
+ export declare class ArvoEventRouter extends AbstractArvoEventHandler {
10
+ private _handlerDefaultSource;
11
+ private readonly _source;
9
12
  /**
10
- * The source name of the router. The router attempts
11
- * to match the `event.to` field with this value
12
- * @property {string} [source]
13
+ * The source name of the router.
14
+ * @returns {string} The router's source name.
15
+ *
16
+ * @remarks
17
+ * The router attempts to match the `event.to` field with this value.
18
+ * If the source is 'arvo.event.router', the `event.to` is not matched and any event is allowed.
19
+ * 'arvo.event.router' is the default source which is set automatically in case a source
20
+ * is not explicitly provided
13
21
  */
14
- readonly source: string | null;
22
+ get source(): string;
15
23
  /**
16
24
  * A list of all available event handlers to be used by the router.
17
25
  * @property {ArvoEventHandler<ArvoContract>[]} handlers
@@ -82,4 +90,35 @@ export declare class ArvoEventRouter {
82
90
  * - The router's default execution units are used for error events.
83
91
  */
84
92
  execute(event: ArvoEvent): Promise<ArvoEvent[]>;
93
+ /**
94
+ * Provides the schema for system error events.
95
+ *
96
+ * @returns An object containing the error event type and schema.
97
+ *
98
+ * @remarks
99
+ * This getter defines the structure for system error events that may be emitted
100
+ * when an unexpected error occurs during event handling. The error event type
101
+ * is prefixed with 'sys.' followed by the handler's source and '.error'.
102
+ * The schema used for these error events is the standard ArvoErrorSchema.
103
+ *
104
+ * @example
105
+ * // If the handler's source is 'user.service'
106
+ * // The system error event type would be 'sys.user.service.error'
107
+ */
108
+ get systemErrorSchema(): {
109
+ type: string;
110
+ schema: import("zod").ZodObject<{
111
+ errorName: import("zod").ZodString;
112
+ errorMessage: import("zod").ZodString;
113
+ errorStack: import("zod").ZodNullable<import("zod").ZodString>;
114
+ }, "strip", import("zod").ZodTypeAny, {
115
+ errorMessage: string;
116
+ errorName: string;
117
+ errorStack: string | null;
118
+ }, {
119
+ errorMessage: string;
120
+ errorName: string;
121
+ errorStack: string | null;
122
+ }>;
123
+ };
85
124
  }
@@ -1,4 +1,19 @@
1
1
  "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
2
17
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
18
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
19
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -35,18 +50,22 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
50
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
51
  }
37
52
  };
53
+ var __importDefault = (this && this.__importDefault) || function (mod) {
54
+ return (mod && mod.__esModule) ? mod : { "default": mod };
55
+ };
38
56
  Object.defineProperty(exports, "__esModule", { value: true });
39
57
  exports.ArvoEventRouter = void 0;
40
58
  var arvo_core_1 = require("arvo-core");
41
59
  var utils_1 = require("../utils");
42
60
  var api_1 = require("@opentelemetry/api");
43
61
  var utils_2 = require("./utils");
44
- var schema_1 = require("arvo-core/dist/ArvoEvent/schema");
45
62
  var utils_3 = require("../OpenTelemetry/utils");
63
+ var AbstractArvoEventHandler_1 = __importDefault(require("../AbstractArvoEventHandler"));
46
64
  /**
47
65
  * ArvoEventRouter class handles routing of ArvoEvents to appropriate event handlers.
48
66
  */
49
- var ArvoEventRouter = /** @class */ (function () {
67
+ var ArvoEventRouter = /** @class */ (function (_super) {
68
+ __extends(ArvoEventRouter, _super);
50
69
  /**
51
70
  * Creates an instance of ArvoEventRouter.
52
71
  * @param {IArvoEventRouter} param - The parameters for initializing the router
@@ -54,35 +73,51 @@ var ArvoEventRouter = /** @class */ (function () {
54
73
  * source in an invalid string
55
74
  */
56
75
  function ArvoEventRouter(param) {
76
+ var _this = _super.call(this) || this;
77
+ _this._handlerDefaultSource = "arvo.event.router";
57
78
  /**
58
79
  * A map of all the available event handlers
59
80
  */
60
- this.handlersMap = {};
61
- this.openInferenceSpanKind = arvo_core_1.OpenInferenceSpanKind.CHAIN;
62
- this.arvoExecutionSpanKind = arvo_core_1.ArvoExecutionSpanKind.EVENT_HANDLER;
63
- this.openTelemetrySpanKind = api_1.SpanKind.INTERNAL;
64
- this.handlers = param.handlers;
65
- if (param.source) {
66
- var error = schema_1.CloudEventContextSchema.pick({
67
- source: true,
68
- }).safeParse({ source: param.source }).error;
69
- if (error) {
70
- throw new Error("The provided 'source' is not a valid string. Error: ".concat(error.message));
71
- }
81
+ _this.handlersMap = {};
82
+ _this.openInferenceSpanKind = arvo_core_1.OpenInferenceSpanKind.CHAIN;
83
+ _this.arvoExecutionSpanKind = arvo_core_1.ArvoExecutionSpanKind.EVENT_HANDLER;
84
+ _this.openTelemetrySpanKind = api_1.SpanKind.INTERNAL;
85
+ _this.handlers = param.handlers;
86
+ if (param.source && !(0, utils_1.isLowerAlphanumeric)(param.source)) {
87
+ throw new Error("Invalid 'source' = '".concat(param.source, "'. The 'source' must only contain alphanumeric characters e.g. test.router"));
72
88
  }
73
- this.source = (0, utils_1.isNullOrUndefined)(param.source) ? null : param.source;
74
- this.executionunits = param.executionunits;
75
- for (var _i = 0, _a = this.handlers; _i < _a.length; _i++) {
89
+ _this._source = (0, utils_1.isNullOrUndefined)(param.source) ? null : param.source;
90
+ _this.executionunits = param.executionunits;
91
+ for (var _i = 0, _a = _this.handlers; _i < _a.length; _i++) {
76
92
  var handler = _a[_i];
77
- if (this.handlersMap[handler.contract.accepts.type]) {
78
- var existingHandler = this.handlersMap[handler.contract.accepts.type];
93
+ if (_this.handlersMap[handler.contract.accepts.type]) {
94
+ var existingHandler = _this.handlersMap[handler.contract.accepts.type];
79
95
  throw new Error((0, arvo_core_1.cleanString)("\n Duplicate handlers for event.type=".concat(handler.contract.accepts.type, " found. There are same 'contract.accept.types' in \n contracts 'uri=").concat(existingHandler.contract.uri, "' and 'uri=").concat(handler.contract.uri, "'. This router does not support handlers\n with the same 'contract.accept.type'.\n ")));
80
96
  }
81
- this.handlersMap[handler.contract.accepts.type] = handler;
97
+ _this.handlersMap[handler.contract.accepts.type] = handler;
82
98
  }
83
- Object.freeze(this.handlers);
84
- Object.freeze(this.handlersMap);
99
+ Object.freeze(_this.handlers);
100
+ Object.freeze(_this.handlersMap);
101
+ return _this;
85
102
  }
103
+ Object.defineProperty(ArvoEventRouter.prototype, "source", {
104
+ /**
105
+ * The source name of the router.
106
+ * @returns {string} The router's source name.
107
+ *
108
+ * @remarks
109
+ * The router attempts to match the `event.to` field with this value.
110
+ * If the source is 'arvo.event.router', the `event.to` is not matched and any event is allowed.
111
+ * 'arvo.event.router' is the default source which is set automatically in case a source
112
+ * is not explicitly provided
113
+ */
114
+ get: function () {
115
+ var _a;
116
+ return (_a = this._source) !== null && _a !== void 0 ? _a : this._handlerDefaultSource;
117
+ },
118
+ enumerable: false,
119
+ configurable: true
120
+ });
86
121
  /**
87
122
  * Executes the routing process for a given ArvoEvent.
88
123
  *
@@ -136,7 +171,7 @@ var ArvoEventRouter = /** @class */ (function () {
136
171
  return __generator(this, function (_b) {
137
172
  switch (_b.label) {
138
173
  case 0:
139
- span = (0, utils_3.createSpanFromEvent)("ArvoEventRouter.source<".concat((_a = this.source) !== null && _a !== void 0 ? _a : 'arvo.event.router', ">.execute<").concat(event.type, ">"), event, {
174
+ span = (0, utils_3.createSpanFromEvent)("ArvoEventRouter.source<".concat((_a = this._source) !== null && _a !== void 0 ? _a : 'arvo.event.router', ">.execute<").concat(event.type, ">"), event, {
140
175
  kind: this.openTelemetrySpanKind,
141
176
  openInference: this.openInferenceSpanKind,
142
177
  arvoExecution: this.arvoExecutionSpanKind,
@@ -144,31 +179,30 @@ var ArvoEventRouter = /** @class */ (function () {
144
179
  return [4 /*yield*/, api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), function () { return __awaiter(_this, void 0, void 0, function () {
145
180
  var otelSpanHeaders, newEvent, results, error_1;
146
181
  var _this = this;
147
- var _a;
148
- return __generator(this, function (_b) {
149
- switch (_b.label) {
182
+ return __generator(this, function (_a) {
183
+ switch (_a.label) {
150
184
  case 0:
151
185
  otelSpanHeaders = (0, arvo_core_1.currentOpenTelemetryHeaders)();
152
186
  newEvent = (0, utils_2.deleteOtelHeaders)(event);
153
- _b.label = 1;
187
+ _a.label = 1;
154
188
  case 1:
155
- _b.trys.push([1, 3, 4, 5]);
189
+ _a.trys.push([1, 3, 4, 5]);
156
190
  span.setStatus({ code: api_1.SpanStatusCode.OK });
157
- if (!(0, utils_1.isNullOrUndefined)(this.source) && newEvent.to !== this.source) {
158
- throw new Error((0, arvo_core_1.cleanString)("\n Invalid event. The 'event.to' is ".concat(newEvent.to, " while this handler \n listens to only 'event.to' equal to ").concat(this.source, ". If this is a mistake,\n please update the 'source' field of the handler\n ")));
191
+ if (!(0, utils_1.isNullOrUndefined)(this._source) && newEvent.to !== this._source) {
192
+ throw new Error((0, arvo_core_1.cleanString)("\n Invalid event. The 'event.to' is ".concat(newEvent.to, " while this handler \n listens to only 'event.to' equal to ").concat(this._source, ". If this is a mistake,\n please update the 'source' field of the handler\n ")));
159
193
  }
160
194
  if (!this.handlersMap[newEvent.type]) {
161
195
  throw new Error((0, arvo_core_1.cleanString)("\n Invalid event (type=".concat(newEvent.type, "). No valid handler \n <handler[*].contract.accepts.type> found in the router.\n ")));
162
196
  }
163
197
  return [4 /*yield*/, this.handlersMap[newEvent.type].execute(newEvent)];
164
198
  case 2:
165
- results = _b.sent();
199
+ results = _a.sent();
166
200
  return [2 /*return*/, results.map(function (event) {
167
201
  var _a;
168
202
  return new arvo_core_1.ArvoEvent({
169
203
  id: event.id,
170
204
  time: event.time,
171
- source: (0, utils_1.getValueOrDefault)(_this.source, event.source),
205
+ source: event.source,
172
206
  specversion: '1.0',
173
207
  type: event.type,
174
208
  subject: event.subject,
@@ -183,8 +217,8 @@ var ArvoEventRouter = /** @class */ (function () {
183
217
  }, event.data, event.cloudevent.extensions);
184
218
  })];
185
219
  case 3:
186
- error_1 = _b.sent();
187
- return [2 /*return*/, (0, utils_1.createHandlerErrorOutputEvent)(error_1, otelSpanHeaders, "sys.arvo.event.router.error", (_a = this.source) !== null && _a !== void 0 ? _a : "arvo.event.router", event, this.executionunits, function () {
220
+ error_1 = _a.sent();
221
+ return [2 /*return*/, (0, utils_1.createHandlerErrorOutputEvent)(error_1, otelSpanHeaders, "sys.".concat(this.source, ".error"), this.source, event, this.executionunits, function () {
188
222
  var args = [];
189
223
  for (var _i = 0; _i < arguments.length; _i++) {
190
224
  args[_i] = arguments[_i];
@@ -203,6 +237,31 @@ var ArvoEventRouter = /** @class */ (function () {
203
237
  });
204
238
  });
205
239
  };
240
+ Object.defineProperty(ArvoEventRouter.prototype, "systemErrorSchema", {
241
+ /**
242
+ * Provides the schema for system error events.
243
+ *
244
+ * @returns An object containing the error event type and schema.
245
+ *
246
+ * @remarks
247
+ * This getter defines the structure for system error events that may be emitted
248
+ * when an unexpected error occurs during event handling. The error event type
249
+ * is prefixed with 'sys.' followed by the handler's source and '.error'.
250
+ * The schema used for these error events is the standard ArvoErrorSchema.
251
+ *
252
+ * @example
253
+ * // If the handler's source is 'user.service'
254
+ * // The system error event type would be 'sys.user.service.error'
255
+ */
256
+ get: function () {
257
+ return {
258
+ type: "sys.".concat(this.source, ".error"),
259
+ schema: arvo_core_1.ArvoErrorSchema,
260
+ };
261
+ },
262
+ enumerable: false,
263
+ configurable: true
264
+ });
206
265
  return ArvoEventRouter;
207
- }());
266
+ }(AbstractArvoEventHandler_1.default));
208
267
  exports.ArvoEventRouter = ArvoEventRouter;
@@ -1,6 +1,7 @@
1
1
  import { SpanKind } from '@opentelemetry/api';
2
2
  import { ArvoEvent, ArvoExecutionSpanKind, OpenInferenceSpanKind } from 'arvo-core';
3
3
  import { IMultiArvoEventHandler } from './types';
4
+ import AbstractArvoEventHandler from '../AbstractArvoEventHandler';
4
5
  /**
5
6
  * Represents a Multi ArvoEvent handler that can process multiple event types.
6
7
  *
@@ -10,7 +11,7 @@ import { IMultiArvoEventHandler } from './types';
10
11
  * without being tied to a specific contract. This makes it more flexible for
11
12
  * scenarios where you need to process various event types with a single handler.
12
13
  */
13
- export default class MultiArvoEventHandler {
14
+ export default class MultiArvoEventHandler extends AbstractArvoEventHandler {
14
15
  /** The default execution cost associated with this handler */
15
16
  readonly executionunits: number;
16
17
  /**
@@ -1,4 +1,19 @@
1
1
  "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
2
17
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
18
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
19
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -35,12 +50,15 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
50
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
51
  }
37
52
  };
53
+ var __importDefault = (this && this.__importDefault) || function (mod) {
54
+ return (mod && mod.__esModule) ? mod : { "default": mod };
55
+ };
38
56
  Object.defineProperty(exports, "__esModule", { value: true });
39
57
  var api_1 = require("@opentelemetry/api");
40
58
  var arvo_core_1 = require("arvo-core");
41
- var schema_1 = require("arvo-core/dist/ArvoEvent/schema");
42
59
  var utils_1 = require("../utils");
43
60
  var utils_2 = require("../OpenTelemetry/utils");
61
+ var AbstractArvoEventHandler_1 = __importDefault(require("../AbstractArvoEventHandler"));
44
62
  /**
45
63
  * Represents a Multi ArvoEvent handler that can process multiple event types.
46
64
  *
@@ -50,7 +68,8 @@ var utils_2 = require("../OpenTelemetry/utils");
50
68
  * without being tied to a specific contract. This makes it more flexible for
51
69
  * scenarios where you need to process various event types with a single handler.
52
70
  */
53
- var MultiArvoEventHandler = /** @class */ (function () {
71
+ var MultiArvoEventHandler = /** @class */ (function (_super) {
72
+ __extends(MultiArvoEventHandler, _super);
54
73
  /**
55
74
  * Creates an instance of MultiArvoEventHandler.
56
75
  *
@@ -59,24 +78,23 @@ var MultiArvoEventHandler = /** @class */ (function () {
59
78
  */
60
79
  function MultiArvoEventHandler(param) {
61
80
  var _a, _b, _c;
62
- this.openInferenceSpanKind = arvo_core_1.OpenInferenceSpanKind.CHAIN;
63
- this.arvoExecutionSpanKind = arvo_core_1.ArvoExecutionSpanKind.EVENT_HANDLER;
64
- this.openTelemetrySpanKind = api_1.SpanKind.INTERNAL;
65
- this.executionunits = param.executionunits;
66
- this._handler = param.handler;
67
- var error = schema_1.CloudEventContextSchema.pick({
68
- source: true,
69
- }).safeParse({ source: param.source }).error;
70
- if (error) {
71
- throw new Error("The provided 'source' is not a valid string. Error: ".concat(error.message));
81
+ var _this = _super.call(this) || this;
82
+ _this.openInferenceSpanKind = arvo_core_1.OpenInferenceSpanKind.CHAIN;
83
+ _this.arvoExecutionSpanKind = arvo_core_1.ArvoExecutionSpanKind.EVENT_HANDLER;
84
+ _this.openTelemetrySpanKind = api_1.SpanKind.INTERNAL;
85
+ _this.executionunits = param.executionunits;
86
+ _this._handler = param.handler;
87
+ if (!(0, utils_1.isLowerAlphanumeric)(param.source)) {
88
+ throw new Error("Invalid 'source' = '".concat(param.source, "'. The 'source' must only contain alphanumeric characters e.g. test.handler"));
72
89
  }
73
- this.source = param.source;
74
- this.arvoExecutionSpanKind =
75
- ((_a = param.spanKind) === null || _a === void 0 ? void 0 : _a.arvoExecution) || this.arvoExecutionSpanKind;
76
- this.openInferenceSpanKind =
77
- ((_b = param.spanKind) === null || _b === void 0 ? void 0 : _b.openInference) || this.openInferenceSpanKind;
78
- this.openTelemetrySpanKind =
79
- ((_c = param.spanKind) === null || _c === void 0 ? void 0 : _c.openTelemetry) || this.openTelemetrySpanKind;
90
+ _this.source = param.source;
91
+ _this.arvoExecutionSpanKind =
92
+ ((_a = param.spanKind) === null || _a === void 0 ? void 0 : _a.arvoExecution) || _this.arvoExecutionSpanKind;
93
+ _this.openInferenceSpanKind =
94
+ ((_b = param.spanKind) === null || _b === void 0 ? void 0 : _b.openInference) || _this.openInferenceSpanKind;
95
+ _this.openTelemetrySpanKind =
96
+ ((_c = param.spanKind) === null || _c === void 0 ? void 0 : _c.openTelemetry) || _this.openTelemetrySpanKind;
97
+ return _this;
80
98
  }
81
99
  /**
82
100
  * Executes the event handler for a given event.
@@ -229,5 +247,5 @@ var MultiArvoEventHandler = /** @class */ (function () {
229
247
  configurable: true
230
248
  });
231
249
  return MultiArvoEventHandler;
232
- }());
250
+ }(AbstractArvoEventHandler_1.default));
233
251
  exports.default = MultiArvoEventHandler;
package/dist/index.d.ts CHANGED
@@ -9,4 +9,5 @@ import { isNullOrUndefined, getValueOrDefault, coalesce, coalesceOrDefault } fro
9
9
  import { IArvoEventRouter } from './ArvoEventRouter/types';
10
10
  import { ArvoEventRouter } from './ArvoEventRouter';
11
11
  import { createArvoEventRouter } from './ArvoEventRouter/helpers';
12
- export { ArvoEventHandler, createArvoEventHandler, IArvoEventHandler, ArvoEventHandlerFunctionOutput, ArvoEventHandlerFunctionInput, ArvoEventHandlerFunction, PartialExcept, MultiArvoEventHandler, MultiArvoEventHandlerFunctionInput, MultiArvoEventHandlerFunctionOutput, MultiArvoEventHandlerFunction, IMultiArvoEventHandler, createMultiArvoEventHandler, isNullOrUndefined, getValueOrDefault, coalesce, coalesceOrDefault, IArvoEventRouter, ArvoEventRouter, createArvoEventRouter, };
12
+ import AbstractArvoEventHandler from './AbstractArvoEventHandler';
13
+ export { ArvoEventHandler, createArvoEventHandler, IArvoEventHandler, ArvoEventHandlerFunctionOutput, ArvoEventHandlerFunctionInput, ArvoEventHandlerFunction, PartialExcept, MultiArvoEventHandler, MultiArvoEventHandlerFunctionInput, MultiArvoEventHandlerFunctionOutput, MultiArvoEventHandlerFunction, IMultiArvoEventHandler, createMultiArvoEventHandler, isNullOrUndefined, getValueOrDefault, coalesce, coalesceOrDefault, IArvoEventRouter, ArvoEventRouter, createArvoEventRouter, AbstractArvoEventHandler, };
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.createArvoEventRouter = exports.ArvoEventRouter = exports.coalesceOrDefault = exports.coalesce = exports.getValueOrDefault = exports.isNullOrUndefined = exports.createMultiArvoEventHandler = exports.MultiArvoEventHandler = exports.createArvoEventHandler = exports.ArvoEventHandler = void 0;
6
+ exports.AbstractArvoEventHandler = exports.createArvoEventRouter = exports.ArvoEventRouter = 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");
@@ -21,3 +21,5 @@ var ArvoEventRouter_1 = require("./ArvoEventRouter");
21
21
  Object.defineProperty(exports, "ArvoEventRouter", { enumerable: true, get: function () { return ArvoEventRouter_1.ArvoEventRouter; } });
22
22
  var helpers_3 = require("./ArvoEventRouter/helpers");
23
23
  Object.defineProperty(exports, "createArvoEventRouter", { enumerable: true, get: function () { return helpers_3.createArvoEventRouter; } });
24
+ var AbstractArvoEventHandler_1 = __importDefault(require("./AbstractArvoEventHandler"));
25
+ exports.AbstractArvoEventHandler = AbstractArvoEventHandler_1.default;
package/dist/utils.d.ts CHANGED
@@ -50,6 +50,7 @@ export declare function coalesceOrDefault<T>(values: (T | null | undefined)[], _
50
50
  * @param events - An array of event handler function outputs.
51
51
  * @param otelSpanHeaders - OpenTelemetry headers for tracing.
52
52
  * @param source - The source of the event.
53
+ * @param defaultAccessControl - The default access control string for the events
53
54
  * @param originalEvent - The original ArvoEvent that triggered the handler.
54
55
  * @param handlerExectionUnits - The number of execution units for the handler.
55
56
  * @param factory - A function to create ArvoEvents.
@@ -61,3 +62,17 @@ export declare const eventHandlerOutputEventCreator: (events: Array<ArvoEventHan
61
62
  export declare const createHandlerErrorOutputEvent: (error: Error, otelSpanHeaders: OpenTelemetryHeaders, type: string, source: string, originalEvent: ArvoEvent, handlerExectionUnits: number, factory: (param: CreateArvoEvent<any, any> & {
62
63
  to: string;
63
64
  }, extensions?: Record<string, string | number | boolean>) => ArvoEvent<any, any, any>) => ArvoEvent<any, any, any>[];
65
+ /**
66
+ * Validates if a string contains only uppercase or lowercase alphanumeric characters.
67
+ *
68
+ * This function checks if the input string consists solely of:
69
+ * - Lowercase letters (a-z)
70
+ * - Numbers (0-9)
71
+ * - Dot (.)
72
+ *
73
+ * It does not allow any special characters, spaces, or other non-alphanumeric characters.
74
+ *
75
+ * @param input - The string to be validated.
76
+ * @returns True if the string contains only alphanumeric characters, false otherwise.
77
+ */
78
+ export declare function isLowerAlphanumeric(input: string): boolean;
package/dist/utils.js CHANGED
@@ -27,6 +27,7 @@ exports.isNullOrUndefined = isNullOrUndefined;
27
27
  exports.getValueOrDefault = getValueOrDefault;
28
28
  exports.coalesce = coalesce;
29
29
  exports.coalesceOrDefault = coalesceOrDefault;
30
+ exports.isLowerAlphanumeric = isLowerAlphanumeric;
30
31
  var arvo_core_1 = require("arvo-core");
31
32
  var api_1 = require("@opentelemetry/api");
32
33
  /**
@@ -96,6 +97,7 @@ function coalesceOrDefault(values, _default) {
96
97
  * @param events - An array of event handler function outputs.
97
98
  * @param otelSpanHeaders - OpenTelemetry headers for tracing.
98
99
  * @param source - The source of the event.
100
+ * @param defaultAccessControl - The default access control string for the events
99
101
  * @param originalEvent - The original ArvoEvent that triggered the handler.
100
102
  * @param handlerExectionUnits - The number of execution units for the handler.
101
103
  * @param factory - A function to create ArvoEvents.
@@ -103,11 +105,12 @@ function coalesceOrDefault(values, _default) {
103
105
  */
104
106
  var eventHandlerOutputEventCreator = function (events, otelSpanHeaders, source, originalEvent, handlerExectionUnits, factory) {
105
107
  return events.map(function (item, index) {
108
+ var _a, _b;
106
109
  var __extensions = item.__extensions, handlerResult = __rest(item, ["__extensions"]);
107
110
  var result = factory(__assign(__assign({}, handlerResult), { traceparent: otelSpanHeaders.traceparent || undefined, tracestate: otelSpanHeaders.tracestate || undefined, source: source, subject: originalEvent.subject,
108
111
  // prioritise returned 'to', 'redirectto' and then
109
112
  // 'source'
110
- to: coalesceOrDefault([handlerResult.to, originalEvent.redirectto], originalEvent.source), executionunits: coalesce(handlerResult.executionunits, handlerExectionUnits) }), __extensions);
113
+ to: coalesceOrDefault([handlerResult.to, originalEvent.redirectto], originalEvent.source), executionunits: coalesce(handlerResult.executionunits, handlerExectionUnits), accesscontrol: (_b = (_a = handlerResult.accesscontrol) !== null && _a !== void 0 ? _a : originalEvent.accesscontrol) !== null && _b !== void 0 ? _b : undefined }), __extensions);
111
114
  Object.entries(result.otelAttributes).forEach(function (_a) {
112
115
  var _b;
113
116
  var key = _a[0], value = _a[1];
@@ -118,7 +121,7 @@ var eventHandlerOutputEventCreator = function (events, otelSpanHeaders, source,
118
121
  };
119
122
  exports.eventHandlerOutputEventCreator = eventHandlerOutputEventCreator;
120
123
  var createHandlerErrorOutputEvent = function (error, otelSpanHeaders, type, source, originalEvent, handlerExectionUnits, factory) {
121
- var _a, _b, _c, _d;
124
+ var _a, _b, _c, _d, _e;
122
125
  (0, arvo_core_1.exceptionToSpan)(error);
123
126
  (_a = api_1.trace.getActiveSpan()) === null || _a === void 0 ? void 0 : _a.setStatus({
124
127
  code: api_1.SpanStatusCode.ERROR,
@@ -137,6 +140,7 @@ var createHandlerErrorOutputEvent = function (error, otelSpanHeaders, type, sour
137
140
  errorMessage: error.message,
138
141
  errorStack: (_d = error.stack) !== null && _d !== void 0 ? _d : null,
139
142
  },
143
+ accesscontrol: (_e = originalEvent.accesscontrol) !== null && _e !== void 0 ? _e : undefined
140
144
  });
141
145
  Object.entries(result.otelAttributes).forEach(function (_a) {
142
146
  var _b;
@@ -146,3 +150,20 @@ var createHandlerErrorOutputEvent = function (error, otelSpanHeaders, type, sour
146
150
  return [result];
147
151
  };
148
152
  exports.createHandlerErrorOutputEvent = createHandlerErrorOutputEvent;
153
+ /**
154
+ * Validates if a string contains only uppercase or lowercase alphanumeric characters.
155
+ *
156
+ * This function checks if the input string consists solely of:
157
+ * - Lowercase letters (a-z)
158
+ * - Numbers (0-9)
159
+ * - Dot (.)
160
+ *
161
+ * It does not allow any special characters, spaces, or other non-alphanumeric characters.
162
+ *
163
+ * @param input - The string to be validated.
164
+ * @returns True if the string contains only alphanumeric characters, false otherwise.
165
+ */
166
+ function isLowerAlphanumeric(input) {
167
+ var alphanumericRegex = /^[a-z0-9.]+$/;
168
+ return alphanumericRegex.test(input);
169
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arvo-event-handler",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
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": {
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@opentelemetry/api": "^1.9.0",
52
- "arvo-core": "^1.1.0",
52
+ "arvo-core": "^1.1.10",
53
53
  "uuid": "^10.0.0",
54
54
  "zod": "^3.23.8"
55
55
  }