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