arvo-core 1.1.4 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -30,4 +30,51 @@ export default class ArvoEventHttp {
30
30
  * @throws {Error} If required fields are missing or if there's an error parsing the input.
31
31
  */
32
32
  static importFromStructured(config: ArvoEventHttpConfig): ArvoEvent;
33
+ /**
34
+ * Validates the content type of the HTTP request.
35
+ * @param actual - The actual content type from the request.
36
+ * @param expected - The expected content type.
37
+ * @throws {Error} If the actual content type doesn't match the expected one.
38
+ */
39
+ private static validateContentType;
40
+ /**
41
+ * Extracts event fields from the HTTP headers.
42
+ * @param headers - The HTTP headers containing event information.
43
+ * @returns An object with extracted event fields.
44
+ */
45
+ private static extractEventFieldsFromHeaders;
46
+ /**
47
+ * Creates an error message for a missing required field.
48
+ * @param type - The type of the missing field.
49
+ * @param isHeader - A flag to distinguish between headers and structured payload
50
+ * @returns A formatted error message string.
51
+ */
52
+ private static createErrorMessageForMissingField;
53
+ /**
54
+ * Validates that all required fields are present in the event data.
55
+ * @param event - The event data to validate.
56
+ * @param isHeader - A flag to distinguish between headers and structured payload
57
+ * @throws {Error} If any required field is missing.
58
+ */
59
+ private static validateRequiredFields;
60
+ /**
61
+ * Extracts extension fields from the HTTP headers.
62
+ * @param headers - The HTTP headers containing event information.
63
+ * @returns An object with extracted extension fields.
64
+ */
65
+ private static extractExtensions;
66
+ /**
67
+ * Creates an ArvoEvent instance from extracted event data, payload, and extensions.
68
+ * @param event - The extracted event data.
69
+ * @param data - The event payload.
70
+ * @param extensions - The extracted extension fields.
71
+ * @returns A new ArvoEvent instance.
72
+ */
73
+ private static createArvoEvent;
74
+ /**
75
+ * Creates an ArvoEvent instance from structured event data.
76
+ * @param eventData - The structured event data.
77
+ * @returns A new ArvoEvent instance.
78
+ */
79
+ private static createArvoEventFromStructured;
33
80
  }
