wsp-ms-core 1.0.7 → 1.0.8-7.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/dist/index.cjs +1525 -179
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +680 -0
- package/dist/index.d.ts +444 -65
- package/dist/index.js +1496 -179
- package/dist/index.js.map +1 -1
- package/package.json +17 -28
- package/dist/index.d.cts +0 -301
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __export = (target, all) => {
|
|
6
8
|
for (var name in all)
|
|
@@ -14,26 +16,53 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
14
16
|
}
|
|
15
17
|
return to;
|
|
16
18
|
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
17
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
28
|
|
|
19
29
|
// src/index.ts
|
|
20
30
|
var src_exports = {};
|
|
21
31
|
__export(src_exports, {
|
|
32
|
+
BaseEvent: () => BaseEvent,
|
|
33
|
+
BaseObject: () => BaseObject,
|
|
34
|
+
BasicUnitOfWork: () => BasicUnitOfWork,
|
|
35
|
+
BasicUnitOfWorkFactory: () => BasicUnitOfWorkFactory,
|
|
36
|
+
Country: () => Country,
|
|
22
37
|
Currency: () => Currency,
|
|
23
38
|
DateTime: () => DateTime,
|
|
39
|
+
DefaultMysqlInboxRunner: () => DefaultMysqlInboxRunner,
|
|
40
|
+
DefaultMysqlOutboxRunner: () => DefaultMysqlOutboxRunner,
|
|
24
41
|
DomainEntity: () => DomainEntity,
|
|
25
42
|
DomainError: () => DomainError,
|
|
26
43
|
DomainEvent: () => DomainEvent,
|
|
27
44
|
Email: () => Email,
|
|
28
45
|
ErrorManager: () => ErrorManager,
|
|
46
|
+
EventBus: () => EventBus,
|
|
47
|
+
EventBusMysqlRepository: () => EventBusMysqlRepository,
|
|
48
|
+
EventManager: () => EventManager,
|
|
49
|
+
ExchangeRates: () => ExchangeRates,
|
|
29
50
|
FatalError: () => FatalError,
|
|
30
51
|
HttpHealthCheckController: () => HttpHealthCheckController,
|
|
31
52
|
HttpNotFoundController: () => HttpNotFoundController,
|
|
53
|
+
InboxRecord: () => InboxRecord,
|
|
54
|
+
IntegrationEvent: () => IntegrationEvent,
|
|
32
55
|
InternalError: () => InternalError,
|
|
56
|
+
KafkaManager: () => KafkaManager,
|
|
33
57
|
Language: () => Language,
|
|
34
58
|
MysqlConnection: () => MysqlConnection,
|
|
35
59
|
MysqlConnector: () => MysqlConnector,
|
|
60
|
+
OutboxRecord: () => OutboxRecord,
|
|
61
|
+
PaymentGateway: () => PaymentGateway,
|
|
62
|
+
PaymentStatus: () => PaymentStatus,
|
|
36
63
|
Price: () => Price,
|
|
64
|
+
ProcessStatus: () => ProcessStatus,
|
|
65
|
+
StringVars: () => StringVars,
|
|
37
66
|
UUID: () => UUID,
|
|
38
67
|
UsageError: () => UsageError,
|
|
39
68
|
ValueObject: () => ValueObject,
|
|
@@ -51,6 +80,9 @@ var ValueObject = class {
|
|
|
51
80
|
this.validate(value);
|
|
52
81
|
this._value = Object.freeze(value);
|
|
53
82
|
}
|
|
83
|
+
toProps() {
|
|
84
|
+
return this._value;
|
|
85
|
+
}
|
|
54
86
|
get value() {
|
|
55
87
|
return this._value;
|
|
56
88
|
}
|
|
@@ -144,6 +176,21 @@ var _DateTime = class _DateTime extends ValueObject {
|
|
|
144
176
|
getWeekdayName(locale = "en") {
|
|
145
177
|
return this._dt.setLocale(locale).toFormat("cccc");
|
|
146
178
|
}
|
|
179
|
+
getDayName(locale = "en") {
|
|
180
|
+
return this._dt.setLocale(locale).toFormat("EEEE");
|
|
181
|
+
}
|
|
182
|
+
format(format) {
|
|
183
|
+
if (!_DateTime.FORMATS.hasOwnProperty(format)) {
|
|
184
|
+
throw new Error(`Invalid format: ${format}`);
|
|
185
|
+
}
|
|
186
|
+
const formatString = _DateTime.FORMATS[format];
|
|
187
|
+
return this._dt.toFormat(formatString);
|
|
188
|
+
}
|
|
189
|
+
toPrimitives() {
|
|
190
|
+
return {
|
|
191
|
+
value: this.value
|
|
192
|
+
};
|
|
193
|
+
}
|
|
147
194
|
static create(input) {
|
|
148
195
|
if (input === void 0) {
|
|
149
196
|
return new _DateTime(_DateTime.toUtcFormat(import_luxon.DateTime.now()));
|
|
@@ -159,39 +206,106 @@ var _DateTime = class _DateTime extends ValueObject {
|
|
|
159
206
|
}
|
|
160
207
|
return new _DateTime(input);
|
|
161
208
|
}
|
|
209
|
+
static now() {
|
|
210
|
+
return _DateTime.create();
|
|
211
|
+
}
|
|
162
212
|
};
|
|
163
213
|
_DateTime.DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
|
214
|
+
_DateTime.FORMAT = "Y-M-D H:M:S";
|
|
215
|
+
_DateTime.FORMAT_Y_M = "Y-M";
|
|
216
|
+
_DateTime.FORMAT_Y_M_D = "Y-M-D";
|
|
217
|
+
_DateTime.FORMAT_Y_M_D_H_m_s = "Y-M-D H:M:S";
|
|
218
|
+
_DateTime.FORMAT_D_M_Y = "D-M-Y";
|
|
219
|
+
_DateTime.FORMATS = {
|
|
220
|
+
"Y-M": "yyyy-MM",
|
|
221
|
+
"Y-M-D": "yyyy-MM-dd",
|
|
222
|
+
"D/M/Y": "dd/MM/yyyy",
|
|
223
|
+
"Y/M/D": "yyyy/MM/dd",
|
|
224
|
+
"D-M-Y": "dd-MM-yyyy",
|
|
225
|
+
"Y.M.D": "yyyy.MM.dd",
|
|
226
|
+
"D.M.Y": "dd.MM.yyyy",
|
|
227
|
+
"Y-M-D H:M": "yyyy-MM-dd HH:mm",
|
|
228
|
+
"D/M/Y H:M": "dd/MM/yyyy HH:mm",
|
|
229
|
+
"Y/M/D H:M": "yyyy/MM/dd HH:mm",
|
|
230
|
+
"D-M-Y H:M": "dd-MM-yyyy HH:mm",
|
|
231
|
+
"Y.M.D H:M": "yyyy.MM.dd HH:mm",
|
|
232
|
+
"D.M.Y H:M": "dd.MM.yyyy HH:mm",
|
|
233
|
+
"Y-M-D H:M:S": "yyyy-MM-dd HH:mm:ss",
|
|
234
|
+
"Y-M-D H:M:S:SSS": "yyyy-MM-dd HH:mm:ss.SSS",
|
|
235
|
+
"D/M/Y H:M:S": "dd/MM/yyyy HH:mm:ss",
|
|
236
|
+
"Y/M/D H:M:S": "yyyy/MM/dd HH:mm:ss",
|
|
237
|
+
"D-M-Y H:M:S": "dd-MM-yyyy HH:mm:ss",
|
|
238
|
+
"Y.M.D H:M:S": "yyyy.MM.dd HH:mm:ss",
|
|
239
|
+
"D.M.Y H:M:S": "dd.MM.yyyy HH:mm:ss",
|
|
240
|
+
"H:M": "HH:mm",
|
|
241
|
+
"H:M:S": "HH:mm:ss"
|
|
242
|
+
};
|
|
164
243
|
var DateTime = _DateTime;
|
|
165
244
|
|
|
245
|
+
// src/domain/contracts/BaseEvent.ts
|
|
246
|
+
var BaseEvent = class {
|
|
247
|
+
constructor(tenantUuid, version, type, payload) {
|
|
248
|
+
this._tenantUuid = tenantUuid;
|
|
249
|
+
this._version = version;
|
|
250
|
+
this._type = type;
|
|
251
|
+
this._payload = payload;
|
|
252
|
+
this._occurredAt = DateTime.now();
|
|
253
|
+
}
|
|
254
|
+
get tenantUuid() {
|
|
255
|
+
return this._tenantUuid;
|
|
256
|
+
}
|
|
257
|
+
get version() {
|
|
258
|
+
return this._version;
|
|
259
|
+
}
|
|
260
|
+
get type() {
|
|
261
|
+
return this._type;
|
|
262
|
+
}
|
|
263
|
+
get payload() {
|
|
264
|
+
return this._payload;
|
|
265
|
+
}
|
|
266
|
+
get ocurredAt() {
|
|
267
|
+
return this._occurredAt;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
166
271
|
// src/domain/contracts/DomainEntity.ts
|
|
167
272
|
var DomainEntity = class {
|
|
168
|
-
constructor(
|
|
169
|
-
this.
|
|
273
|
+
constructor(props) {
|
|
274
|
+
this._events = [];
|
|
170
275
|
this.props = props;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
this.
|
|
276
|
+
}
|
|
277
|
+
recordEvent(event) {
|
|
278
|
+
this._events.push(event);
|
|
174
279
|
}
|
|
175
280
|
touch() {
|
|
176
|
-
this.
|
|
281
|
+
this.props.updatedAt = DateTime.now();
|
|
282
|
+
}
|
|
283
|
+
get uuid() {
|
|
284
|
+
return this.props.uuid;
|
|
177
285
|
}
|
|
178
286
|
get createdAt() {
|
|
179
|
-
return this.
|
|
287
|
+
return this.props.createdAt;
|
|
180
288
|
}
|
|
181
289
|
get updatedAt() {
|
|
182
|
-
return this.
|
|
290
|
+
return this.props.updatedAt;
|
|
183
291
|
}
|
|
184
292
|
get deletedAt() {
|
|
185
|
-
return this.
|
|
293
|
+
return this.props.deletedAt;
|
|
186
294
|
}
|
|
187
295
|
get isDeleted() {
|
|
188
|
-
return Boolean(this.
|
|
296
|
+
return Boolean(this.props.deletedAt);
|
|
189
297
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
298
|
+
pullEvents() {
|
|
299
|
+
const events = this._events;
|
|
300
|
+
this._events = [];
|
|
301
|
+
return events;
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/domain/contracts/BaseObject.ts
|
|
306
|
+
var BaseObject = class {
|
|
307
|
+
constructor(props) {
|
|
308
|
+
this.props = props;
|
|
195
309
|
}
|
|
196
310
|
};
|
|
197
311
|
|
|
@@ -203,20 +317,6 @@ var DomainError = class extends Error {
|
|
|
203
317
|
}
|
|
204
318
|
};
|
|
205
319
|
|
|
206
|
-
// src/domain/contracts/DomainEvent.ts
|
|
207
|
-
var DomainEvent = class {
|
|
208
|
-
constructor(payload) {
|
|
209
|
-
this._payload = payload;
|
|
210
|
-
this._occurredAt = DateTime.create();
|
|
211
|
-
}
|
|
212
|
-
get payload() {
|
|
213
|
-
return this._payload;
|
|
214
|
-
}
|
|
215
|
-
get occurredAt() {
|
|
216
|
-
return this._occurredAt;
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
320
|
// src/domain/errors/FatalError.ts
|
|
221
321
|
var FatalError = class extends DomainError {
|
|
222
322
|
constructor(type, message = "") {
|
|
@@ -239,6 +339,424 @@ var UsageError = class extends DomainError {
|
|
|
239
339
|
}
|
|
240
340
|
};
|
|
241
341
|
|
|
342
|
+
// src/domain/events/DomainEvent.ts
|
|
343
|
+
var DomainEvent = class extends BaseEvent {
|
|
344
|
+
constructor(tenantUuid, version, type, payload, aggregateUuid, aggregateType) {
|
|
345
|
+
super(tenantUuid, version, type, payload);
|
|
346
|
+
this._aggregateUuid = aggregateUuid;
|
|
347
|
+
this._aggregateType = aggregateType;
|
|
348
|
+
}
|
|
349
|
+
get aggregateUuid() {
|
|
350
|
+
return this._aggregateUuid;
|
|
351
|
+
}
|
|
352
|
+
get aggregateType() {
|
|
353
|
+
return this._aggregateType;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
// src/domain/value-objects/payments/PaymentGateway.ts
|
|
358
|
+
var _PaymentGateway = class _PaymentGateway extends ValueObject {
|
|
359
|
+
constructor(gateway) {
|
|
360
|
+
super(gateway);
|
|
361
|
+
}
|
|
362
|
+
validate(value) {
|
|
363
|
+
if (!_PaymentGateway.SUPPORTED.includes(value)) {
|
|
364
|
+
throw new InternalError(`Payment gateway <${value}> is not supported`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
isExternal() {
|
|
368
|
+
return _PaymentGateway.EXTERNALS.includes(this.value);
|
|
369
|
+
}
|
|
370
|
+
get isMercadoPago() {
|
|
371
|
+
return this.equals(_PaymentGateway.MERCADOPAGO);
|
|
372
|
+
}
|
|
373
|
+
get isHandy() {
|
|
374
|
+
return this.equals(_PaymentGateway.HANDY);
|
|
375
|
+
}
|
|
376
|
+
get isWonaDebit() {
|
|
377
|
+
return this.equals(_PaymentGateway.WONA_DEBIT);
|
|
378
|
+
}
|
|
379
|
+
get isWonaCard() {
|
|
380
|
+
return this.equals(_PaymentGateway.WONA_CARD);
|
|
381
|
+
}
|
|
382
|
+
get isWonaCash() {
|
|
383
|
+
return this.equals(_PaymentGateway.WONA_CASH);
|
|
384
|
+
}
|
|
385
|
+
get isWonaTransfer() {
|
|
386
|
+
return this.equals(_PaymentGateway.WONA_TRANSFER);
|
|
387
|
+
}
|
|
388
|
+
get isWonaMercadoPago() {
|
|
389
|
+
return this.equals(_PaymentGateway.WONA_MERCADOPAGO);
|
|
390
|
+
}
|
|
391
|
+
toPrimitives() {
|
|
392
|
+
return { value: this.value };
|
|
393
|
+
}
|
|
394
|
+
static create(gateway) {
|
|
395
|
+
return new _PaymentGateway(gateway.trim().toUpperCase());
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
_PaymentGateway.SUPPORTED = [
|
|
399
|
+
"MERCADOPAGO",
|
|
400
|
+
"HANDY",
|
|
401
|
+
"WONA_DEBIT",
|
|
402
|
+
"WONA_CARD",
|
|
403
|
+
"WONA_CASH",
|
|
404
|
+
"WONA_TRANSFER",
|
|
405
|
+
"WONA_MERCADOPAGO"
|
|
406
|
+
];
|
|
407
|
+
_PaymentGateway.EXTERNALS = ["MERCADOPAGO", "STRIPE"];
|
|
408
|
+
_PaymentGateway.MERCADOPAGO = new _PaymentGateway("MERCADOPAGO");
|
|
409
|
+
_PaymentGateway.HANDY = new _PaymentGateway("HANDY");
|
|
410
|
+
_PaymentGateway.WONA_DEBIT = new _PaymentGateway("WONA_DEBIT");
|
|
411
|
+
_PaymentGateway.WONA_CARD = new _PaymentGateway("WONA_CARD");
|
|
412
|
+
_PaymentGateway.WONA_CASH = new _PaymentGateway("WONA_CASH");
|
|
413
|
+
_PaymentGateway.WONA_TRANSFER = new _PaymentGateway("WONA_TRANSFER");
|
|
414
|
+
_PaymentGateway.WONA_MERCADOPAGO = new _PaymentGateway("WONA_MERCADOPAGO");
|
|
415
|
+
var PaymentGateway = _PaymentGateway;
|
|
416
|
+
|
|
417
|
+
// src/domain/value-objects/payments/PaymentStatus.ts
|
|
418
|
+
var _PaymentStatus = class _PaymentStatus extends ValueObject {
|
|
419
|
+
constructor(status) {
|
|
420
|
+
super(status);
|
|
421
|
+
}
|
|
422
|
+
validate(status) {
|
|
423
|
+
if (!_PaymentStatus.SUPPORTED.includes(status)) {
|
|
424
|
+
throw new InternalError(`Payment status <${status}> is not supported`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
get isDone() {
|
|
428
|
+
return this.value === "DONE";
|
|
429
|
+
}
|
|
430
|
+
get isPending() {
|
|
431
|
+
return this.value === "PENDING";
|
|
432
|
+
}
|
|
433
|
+
get isInProgress() {
|
|
434
|
+
return this.value === "IN_PROGRESS";
|
|
435
|
+
}
|
|
436
|
+
get isFailed() {
|
|
437
|
+
return this.value === "FAILED";
|
|
438
|
+
}
|
|
439
|
+
get isCanceled() {
|
|
440
|
+
return this.value === "CANCELED";
|
|
441
|
+
}
|
|
442
|
+
get isHold() {
|
|
443
|
+
return this.value === "HOLD";
|
|
444
|
+
}
|
|
445
|
+
get isPendingRefund() {
|
|
446
|
+
return this.value === "PENDING_REFUND";
|
|
447
|
+
}
|
|
448
|
+
get isRefunded() {
|
|
449
|
+
return this.value === "REFUNDED";
|
|
450
|
+
}
|
|
451
|
+
toPrimitives() {
|
|
452
|
+
return { value: this.value };
|
|
453
|
+
}
|
|
454
|
+
static create(gateway) {
|
|
455
|
+
return new _PaymentStatus(gateway.trim().toUpperCase());
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
_PaymentStatus.SUPPORTED = ["DONE", "PENDING", "FAILED", "CANCELED", "HOLD", "PENDING_REFUND", "REFUNDED", "IN_PROGRESS"];
|
|
459
|
+
_PaymentStatus.DONE = new _PaymentStatus("DONE");
|
|
460
|
+
_PaymentStatus.PENDING = new _PaymentStatus("PENDING");
|
|
461
|
+
_PaymentStatus.IN_PROGRESS = new _PaymentStatus("IN_PROGRESS");
|
|
462
|
+
_PaymentStatus.FAILED = new _PaymentStatus("FAILED");
|
|
463
|
+
_PaymentStatus.CANCELED = new _PaymentStatus("CANCELED");
|
|
464
|
+
_PaymentStatus.HOLD = new _PaymentStatus("HOLD");
|
|
465
|
+
_PaymentStatus.PENDING_REFUND = new _PaymentStatus("PENDING_REFUND");
|
|
466
|
+
_PaymentStatus.REFUNDED = new _PaymentStatus("REFUNDED");
|
|
467
|
+
var PaymentStatus = _PaymentStatus;
|
|
468
|
+
|
|
469
|
+
// src/utils/StringVars.ts
|
|
470
|
+
var StringVars = class {
|
|
471
|
+
static parse(str, ob) {
|
|
472
|
+
const regex = /{{(.*?)}}/g;
|
|
473
|
+
return str.replace(regex, (match, variable) => {
|
|
474
|
+
if (ob.hasOwnProperty(variable.trim())) {
|
|
475
|
+
return ob[variable.trim()];
|
|
476
|
+
} else {
|
|
477
|
+
return match;
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// src/infrastructure/errors/ErrorManager.ts
|
|
484
|
+
var _ErrorManager = class _ErrorManager {
|
|
485
|
+
constructor(logger = null) {
|
|
486
|
+
this.logger = logger;
|
|
487
|
+
}
|
|
488
|
+
getDefaultMessage(lang) {
|
|
489
|
+
return _ErrorManager.DEFAULT_MESSAGES[lang.value] || _ErrorManager.DEFAULT_MESSAGES[lang.base()] || "error";
|
|
490
|
+
}
|
|
491
|
+
onFatal(err, lang) {
|
|
492
|
+
this.logger?.fatal(err.type, err.message);
|
|
493
|
+
return { status: "ERROR", message: this.getDefaultMessage(lang) };
|
|
494
|
+
}
|
|
495
|
+
onInternal(err, lang) {
|
|
496
|
+
this.logger?.error(err.type, err.message);
|
|
497
|
+
return { status: "ERROR", message: this.getDefaultMessage(lang) };
|
|
498
|
+
}
|
|
499
|
+
onUsage(err, lang) {
|
|
500
|
+
const tmpl = _ErrorManager.TEMPLATES.get(err.type);
|
|
501
|
+
if (!tmpl) {
|
|
502
|
+
this.logger?.error("TEMPLATE_NOT_FOUND", `${err.type}`);
|
|
503
|
+
return { status: "ERROR", message: this.getDefaultMessage(lang) };
|
|
504
|
+
}
|
|
505
|
+
const code = lang.value;
|
|
506
|
+
const base = lang.base();
|
|
507
|
+
const rawMsg = tmpl.languages[code] ?? tmpl.languages[base] ?? this.getDefaultMessage(lang);
|
|
508
|
+
return {
|
|
509
|
+
status: 400,
|
|
510
|
+
message: StringVars.parse(rawMsg, err.vars)
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
onUnknown(err, lang) {
|
|
514
|
+
this.logger?.error("UNKNOWN_ERROR", err.message);
|
|
515
|
+
return { status: "ERROR", message: this.getDefaultMessage(lang) };
|
|
516
|
+
}
|
|
517
|
+
handle(err, lang) {
|
|
518
|
+
if (["local", "dev"].includes(process.env.ENVIRONMENT ?? "")) {
|
|
519
|
+
console.log(err);
|
|
520
|
+
}
|
|
521
|
+
if (err instanceof FatalError) {
|
|
522
|
+
return this.onFatal(err, lang);
|
|
523
|
+
}
|
|
524
|
+
if (err instanceof InternalError) {
|
|
525
|
+
return this.onInternal(err, lang);
|
|
526
|
+
}
|
|
527
|
+
if (err instanceof UsageError) {
|
|
528
|
+
return this.onUsage(err, lang);
|
|
529
|
+
}
|
|
530
|
+
return this.onUnknown(err, lang);
|
|
531
|
+
}
|
|
532
|
+
static addTemplate(template) {
|
|
533
|
+
_ErrorManager.TEMPLATES.set(template.type, template);
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
_ErrorManager.DEFAULT_MESSAGES = {
|
|
537
|
+
"es": "Ups, hemos encontrado un error. Nuestro equipo ya est\xE1 trabajando para solucionarlo",
|
|
538
|
+
"en": "Ups, we found an error. Our team is working on it.",
|
|
539
|
+
"pt": "Ops, encontramos um bug. Nossa equipe j\xE1 est\xE1 trabalhando para resolver isso."
|
|
540
|
+
};
|
|
541
|
+
_ErrorManager.APP_ERRORS = {
|
|
542
|
+
UNDEFINED: "UNDEFINED_ERROR",
|
|
543
|
+
PROCESS: "PROCESS_ERROR",
|
|
544
|
+
DATABASE: "DATABASE_ERROR"
|
|
545
|
+
};
|
|
546
|
+
_ErrorManager.TEMPLATES = /* @__PURE__ */ new Map();
|
|
547
|
+
var ErrorManager = _ErrorManager;
|
|
548
|
+
|
|
549
|
+
// src/domain/value-objects/Country.ts
|
|
550
|
+
ErrorManager.addTemplate({
|
|
551
|
+
type: "INVALID_COUNTRY",
|
|
552
|
+
languages: {
|
|
553
|
+
"es": "El pa\xEDs <{{country}}> no es v\xE1lido o no est\xE1 soportado",
|
|
554
|
+
"en": "Country <{{country}}> is not valid or not supported"
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
ErrorManager.addTemplate({
|
|
558
|
+
type: "COUNTRY_NOT_FOUND_BY_ALPHA2",
|
|
559
|
+
languages: {
|
|
560
|
+
"es": "No se encontr\xF3 pa\xEDs con c\xF3digo alpha2 <{{alpha2}}>",
|
|
561
|
+
"en": "Country not found with alpha2 code <{{alpha2}}>"
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
ErrorManager.addTemplate({
|
|
565
|
+
type: "COUNTRY_NOT_FOUND_BY_UUID",
|
|
566
|
+
languages: {
|
|
567
|
+
"es": "No se encontr\xF3 pa\xEDs con UUID <{{uuid}}>",
|
|
568
|
+
"en": "Country not found with UUID <{{uuid}}>"
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
var _Country = class _Country extends ValueObject {
|
|
572
|
+
constructor(country) {
|
|
573
|
+
const normalizedCountry = country.toUpperCase().trim();
|
|
574
|
+
super(normalizedCountry);
|
|
575
|
+
this._name = normalizedCountry;
|
|
576
|
+
this._alpha2 = _Country.COUNTRIES[normalizedCountry].alpha2;
|
|
577
|
+
this._alpha3 = _Country.COUNTRIES[normalizedCountry].alpha3;
|
|
578
|
+
this._numeric = _Country.COUNTRIES[normalizedCountry].numeric;
|
|
579
|
+
this._uuid = _Country.COUNTRIES[normalizedCountry].uuid;
|
|
580
|
+
this._phoneCode = _Country.COUNTRIES[normalizedCountry].phoneCode;
|
|
581
|
+
this._url = _Country.COUNTRIES[normalizedCountry].url;
|
|
582
|
+
}
|
|
583
|
+
validate(country) {
|
|
584
|
+
if (!_Country.NAMES.includes(country)) {
|
|
585
|
+
throw new UsageError("INVALID_COUNTRY", { country });
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
name() {
|
|
589
|
+
return this._name;
|
|
590
|
+
}
|
|
591
|
+
alpha2() {
|
|
592
|
+
return this._alpha2;
|
|
593
|
+
}
|
|
594
|
+
alpha3() {
|
|
595
|
+
return this._alpha3;
|
|
596
|
+
}
|
|
597
|
+
numeric() {
|
|
598
|
+
return this._numeric;
|
|
599
|
+
}
|
|
600
|
+
uuid() {
|
|
601
|
+
return this._uuid;
|
|
602
|
+
}
|
|
603
|
+
phoneCode() {
|
|
604
|
+
return this._phoneCode;
|
|
605
|
+
}
|
|
606
|
+
url() {
|
|
607
|
+
return this._url;
|
|
608
|
+
}
|
|
609
|
+
static findCountryByAlpha2(alpha2) {
|
|
610
|
+
for (const [country, codes] of Object.entries(_Country.COUNTRIES)) {
|
|
611
|
+
if (codes.alpha2 === alpha2.toUpperCase()) {
|
|
612
|
+
return new _Country(country);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
throw new UsageError("COUNTRY_NOT_FOUND_BY_ALPHA2", { alpha2 });
|
|
616
|
+
}
|
|
617
|
+
static findCountryByUUID(uuid) {
|
|
618
|
+
for (const [country, codes] of Object.entries(_Country.COUNTRIES)) {
|
|
619
|
+
if (codes.uuid === uuid) {
|
|
620
|
+
return new _Country(country);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
throw new UsageError("COUNTRY_NOT_FOUND_BY_UUID", { uuid });
|
|
624
|
+
}
|
|
625
|
+
static create(country) {
|
|
626
|
+
return new _Country(country);
|
|
627
|
+
}
|
|
628
|
+
static createOrDefault(country) {
|
|
629
|
+
try {
|
|
630
|
+
return new _Country(country);
|
|
631
|
+
} catch (error) {
|
|
632
|
+
return _Country.DEFAULT;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
toPrimitives() {
|
|
636
|
+
return {
|
|
637
|
+
value: this.value,
|
|
638
|
+
name: this._name,
|
|
639
|
+
alpha2: this._alpha2,
|
|
640
|
+
alpha3: this._alpha3,
|
|
641
|
+
numeric: this._numeric,
|
|
642
|
+
uuid: this._uuid,
|
|
643
|
+
phoneCode: this._phoneCode,
|
|
644
|
+
url: this._url
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
static isValid(country) {
|
|
648
|
+
try {
|
|
649
|
+
_Country.create(country);
|
|
650
|
+
return true;
|
|
651
|
+
} catch {
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
_Country.COUNTRIES = {
|
|
657
|
+
URUGUAY: {
|
|
658
|
+
alpha2: "UY",
|
|
659
|
+
alpha3: "URY",
|
|
660
|
+
numeric: "858",
|
|
661
|
+
phoneCode: "+598",
|
|
662
|
+
uuid: "5739ecc0-d12b-4db5-8897-e03a04a95c72",
|
|
663
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/uruguay.png"
|
|
664
|
+
},
|
|
665
|
+
ARGENTINA: {
|
|
666
|
+
alpha2: "AR",
|
|
667
|
+
alpha3: "ARG",
|
|
668
|
+
numeric: "032",
|
|
669
|
+
phoneCode: "+54",
|
|
670
|
+
uuid: "66663efe-ab7a-4166-b971-9f36fd0ea6b2",
|
|
671
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/argentina.png"
|
|
672
|
+
},
|
|
673
|
+
ECUADOR: {
|
|
674
|
+
alpha2: "EC",
|
|
675
|
+
alpha3: "ECU",
|
|
676
|
+
numeric: "218",
|
|
677
|
+
phoneCode: "+593",
|
|
678
|
+
uuid: "ee109239-0150-4e5f-9ff2-a85f270092b1",
|
|
679
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/ecuador.png"
|
|
680
|
+
},
|
|
681
|
+
PERU: {
|
|
682
|
+
alpha2: "PE",
|
|
683
|
+
alpha3: "PER",
|
|
684
|
+
numeric: "604",
|
|
685
|
+
phoneCode: "+51",
|
|
686
|
+
uuid: "e4d61ef5-b92d-4f9c-8ec1-23f4beb50abd",
|
|
687
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/peru.png"
|
|
688
|
+
},
|
|
689
|
+
BRASIL: {
|
|
690
|
+
alpha2: "BR",
|
|
691
|
+
alpha3: "BRA",
|
|
692
|
+
numeric: "076",
|
|
693
|
+
phoneCode: "+55",
|
|
694
|
+
uuid: "b7b91d72-deaf-4641-957c-a65003e33104",
|
|
695
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/brasil.png"
|
|
696
|
+
},
|
|
697
|
+
CHILE: {
|
|
698
|
+
alpha2: "CL",
|
|
699
|
+
alpha3: "CHL",
|
|
700
|
+
numeric: "152",
|
|
701
|
+
phoneCode: "+56",
|
|
702
|
+
uuid: "f69b35f4-d734-4c76-866c-29a18bf000fb",
|
|
703
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/chile.png"
|
|
704
|
+
},
|
|
705
|
+
VENEZUELA: {
|
|
706
|
+
alpha2: "VE",
|
|
707
|
+
alpha3: "VEN",
|
|
708
|
+
numeric: "862",
|
|
709
|
+
phoneCode: "+58",
|
|
710
|
+
uuid: "31b6c591-63f6-43db-8ea9-829bb03746c5",
|
|
711
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/venezuela.png"
|
|
712
|
+
},
|
|
713
|
+
COLOMBIA: {
|
|
714
|
+
alpha2: "CO",
|
|
715
|
+
alpha3: "COL",
|
|
716
|
+
numeric: "170",
|
|
717
|
+
phoneCode: "+57",
|
|
718
|
+
uuid: "6fdfe34b-6726-4604-96af-665ea5fc9239",
|
|
719
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/colombia.png"
|
|
720
|
+
},
|
|
721
|
+
BOLIVIA: {
|
|
722
|
+
alpha2: "BO",
|
|
723
|
+
alpha3: "BOL",
|
|
724
|
+
numeric: "068",
|
|
725
|
+
phoneCode: "+591",
|
|
726
|
+
uuid: "948886db-c280-4ba7-a777-a76c180b295b",
|
|
727
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/bolivia.png"
|
|
728
|
+
},
|
|
729
|
+
PARAGUAY: {
|
|
730
|
+
alpha2: "PY",
|
|
731
|
+
alpha3: "PRY",
|
|
732
|
+
numeric: "600",
|
|
733
|
+
phoneCode: "+595",
|
|
734
|
+
uuid: "d67b3472-e38d-4900-8ae3-02d99cd1d884",
|
|
735
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/paraguay.png"
|
|
736
|
+
},
|
|
737
|
+
USA: {
|
|
738
|
+
alpha2: "US",
|
|
739
|
+
alpha3: "USA",
|
|
740
|
+
numeric: "840",
|
|
741
|
+
phoneCode: "+1",
|
|
742
|
+
uuid: "16ac3b9b-8f7b-4c54-91d5-d62c7cd74ad4",
|
|
743
|
+
url: "https://dev-wonasports.s3.us-east-2.amazonaws.com/assets/usa.png"
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
_Country.NAMES = Object.keys(_Country.COUNTRIES);
|
|
747
|
+
_Country.DEFAULT = new _Country("URUGUAY");
|
|
748
|
+
_Country.ARGENTINA = new _Country("ARGENTINA");
|
|
749
|
+
_Country.ECUADOR = new _Country("ECUADOR");
|
|
750
|
+
_Country.PERU = new _Country("PERU");
|
|
751
|
+
_Country.BRASIL = new _Country("BRASIL");
|
|
752
|
+
_Country.CHILE = new _Country("CHILE");
|
|
753
|
+
_Country.VENEZUELA = new _Country("VENEZUELA");
|
|
754
|
+
_Country.COLOMBIA = new _Country("COLOMBIA");
|
|
755
|
+
_Country.BOLIVIA = new _Country("BOLIVIA");
|
|
756
|
+
_Country.PARAGUAY = new _Country("PARAGUAY");
|
|
757
|
+
_Country.USA = new _Country("USA");
|
|
758
|
+
var Country = _Country;
|
|
759
|
+
|
|
242
760
|
// src/domain/value-objects/Currency.ts
|
|
243
761
|
var _Currency = class _Currency extends ValueObject {
|
|
244
762
|
constructor(alpha) {
|
|
@@ -254,6 +772,11 @@ var _Currency = class _Currency extends ValueObject {
|
|
|
254
772
|
throw new Error(`Currency <${code}> is not supported`);
|
|
255
773
|
}
|
|
256
774
|
}
|
|
775
|
+
toPrimitives() {
|
|
776
|
+
return {
|
|
777
|
+
value: this.value
|
|
778
|
+
};
|
|
779
|
+
}
|
|
257
780
|
static create(raw) {
|
|
258
781
|
if (typeof raw === "number" || _Currency.NUM_REGEX.test(raw)) {
|
|
259
782
|
const num = Number(raw);
|
|
@@ -307,6 +830,11 @@ var _Email = class _Email extends ValueObject {
|
|
|
307
830
|
throw new Error(`Email <${value}> is not a valid address`);
|
|
308
831
|
}
|
|
309
832
|
}
|
|
833
|
+
toPrimitives() {
|
|
834
|
+
return {
|
|
835
|
+
value: this.value
|
|
836
|
+
};
|
|
837
|
+
}
|
|
310
838
|
static create(raw) {
|
|
311
839
|
return new _Email(raw);
|
|
312
840
|
}
|
|
@@ -324,12 +852,18 @@ var _Language = class _Language extends ValueObject {
|
|
|
324
852
|
}
|
|
325
853
|
validate(value) {
|
|
326
854
|
if (!_Language.SUPPORTED.includes(value)) {
|
|
327
|
-
throw new
|
|
855
|
+
throw new InternalError(`Language <${value}> is not supported`);
|
|
328
856
|
}
|
|
329
857
|
}
|
|
330
858
|
base() {
|
|
331
859
|
return this.value.split("-")[0];
|
|
332
860
|
}
|
|
861
|
+
toPrimitives() {
|
|
862
|
+
return {
|
|
863
|
+
base: this.base(),
|
|
864
|
+
value: this.value
|
|
865
|
+
};
|
|
866
|
+
}
|
|
333
867
|
static create(raw) {
|
|
334
868
|
const normalized = raw.trim().toLowerCase().replace("_", "-");
|
|
335
869
|
try {
|
|
@@ -410,25 +944,43 @@ _Language.SPANISH_PUERTO_RICO = new _Language("es-pr");
|
|
|
410
944
|
var Language = _Language;
|
|
411
945
|
|
|
412
946
|
// src/domain/value-objects/Price.ts
|
|
947
|
+
ErrorManager.addTemplate({
|
|
948
|
+
type: "INVALID_PRICE_AMOUNT",
|
|
949
|
+
languages: {
|
|
950
|
+
"es": "El precio <{{amount}}> no es v\xE1lido",
|
|
951
|
+
"en": "Price amount <{{amount}}> is not a valid number"
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
ErrorManager.addTemplate({
|
|
955
|
+
type: "INVALID_PRICE_RANGE",
|
|
956
|
+
languages: {
|
|
957
|
+
"es": "El precio <{{amount}}> debe ser \u2265 {{min}} y \u2264 {{max}}",
|
|
958
|
+
"en": "Price amount <{{amount}}> must be \u2265 {{min}} and \u2264 {{max}}"
|
|
959
|
+
}
|
|
960
|
+
});
|
|
413
961
|
var _Price = class _Price extends ValueObject {
|
|
414
962
|
constructor(amount, currency) {
|
|
415
963
|
super({ amount, currency });
|
|
416
|
-
this.amount = amount;
|
|
417
|
-
this.currency = currency;
|
|
418
964
|
}
|
|
419
965
|
validate(props) {
|
|
420
966
|
const { amount, currency } = props;
|
|
421
967
|
if (typeof amount !== "number" || Number.isNaN(amount) || !Number.isFinite(amount)) {
|
|
422
|
-
throw new
|
|
968
|
+
throw new UsageError("INVALID_PRICE_AMOUNT", { amount });
|
|
423
969
|
}
|
|
424
|
-
if (amount < _Price.MIN_AMOUNT) {
|
|
425
|
-
throw new
|
|
970
|
+
if (amount < _Price.MIN_AMOUNT || amount > _Price.MAX_AMOUNT) {
|
|
971
|
+
throw new UsageError("INVALID_PRICE_RANGE", { amount, min: _Price.MIN_AMOUNT, max: _Price.MAX_AMOUNT });
|
|
426
972
|
}
|
|
427
973
|
}
|
|
974
|
+
get amount() {
|
|
975
|
+
return this._value.amount;
|
|
976
|
+
}
|
|
977
|
+
get currency() {
|
|
978
|
+
return this._value.currency;
|
|
979
|
+
}
|
|
428
980
|
equals(other) {
|
|
429
981
|
if (!other)
|
|
430
982
|
return false;
|
|
431
|
-
return this.amount === other.amount && this.currency.equals(other.currency);
|
|
983
|
+
return this._value.amount === other.amount && this.currency.equals(other.currency);
|
|
432
984
|
}
|
|
433
985
|
assertSameCurrency(other) {
|
|
434
986
|
if (!this.currency.equals(other.currency)) {
|
|
@@ -443,190 +995,537 @@ var _Price = class _Price extends ValueObject {
|
|
|
443
995
|
this.assertSameCurrency(other);
|
|
444
996
|
return _Price.create(this.amount - other.amount, this.currency);
|
|
445
997
|
}
|
|
998
|
+
toPrimitives() {
|
|
999
|
+
return {
|
|
1000
|
+
amount: this.amount,
|
|
1001
|
+
currency: this.currency.value
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
446
1004
|
static create(amount, currency) {
|
|
447
1005
|
const cur = currency instanceof Currency ? currency : Currency.create(currency);
|
|
448
1006
|
return new _Price(amount, cur);
|
|
449
1007
|
}
|
|
1008
|
+
static createFromPrimitives(data) {
|
|
1009
|
+
return new _Price(Number(data.amount), Currency.create(String(data.currency)));
|
|
1010
|
+
}
|
|
450
1011
|
};
|
|
451
1012
|
_Price.MIN_AMOUNT = -1e6;
|
|
1013
|
+
_Price.MAX_AMOUNT = 1e9;
|
|
452
1014
|
var Price = _Price;
|
|
453
1015
|
|
|
1016
|
+
// src/domain/value-objects/ProcessStatus.ts
|
|
1017
|
+
var _ProcessStatus = class _ProcessStatus extends ValueObject {
|
|
1018
|
+
constructor(status) {
|
|
1019
|
+
super(status.trim().toUpperCase());
|
|
1020
|
+
}
|
|
1021
|
+
validate(value) {
|
|
1022
|
+
if (!_ProcessStatus.SUPPORTED.includes(value)) {
|
|
1023
|
+
throw new InternalError(`Domain event status <${value}> is not supported`);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
toPrimitives() {
|
|
1027
|
+
return void 0;
|
|
1028
|
+
}
|
|
1029
|
+
static create(status) {
|
|
1030
|
+
return new _ProcessStatus(status);
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
_ProcessStatus.SUPPORTED = ["PENDING", "PROCESSING", "PROCESSED", "FAILED", "DEAD"];
|
|
1034
|
+
_ProcessStatus.PENDING = new _ProcessStatus("PENDING");
|
|
1035
|
+
_ProcessStatus.PROCESSING = new _ProcessStatus("PROCESSING");
|
|
1036
|
+
_ProcessStatus.PROCESSED = new _ProcessStatus("PROCESSED");
|
|
1037
|
+
_ProcessStatus.FAILED = new _ProcessStatus("FAILED");
|
|
1038
|
+
_ProcessStatus.DEAD = new _ProcessStatus("DEAD");
|
|
1039
|
+
var ProcessStatus = _ProcessStatus;
|
|
1040
|
+
|
|
454
1041
|
// src/domain/value-objects/UUID.ts
|
|
455
|
-
var
|
|
1042
|
+
var crypto = __toESM(require("crypto"));
|
|
1043
|
+
var _UUID = class _UUID extends ValueObject {
|
|
456
1044
|
constructor(value) {
|
|
457
1045
|
super(value);
|
|
458
1046
|
}
|
|
459
1047
|
validate(uuid) {
|
|
460
1048
|
if (!_UUID.isValid(uuid)) {
|
|
461
|
-
throw new
|
|
1049
|
+
throw new InternalError(`Invalid uuid <${uuid}>`);
|
|
462
1050
|
}
|
|
463
1051
|
}
|
|
1052
|
+
toPrimitives() {
|
|
1053
|
+
return { value: this.value };
|
|
1054
|
+
}
|
|
464
1055
|
static create(uuid) {
|
|
465
1056
|
return new _UUID(uuid ?? crypto.randomUUID());
|
|
466
1057
|
}
|
|
467
|
-
static
|
|
468
|
-
|
|
1058
|
+
static version(uuid) {
|
|
1059
|
+
const m = /^[0-9a-f]{8}-[0-9a-f]{4}-([1-8])[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.exec(uuid);
|
|
1060
|
+
return m ? Number(m[1]) : void 0;
|
|
1061
|
+
}
|
|
1062
|
+
static isNil(uuid) {
|
|
1063
|
+
return /^0{8}-0{4}-0{4}-0{4}-0{12}$/i.test(uuid);
|
|
1064
|
+
}
|
|
1065
|
+
static isRFCStyle(uuid) {
|
|
1066
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid);
|
|
1067
|
+
}
|
|
1068
|
+
static isValid(uuid, opts = {}) {
|
|
1069
|
+
const allowed = opts.allowedVersions ?? [1, 2, 3, 4, 5, 6, 7, 8];
|
|
1070
|
+
const allowNil = opts.allowNil ?? false;
|
|
1071
|
+
if (allowNil && _UUID.isNil(uuid))
|
|
1072
|
+
return true;
|
|
1073
|
+
if (!_UUID.isRFCStyle(uuid))
|
|
1074
|
+
return false;
|
|
1075
|
+
const v = _UUID.version(uuid);
|
|
1076
|
+
return !!v && allowed.includes(v);
|
|
469
1077
|
}
|
|
470
1078
|
};
|
|
1079
|
+
_UUID.NIL = "00000000-0000-0000-0000-000000000000";
|
|
1080
|
+
var UUID = _UUID;
|
|
471
1081
|
|
|
472
|
-
// src/
|
|
473
|
-
var
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
1082
|
+
// src/application/contracts/IntegrationEvent.ts
|
|
1083
|
+
var IntegrationEvent = class extends BaseEvent {
|
|
1084
|
+
constructor(tenantUuid, version, type, payload, aggregateUuid, aggregateType) {
|
|
1085
|
+
super(tenantUuid, version, type, payload);
|
|
1086
|
+
this._aggregateUuid = aggregateUuid;
|
|
1087
|
+
this._aggregateType = aggregateType;
|
|
1088
|
+
}
|
|
1089
|
+
get aggregateUuid() {
|
|
1090
|
+
return this._aggregateUuid;
|
|
1091
|
+
}
|
|
1092
|
+
get aggregateType() {
|
|
1093
|
+
return this._aggregateType;
|
|
483
1094
|
}
|
|
484
1095
|
};
|
|
485
1096
|
|
|
486
|
-
// src/
|
|
487
|
-
var
|
|
488
|
-
constructor(
|
|
489
|
-
this.
|
|
1097
|
+
// src/application/event-bus/EventBus.ts
|
|
1098
|
+
var _EventBus = class _EventBus {
|
|
1099
|
+
constructor(repository) {
|
|
1100
|
+
this.repository = repository;
|
|
1101
|
+
}
|
|
1102
|
+
async publish(event) {
|
|
1103
|
+
const mapper = _EventBus.MAPPERS.get(event.type);
|
|
1104
|
+
if (!mapper) {
|
|
1105
|
+
throw new InternalError(ErrorManager.APP_ERRORS.PROCESS, `Eventbus mapper not found for <${event.type}>`);
|
|
1106
|
+
}
|
|
1107
|
+
await this.repository.create(mapper(event));
|
|
490
1108
|
}
|
|
491
|
-
|
|
492
|
-
|
|
1109
|
+
async publishMany(events) {
|
|
1110
|
+
for (let event of events) {
|
|
1111
|
+
await this.publish(event);
|
|
1112
|
+
}
|
|
493
1113
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
return { status: "ERROR", message: this.getDefaultMessage(lang) };
|
|
1114
|
+
static addMapper(eventType, mapper) {
|
|
1115
|
+
_EventBus.MAPPERS.set(eventType, mapper);
|
|
497
1116
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
1117
|
+
};
|
|
1118
|
+
_EventBus.MAPPERS = /* @__PURE__ */ new Map();
|
|
1119
|
+
var EventBus = _EventBus;
|
|
1120
|
+
|
|
1121
|
+
// src/application/unit-of-work/BasicUnitOfWork.ts
|
|
1122
|
+
var BasicUnitOfWork = class {
|
|
1123
|
+
constructor(conn) {
|
|
1124
|
+
this.connection = conn;
|
|
501
1125
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
1126
|
+
async execute(fn) {
|
|
1127
|
+
await this.connection.begin();
|
|
1128
|
+
try {
|
|
1129
|
+
const result = await fn();
|
|
1130
|
+
await this.connection.commit();
|
|
1131
|
+
return result;
|
|
1132
|
+
} catch (err) {
|
|
1133
|
+
await this.connection.rollback();
|
|
1134
|
+
throw err;
|
|
1135
|
+
} finally {
|
|
1136
|
+
await this.connection.close();
|
|
507
1137
|
}
|
|
508
|
-
const code = lang.value;
|
|
509
|
-
const base = lang.base();
|
|
510
|
-
const rawMsg = tmpl.languages[code] ?? tmpl.languages[base] ?? this.getDefaultMessage(lang);
|
|
511
|
-
return {
|
|
512
|
-
status: "ERROR",
|
|
513
|
-
message: StringVars.parse(rawMsg, err.vars)
|
|
514
|
-
};
|
|
515
1138
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
1139
|
+
};
|
|
1140
|
+
|
|
1141
|
+
// src/application/unit-of-work/BasicUnitOfWorkFactory.ts
|
|
1142
|
+
var BasicUnitOfWorkFactory = class {
|
|
1143
|
+
constructor(connector) {
|
|
1144
|
+
this.connector = connector;
|
|
519
1145
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
1146
|
+
async create() {
|
|
1147
|
+
const conn = await this.connector.getConnection();
|
|
1148
|
+
return new BasicUnitOfWork(conn);
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
// src/infrastructure/contracts/EventManager.ts
|
|
1153
|
+
var EventManager = class {
|
|
1154
|
+
constructor(connection) {
|
|
1155
|
+
this._connection = connection;
|
|
1156
|
+
this._topics = [];
|
|
1157
|
+
this._callbackList = {};
|
|
1158
|
+
this._onStart = null;
|
|
1159
|
+
this._onConnected = null;
|
|
1160
|
+
this._onSubscribe = null;
|
|
1161
|
+
this._onMessage = null;
|
|
1162
|
+
this._onError = null;
|
|
1163
|
+
this._onCrash = null;
|
|
1164
|
+
this._onReconnect = null;
|
|
1165
|
+
}
|
|
1166
|
+
async execRoute(topic, event) {
|
|
1167
|
+
if (this._callbackList[topic]) {
|
|
1168
|
+
await this._callbackList[topic](event);
|
|
529
1169
|
}
|
|
530
|
-
|
|
531
|
-
|
|
1170
|
+
}
|
|
1171
|
+
async execCallback(callback, data) {
|
|
1172
|
+
if (callback) {
|
|
1173
|
+
await callback(data);
|
|
532
1174
|
}
|
|
533
|
-
return this.onUnknown(err, lang);
|
|
534
1175
|
}
|
|
535
|
-
|
|
536
|
-
|
|
1176
|
+
route(topic, callback) {
|
|
1177
|
+
this._topics.push(topic);
|
|
1178
|
+
this._callbackList[topic] = callback;
|
|
1179
|
+
}
|
|
1180
|
+
onStart(callback) {
|
|
1181
|
+
this._onStart = callback;
|
|
1182
|
+
}
|
|
1183
|
+
onConnected(callback) {
|
|
1184
|
+
this._onConnected = callback;
|
|
1185
|
+
}
|
|
1186
|
+
onSubscribe(callback) {
|
|
1187
|
+
this._onSubscribe = callback;
|
|
1188
|
+
}
|
|
1189
|
+
onMessage(callback) {
|
|
1190
|
+
this._onMessage = callback;
|
|
1191
|
+
}
|
|
1192
|
+
onError(callback) {
|
|
1193
|
+
this._onError = callback;
|
|
1194
|
+
}
|
|
1195
|
+
onCrash(callback) {
|
|
1196
|
+
this._onCrash = callback;
|
|
1197
|
+
}
|
|
1198
|
+
onReconnect(callback) {
|
|
1199
|
+
this._onReconnect = callback;
|
|
1200
|
+
}
|
|
1201
|
+
get topics() {
|
|
1202
|
+
return this._topics;
|
|
1203
|
+
}
|
|
1204
|
+
get callbackList() {
|
|
1205
|
+
return this._callbackList;
|
|
537
1206
|
}
|
|
538
1207
|
};
|
|
539
|
-
_ErrorManager.DEFAULT_MESSAGES = {
|
|
540
|
-
"es": "Ups, hemos encontrado un error. Nuestro equipo ya est\xE1 trabajando para solucionarlo",
|
|
541
|
-
"en": "Ups, we found an error. Our team is working on it.",
|
|
542
|
-
"pt": "Ops, encontramos um bug. Nossa equipe j\xE1 est\xE1 trabalhando para resolver isso."
|
|
543
|
-
};
|
|
544
|
-
_ErrorManager.APP_ERRORS = {
|
|
545
|
-
UNDEFINED: "UNDEFINED_ERROR",
|
|
546
|
-
PROCESS: "PROCESS_ERROR",
|
|
547
|
-
DATABASE: "DATABASE_ERROR"
|
|
548
|
-
};
|
|
549
|
-
_ErrorManager.TEMPLATES = /* @__PURE__ */ new Map();
|
|
550
|
-
var ErrorManager = _ErrorManager;
|
|
551
|
-
|
|
552
|
-
// src/infrastructure/mysql/MysqlConnector.ts
|
|
553
|
-
var import_promise = require("mysql2/promise");
|
|
554
1208
|
|
|
555
|
-
// src/infrastructure/
|
|
556
|
-
var
|
|
557
|
-
constructor(
|
|
558
|
-
this.
|
|
1209
|
+
// src/infrastructure/contracts/OutboxRecord.ts
|
|
1210
|
+
var OutboxRecord = class _OutboxRecord {
|
|
1211
|
+
constructor(eventUuid, eventType, tenantUuid, aggregateUuid, aggregateType, topic, payload, status, attempts, errorMessage, publishedAt, lastAttempt, createdAt) {
|
|
1212
|
+
this._eventUuid = eventUuid;
|
|
1213
|
+
this._tenantUuid = tenantUuid;
|
|
1214
|
+
this._aggregateUuid = aggregateUuid;
|
|
1215
|
+
this._aggregateType = aggregateType;
|
|
1216
|
+
this._eventType = eventType;
|
|
1217
|
+
this._topic = topic;
|
|
1218
|
+
this._payload = payload;
|
|
1219
|
+
this._status = status;
|
|
1220
|
+
this._attempts = attempts;
|
|
1221
|
+
this._errorMessage = errorMessage;
|
|
1222
|
+
this._publishedAt = publishedAt;
|
|
1223
|
+
this._lastAttempt = lastAttempt;
|
|
1224
|
+
this._createdAt = createdAt ?? DateTime.now();
|
|
559
1225
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
return rows;
|
|
1226
|
+
get eventUuid() {
|
|
1227
|
+
return this._eventUuid;
|
|
563
1228
|
}
|
|
564
|
-
|
|
565
|
-
|
|
1229
|
+
get tenantUuid() {
|
|
1230
|
+
return this._tenantUuid;
|
|
566
1231
|
}
|
|
567
|
-
|
|
568
|
-
|
|
1232
|
+
get aggregateUuid() {
|
|
1233
|
+
return this._aggregateUuid;
|
|
569
1234
|
}
|
|
570
|
-
|
|
571
|
-
|
|
1235
|
+
get aggregateType() {
|
|
1236
|
+
return this._aggregateType;
|
|
572
1237
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
try {
|
|
576
|
-
const result = await fn(this);
|
|
577
|
-
await this.commit();
|
|
578
|
-
return result;
|
|
579
|
-
} catch (err) {
|
|
580
|
-
await this.rollback();
|
|
581
|
-
throw err;
|
|
582
|
-
}
|
|
1238
|
+
get eventType() {
|
|
1239
|
+
return this._eventType;
|
|
583
1240
|
}
|
|
584
|
-
|
|
585
|
-
this.
|
|
1241
|
+
get topic() {
|
|
1242
|
+
return this._topic;
|
|
1243
|
+
}
|
|
1244
|
+
get payload() {
|
|
1245
|
+
return this._payload;
|
|
1246
|
+
}
|
|
1247
|
+
get status() {
|
|
1248
|
+
return this._status;
|
|
1249
|
+
}
|
|
1250
|
+
get attempts() {
|
|
1251
|
+
return this._attempts;
|
|
1252
|
+
}
|
|
1253
|
+
get errorMessage() {
|
|
1254
|
+
return this._errorMessage;
|
|
1255
|
+
}
|
|
1256
|
+
get publishedAt() {
|
|
1257
|
+
return this._publishedAt;
|
|
1258
|
+
}
|
|
1259
|
+
get lastAttempt() {
|
|
1260
|
+
return this._lastAttempt;
|
|
1261
|
+
}
|
|
1262
|
+
get createdAt() {
|
|
1263
|
+
return this._createdAt;
|
|
1264
|
+
}
|
|
1265
|
+
incrementAttempts() {
|
|
1266
|
+
this._attempts++;
|
|
1267
|
+
this._lastAttempt = DateTime.now();
|
|
1268
|
+
}
|
|
1269
|
+
markProcessed() {
|
|
1270
|
+
this._status = ProcessStatus.PROCESSED;
|
|
1271
|
+
this._publishedAt = DateTime.now();
|
|
1272
|
+
}
|
|
1273
|
+
markProcessing() {
|
|
1274
|
+
this.incrementAttempts();
|
|
1275
|
+
this._status = ProcessStatus.PROCESSING;
|
|
1276
|
+
}
|
|
1277
|
+
markWithError(error) {
|
|
1278
|
+
this._status = this.attempts < 5 ? ProcessStatus.FAILED : ProcessStatus.DEAD;
|
|
1279
|
+
this._errorMessage = error;
|
|
1280
|
+
}
|
|
1281
|
+
toPrimitives() {
|
|
1282
|
+
return {
|
|
1283
|
+
eventUuid: this.eventUuid.value,
|
|
1284
|
+
eventType: this.eventType,
|
|
1285
|
+
tenantUuid: this.tenantUuid.value,
|
|
1286
|
+
aggregateUuid: this.aggregateUuid.value,
|
|
1287
|
+
aggregateType: this.aggregateType,
|
|
1288
|
+
topic: this.topic,
|
|
1289
|
+
payload: this.payload,
|
|
1290
|
+
status: this.status.value,
|
|
1291
|
+
attempts: this.attempts,
|
|
1292
|
+
errorMessage: this.errorMessage ?? void 0,
|
|
1293
|
+
publishedAt: this.publishedAt?.value ?? void 0,
|
|
1294
|
+
lastAttempt: this.lastAttempt?.value ?? void 0,
|
|
1295
|
+
createdAt: this.createdAt.value
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
static reconstitute(data) {
|
|
1299
|
+
return new _OutboxRecord(
|
|
1300
|
+
UUID.create(data.event_uuid),
|
|
1301
|
+
String(data.event_type),
|
|
1302
|
+
UUID.create(data.tenant_uuid),
|
|
1303
|
+
UUID.create(data.aggregate_uuid),
|
|
1304
|
+
String(data.aggregate_type),
|
|
1305
|
+
String(data.topic),
|
|
1306
|
+
String(data.payload),
|
|
1307
|
+
ProcessStatus.create(data.status),
|
|
1308
|
+
Number(data.attempts),
|
|
1309
|
+
data.error_message ?? void 0,
|
|
1310
|
+
data.published_at ? DateTime.create(data.published_at) : void 0,
|
|
1311
|
+
data.last_attempt ? DateTime.create(data.last_attempt) : void 0,
|
|
1312
|
+
data.created_at ? DateTime.create(data.created_at) : void 0
|
|
1313
|
+
);
|
|
586
1314
|
}
|
|
587
1315
|
};
|
|
588
1316
|
|
|
589
|
-
// src/infrastructure/
|
|
590
|
-
var
|
|
591
|
-
constructor(
|
|
592
|
-
this.
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
1317
|
+
// src/infrastructure/contracts/InboxRecord.ts
|
|
1318
|
+
var InboxRecord = class _InboxRecord {
|
|
1319
|
+
constructor(eventUuid, tenantUuid, topic, producer, payload, status, attempts, errorMessage, lastAttempt, processedAt, createdAt) {
|
|
1320
|
+
this._eventUuid = eventUuid;
|
|
1321
|
+
this._tenantUuid = tenantUuid;
|
|
1322
|
+
this._topic = topic;
|
|
1323
|
+
this._producer = producer;
|
|
1324
|
+
this._payload = payload;
|
|
1325
|
+
this._status = status;
|
|
1326
|
+
this._attempts = attempts ?? 0;
|
|
1327
|
+
this._errorMessage = errorMessage ?? void 0;
|
|
1328
|
+
this._lastAttempt = lastAttempt ?? void 0;
|
|
1329
|
+
this._processedAt = processedAt ?? void 0;
|
|
1330
|
+
this._createdAt = createdAt ?? DateTime.now();
|
|
601
1331
|
}
|
|
602
|
-
|
|
603
|
-
return
|
|
1332
|
+
get eventUuid() {
|
|
1333
|
+
return this._eventUuid;
|
|
604
1334
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
return this.wrap(conn);
|
|
1335
|
+
get tenantUuid() {
|
|
1336
|
+
return this._tenantUuid;
|
|
608
1337
|
}
|
|
609
|
-
|
|
610
|
-
|
|
1338
|
+
get topic() {
|
|
1339
|
+
return this._topic;
|
|
611
1340
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
1341
|
+
get producer() {
|
|
1342
|
+
return this._producer;
|
|
1343
|
+
}
|
|
1344
|
+
get payload() {
|
|
1345
|
+
return this._payload;
|
|
1346
|
+
}
|
|
1347
|
+
get status() {
|
|
1348
|
+
return this._status;
|
|
1349
|
+
}
|
|
1350
|
+
get attempts() {
|
|
1351
|
+
return this._attempts;
|
|
1352
|
+
}
|
|
1353
|
+
get errorMessage() {
|
|
1354
|
+
return this._errorMessage;
|
|
1355
|
+
}
|
|
1356
|
+
get lastAttempt() {
|
|
1357
|
+
return this._lastAttempt;
|
|
1358
|
+
}
|
|
1359
|
+
get processedAt() {
|
|
1360
|
+
return this._processedAt;
|
|
1361
|
+
}
|
|
1362
|
+
get createdAt() {
|
|
1363
|
+
return this._createdAt;
|
|
1364
|
+
}
|
|
1365
|
+
incrementAttempts() {
|
|
1366
|
+
this._attempts++;
|
|
1367
|
+
this._lastAttempt = DateTime.now();
|
|
1368
|
+
}
|
|
1369
|
+
markProcessed() {
|
|
1370
|
+
this._status = ProcessStatus.PROCESSED;
|
|
1371
|
+
this._processedAt = DateTime.now();
|
|
1372
|
+
}
|
|
1373
|
+
markProcessing() {
|
|
1374
|
+
this.incrementAttempts();
|
|
1375
|
+
this._status = ProcessStatus.PROCESSING;
|
|
1376
|
+
}
|
|
1377
|
+
markWithError(error) {
|
|
1378
|
+
this._status = this.attempts < 5 ? ProcessStatus.FAILED : ProcessStatus.DEAD;
|
|
1379
|
+
this._errorMessage = error;
|
|
1380
|
+
}
|
|
1381
|
+
toPrimitives() {
|
|
1382
|
+
return {
|
|
1383
|
+
eventUuid: this.eventUuid.value,
|
|
1384
|
+
tenantUuid: this.tenantUuid.value,
|
|
1385
|
+
topic: this.topic,
|
|
1386
|
+
producer: this.producer,
|
|
1387
|
+
payload: this.payload,
|
|
1388
|
+
status: this.status.value,
|
|
1389
|
+
attempts: this.attempts,
|
|
1390
|
+
errorMessage: this.errorMessage ?? void 0,
|
|
1391
|
+
lastAttempt: this.lastAttempt?.value ?? void 0,
|
|
1392
|
+
processedAt: this.processedAt?.value ?? void 0,
|
|
1393
|
+
createdAt: this.createdAt.value
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
static reconstitute(data) {
|
|
1397
|
+
return new _InboxRecord(
|
|
1398
|
+
UUID.create(data.event_uuid),
|
|
1399
|
+
UUID.create(data.tenant_uuid),
|
|
1400
|
+
String(data.topic),
|
|
1401
|
+
String(data.producer),
|
|
1402
|
+
String(data.payload),
|
|
1403
|
+
ProcessStatus.create(data.status),
|
|
1404
|
+
Number(data.attempts),
|
|
1405
|
+
data.error_message ?? void 0,
|
|
1406
|
+
data.last_attempt ? DateTime.create(data.last_attempt) : void 0,
|
|
1407
|
+
data.processed_at ? DateTime.create(data.processed_at) : void 0,
|
|
1408
|
+
data.created_at ? DateTime.create(data.created_at) : void 0
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
|
|
1413
|
+
// src/infrastructure/event-bus/EventBusMysqlRepository.ts
|
|
1414
|
+
var EventBusMysqlRepository = class {
|
|
1415
|
+
constructor(connection) {
|
|
1416
|
+
this.connection = connection;
|
|
1417
|
+
}
|
|
1418
|
+
recordToRowValues(record) {
|
|
1419
|
+
return [
|
|
1420
|
+
record.eventUuid.value,
|
|
1421
|
+
record.eventType,
|
|
1422
|
+
record.tenantUuid.value,
|
|
1423
|
+
record.aggregateUuid.value,
|
|
1424
|
+
record.aggregateType,
|
|
1425
|
+
record.topic,
|
|
1426
|
+
record.payload,
|
|
1427
|
+
record.status.value,
|
|
1428
|
+
record.attempts,
|
|
1429
|
+
record.errorMessage,
|
|
1430
|
+
record.publishedAt?.value,
|
|
1431
|
+
record.lastAttempt?.value,
|
|
1432
|
+
record.createdAt.value
|
|
1433
|
+
];
|
|
1434
|
+
}
|
|
1435
|
+
async create(record) {
|
|
1436
|
+
const values = this.recordToRowValues(record);
|
|
1437
|
+
await this.connection.query(
|
|
1438
|
+
`INSERT INTO events_outbox (event_uuid, event_type, tenant_uuid, aggregate_uuid, aggregate_type, topic,
|
|
1439
|
+
payload, status, attempts, error_message, published_at, last_attempt, created_at)
|
|
1440
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
1441
|
+
values
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
async update(record) {
|
|
1445
|
+
const values = [record.status.value, record.attempts, record.errorMessage, record.publishedAt?.value, record.lastAttempt?.value, record.eventUuid.value];
|
|
1446
|
+
await this.connection.query(
|
|
1447
|
+
`UPDATE events_outbox
|
|
1448
|
+
SET status = ?,
|
|
1449
|
+
attempts = ?,
|
|
1450
|
+
error_message = ?,
|
|
1451
|
+
published_at = ?,
|
|
1452
|
+
last_attempt = ?
|
|
1453
|
+
WHERE event_uuid = ?`,
|
|
1454
|
+
values
|
|
1455
|
+
);
|
|
1456
|
+
}
|
|
1457
|
+
async listPending(limit) {
|
|
1458
|
+
const result = await this.connection.query(
|
|
1459
|
+
`SELECT * FROM events_outbox WHERE status IN ('PENDING','FAILED') AND published_at IS NULL LIMIT ${limit}`,
|
|
1460
|
+
[]
|
|
1461
|
+
);
|
|
1462
|
+
return result.length > 0 ? result.map((r) => OutboxRecord.reconstitute(r)) : [];
|
|
624
1463
|
}
|
|
625
1464
|
};
|
|
626
|
-
_MysqlConnector.DEFAULT_POOL_SIZE = 10;
|
|
627
|
-
var MysqlConnector = _MysqlConnector;
|
|
628
1465
|
|
|
629
1466
|
// src/infrastructure/express/ExpressAdapters.ts
|
|
1467
|
+
var BOOL_TRUE = /* @__PURE__ */ new Set(["1", "true", "yes", "y", "on"]);
|
|
1468
|
+
var BOOL_FALSE = /* @__PURE__ */ new Set(["0", "false", "no", "n", "off"]);
|
|
1469
|
+
var NUMERIC_KEY_RE = /^(?:page|qty|limit|offset|total|amount|price|count|rounding|min[A-Z_].*|max[A-Z_].*)$/i;
|
|
1470
|
+
var DATE_KEY_RE = /(At|Date|_at|_date)$/i;
|
|
1471
|
+
function toUtcDateTimeString(raw) {
|
|
1472
|
+
const s = raw.trim();
|
|
1473
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(s))
|
|
1474
|
+
return `${s} 00:00:00`;
|
|
1475
|
+
if (/^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}$/.test(s))
|
|
1476
|
+
return s;
|
|
1477
|
+
const d = new Date(s);
|
|
1478
|
+
if (Number.isNaN(d.getTime()))
|
|
1479
|
+
return void 0;
|
|
1480
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
1481
|
+
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`;
|
|
1482
|
+
}
|
|
1483
|
+
function coerceScalar(key, v) {
|
|
1484
|
+
if (v == null)
|
|
1485
|
+
return void 0;
|
|
1486
|
+
if (typeof v !== "string")
|
|
1487
|
+
return v;
|
|
1488
|
+
const s = v.trim();
|
|
1489
|
+
if (s === "")
|
|
1490
|
+
return void 0;
|
|
1491
|
+
if (s.toLowerCase() === "null")
|
|
1492
|
+
return null;
|
|
1493
|
+
const low = s.toLowerCase();
|
|
1494
|
+
if (BOOL_TRUE.has(low))
|
|
1495
|
+
return true;
|
|
1496
|
+
if (BOOL_FALSE.has(low))
|
|
1497
|
+
return false;
|
|
1498
|
+
if (NUMERIC_KEY_RE.test(key) && /^-?\d+(\.\d+)?$/.test(s)) {
|
|
1499
|
+
const n = Number(s);
|
|
1500
|
+
if (Number.isFinite(n))
|
|
1501
|
+
return n;
|
|
1502
|
+
}
|
|
1503
|
+
if (DATE_KEY_RE.test(key)) {
|
|
1504
|
+
return toUtcDateTimeString(s) ?? s;
|
|
1505
|
+
}
|
|
1506
|
+
return s;
|
|
1507
|
+
}
|
|
1508
|
+
function normalizeQuery(q) {
|
|
1509
|
+
const out = {};
|
|
1510
|
+
for (const [key, raw] of Object.entries(q)) {
|
|
1511
|
+
const values = Array.isArray(raw) ? raw : typeof raw === "string" && raw.includes(",") ? raw.split(",").map((s) => s.trim()).filter(Boolean) : [raw];
|
|
1512
|
+
const coerced = values.map((v) => coerceScalar(key, v)).filter((v) => v !== void 0);
|
|
1513
|
+
if (coerced.length === 1)
|
|
1514
|
+
out[key] = coerced[0];
|
|
1515
|
+
else if (coerced.length > 1)
|
|
1516
|
+
out[key] = coerced;
|
|
1517
|
+
}
|
|
1518
|
+
return out;
|
|
1519
|
+
}
|
|
1520
|
+
function isReadableStream(x) {
|
|
1521
|
+
return x && typeof x.pipe === "function";
|
|
1522
|
+
}
|
|
1523
|
+
function hasHeader(headers, name) {
|
|
1524
|
+
if (!headers)
|
|
1525
|
+
return false;
|
|
1526
|
+
const lname = name.toLowerCase();
|
|
1527
|
+
return Object.keys(headers).some((h) => h.toLowerCase() === lname);
|
|
1528
|
+
}
|
|
630
1529
|
function adaptExpressRoute(Controller) {
|
|
631
1530
|
return async (req, res, next) => {
|
|
632
1531
|
const rawLangHeader = req.headers["accept-language"] ?? req.headers["Accept-Language"] ?? "es";
|
|
@@ -635,14 +1534,49 @@ function adaptExpressRoute(Controller) {
|
|
|
635
1534
|
const httpRequest = {
|
|
636
1535
|
headers: req.headers,
|
|
637
1536
|
params: req.params,
|
|
638
|
-
query:
|
|
1537
|
+
query: normalizeQuery(req.query),
|
|
639
1538
|
lang,
|
|
640
1539
|
body: req.body
|
|
641
1540
|
};
|
|
642
1541
|
try {
|
|
643
1542
|
const controller = new Controller();
|
|
644
|
-
const { statusCode, body } = await controller.handle(httpRequest);
|
|
645
|
-
|
|
1543
|
+
const { statusCode, body, headers } = await controller.handle(httpRequest);
|
|
1544
|
+
if (headers)
|
|
1545
|
+
res.set(headers);
|
|
1546
|
+
if (isReadableStream(body)) {
|
|
1547
|
+
if (!hasHeader(headers, "Content-Type"))
|
|
1548
|
+
res.set("Content-Type", "application/octet-stream");
|
|
1549
|
+
res.status(statusCode);
|
|
1550
|
+
body.on("error", next);
|
|
1551
|
+
body.pipe(res);
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
const isArrayBuffer = typeof body === "object" && body instanceof ArrayBuffer;
|
|
1555
|
+
const isArrayBufferView = typeof body === "object" && body != null && ArrayBuffer.isView(body);
|
|
1556
|
+
if (Buffer.isBuffer(body) || isArrayBuffer || isArrayBufferView) {
|
|
1557
|
+
let buf;
|
|
1558
|
+
if (Buffer.isBuffer(body)) {
|
|
1559
|
+
buf = body;
|
|
1560
|
+
} else if (isArrayBuffer) {
|
|
1561
|
+
buf = Buffer.from(body);
|
|
1562
|
+
} else {
|
|
1563
|
+
const view = body;
|
|
1564
|
+
buf = Buffer.from(view.buffer, view.byteOffset, view.byteLength);
|
|
1565
|
+
}
|
|
1566
|
+
if (!hasHeader(headers, "Content-Type"))
|
|
1567
|
+
res.set("Content-Type", "application/octet-stream");
|
|
1568
|
+
if (!res.getHeader("Content-Length"))
|
|
1569
|
+
res.set("Content-Length", String(buf.length));
|
|
1570
|
+
res.status(statusCode);
|
|
1571
|
+
res.end(buf);
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
const hasCT = hasHeader(headers, "Content-Type");
|
|
1575
|
+
if (typeof body === "string" || hasCT) {
|
|
1576
|
+
res.status(statusCode).send(body);
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
res.status(statusCode).json(body ?? {});
|
|
646
1580
|
} catch (err) {
|
|
647
1581
|
next(err);
|
|
648
1582
|
}
|
|
@@ -659,49 +1593,461 @@ function adaptExpressErrorHandler(errorManager) {
|
|
|
659
1593
|
};
|
|
660
1594
|
}
|
|
661
1595
|
|
|
662
|
-
// src/infrastructure/http/
|
|
1596
|
+
// src/infrastructure/http/DefaultController.ts
|
|
1597
|
+
var HttpHealthCheckController = class {
|
|
1598
|
+
async handle(request) {
|
|
1599
|
+
return {
|
|
1600
|
+
statusCode: 200,
|
|
1601
|
+
body: {
|
|
1602
|
+
date: DateTime.create().value,
|
|
1603
|
+
code: 200
|
|
1604
|
+
}
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
};
|
|
663
1608
|
var HttpNotFoundController = class {
|
|
664
1609
|
async handle(request) {
|
|
665
1610
|
return {
|
|
666
1611
|
statusCode: 404,
|
|
667
1612
|
body: {
|
|
668
|
-
status: "NOT_FOUND",
|
|
669
1613
|
message: `Route ${request.headers.location} not found`
|
|
670
1614
|
}
|
|
671
1615
|
};
|
|
672
1616
|
}
|
|
673
1617
|
};
|
|
674
1618
|
|
|
675
|
-
// src/infrastructure/
|
|
676
|
-
var
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
1619
|
+
// src/infrastructure/kafka/KafkaManager.ts
|
|
1620
|
+
var import_kafkajs = require("kafkajs");
|
|
1621
|
+
var KafkaManager = class extends EventManager {
|
|
1622
|
+
constructor(connection) {
|
|
1623
|
+
super(connection);
|
|
1624
|
+
this.kafka = new import_kafkajs.Kafka({
|
|
1625
|
+
brokers: this._connection.brokers,
|
|
1626
|
+
ssl: true,
|
|
1627
|
+
sasl: {
|
|
1628
|
+
mechanism: "scram-sha-256",
|
|
1629
|
+
username: this._connection.userName,
|
|
1630
|
+
password: this._connection.password
|
|
1631
|
+
},
|
|
1632
|
+
logLevel: import_kafkajs.logLevel.ERROR
|
|
1633
|
+
});
|
|
1634
|
+
this.consumer = this.kafka.consumer({ groupId: process.env.KAFKA_GROUP || "default" });
|
|
1635
|
+
this.producer = this.kafka.producer();
|
|
1636
|
+
}
|
|
1637
|
+
async run(autocommit) {
|
|
1638
|
+
const __run = async () => {
|
|
1639
|
+
await this.execCallback(this._onStart, { message: `--- ${this.constructor.name} started ---` });
|
|
1640
|
+
await this.consumer.connect();
|
|
1641
|
+
await this.execCallback(this._onConnected, { message: `--- ${this.constructor.name} connected to ${this._connection.brokers} ---` });
|
|
1642
|
+
for (let topic of this._topics) {
|
|
1643
|
+
try {
|
|
1644
|
+
await this.consumer.subscribe({ topic, fromBeginning: true });
|
|
1645
|
+
await this.execCallback(this._onSubscribe, { message: `--- ${this.constructor.name} subscribed to ${topic} ---` });
|
|
1646
|
+
} catch (error) {
|
|
1647
|
+
await this.execCallback(this._onConnected, { message: `Error on subscribe to kafka topic: ${topic}` });
|
|
1648
|
+
}
|
|
684
1649
|
}
|
|
1650
|
+
await this.consumer.run({
|
|
1651
|
+
autoCommit: autocommit,
|
|
1652
|
+
// @ts-ignore
|
|
1653
|
+
eachMessage: async ({ topic, partition, message, heartbeat }) => {
|
|
1654
|
+
try {
|
|
1655
|
+
await this.execCallback(this._onMessage, `[New message detected for ${topic}]: ${message.value?.toString()}`);
|
|
1656
|
+
const json = JSON.parse(String(message.value?.toString()));
|
|
1657
|
+
await this.execRoute(topic, {
|
|
1658
|
+
topic: String(json.topic),
|
|
1659
|
+
producer: String(json.producer),
|
|
1660
|
+
tenant: UUID.create(String(json.tenant)),
|
|
1661
|
+
message: json.message
|
|
1662
|
+
});
|
|
1663
|
+
const next = (BigInt(message.offset) + 1n).toString();
|
|
1664
|
+
await this.consumer.commitOffsets([{ topic, partition, offset: next }]);
|
|
1665
|
+
await heartbeat();
|
|
1666
|
+
} catch (error) {
|
|
1667
|
+
await this.execCallback(this._onError, error);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
});
|
|
1671
|
+
};
|
|
1672
|
+
try {
|
|
1673
|
+
await __run();
|
|
1674
|
+
} catch (error) {
|
|
1675
|
+
await this.execCallback(this._onError, new InternalError(ErrorManager.APP_ERRORS.PROCESS, error.toString()));
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
async send(e) {
|
|
1679
|
+
const evt = {
|
|
1680
|
+
date: DateTime.now().value,
|
|
1681
|
+
tenant: e.tenant.value,
|
|
1682
|
+
producer: e.producer,
|
|
1683
|
+
data: JSON.parse(e.message)
|
|
685
1684
|
};
|
|
1685
|
+
try {
|
|
1686
|
+
if (!this.producer) {
|
|
1687
|
+
throw new InternalError(ErrorManager.APP_ERRORS.PROCESS, "Producer not initialized");
|
|
1688
|
+
}
|
|
1689
|
+
await this.producer.connect();
|
|
1690
|
+
await this.producer.send({
|
|
1691
|
+
topic: e.topic,
|
|
1692
|
+
messages: [{ value: JSON.stringify(evt) }]
|
|
1693
|
+
});
|
|
1694
|
+
await this.producer.disconnect();
|
|
1695
|
+
} catch (error) {
|
|
1696
|
+
throw new InternalError(error.toString());
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
async start(autocommit = false) {
|
|
1700
|
+
this.consumer.on(this.consumer.events.CRASH, async (error) => {
|
|
1701
|
+
await this.execCallback(this._onError, new InternalError(ErrorManager.APP_ERRORS.PROCESS, error.payload.error.stack));
|
|
1702
|
+
});
|
|
1703
|
+
await this.run(autocommit);
|
|
1704
|
+
}
|
|
1705
|
+
async pause() {
|
|
1706
|
+
}
|
|
1707
|
+
async restart() {
|
|
1708
|
+
await this.consumer.stop();
|
|
1709
|
+
await this.start();
|
|
1710
|
+
}
|
|
1711
|
+
async stop() {
|
|
1712
|
+
await this.consumer.stop();
|
|
1713
|
+
}
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1716
|
+
// src/infrastructure/mysql/Mysql.ts
|
|
1717
|
+
var import_promise = require("mysql2/promise");
|
|
1718
|
+
var _MysqlConnector = class _MysqlConnector {
|
|
1719
|
+
constructor(pool) {
|
|
1720
|
+
this._pool = pool ?? (0, import_promise.createPool)({
|
|
1721
|
+
host: process.env.DB_HOST,
|
|
1722
|
+
port: Number(process.env.DB_PORT ?? 3306),
|
|
1723
|
+
user: process.env.DB_USER,
|
|
1724
|
+
password: process.env.DB_PASSWORD,
|
|
1725
|
+
database: process.env.DB_DATABASE,
|
|
1726
|
+
dateStrings: true,
|
|
1727
|
+
connectionLimit: Number(process.env.DB_POOL_SIZE ?? _MysqlConnector.DEFAULT_POOL_SIZE),
|
|
1728
|
+
decimalNumbers: true
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
async wrap(conn) {
|
|
1732
|
+
return new MysqlConnection(conn);
|
|
1733
|
+
}
|
|
1734
|
+
async query(sql, params = []) {
|
|
1735
|
+
const [rows] = await this._pool.query(sql, params);
|
|
1736
|
+
return rows;
|
|
1737
|
+
}
|
|
1738
|
+
async getConnection() {
|
|
1739
|
+
const conn = await this._pool.getConnection();
|
|
1740
|
+
return this.wrap(conn);
|
|
1741
|
+
}
|
|
1742
|
+
async closePool() {
|
|
1743
|
+
await this._pool.end();
|
|
1744
|
+
}
|
|
1745
|
+
static async ping() {
|
|
1746
|
+
const connector = new _MysqlConnector();
|
|
1747
|
+
try {
|
|
1748
|
+
const conn = await connector._pool.getConnection();
|
|
1749
|
+
await conn.ping();
|
|
1750
|
+
conn.release();
|
|
1751
|
+
return true;
|
|
1752
|
+
} catch {
|
|
1753
|
+
return false;
|
|
1754
|
+
} finally {
|
|
1755
|
+
await connector.closePool();
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
};
|
|
1759
|
+
_MysqlConnector.DEFAULT_POOL_SIZE = 20;
|
|
1760
|
+
var MysqlConnector = _MysqlConnector;
|
|
1761
|
+
var MysqlConnection = class {
|
|
1762
|
+
constructor(conn) {
|
|
1763
|
+
this._conn = conn;
|
|
1764
|
+
}
|
|
1765
|
+
async query(statement, params = []) {
|
|
1766
|
+
const [rows] = await this._conn.query(statement, params);
|
|
1767
|
+
return rows;
|
|
1768
|
+
}
|
|
1769
|
+
async begin() {
|
|
1770
|
+
await this._conn.beginTransaction();
|
|
1771
|
+
}
|
|
1772
|
+
async commit() {
|
|
1773
|
+
await this._conn.commit();
|
|
1774
|
+
}
|
|
1775
|
+
async rollback() {
|
|
1776
|
+
await this._conn.rollback();
|
|
1777
|
+
}
|
|
1778
|
+
async transaction(fn) {
|
|
1779
|
+
await this.begin();
|
|
1780
|
+
try {
|
|
1781
|
+
const result = await fn(this);
|
|
1782
|
+
await this.commit();
|
|
1783
|
+
return result;
|
|
1784
|
+
} catch (err) {
|
|
1785
|
+
await this.rollback();
|
|
1786
|
+
throw err;
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
async close() {
|
|
1790
|
+
await this._conn.release();
|
|
1791
|
+
}
|
|
1792
|
+
};
|
|
1793
|
+
|
|
1794
|
+
// src/infrastructure/runners/default-mysql-outbox-runner.ts
|
|
1795
|
+
var DefaultMysqlOutboxRunner = class {
|
|
1796
|
+
constructor(uowFactory, eventManager) {
|
|
1797
|
+
this.errors = [];
|
|
1798
|
+
this.uowFactory = uowFactory;
|
|
1799
|
+
this.eventManager = eventManager;
|
|
1800
|
+
this.interval = Number(process.env.OUTBOX_RUNNER_INTERVAL_MS || 5e3);
|
|
1801
|
+
this.maxEvents = Number(process.env.OUTBOX_RUNNER_MAX_EVENTS || 20);
|
|
1802
|
+
}
|
|
1803
|
+
addError(error) {
|
|
1804
|
+
this.errors.push(error);
|
|
1805
|
+
}
|
|
1806
|
+
logErrors() {
|
|
1807
|
+
if (this.errors.length > 0) {
|
|
1808
|
+
console.error(this.errors);
|
|
1809
|
+
this.errors = [];
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
async sleep() {
|
|
1813
|
+
return new Promise((r) => setTimeout(r, this.maxEvents));
|
|
1814
|
+
}
|
|
1815
|
+
async processOutboxRecord(e, eventBusRepository) {
|
|
1816
|
+
try {
|
|
1817
|
+
e.markProcessing();
|
|
1818
|
+
await eventBusRepository.update(e);
|
|
1819
|
+
await this.eventManager.send({
|
|
1820
|
+
topic: e.topic,
|
|
1821
|
+
producer: process.env.NAME && process.env.ENVIRONMENT ? `${process.env.NAME}-${process.env.ENVIRONMENT}` : "unknown",
|
|
1822
|
+
tenant: e.tenantUuid,
|
|
1823
|
+
message: e.payload
|
|
1824
|
+
});
|
|
1825
|
+
e.markProcessed();
|
|
1826
|
+
} catch (error) {
|
|
1827
|
+
const type = String(error.type);
|
|
1828
|
+
e.markWithError(type);
|
|
1829
|
+
throw new Error(type);
|
|
1830
|
+
} finally {
|
|
1831
|
+
await eventBusRepository.update(e);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
async process() {
|
|
1835
|
+
const uow = await this.uowFactory.create();
|
|
1836
|
+
const eventBusRepository = new EventBusMysqlRepository(uow.connection);
|
|
1837
|
+
await uow.execute(async () => {
|
|
1838
|
+
const records = await eventBusRepository.listPending(this.maxEvents);
|
|
1839
|
+
for (let record of records) {
|
|
1840
|
+
try {
|
|
1841
|
+
await this.processOutboxRecord(record, eventBusRepository);
|
|
1842
|
+
} catch (error) {
|
|
1843
|
+
this.addError({ eventUuid: record.eventUuid.value, error: error.toString() });
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
this.logErrors();
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
async start() {
|
|
1850
|
+
console.log("[outbox-runner]: start");
|
|
1851
|
+
for (; ; ) {
|
|
1852
|
+
await this.process();
|
|
1853
|
+
await this.sleep();
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
};
|
|
1857
|
+
|
|
1858
|
+
// src/infrastructure/inbox/InboxMysqlRepository.ts
|
|
1859
|
+
var InboxMysqlRepository = class {
|
|
1860
|
+
constructor(connection) {
|
|
1861
|
+
this.connection = connection;
|
|
1862
|
+
}
|
|
1863
|
+
recordToRowValues(record) {
|
|
1864
|
+
return [
|
|
1865
|
+
record.eventUuid.value,
|
|
1866
|
+
record.tenantUuid.value,
|
|
1867
|
+
record.topic,
|
|
1868
|
+
record.producer,
|
|
1869
|
+
record.payload,
|
|
1870
|
+
record.status.value,
|
|
1871
|
+
record.attempts,
|
|
1872
|
+
record.errorMessage,
|
|
1873
|
+
record.lastAttempt?.value ?? null,
|
|
1874
|
+
record.processedAt?.value ?? null,
|
|
1875
|
+
record.createdAt.value
|
|
1876
|
+
];
|
|
1877
|
+
}
|
|
1878
|
+
async create(record) {
|
|
1879
|
+
const values = this.recordToRowValues(record);
|
|
1880
|
+
await this.connection.query(
|
|
1881
|
+
`INSERT INTO events_inbox (event_uuid, tenant_uuid, topic, producer,
|
|
1882
|
+
payload, status, attempts, error_message, last_attempt, processed_at, created_at)
|
|
1883
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
1884
|
+
values
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
async update(record) {
|
|
1888
|
+
const values = [record.status.value, record.attempts, record.errorMessage, record.processedAt?.value, record.lastAttempt?.value, record.eventUuid.value];
|
|
1889
|
+
await this.connection.query(
|
|
1890
|
+
`UPDATE events_inbox
|
|
1891
|
+
SET status = ?,
|
|
1892
|
+
attempts = ?,
|
|
1893
|
+
error_message = ?,
|
|
1894
|
+
processed_at = ?,
|
|
1895
|
+
last_attempt = ?
|
|
1896
|
+
WHERE event_uuid = ?`,
|
|
1897
|
+
values
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
async listPending(limit) {
|
|
1901
|
+
const result = await this.connection.query(
|
|
1902
|
+
`SELECT * FROM events_inbox WHERE status IN ('PENDING','FAILED') AND events_inbox.processed_at IS NULL LIMIT ${limit}`,
|
|
1903
|
+
[]
|
|
1904
|
+
);
|
|
1905
|
+
return result.length > 0 ? result.map((r) => InboxRecord.reconstitute(r)) : [];
|
|
1906
|
+
}
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
// src/infrastructure/runners/default-mysql-inbox-runner.ts
|
|
1910
|
+
var DefaultMysqlInboxRunner = class {
|
|
1911
|
+
constructor(uowFactory, eventManager) {
|
|
1912
|
+
this.topics = [];
|
|
1913
|
+
this.uowFactory = uowFactory;
|
|
1914
|
+
this.eventManager = eventManager;
|
|
1915
|
+
this.interval = Number(process.env.OUTBOX_RUNNER_INTERVAL_MS || 5e3);
|
|
1916
|
+
this.maxEvents = Number(process.env.OUTBOX_RUNNER_MAX_EVENTS || 20);
|
|
1917
|
+
}
|
|
1918
|
+
async saveEvent(e, repository) {
|
|
1919
|
+
let record = new InboxRecord(
|
|
1920
|
+
UUID.create(),
|
|
1921
|
+
e.tenant,
|
|
1922
|
+
e.topic,
|
|
1923
|
+
e.producer,
|
|
1924
|
+
JSON.stringify(e.message),
|
|
1925
|
+
ProcessStatus.PENDING
|
|
1926
|
+
);
|
|
1927
|
+
try {
|
|
1928
|
+
await repository.create(record);
|
|
1929
|
+
} catch (error) {
|
|
1930
|
+
const type = String(error.type);
|
|
1931
|
+
record.markWithError(type);
|
|
1932
|
+
throw new Error(type);
|
|
1933
|
+
} finally {
|
|
1934
|
+
await repository.update(record);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
subscribeTo(topic) {
|
|
1938
|
+
this.topics.push(topic);
|
|
1939
|
+
}
|
|
1940
|
+
async process() {
|
|
1941
|
+
const uow = await this.uowFactory.create();
|
|
1942
|
+
const inboxRepository = new InboxMysqlRepository(uow.connection);
|
|
1943
|
+
await uow.execute(async () => {
|
|
1944
|
+
for (let topic of this.topics) {
|
|
1945
|
+
try {
|
|
1946
|
+
this.eventManager.route(topic, async (e) => {
|
|
1947
|
+
await this.saveEvent(e, inboxRepository);
|
|
1948
|
+
});
|
|
1949
|
+
} catch (error) {
|
|
1950
|
+
console.log(error.toString());
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
await this.eventManager.start();
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
async start() {
|
|
1957
|
+
console.log("[inbox-runner]: start");
|
|
1958
|
+
for (; ; ) {
|
|
1959
|
+
await this.process();
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
|
|
1964
|
+
// src/utils/ExchangeRates.ts
|
|
1965
|
+
var ExchangeRates = class _ExchangeRates extends BaseObject {
|
|
1966
|
+
constructor(props) {
|
|
1967
|
+
super(props);
|
|
1968
|
+
}
|
|
1969
|
+
getRate(currency) {
|
|
1970
|
+
if (Object.keys(this.props.rates).includes(currency.value)) {
|
|
1971
|
+
return this.props.rates[currency.value];
|
|
1972
|
+
}
|
|
1973
|
+
return null;
|
|
1974
|
+
}
|
|
1975
|
+
get base() {
|
|
1976
|
+
return this.props.base;
|
|
1977
|
+
}
|
|
1978
|
+
get rates() {
|
|
1979
|
+
return this.props.rates;
|
|
1980
|
+
}
|
|
1981
|
+
get date() {
|
|
1982
|
+
return this.props.date;
|
|
1983
|
+
}
|
|
1984
|
+
toProps() {
|
|
1985
|
+
return this.props;
|
|
1986
|
+
}
|
|
1987
|
+
toPrimitives() {
|
|
1988
|
+
return {
|
|
1989
|
+
base: this.props.base.value,
|
|
1990
|
+
rates: this.props.rates,
|
|
1991
|
+
date: this.props.date.value
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
exchangeToBase(price) {
|
|
1995
|
+
const rate = this.getRate(price.currency);
|
|
1996
|
+
if (!rate) {
|
|
1997
|
+
throw new InternalError("INVALID_EXCHANGE_RATE_CURRENCY", `Avaiable rates: ${this.props.rates} - Base Currency:${this.props.base.value} - Price Currency: ${price.currency.value}`);
|
|
1998
|
+
}
|
|
1999
|
+
if (price.currency.value === this.props.base.value) {
|
|
2000
|
+
return price;
|
|
2001
|
+
}
|
|
2002
|
+
return Price.create(parseFloat((price.amount / rate).toFixed(2)), this.props.base.value);
|
|
2003
|
+
}
|
|
2004
|
+
static create(props) {
|
|
2005
|
+
return new _ExchangeRates(props);
|
|
2006
|
+
}
|
|
2007
|
+
static createFromPrimitives(data) {
|
|
2008
|
+
return _ExchangeRates.create({
|
|
2009
|
+
base: Currency.create(data.base),
|
|
2010
|
+
rates: data.rates ?? [],
|
|
2011
|
+
date: DateTime.create(data.date ?? "")
|
|
2012
|
+
});
|
|
686
2013
|
}
|
|
687
2014
|
};
|
|
688
2015
|
// Annotate the CommonJS export names for ESM import in node:
|
|
689
2016
|
0 && (module.exports = {
|
|
2017
|
+
BaseEvent,
|
|
2018
|
+
BaseObject,
|
|
2019
|
+
BasicUnitOfWork,
|
|
2020
|
+
BasicUnitOfWorkFactory,
|
|
2021
|
+
Country,
|
|
690
2022
|
Currency,
|
|
691
2023
|
DateTime,
|
|
2024
|
+
DefaultMysqlInboxRunner,
|
|
2025
|
+
DefaultMysqlOutboxRunner,
|
|
692
2026
|
DomainEntity,
|
|
693
2027
|
DomainError,
|
|
694
2028
|
DomainEvent,
|
|
695
2029
|
Email,
|
|
696
2030
|
ErrorManager,
|
|
2031
|
+
EventBus,
|
|
2032
|
+
EventBusMysqlRepository,
|
|
2033
|
+
EventManager,
|
|
2034
|
+
ExchangeRates,
|
|
697
2035
|
FatalError,
|
|
698
2036
|
HttpHealthCheckController,
|
|
699
2037
|
HttpNotFoundController,
|
|
2038
|
+
InboxRecord,
|
|
2039
|
+
IntegrationEvent,
|
|
700
2040
|
InternalError,
|
|
2041
|
+
KafkaManager,
|
|
701
2042
|
Language,
|
|
702
2043
|
MysqlConnection,
|
|
703
2044
|
MysqlConnector,
|
|
2045
|
+
OutboxRecord,
|
|
2046
|
+
PaymentGateway,
|
|
2047
|
+
PaymentStatus,
|
|
704
2048
|
Price,
|
|
2049
|
+
ProcessStatus,
|
|
2050
|
+
StringVars,
|
|
705
2051
|
UUID,
|
|
706
2052
|
UsageError,
|
|
707
2053
|
ValueObject,
|