framework-do-dede 3.4.0 → 4.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 (43) hide show
  1. package/README.md +77 -14
  2. package/dist/application/controller.d.ts +6 -2
  3. package/dist/application/controller.js +10 -18
  4. package/dist/application/index.d.ts +1 -1
  5. package/dist/application/index.js +1 -1
  6. package/dist/application/services.d.ts +2 -1
  7. package/dist/application/services.js +3 -3
  8. package/dist/dede.d.ts +10 -1
  9. package/dist/dede.js +30 -9
  10. package/dist/domain/entity.d.ts +4 -0
  11. package/dist/domain/entity.js +25 -0
  12. package/dist/domain/errors/app-error.d.ts +12 -0
  13. package/dist/domain/errors/app-error.js +14 -0
  14. package/dist/domain/errors/http-errors.d.ts +42 -0
  15. package/dist/domain/errors/http-errors.js +40 -0
  16. package/dist/domain/index.d.ts +2 -0
  17. package/dist/domain/index.js +2 -0
  18. package/dist/http/controller.handler.d.ts +4 -5
  19. package/dist/http/controller.handler.js +27 -119
  20. package/dist/http/errors/server.d.ts +2 -28
  21. package/dist/http/errors/server.js +2 -49
  22. package/dist/http/http-server.d.ts +2 -0
  23. package/dist/http/http-server.js +1 -1
  24. package/dist/http/index.d.ts +2 -2
  25. package/dist/http/index.js +2 -2
  26. package/dist/index.d.ts +4 -3
  27. package/dist/index.js +4 -3
  28. package/dist/infra/di/registry.d.ts +4 -6
  29. package/dist/infra/di/registry.js +7 -10
  30. package/dist/{application → infra/serialization}/entity.d.ts +3 -1
  31. package/dist/{application → infra/serialization}/entity.js +7 -25
  32. package/dist/interface/errors/http-error-mapper.d.ts +10 -0
  33. package/dist/interface/errors/http-error-mapper.js +31 -0
  34. package/dist/interface/http/middleware-executor.d.ts +10 -0
  35. package/dist/interface/http/middleware-executor.js +33 -0
  36. package/dist/interface/http/request-mapper.d.ts +21 -0
  37. package/dist/interface/http/request-mapper.js +55 -0
  38. package/dist/interface/validation/class-validator.d.ts +6 -0
  39. package/dist/interface/validation/class-validator.js +28 -0
  40. package/dist/interface/validation/validator.d.ts +5 -0
  41. package/dist/interface/validation/validator.js +1 -0
  42. package/dist/protocols/repository.d.ts +1 -1
  43. package/package.json +5 -2
package/README.md CHANGED
@@ -15,7 +15,7 @@ Um framework TypeScript simples para construir APIs HTTP com controllers, use ca
15
15
  - Entity e Serialização
16
16
  - Hooks Before/After ToEntity
17
17
  - Storage Gateway
18
- - DI (Registry/Inject)
18
+ - DI (Container/Inject)
19
19
  - Errors
20
20
  - Protocolos de Repositório
21
21
  - Exemplos
@@ -23,6 +23,7 @@ Um framework TypeScript simples para construir APIs HTTP com controllers, use ca
23
23
  - Elysia
24
24
  - Fila com AfterToEntity
25
25
  - Testes
26
+ - Benchmark
26
27
 
27
28
  ## Instalação
28
29
 
@@ -62,17 +63,19 @@ class HelloUseCase extends UseCase<{ name?: string }, { message: string }> {
62
63
  }
63
64
  }
64
65
 