@@ -87,75 +87,12 @@ var ArvoEventHttp = /** @class */ (function () {
87
87
  * @throws {Error} If required fields are missing or if there's an error parsing the input.
88
88
  */
89
89
  ArvoEventHttp.importFromBinary = function (config) {
90
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
91
- try {
92
- if (config.headers['content-type'] !== 'application/json') {
93
- throw new Error("Invalid content-type: ".concat(config.headers['content-type'], ". Expected: application/json"));
94
- }
95
- var eventFields = [
96
- 'id',
97
- 'type',
98
- 'accesscontrol',
99
- 'executionunits',
100
- 'traceparent',
101
- 'tracestate',
102
- 'datacontenttype',
103
- 'specversion',
104
- 'time',
105
- 'source',
106
- 'subject',
107
- 'to',
108
- 'redirectto',
109
- 'dataschema',
110
- ];
111
- var event_1 = {};
112
- // Extract event fields from headers
113
- for (var _i = 0, eventFields_1 = eventFields; _i < eventFields_1.length; _i++) {
114
- var field = eventFields_1[_i];
115
- var headerKey = "ce-".concat(field);
116
- if (headerKey in config.headers) {
117
- event_1[field] = config.headers[headerKey];
118
- }
119
- }
120
- // Validate required fields
121
- if (!event_1.type || !event_1.source || !event_1.subject) {
122
- throw new Error('Missing required header fields: ce-type, ce-source, or ce-subject');
123
- }
124
- // Extract extensions
125
- var prefixedEventFields_1 = eventFields.map(function (item) { return "ce-".concat(item); });
126
- var extensions = Object.entries(config.headers)
127
- .filter(function (_a) {
128
- var key = _a[0];
129
- return key.startsWith('ce-') && !prefixedEventFields_1.includes(key);
130
- })
131
- .reduce(function (acc, _a) {
132
- var key = _a[0], value = _a[1];
133
- acc[key.slice(3)] = value;
134
- return acc;
135
- }, {});
136
- // Create and return ArvoEvent
137
- return new ArvoEvent_1.default({
138
- id: (_a = event_1.id) !== null && _a !== void 0 ? _a : (0, uuid_1.v4)(),
139
- type: event_1.type,
140
- accesscontrol: (_b = event_1.accesscontrol) !== null && _b !== void 0 ? _b : null,
141
- executionunits: event_1.executionunits
142
- ? Number(event_1.executionunits)
143
- : null,
144
- traceparent: (_c = event_1.traceparent) !== null && _c !== void 0 ? _c : null,
145
- tracestate: (_d = event_1.tracestate) !== null && _d !== void 0 ? _d : null,
146
- datacontenttype: (_e = event_1.datacontenttype) !== null && _e !== void 0 ? _e : schema_1.ArvoDataContentType,
147
- specversion: (_f = event_1.specversion) !== null && _f !== void 0 ? _f : '1.0',
148
- time: (_g = event_1.time) !== null && _g !== void 0 ? _g : (0, utils_1.createTimestamp)(),
149
- source: event_1.source,
150
- subject: event_1.subject,
151
- to: (_h = event_1.to) !== null && _h !== void 0 ? _h : null,
152
- redirectto: (_j = event_1.redirectto) !== null && _j !== void 0 ? _j : null,
153
- dataschema: (_k = event_1.dataschema) !== null && _k !== void 0 ? _k : null,
154
- }, config.data, extensions);
155
- }
156
- catch (error) {
157
- throw new Error("Failed to import ArvoEvent from binary: ".concat(error.message));
158
- }
90
+ var _a, _b;
91
+ this.validateContentType((_b = (_a = config.headers['content-type']) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "", 'application/json');
92
+ var event = this.extractEventFieldsFromHeaders(config.headers);
93
+ this.validateRequiredFields(event, true);
94
+ var extensions = this.extractExtensions(config.headers);
95
+ return this.createArvoEvent(event, config.data, extensions);
159
96
  };
160
97
  /**
161
98
  * Imports an ArvoEvent from a structured-mode HTTP representation.
@@ -164,35 +101,132 @@ var ArvoEventHttp = /** @class */ (function () {
164
101
  * @throws {Error} If required fields are missing or if there's an error parsing the input.
165
102
  */
166
103
  ArvoEventHttp.importFromStructured = function (config) {
167
- try {
168
- if (config.headers['content-type'] !== schema_1.ArvoDataContentType) {
169
- throw new Error("Invalid content-type: ".concat(config.headers['content-type'], ". Expected: ").concat(schema_1.ArvoDataContentType));
170
- }
171
- var eventData = config.data;
172
- if (!eventData.type || !eventData.source || !eventData.subject) {
173
- throw new Error('Missing required fields: type, source, or subject');
174
- }
175
- var id = eventData.id, type = eventData.type, source = eventData.source, subject = eventData.subject, time = eventData.time, datacontenttype = eventData.datacontenttype, specversion = eventData.specversion, dataschema = eventData.dataschema, data = eventData.data, to = eventData.to, accesscontrol = eventData.accesscontrol, redirectto = eventData.redirectto, executionunits = eventData.executionunits, traceparent = eventData.traceparent, tracestate = eventData.tracestate, extensions = __rest(eventData, ["id", "type", "source", "subject", "time", "datacontenttype", "specversion", "dataschema", "data", "to", "accesscontrol", "redirectto", "executionunits", "traceparent", "tracestate"]);
176
- return new ArvoEvent_1.default({
177
- id: id !== null && id !== void 0 ? id : (0, uuid_1.v4)(),
178
- type: type,
179
- source: source,
180
- subject: subject,
181
- time: time !== null && time !== void 0 ? time : (0, utils_1.createTimestamp)(),
182
- datacontenttype: datacontenttype !== null && datacontenttype !== void 0 ? datacontenttype : schema_1.ArvoDataContentType,
183
- specversion: specversion !== null && specversion !== void 0 ? specversion : '1.0',
184
- dataschema: dataschema !== null && dataschema !== void 0 ? dataschema : null,
185
- to: to !== null && to !== void 0 ? to : null,
186
- accesscontrol: accesscontrol !== null && accesscontrol !== void 0 ? accesscontrol : null,
187
- redirectto: redirectto !== null && redirectto !== void 0 ? redirectto : null,
188
- executionunits: executionunits ? Number(executionunits) : null,
189
- traceparent: traceparent !== null && traceparent !== void 0 ? traceparent : null,
190
- tracestate: tracestate !== null && tracestate !== void 0 ? tracestate : null,
191
- }, data !== null && data !== void 0 ? data : {}, extensions);
104
+ var _a, _b;
105
+ this.validateContentType((_b = (_a = config.headers['content-type']) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "", schema_1.ArvoDataContentType);
106
+ var eventData = config.data;
107
+ this.validateRequiredFields(eventData, false);
108
+ return this.createArvoEventFromStructured(eventData);
109
+ };
110
+ /**
111
+ * Validates the content type of the HTTP request.
112
+ * @param actual - The actual content type from the request.
113
+ * @param expected - The expected content type.
114
+ * @throws {Error} If the actual content type doesn't match the expected one.
115
+ */
116
+ ArvoEventHttp.validateContentType = function (actual, expected) {
117
+ if (actual !== expected) {
118
+ throw new Error("Invalid content-type: ".concat(actual, ". Expected: ").concat(expected));
192
119
  }
193
- catch (error) {
194
- throw new Error("Failed to import ArvoEvent from structured: ".concat(error.message));
120
+ };
121
+ /**
122
+ * Extracts event fields from the HTTP headers.
123
+ * @param headers - The HTTP headers containing event information.
124
+ * @returns An object with extracted event fields.
125
+ */
126
+ ArvoEventHttp.extractEventFieldsFromHeaders = function (headers) {
127
+ var eventFields = ['id', 'type', 'accesscontrol', 'executionunits', 'traceparent', 'tracestate', 'datacontenttype', 'specversion', 'time', 'source', 'subject', 'to', 'redirectto', 'dataschema'];
128
+ return Object.fromEntries(eventFields
129
+ .map(function (field) { return ["ce-".concat(field), headers["ce-".concat(field)]]; })
130
+ .filter(function (_a) {
131
+ var value = _a[1];
132
+ return value !== undefined;
133
+ })
134
+ .map(function (_a) {
135
+ var key = _a[0], value = _a[1];
136
+ return [key.slice(3), value];
137
+ }));
138
+ };
139
+ /**
140
+ * Creates an error message for a missing required field.
141
+ * @param type - The type of the missing field.
142
+ * @param isHeader - A flag to distinguish between headers and structured payload
143
+ * @returns A formatted error message string.
144
+ */
145
+ ArvoEventHttp.createErrorMessageForMissingField = function (type, isHeader) {
146
+ if (isHeader) {
147
+ return "Missing required header field(s): ".concat(type);
195
148
  }
149
+ return "Missing required field(s): ".concat(type);
150
+ };
151
+ /**
152
+ * Validates that all required fields are present in the event data.
153
+ * @param event - The event data to validate.
154
+ * @param isHeader - A flag to distinguish between headers and structured payload
155
+ * @throws {Error} If any required field is missing.
156
+ */
157
+ ArvoEventHttp.validateRequiredFields = function (event, isHeader) {
158
+ ['type', 'source', 'subject'].forEach(function (field) {
159
+ if (!event[field]) {
160
+ throw new Error(ArvoEventHttp.createErrorMessageForMissingField(isHeader ? "ce-".concat(field) : field, isHeader));
161
+ }
162
+ });
163
+ };
164
+ /**
165
+ * Extracts extension fields from the HTTP headers.
166
+ * @param headers - The HTTP headers containing event information.
167
+ * @returns An object with extracted extension fields.
168
+ */
169
+ ArvoEventHttp.extractExtensions = function (headers) {
170
+ var eventFields = ['id', 'type', 'accesscontrol', 'executionunits', 'traceparent', 'tracestate', 'datacontenttype', 'specversion', 'time', 'source', 'subject', 'to', 'redirectto', 'dataschema'];
171
+ return Object.fromEntries(Object.entries(headers)
172
+ .filter(function (_a) {
173
+ var key = _a[0];
174
+ return key.startsWith('ce-') && !eventFields.includes(key.slice(3));
175
+ })
176
+ .map(function (_a) {
177
+ var key = _a[0], value = _a[1];
178
+ return [key.slice(3), value];
179
+ }));
180
+ };
181
+ /**
182
+ * Creates an ArvoEvent instance from extracted event data, payload, and extensions.
183
+ * @param event - The extracted event data.
184
+ * @param data - The event payload.
185
+ * @param extensions - The extracted extension fields.
186
+ * @returns A new ArvoEvent instance.
187
+ */
188
+ ArvoEventHttp.createArvoEvent = function (event, data, extensions) {
189
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
190
+ return new ArvoEvent_1.default({
191
+ id: (_a = event.id) !== null && _a !== void 0 ? _a : (0, uuid_1.v4)(),
192
+ type: event.type,
193
+ accesscontrol: (_b = event.accesscontrol) !== null && _b !== void 0 ? _b : null,
194
+ executionunits: event.executionunits ? Number(event.executionunits) : null,
195
+ traceparent: (_c = event.traceparent) !== null && _c !== void 0 ? _c : null,
196
+ tracestate: (_d = event.tracestate) !== null && _d !== void 0 ? _d : null,
197
+ datacontenttype: (_e = event.datacontenttype) !== null && _e !== void 0 ? _e : schema_1.ArvoDataContentType,
198
+ specversion: (_f = event.specversion) !== null && _f !== void 0 ? _f : '1.0',
199
+ time: (_g = event.time) !== null && _g !== void 0 ? _g : (0, utils_1.createTimestamp)(),
200
+ source: event.source,
201
+ subject: event.subject,
202
+ to: (_h = event.to) !== null && _h !== void 0 ? _h : null,
203
+ redirectto: (_j = event.redirectto) !== null && _j !== void 0 ? _j : null,
204
+ dataschema: (_k = event.dataschema) !== null && _k !== void 0 ? _k : null,
205
+ }, data, extensions);
206
+ };
207
+ /**
208
+ * Creates an ArvoEvent instance from structured event data.
209
+ * @param eventData - The structured event data.
210
+ * @returns A new ArvoEvent instance.
211
+ */
212
+ ArvoEventHttp.createArvoEventFromStructured = function (eventData) {
213
+ var id = eventData.id, type = eventData.type, source = eventData.source, subject = eventData.subject, time = eventData.time, datacontenttype = eventData.datacontenttype, specversion = eventData.specversion, dataschema = eventData.dataschema, data = eventData.data, to = eventData.to, accesscontrol = eventData.accesscontrol, redirectto = eventData.redirectto, executionunits = eventData.executionunits, traceparent = eventData.traceparent, tracestate = eventData.tracestate, extensions = __rest(eventData, ["id", "type", "source", "subject", "time", "datacontenttype", "specversion", "dataschema", "data", "to", "accesscontrol", "redirectto", "executionunits", "traceparent", "tracestate"]);
214
+ return ArvoEventHttp.createArvoEvent({
215
+ id: id !== null && id !== void 0 ? id : (0, uuid_1.v4)(),
216
+ type: type,
217
+ source: source,
218
+ subject: subject,
219
+ time: time !== null && time !== void 0 ? time : (0, utils_1.createTimestamp)(),
220
+ datacontenttype: datacontenttype !== null && datacontenttype !== void 0 ? datacontenttype : schema_1.ArvoDataContentType,
221
+ specversion: specversion !== null && specversion !== void 0 ? specversion : '1.0',
222
+ dataschema: dataschema !== null && dataschema !== void 0 ? dataschema : null,
223
+ to: to !== null && to !== void 0 ? to : null,
224
+ accesscontrol: accesscontrol !== null && accesscontrol !== void 0 ? accesscontrol : null,
225
+ redirectto: redirectto !== null && redirectto !== void 0 ? redirectto : null,
226
+ executionunits: executionunits ? Number(executionunits) : null,
227
+ traceparent: traceparent !== null && traceparent !== void 0 ? traceparent : null,
228
+ tracestate: tracestate !== null && tracestate !== void 0 ? tracestate : null,
229
+ }, data !== null && data !== void 0 ? data : {}, extensions);
196
230
  };
197
231
  return ArvoEventHttp;
198
232
  }());
package/dist/types.d.ts CHANGED
@@ -62,13 +62,21 @@ type InferZodSchema<T> = T extends z.ZodTypeAny ? z.infer<T> : never;
62
62
  * // MyContractType will have properties uri, accepts, and emits
63
63
  */
64
64
  export type InferArvoContract<T extends ArvoContract<string, string, z.ZodTypeAny, Record<string, z.ZodTypeAny>>> = T extends ArvoContract<infer TUri, infer TType, infer TAcceptSchema, infer TEmits> ? {
65
+ /** The URI of the contract */
65
66
  uri: TUri;
67
+ /** The event type that this contract accepts */
66
68
  accepts: InferArvoEvent<ArvoEvent<InferZodSchema<TAcceptSchema>, {}, TType>>;
69
+ /** The event types that this contract can emit */
67
70
  emits: {
68
71
  [K in keyof TEmits]: InferArvoEvent<ArvoEvent<InferZodSchema<TEmits[K]>, {}, K & string>>;
69
- } & {
70
- [K in `sys.${TType}.error`]: InferArvoEvent<ArvoEvent<InferZodSchema<T['systemError']['schema']>, {}, T['systemError']['type']>>;
71
72
  };
73
+ /** The system error event type for this contract */
72
74
  systemError: InferArvoEvent<ArvoEvent<InferZodSchema<T['systemError']['schema']>, {}, T['systemError']['type']>>;
75
+ /** Union type of all emittable events, including regular events and system error */
76
+ emittableEvents: ({
77
+ [K in keyof TEmits]: InferArvoEvent<ArvoEvent<InferZodSchema<TEmits[K]>, {}, K & string>>;
78
+ } & {
79
+ [K in `sys.${TType}.error`]: InferArvoEvent<ArvoEvent<InferZodSchema<T['systemError']['schema']>, {}, T['systemError']['type']>>;
80
+ })[keyof TEmits | `sys.${TType}.error`];
73
81
  } : never;
74
82
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arvo-core",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "This core package contains all the core classes and components of the Arvo Event Driven System",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {