wsp-ms-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +29 -0
  2. package/jest.config.cjs +9 -0
  3. package/package.json +71 -0
  4. package/src/application/contracts/EventBus.ts +7 -0
  5. package/src/application/contracts/EventBusRepository.ts +10 -0
  6. package/src/domain/contracts/DomainEntity.ts +58 -0
  7. package/src/domain/contracts/DomainError.ts +9 -0
  8. package/src/domain/contracts/DomainEvent.ts +22 -0
  9. package/src/domain/contracts/ValueObject.ts +26 -0
  10. package/src/domain/errors/FatalError.ts +9 -0
  11. package/src/domain/errors/InternalError.ts +9 -0
  12. package/src/domain/errors/UsageError.ts +12 -0
  13. package/src/domain/value-objects/Currency.ts +68 -0
  14. package/src/domain/value-objects/DateTime.ts +132 -0
  15. package/src/domain/value-objects/Email.ts +24 -0
  16. package/src/domain/value-objects/Language.ts +94 -0
  17. package/src/domain/value-objects/Price.ts +54 -0
  18. package/src/domain/value-objects/UUID.ts +23 -0
  19. package/src/index.ts +43 -0
  20. package/src/infrastructure/contracts/DatabaseConnection.ts +11 -0
  21. package/src/infrastructure/contracts/DatabaseConnector.ts +8 -0
  22. package/src/infrastructure/contracts/Logger.ts +9 -0
  23. package/src/infrastructure/errors/ErrorManager.ts +93 -0
  24. package/src/infrastructure/mysql/MysqlConnection.ts +45 -0
  25. package/src/infrastructure/mysql/MysqlConnector.ts +51 -0
  26. package/src/utils/StringVars.ts +14 -0
  27. package/test/domain/value-objects/Currency.test.ts +48 -0
  28. package/test/domain/value-objects/DateTime.test.ts +32 -0
  29. package/test/domain/value-objects/Email.test.ts +38 -0
  30. package/test/domain/value-objects/Language.test.ts +76 -0
  31. package/test/domain/value-objects/Price.test.ts +96 -0
  32. package/test/domain/value-objects/UUID.test.ts +18 -0
  33. package/test/infrastructure/errors/ErrorManager.test.ts +125 -0
  34. package/test/infrastructure/mysql/MysqlConnection.test.ts +45 -0
  35. package/tsconfig.json +14 -0
  36. package/tsup.config.ts +18 -0
@@ -0,0 +1,125 @@
1
+ import { ErrorManager, ErrorTemplate } from '@infrastructure/errors/ErrorManager';
2
+ import { Language } from '@domain/value-objects/Language';
3
+ import {Logger} from "@infrastructure/contracts/Logger";
4
+ import {FatalError} from "@domain/errors/FatalError";
5
+ import {InternalError} from "@domain/errors/InternalError";
6
+ import {UsageError} from "@domain/errors/UsageError";
7
+
8
+ describe('ErrorManager', () => {
9
+ let logger: Logger;
10
+ let manager: ErrorManager;
11
+
12
+ beforeEach(() => {
13
+ // Reset environment and templates
14
+ delete process.env.ENVIRONMENT;
15
+ manager = new ErrorManager(logger = {
16
+ debug: jest.fn(),
17
+ info: jest.fn(),
18
+ warn: jest.fn(),
19
+ error: jest.fn(),
20
+ fatal: jest.fn(),
21
+ });
22
+ // Clear private TEMPLATES map
23
+ (ErrorManager as any).TEMPLATES.clear();
24
+ });
25
+
26
+ describe('handle FatalError', () => {
27
+ it('logs fatal and returns default message for exact language', () => {
28
+ const err = new FatalError('TEST_FATAL', 'fatal happened');
29
+ const lang = Language.create('es');
30
+ const res = manager.handle(err, lang);
31
+ expect(logger.fatal).toHaveBeenCalledWith('TEST_FATAL', 'fatal happened');
32
+ expect(res).toEqual({
33
+ status: 'ERROR',
34
+ message: 'Ups, hemos encontrado un error. Nuestro equipo ya está trabajando para solucionarlo',
35
+ });
36
+ });
37
+
38
+ it('falls back to base language if specific not defined', () => {
39
+ const err = new FatalError('TF', 'msg');
40
+ const lang = Language.create('es-uy');
41
+ const res = manager.handle(err, lang);
42
+ // 'es-uy' not in DEFAULT_MESSAGES, fallback to 'es'
43
+ expect(res.message).toContain('Ups, hemos encontrado un error');
44
+ });
45
+ });
46
+
47
+ describe('handle InternalError', () => {
48
+ it('logs error and returns default message', () => {
49
+ const err = new InternalError('DB_ERR', 'db failure');
50
+ const lang = Language.create('en-gb');
51
+ const res = manager.handle(err, lang);
52
+ expect(logger.error).toHaveBeenCalledWith('DB_ERR', 'db failure');
53
+ expect(res).toEqual({
54
+ status: 'ERROR',
55
+ message: 'Ups, we found an error. Our team is working on it.',
56
+ });
57
+ });
58
+ });
59
+
60
+ describe('handle UsageError without template', () => {
61
+ it('logs template-not-found and returns default fallback', () => {
62
+ const err = new UsageError('MISSING', { foo: 'bar' });
63
+ const lang = Language.create('pt-br');
64
+ const res = manager.handle(err, lang);
65
+ expect(logger.error).toHaveBeenCalledWith('TEMPLATE_NOT_FOUND', 'MISSING');
66
+ expect(res).toEqual({
67
+ status: 'ERROR',
68
+ message: 'Ops, encontramos um bug. Nossa equipe já está trabalhando para resolver isso.',
69
+ });
70
+ });
71
+ });
72
+
73
+ describe('handle UsageError with template', () => {
74
+ it('renders template for exact locale', () => {
75
+ const tmpl: ErrorTemplate = {
76
+ type: 'GREETING',
77
+ languages: {
78
+ 'es': 'Hola {{name}}',
79
+ 'en': 'Hello {{name}}',
80
+ },
81
+ };
82
+ ErrorManager.addTemplate(tmpl);
83
+
84
+ const err = new UsageError('GREETING', { name: 'Luis' });
85
+ const lang = Language.create('es');
86
+ const res = manager.handle(err, lang);
87
+ expect(res).toEqual({
88
+ status: 'ERROR',
89
+ message: 'Hola Luis',
90
+ });
91
+ });
92
+
93
+ it('falls back to base locale if exact not present', () => {
94
+ const tmpl: ErrorTemplate = {
95
+ type: 'BYE',
96
+ languages: {
97
+ 'en': 'Bye {{who}}',
98
+ },
99
+ };
100
+ ErrorManager.addTemplate(tmpl);
101
+
102
+ const err = new UsageError('BYE', { who: 'World' });
103
+ const lang = Language.create('en-au');
104
+ const res = manager.handle(err, lang);
105
+ expect(res).toEqual({
106
+ status: 'ERROR',
107
+ message: 'Bye World',
108
+ });
109
+ });
110
+ });
111
+
112
+ describe('handle unknown Error', () => {
113
+ it('logs unknown and returns default message', () => {
114
+ const err = new Error('something bad');
115
+ const lang = Language.create('en');
116
+ const res = manager.handle(err, lang);
117
+ expect(logger.error).toHaveBeenCalledWith('UNKNOWN_ERROR', 'something bad');
118
+ expect(res).toEqual({
119
+ status: 'ERROR',
120
+ message: 'Ups, we found an error. Our team is working on it.',
121
+ });
122
+ });
123
+ });
124
+
125
+ });
@@ -0,0 +1,45 @@
1
+ import { MysqlConnection } from '@infrastructure/mysql/MysqlConnection';
2
+ import { PoolConnection } from 'mysql2/promise';
3
+
4
+ describe('MysqlConnection transaction()', () => {
5
+ it('wraps begin → commit on success', async () => {
6
+ const mockConn = {
7
+ beginTransaction: jest.fn(),
8
+ commit: jest.fn(),
9
+ rollback: jest.fn(),
10
+ query: jest.fn().mockResolvedValue([[]]),
11
+ release: jest.fn(),
12
+ } as unknown as PoolConnection;
13
+
14
+ const db = new MysqlConnection(mockConn);
15
+
16
+ await db.transaction(async (c) => {
17
+ await c.query('SELECT 1');
18
+ });
19
+
20
+ expect(mockConn.beginTransaction).toHaveBeenCalled();
21
+ expect(mockConn.commit).toHaveBeenCalled();
22
+ expect(mockConn.rollback).not.toHaveBeenCalled();
23
+ });
24
+
25
+ it('wraps begin → rollback on error', async () => {
26
+ const mockConn = {
27
+ beginTransaction: jest.fn(),
28
+ commit: jest.fn(),
29
+ rollback: jest.fn(),
30
+ query: jest.fn().mockResolvedValue([[]]),
31
+ release: jest.fn(),
32
+ } as unknown as PoolConnection;
33
+
34
+ const db = new MysqlConnection(mockConn);
35
+
36
+ await expect(
37
+ db.transaction(async () => {
38
+ throw new Error('fail');
39
+ }),
40
+ ).rejects.toThrow('fail');
41
+
42
+ expect(mockConn.rollback).toHaveBeenCalled();
43
+ expect(mockConn.commit).not.toHaveBeenCalled();
44
+ });
45
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "types": ["node", "jest"],
6
+ "baseUrl": "src",
7
+ "paths": {
8
+ "@domain/*": ["domain/*"],
9
+ "@application/*": ["application/*"],
10
+ "@infrastructure/*":["infrastructure/*"],
11
+ "@utils/*": ["utils/*"]
12
+ },
13
+ }
14
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { defineConfig } from 'tsup';
2
+ import alias from 'esbuild-plugin-alias';
3
+ import path from 'path';
4
+
5
+ export default defineConfig({
6
+ entry: ['src/index.ts'],
7
+ format: ['esm', 'cjs'],
8
+ dts: true,
9
+ sourcemap: true,
10
+ esbuildPlugins: [
11
+ alias({
12
+ '@domain': path.resolve(__dirname, 'src/domain'),
13
+ '@application': path.resolve(__dirname, 'src/application'),
14
+ '@infrastructure':path.resolve(__dirname, 'src/infrastructure'),
15
+ '@utils': path.resolve(__dirname, 'src/utils'),
16
+ }),
17
+ ],
18
+ });