65
- await Dede.start({
66
+ const app = await Dede.create({
66
67
  framework: { use: 'express', port: 3000 },
67
68
  registries: []
68
69
  });
70
+ app.registerControllers([HelloController]);
71
+ app.listen();
69
72
  ```
70
73
 
71
74
  ## Conceitos
72
75
 
73
76
  ### Controllers e Rotas
74
77
 
75
- Use decorators para expor métodos como rotas HTTP. O Controller registra o class loader no Registry e o ControllerHandler monta as rotas em runtime.
78
+ Use decorators para expor métodos como rotas HTTP. O Controller define metadados, e o ControllerHandler monta as rotas em runtime a partir da lista de controllers passada ao `app.registerControllers(...)`.
76
79
 
77
80
  ```ts
78
81
  import { Controller, Get, Post, Put, Delete, Patch } from './src';
@@ -105,6 +108,7 @@ Opções de rota (comuns):
105
108
  - `params`, `query`, `headers`, `body`: array de strings no formato `campo|tipo`
106
109
  - `bodyFilter`: `"restrict" | "none"`
107
110
  - `responseType`: `"json" | "text" | "html"`
111
+ - `validator`: pode ser uma classe com decorators do `class-validator` **ou** um objeto com `validate(data)` (sync/async)
108
112
 
109
113
  ### Input, params e filtros
110
114
 
@@ -121,7 +125,7 @@ Tipos suportados no filtro:
121
125
 
122
126
  - `boolean`, `integer`, `string`, `number`
123
127
 
124
- Exemplo:
128
+ Exemplos:
125
129
 
126
130
  ```ts
127
131
  @Put({
@@ -129,13 +133,38 @@ Exemplo:
129
133
  query: ['active|boolean'],
130
134
  headers: ['x-type|string'],
131
135
  body: ['name|string'],
132
- bodyFilter: 'restrict'
136
+ bodyFilter: 'restrict',
137
+ validator: CreateUserDto
133
138
  })
134
139
  async update(request: { data: any }) {
135
140
  // request.data: { id, active, 'x-type', name }
136
141
  }
137
142
  ```
138
143
 
144
+ ```ts
145
+ import 'reflect-metadata'
146
+ import { IsEmail, IsNotEmpty } from 'class-validator'
147
+
148
+ class CreateUserDto {
149
+ @IsNotEmpty({ message: 'O nome é obrigatório.' })
150
+ name!: string
151
+
152
+ @IsEmail({}, { message: 'Email inválido.' })
153
+ email?: string
154
+ }
155
+ ```
156
+
157
+ ```ts
158
+ @Put({
159
+ body: ['name|string', 'email|string'],
160
+ bodyFilter: 'restrict',
161
+ validator: CreateUserDto
162
+ })
163
+ async update(request: { data: any }) {}
164
+ ```
165
+
166
+ Obs: o framework usa `class-validator` como `peerDependency`, então o projeto que consome deve ter a mesma versão instalada.
167
+
139
168
  Suporte a notacao com colchetes:
140
169
 
141
170
  ```json
@@ -229,6 +258,8 @@ Entities suportam:
229
258
  - `toData()` e `toAsyncData()`
230
259
  - `@Serialize`, `@Restrict`, `@VirtualProperty`, `@GetterPrefix`
231
260
 
261
+ Obs: a serializacao fica na camada de infraestrutura, mas a API continua sendo exposta pelo framework (importe direto de `./src`).
262
+
232
263
  ```ts
233
264
  import { Entity, Serialize, Restrict, VirtualProperty, GetterPrefix } from './src';
234
265
 
@@ -319,21 +350,22 @@ class FileService {
319
350
  }
320
351
  ```
321
352
 
322
- ### DI (Registry/Inject)
353
+ ### DI (Container/Inject)
323
354
 
324
- Registre dependencias ao iniciar o server:
355
+ Registre dependencias ao iniciar o server (usando o container padrão):
325
356
 
326
357
  ```ts
327
358
  import { Dede } from './src';
328
359
 
329
360
  class UserRepository { /* ... */ }
330
361
 
331
- await Dede.start({
362
+ const app = await Dede.create({
332
363
  framework: { use: 'express', port: 3000 },
333
364
  registries: [
334
365
  { name: 'UserRepository', classLoader: UserRepository }
335
366
  ]
336
367
  });
368
+ app.listen();
337
369
  ```
338
370
 
339
371
  Use `@Inject('Name')` para injetar dependencias:
@@ -363,7 +395,7 @@ Erros de dominio disponiveis:
363
395
  - `UnprocessableEntity` (422)
364
396
  - `InternalServerError` (500)
365
397
 
366
- Quando um erro e lancado, o handler padroniza a resposta. Se o erro for `CustomServerError`, o payload customizado sera retornado diretamente.
398
+ Quando um erro e lancado, o handler padroniza a resposta. Erros de dominio (`AppError`) sao mapeados para HTTP. Se o erro for `CustomServerError`, o payload customizado sera retornado diretamente.
367
399
 
368
400
  ### Protocolos de Repositorio
369
401
 
@@ -385,7 +417,7 @@ Interfaces tipadas para padrao de repositorio:
385
417
 
386
418
  ```ts
387
419
  import { Dede } from './src/dede';
388
- import './example/express_app/example.controller';
420
+ import { ExampleController } from './example/express_app/example.controller';
389
421
 
390
422
  class UserRepository {
391
423
  async findById(id: string) {
@@ -393,28 +425,32 @@ class UserRepository {
393
425
  }
394
426
  }
395
427
 
396
- await Dede.start({
428
+ const app = await Dede.create({
397
429
  framework: { use: 'express', port: 3000 },
398
430
  registries: [{ name: 'UserRepository', classLoader: UserRepository }]
399
431
  });
432
+ app.registerControllers([ExampleController]);
433
+ app.listen();
400
434
  ```
401
435
 
402
436
  ### Elysia
403
437
 
404
438
  ```ts
405
439
  import { Dede } from './src/dede';
406
- import './example/express_app/example.controller';
440
+ import { ExampleController } from './example/express_app/example.controller';
407
441
 
408
- await Dede.start({
442
+ const app = await Dede.create({
409
443
  framework: { use: 'elysia', port: 3001 },
410
444
  registries: []
411
445
  });
446
+ app.registerControllers([ExampleController]);
447
+ app.listen();
412
448
  ```
413
449
 
414
450
  ### Fila com AfterToEntity
415
451
 
416
452
  ```ts
417
- import { Entity, AfterToEntity } from './src/application/entity';
453
+ import { Entity, AfterToEntity } from './src';
418
454
 
419
455
  type QueueJob = { type: string; payload: Record<string, any> };
420
456
 
@@ -461,3 +497,30 @@ const serialized = entity.toEntity();
461
497
  ```bash
462
498
  npm test -- tests/src/application/entity.spec.ts --runInBand
463
499
  ```
500
+
501
+ Testes de integração (exemplos):
502
+
503
+ ```bash
504
+ RUN_EXAMPLE_TESTS=true npm test -- example/tests/main.test.ts
505
+ ```
506
+
507
+ Obs: os testes de Elysia só rodam no runtime do Bun (em Node eles são ignorados).
508
+
509
+ ## Benchmark
510
+
511
+ Resultados locais ficam em `bench/results.md`. Para rodar:
512
+
513
+ ```bash
514
+ npm run bench:compare
515
+ ```
516
+
517
+ Parâmetros (opcional):
518
+
519
+ ```bash
520
+ BENCH_REQUESTS=5000 BENCH_CONCURRENCY=50 BENCH_WARMUP=200 npm run bench:compare
521
+ ```
522
+
523
+ Resumo (média de 3 rodadas locais, 5000 req / conc 50 / warmup 200):
524
+
525
+ - Express: avg 3.34 ms, p50 2.45 ms, p95 8.54 ms, 8298.61 req/s
526
+ - Elysia: avg 3.16 ms, p50 2.63 ms, p95 6.98 ms, 8765.78 req/s
@@ -1,4 +1,5 @@
1
1
  import 'reflect-metadata';
2
+ import type { ValidatorLike } from "../interface/validation/validator";
2
3
  export interface Middleware {
3
4
  execute(input: Input<any>): Promise<any>;
4
5
  }
@@ -28,8 +29,6 @@ export interface Input<T, K = any> {
28
29
  type BodyFilter = "restrict" | "none";
29
30
  export declare function Controller(basePath?: string): (target: any) => void;
30
31
  export declare function Tracing<R>(tracer: Tracer<R>): (target: any, propertyKey?: string) => void;
31
- export declare function getControllers(): any[];
32
- export declare function flushControllers(): void;
33
32
  export declare function UseMiddleware(middlewareClass: MiddlewareDefinition): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
34
33
  export declare function UseMiddlewares(middlewareClasses: MiddlewareDefinition[]): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
35
34
  export declare function Post(config?: {
@@ -41,6 +40,7 @@ export declare function Post(config?: {
41
40
  body?: string[];
42
41
  bodyFilter?: BodyFilter;
43
42
  responseType?: 'json' | 'text' | 'html';
43
+ validator?: ValidatorLike;
44
44
  }): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
45
45
  export declare function Get(config?: {
46
46
  path?: string;
@@ -49,6 +49,7 @@ export declare function Get(config?: {
49
49
  query?: string[];
50
50
  headers?: string[];
51
51
  responseType?: 'json' | 'text' | 'html';
52
+ validator?: ValidatorLike;
52
53
  }): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
53
54
  export declare function Put(config?: {
54
55
  path?: string;
@@ -59,6 +60,7 @@ export declare function Put(config?: {
59
60
  body?: string[];
60
61
  bodyFilter?: BodyFilter;
61
62
  responseType?: 'json' | 'text' | 'html';
63
+ validator?: ValidatorLike;
62
64
  }): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
63
65
  export declare function Patch(config?: {
64
66
  path?: string;
@@ -69,6 +71,7 @@ export declare function Patch(config?: {
69
71
  body?: string[];
70
72
  bodyFilter?: BodyFilter;
71
73
  responseType?: 'json' | 'text' | 'html';
74
+ validator?: ValidatorLike;
72
75
  }): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
73
76
  export declare function Delete(config?: {
74
77
  path?: string;
@@ -79,5 +82,6 @@ export declare function Delete(config?: {
79
82
  body?: string[];
80
83
  bodyFilter?: BodyFilter;
81
84
  responseType?: 'json' | 'text' | 'html';
85
+ validator?: ValidatorLike;
82
86
  }): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
83
87
  export {};
@@ -1,14 +1,10 @@
1
1
  import 'reflect-metadata';
2
2
  import { FrameworkError } from "../http/errors/framework";
3
- import { Registry } from "../infra/di/registry";
4
- let controllers = [];
5
3
  export function Controller(basePath = '/') {
6
4
  return function (target) {
7
5
  if (!basePath)
8
6
  throw new FrameworkError('basePath cannot be empty');
9
7
  Reflect.defineMetadata('basePath', basePath, target);
10
- controllers.push(target.name);
11
- Registry.load(target.name, target);
12
8
  };
13
9
  }
14
10
  export function Tracing(tracer) {
@@ -21,15 +17,6 @@ export function Tracing(tracer) {
21
17
  }
22
18
  };
23
19
  }
24
- export function getControllers() {
25
- return controllers.map((controller) => Registry.inject(controller));
26
- }
27
- export function flushControllers() {
28
- controllers.map((controller) => {
29
- Registry.remove(controller);
30
- });
31
- controllers = [];
32
- }
33
20
  function isClass(fn) {
34
21
  return /^\s*class\s/.test(Function.prototype.toString.call(fn));
35
22
  }
@@ -78,7 +65,8 @@ export function Post(config = {}) {
78
65
  body: config.body,
79
66
  bodyFilter: config.bodyFilter || 'none',
80
67
  statusCode: config.statusCode || 200,
81
- responseType: config.responseType || 'json'
68
+ responseType: config.responseType || 'json',
69
+ validator: config.validator
82
70
  }, target, propertyKey);
83
71
  };
84
72
  }
@@ -91,7 +79,8 @@ export function Get(config = {}) {
91
79
  query: config.query,
92
80
  headers: config.headers,
93
81
  statusCode: config.statusCode || 200,
94
- responseType: config.responseType || 'json'
82
+ responseType: config.responseType || 'json',
83
+ validator: config.validator
95
84
  }, target, propertyKey);
96
85
  };
97
86
  }
@@ -106,7 +95,8 @@ export function Put(config = {}) {
106
95
  body: config.body,
107
96
  bodyFilter: config.bodyFilter || 'none',
108
97
  statusCode: config.statusCode || 200,
109
- responseType: config.responseType || 'json'
98
+ responseType: config.responseType || 'json',
99
+ validator: config.validator
110
100
  }, target, propertyKey);
111
101
  };
112
102
  }
@@ -121,7 +111,8 @@ export function Patch(config = {}) {
121
111
  body: config.body,
122
112
  bodyFilter: config.bodyFilter || 'none',
123
113
  statusCode: config.statusCode || 200,
124
- responseType: config.responseType || 'json'
114
+ responseType: config.responseType || 'json',
115
+ validator: config.validator
125
116
  }, target, propertyKey);
126
117
  };
127
118
  }
@@ -136,7 +127,8 @@ export function Delete(config = {}) {
136
127
  body: config.body,
137
128
  bodyFilter: config.bodyFilter || 'none',
138
129
  statusCode: config.statusCode || 200,
139
- responseType: config.responseType || 'json'
130
+ responseType: config.responseType || 'json',
131
+ validator: config.validator
140
132
  }, target, propertyKey);
141
133
  };
142
134
  }
@@ -1,5 +1,5 @@
1
1
  import { Controller, Post, Get, Put, Delete, Patch, UseMiddleware, UseMiddlewares, Tracing, type Middleware, type Input, type Tracer, type TracerData } from './controller';
2
- import { Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity } from './entity';
2
+ import { Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity } from '../infra/serialization/entity';
3
3
  import { DecorateUseCase, UseCase } from './usecase';
4
4
  import { Storage, type StorageGateway } from './services';
5
5
  export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Storage, Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity, };
@@ -1,5 +1,5 @@
1
1
  import { Controller, Post, Get, Put, Delete, Patch, UseMiddleware, UseMiddlewares, Tracing } from './controller';
2
- import { Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity } from './entity';
2
+ import { Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity } from '../infra/serialization/entity';
3
3
  import { DecorateUseCase, UseCase } from './usecase';
4
4
  import { Storage } from './services';
5
5
  export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Storage, Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity, };
@@ -1,7 +1,8 @@
1
+ import { Container } from "../infra/di/registry";
1
2
  import 'reflect-metadata';
2
3
  export interface StorageGateway {
3
4
  save(file: File, path: string): Promise<void>;
4
5
  get(key: string): Promise<string>;
5
6
  delete(key: string): Promise<boolean>;
6
7
  }
7
- export declare function Storage(gatewayName: string): (target: any, propertyKey: string) => void;
8
+ export declare function Storage(gatewayName: string, container?: Container): (target: any, propertyKey: string) => void;
@@ -1,12 +1,12 @@
1
- import { Registry } from "../infra/di/registry";
1
+ import { DefaultContainer } from "../infra/di/registry";
2
2
  import 'reflect-metadata';
3
- export function Storage(gatewayName) {
3
+ export function Storage(gatewayName, container = DefaultContainer) {
4
4
  return function (target, propertyKey) {
5
5
  let dependency;
6
6
  Object.defineProperty(target, propertyKey, {
7
7
  get: function () {
8
8
  if (!dependency) {
9
- dependency = Registry.inject(gatewayName);
9
+ dependency = container.inject(gatewayName);
10
10
  }
11
11
  if (!dependency.save || !dependency.get || !dependency.delete) {
12
12
  throw new Error(`${gatewayName} is not a valid StorageGateway`);
package/dist/dede.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Container } from "./infra/di/registry";
1
2
  export type Register = {
2
3
  name: string;
3
4
  classLoader: any;
@@ -8,15 +9,23 @@ export type Options = {
8
9
  port?: number;
9
10
  middlewares?: CallableFunction[];
10
11
  };
12
+ controllers?: any[];
11
13
  registries: Register[];
12
14
  defaultServerError?: string;
15
+ container?: Container;
13
16
  };
14
17
  export declare class Dede {
15
18
  private readonly framework;
16
19
  private readonly defaultServerError?;
20
+ private readonly container;
17
21
  private readonly httpServer;
22
+ private readonly port?;
23
+ private controllersRegistered;
18
24
  private constructor();
19
- static start({ framework, registries, defaultServerError }: Options): Promise<Dede>;
25
+ static create({ framework, registries, defaultServerError, container }: Options): Promise<Dede>;
26
+ static start({ framework, registries, defaultServerError, container, controllers }: Options): Promise<Dede>;
20
27
  stop(): Promise<void>;
28
+ registerControllers(controllers: any[]): void;
29
+ listen(port?: number): void;
21
30
  private static loadRegistries;
22
31
  }
package/dist/dede.js CHANGED
@@ -1,11 +1,14 @@
1
1
  import ControllerHandler from "./http/controller.handler";
2
2
  import { ElysiaServerAdapter } from "./http/elysia-server.adapter";
3
3
  import { ExpressServerAdapter } from "./http/express-server.adapter";
4
- import { Registry } from "./infra/di/registry";
4
+ import { Container, DefaultContainer, setDefaultContainer } from "./infra/di/registry";
5
5
  export class Dede {
6
- constructor(framework, defaultServerError) {
6
+ constructor(framework, defaultServerError, container = DefaultContainer) {
7
7
  this.framework = framework;
8
8
  this.defaultServerError = defaultServerError;
9
+ this.container = container;
10
+ this.controllersRegistered = false;
11
+ this.port = framework.port;
9
12
  if (framework.use === 'elysia') {
10
13
  this.httpServer = new ElysiaServerAdapter(framework.middlewares || []);
11
14
  }
@@ -14,19 +17,37 @@ export class Dede {
14
17
  }
15
18
  if (defaultServerError)
16
19
  this.httpServer.setDefaultMessageError(defaultServerError);
17
- new ControllerHandler(this.httpServer, framework.port || 80);
18
20
  }
19
- static async start({ framework, registries, defaultServerError }) {
20
- await this.loadRegistries(registries);
21
- return new Dede(framework, defaultServerError);
21
+ static async create({ framework, registries, defaultServerError, container }) {
22
+ const appContainer = container ?? new Container();
23
+ setDefaultContainer(appContainer);
24
+ await this.loadRegistries(appContainer, registries);
25
+ return new Dede(framework, defaultServerError, appContainer);
26
+ }
27
+ static async start({ framework, registries, defaultServerError, container, controllers }) {
28
+ const app = await Dede.create({ framework, registries, defaultServerError, container, controllers });
29
+ if (controllers && controllers.length > 0) {
30
+ app.registerControllers(controllers);
31
+ }
32
+ app.listen();
33
+ return app;
22
34
  }
23
35
  async stop() {
24
36
  await this.httpServer.close();
25
37
  }
26
- static async loadRegistries(registries) {
38
+ registerControllers(controllers) {
39
+ if (this.controllersRegistered)
40
+ return;
41
+ new ControllerHandler(this.httpServer, controllers);
42
+ this.controllersRegistered = true;
43
+ }
44
+ listen(port) {
45
+ const resolvedPort = port ?? this.port ?? 80;
46
+ this.httpServer.listen(resolvedPort);
47
+ }
48
+ static async loadRegistries(container, registries) {
27
49
  registries.forEach(({ classLoader, name }) => {
28
- Registry.load(name, classLoader);
50
+ container.load(name, classLoader);
29
51
  });
30
- return new Promise(resolve => setTimeout(resolve, 500));
31
52
  }
32
53
  }
@@ -0,0 +1,4 @@
1
+ export declare abstract class Entity {
2
+ [x: string]: any;
3
+ protected generateGetters(): void;
4
+ }
@@ -0,0 +1,25 @@
1
+ export class Entity {
2
+ generateGetters() {
3
+ for (const property of Object.keys(this)) {
4
+ if (typeof this[property] === 'function')
5
+ continue;
6
+ let prefixName = null;
7
+ // @ts-ignore
8
+ if (this.constructor.propertiesConfigs && this.constructor.propertiesConfigs[property] && this.constructor.propertiesConfigs[property].prefix) {
9
+ // @ts-ignore
10
+ prefixName = this.constructor.propertiesConfigs[property].prefix;
11
+ }
12
+ else {
13
+ const isBoolean = this[property] ? typeof this[property] === 'boolean' : false;
14
+ prefixName = isBoolean ? 'is' : 'get';
15
+ }
16
+ let getterName = null;
17
+ if (property[0]) {
18
+ getterName = `${prefixName}${property[0].toUpperCase()}${property.slice(1)}`;
19
+ if (this[getterName])
20
+ continue;
21
+ this[getterName] = () => this[property];
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,12 @@
1
+ export type AppErrorData = {
2
+ message: string;
3
+ code?: string;
4
+ details?: Record<string, any>;
5
+ };
6
+ export declare abstract class AppError extends Error {
7
+ private readonly statusCode;
8
+ private readonly data?;
9
+ constructor(message: string, statusCode: number, data?: AppErrorData);
10
+ getStatusCode(): number;
11
+ getData(): AppErrorData | undefined;
12
+ }
@@ -0,0 +1,14 @@
1
+ export class AppError extends Error {
2
+ constructor(message, statusCode, data) {
3
+ super(message);
4
+ this.name = this.constructor.name;
5
+ this.statusCode = statusCode;
6
+ this.data = data;
7
+ }
8
+ getStatusCode() {
9
+ return this.statusCode;
10
+ }
11
+ getData() {
12
+ return this.data;
13
+ }
14
+ }
@@ -0,0 +1,42 @@
1
+ import { AppError } from './app-error';
2
+ export declare class BadRequest extends AppError {
3
+ constructor(message: string, data?: {
4
+ code?: string;
5
+ details?: Record<string, any>;
6
+ });
7
+ }
8
+ export declare class Unauthorized extends AppError {
9
+ constructor(message: string, data?: {
10
+ code?: string;
11
+ details?: Record<string, any>;
12
+ });
13
+ }
14
+ export declare class Forbidden extends AppError {
15
+ constructor(message: string, data?: {
16
+ code?: string;
17
+ details?: Record<string, any>;
18
+ });
19
+ }
20
+ export declare class NotFound extends AppError {
21
+ constructor(message: string, data?: {
22
+ code?: string;
23
+ details?: Record<string, any>;
24
+ });
25
+ }
26
+ export declare class Conflict extends AppError {
27
+ constructor(message: string, data?: {
28
+ code?: string;
29
+ details?: Record<string, any>;
30
+ });
31
+ }
32
+ export declare class UnprocessableEntity extends AppError {
33
+ constructor(message: string, data?: {
34
+ code?: string;
35
+ details?: Record<string, any>;
36
+ });
37
+ }
38
+ export declare class InternalServerError extends AppError {
39
+ private readonly unexpectedError;
40
+ constructor(unexpectedError: string, defaultMessage?: string);
41
+ getUnexpectedError(): string;
42
+ }
@@ -0,0 +1,40 @@
1
+ import { AppError } from './app-error';
2
+ export class BadRequest extends AppError {
3
+ constructor(message, data) {
4
+ super(message, 400, data ? { message, ...data } : undefined);
5
+ }
6
+ }
7
+ export class Unauthorized extends AppError {
8
+ constructor(message, data) {
9
+ super(message, 401, data ? { message, ...data } : undefined);
10
+ }
11
+ }
12
+ export class Forbidden extends AppError {
13
+ constructor(message, data) {
14
+ super(message, 403, data ? { message, ...data } : undefined);
15
+ }
16
+ }
17
+ export class NotFound extends AppError {
18
+ constructor(message, data) {
19
+ super(message, 404, data ? { message, ...data } : undefined);
20
+ }
21
+ }
22
+ export class Conflict extends AppError {
23
+ constructor(message, data) {
24
+ super(message, 409, data ? { message, ...data } : undefined);
25
+ }
26
+ }
27
+ export class UnprocessableEntity extends AppError {
28
+ constructor(message, data) {
29
+ super(message, 422, data ? { message, ...data } : undefined);
30
+ }
31
+ }
32
+ export class InternalServerError extends AppError {
33
+ constructor(unexpectedError, defaultMessage = 'Ops, An unexpected error occurred') {
34
+ super(defaultMessage, 500, { message: defaultMessage });
35
+ this.unexpectedError = unexpectedError;
36
+ }
37
+ getUnexpectedError() {
38
+ return this.unexpectedError;
39
+ }
40
+ }
@@ -0,0 +1,2 @@
1
+ import { Entity } from './entity';
2
+ export { Entity };
@@ -0,0 +1,2 @@
1
+ import { Entity } from './entity';
2
+ export { Entity };
@@ -1,10 +1,9 @@
1
1
  import HttpServer from "../http/http-server";
2
2
  export default class ControllerHandler {
3
- constructor(httpServer: HttpServer, port: number);
4
- private executeMiddlewares;
3
+ private readonly requestMapper;
4
+ private readonly middlewareExecutor;
5
+ private readonly errorMapper;
6
+ constructor(httpServer: HttpServer, controllers?: any[]);
5
7
  private registryControllers;
6
8
  private resolveMiddleware;
7
- private filter;
8
- private extractError;
9
- private normalizeBracketNotation;
10
9
  }