@onerb/core 2.0.0 → 2.0.1
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/README.md +150 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @onerb/core
|
|
2
|
+
|
|
3
|
+
Utilitários centrais para projetos Onerb. Este pacote fornece uma classe de erro de aplicação e um tipo `Either` para modelar sucesso/erro sem exceções no domínio.
|
|
4
|
+
|
|
5
|
+
## Requisitos
|
|
6
|
+
|
|
7
|
+
- Node.js com suporte a ESM.
|
|
8
|
+
- TypeScript (opcional, recomendado para tipagem).
|
|
9
|
+
|
|
10
|
+
## Instalação
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i @onerb/core
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
yarn add @onerb/core
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @onerb/core
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## O que está disponível
|
|
25
|
+
|
|
26
|
+
- `AppError`: erro de aplicação com `code` e `detail`.
|
|
27
|
+
- `Either`, `Left`, `Right`, `left`, `right`: utilitários para fluxo de sucesso/erro sem `throw` no domínio.
|
|
28
|
+
|
|
29
|
+
## Importação
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { AppError, Either, left, right } from '@onerb/core';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Uso
|
|
36
|
+
|
|
37
|
+
### 1) Domínio: só repassa o erro (sem `throw`)
|
|
38
|
+
|
|
39
|
+
Exemplo de caso de uso no domínio que valida dados e retorna `Either`. Se ocorrer erro, ele é repassado (retornando `Left`).
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { AppError, Either, left, right } from '@onerb/core';
|
|
43
|
+
|
|
44
|
+
type CreateUserInput = {
|
|
45
|
+
email: string;
|
|
46
|
+
name: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
type User = {
|
|
50
|
+
id: string;
|
|
51
|
+
email: string;
|
|
52
|
+
name: string;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
function createUser(input: CreateUserInput): Either<AppError, User> {
|
|
56
|
+
if (!input.email.includes('@')) {
|
|
57
|
+
return left(
|
|
58
|
+
new AppError('Email inválido', {
|
|
59
|
+
code: 'USER_EMAIL_INVALID',
|
|
60
|
+
detail: `email recebido: ${input.email}`,
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const user: User = {
|
|
66
|
+
id: crypto.randomUUID(),
|
|
67
|
+
email: input.email,
|
|
68
|
+
name: input.name,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return right(user);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2) Aplicação: coordena e pode lançar `throw`
|
|
76
|
+
|
|
77
|
+
Na camada de aplicação, você pode coordenar chamadas do domínio e decidir transformar `Left` em exceção (por exemplo para integração com frameworks HTTP).
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { AppError } from '@onerb/core';
|
|
81
|
+
|
|
82
|
+
async function handleCreateUser(input: { email: string; name: string }) {
|
|
83
|
+
const result = createUser(input);
|
|
84
|
+
|
|
85
|
+
if (result.isLeft()) {
|
|
86
|
+
// Aqui a aplicação decide lançar o erro
|
|
87
|
+
throw result.fold((err) => err, (user) => user);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return result.fold(
|
|
91
|
+
() => {
|
|
92
|
+
// Este ramo não será chamado porque já checamos isLeft
|
|
93
|
+
throw new AppError('Erro inesperado', { code: 'UNEXPECTED' });
|
|
94
|
+
},
|
|
95
|
+
(user) => user
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3) Coordenação entre domínio e aplicação
|
|
101
|
+
|
|
102
|
+
A aplicação pode orquestrar múltiplas operações de domínio, repassando `Left` sem `throw` e só convertendo para exceção no ponto de integração.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { AppError, Either, left, right } from '@onerb/core';
|
|
106
|
+
|
|
107
|
+
function validateEmail(email: string): Either<AppError, true> {
|
|
108
|
+
if (!email.includes('@')) {
|
|
109
|
+
return left(new AppError('Email inválido', { code: 'USER_EMAIL_INVALID' }));
|
|
110
|
+
}
|
|
111
|
+
return right(true);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function ensureName(name: string): Either<AppError, true> {
|
|
115
|
+
if (name.trim().length === 0) {
|
|
116
|
+
return left(new AppError('Nome obrigatório', { code: 'USER_NAME_REQUIRED' }));
|
|
117
|
+
}
|
|
118
|
+
return right(true);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function createUserDomain(input: { email: string; name: string }): Either<AppError, { id: string; email: string; name: string }> {
|
|
122
|
+
const emailCheck = validateEmail(input.email);
|
|
123
|
+
if (emailCheck.isLeft()) return emailCheck;
|
|
124
|
+
|
|
125
|
+
const nameCheck = ensureName(input.name);
|
|
126
|
+
if (nameCheck.isLeft()) return nameCheck;
|
|
127
|
+
|
|
128
|
+
return right({ id: crypto.randomUUID(), email: input.email, name: input.name });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function createUserApp(input: { email: string; name: string }) {
|
|
132
|
+
const result = createUserDomain(input);
|
|
133
|
+
|
|
134
|
+
if (result.isLeft()) {
|
|
135
|
+
throw result.fold((err) => err, () => new Error('Inalcançável'));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return result.fold(
|
|
139
|
+
() => {
|
|
140
|
+
throw new AppError('Erro inesperado', { code: 'UNEXPECTED' });
|
|
141
|
+
},
|
|
142
|
+
(user) => user
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Notas
|
|
148
|
+
|
|
149
|
+
- O `Either` ajuda a manter o domínio livre de exceções, favorecendo retornos explícitos.
|
|
150
|
+
- A decisão de lançar erros (`throw`) fica na camada de aplicação, onde há integração com infraestrutura (HTTP, filas, etc.).
|