@odg/chemical-x 2.1.3 → 2.3.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.
- package/README.md +2 -0
- package/agents.md +158 -0
- package/dist/Support/Decorators/OdgDecorators.d.ts +3 -2
- package/dist/Support/Decorators/OdgDecorators.js +6 -6
- package/dist/Support/Decorators/OdgDecorators.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/crawlers.md +240 -0
- package/docs/decorators.md +258 -0
- package/docs/exceptions.md +212 -0
- package/docs/helpers.md +223 -0
- package/package.json +4 -2
package/docs/helpers.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
## Chemical-X Helpers - Detailed Guide
|
|
2
|
+
|
|
3
|
+
Funções utilitárias para controle de fluxo assíncrono com tratamento de erros tipado. Não requerem browser driver.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { retry, sleep, timeout, throwIf, RetryAction } from "@odg/chemical-x";
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
### `retry(options)`
|
|
12
|
+
|
|
13
|
+
Retenta um callback N vezes com controle fino sobre sleep, abort e decisão por tentativa.
|
|
14
|
+
|
|
15
|
+
**Assinatura:**
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// Quando `when` retorna Default | Retry | Throw (ou não fornecido): retorna ReturnType
|
|
19
|
+
async function retry<ReturnType>(options: {
|
|
20
|
+
times: number;
|
|
21
|
+
sleep?: number;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
callback(attempt: number, signal?: AbortSignal): Promise<ReturnType> | ReturnType;
|
|
24
|
+
when?(exception: Exception, times: number): Promise<RetryAction> | RetryAction;
|
|
25
|
+
}): Promise<ReturnType>;
|
|
26
|
+
|
|
27
|
+
// Quando `when` pode retornar Resolve: retorno inclui undefined
|
|
28
|
+
async function retry<ReturnType>(options: {
|
|
29
|
+
times: number;
|
|
30
|
+
sleep?: number;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
callback(attempt: number, signal?: AbortSignal): Promise<ReturnType> | ReturnType;
|
|
33
|
+
when?(exception: Exception, times: number): Promise<RetryAction> | RetryAction;
|
|
34
|
+
}): Promise<ReturnType | undefined>;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Parâmetros:**
|
|
38
|
+
|
|
39
|
+
| Parâmetro | Tipo | Obrigatório | Descrição |
|
|
40
|
+
|---|---|---|---|
|
|
41
|
+
| `times` | `number` | Sim | Número máximo de tentativas. `InvalidArgumentException` se < 1 |
|
|
42
|
+
| `sleep` | `number` | Não | Milissegundos entre tentativas |
|
|
43
|
+
| `signal` | `AbortSignal` | Não | Sinal de abort para cancelar retries |
|
|
44
|
+
| `callback` | `(attempt, signal?) => T` | Sim | Função a ser retentada. Recebe número da tentativa atual |
|
|
45
|
+
| `when` | `(exception, times) => RetryAction` | Não | Decide ação por tentativa: `Retry`, `Throw`, `Resolve`, `Default` |
|
|
46
|
+
|
|
47
|
+
**Comportamento:**
|
|
48
|
+
|
|
49
|
+
1. Executa `callback(attempt, signal)` até `times` tentativas
|
|
50
|
+
2. Se callback sucede → retorna resultado
|
|
51
|
+
3. Se callback falha e `when` está definido → chama `when(exception, remainingTimes)`:
|
|
52
|
+
- `RetryAction.Retry` → retenta imediatamente (ignora `times`)
|
|
53
|
+
- `RetryAction.Throw` → lança exceção imediatamente
|
|
54
|
+
- `RetryAction.Resolve` → resolve com `undefined`
|
|
55
|
+
- `RetryAction.Default` → segue contagem normal de `times`
|
|
56
|
+
4. Se todas tentativas esgotam → lança `RetryException`
|
|
57
|
+
5. Entre tentativas, aguarda `sleep` ms (se definido)
|
|
58
|
+
|
|
59
|
+
**Exemplo:**
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const data = await retry({
|
|
63
|
+
times: 3,
|
|
64
|
+
sleep: 1000,
|
|
65
|
+
callback: async (attempt) => {
|
|
66
|
+
return await fetchData(attempt);
|
|
67
|
+
},
|
|
68
|
+
when: (exception, times) => {
|
|
69
|
+
if (exception instanceof FatalError) return RetryAction.Throw;
|
|
70
|
+
return RetryAction.Default;
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
See also: `tests/vitest/helpers/retry.test.ts` para exemplos completos de padrões com retry.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### `sleep(milliseconds, options?)`
|
|
80
|
+
|
|
81
|
+
Pausa assíncrona com suporte a cancelamento via `AbortSignal`.
|
|
82
|
+
|
|
83
|
+
**Assinatura:**
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
async function sleep(milliseconds: number, options?: { signal?: AbortSignal }): Promise<void>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Parâmetros:**
|
|
90
|
+
|
|
91
|
+
| Parâmetro | Tipo | Obrigatório | Descrição |
|
|
92
|
+
|---|---|---|---|
|
|
93
|
+
| `milliseconds` | `number` | Sim | Duração da pausa em milissegundos |
|
|
94
|
+
| `options.signal` | `AbortSignal` | Não | Sinal para cancelar o sleep antecipadamente |
|
|
95
|
+
|
|
96
|
+
**Exemplo:**
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
await sleep(2000); // Pausa 2 segundos
|
|
100
|
+
|
|
101
|
+
// Com abort
|
|
102
|
+
const controller = new AbortController();
|
|
103
|
+
await sleep(5000, { signal: controller.signal });
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
### `timeout(options)`
|
|
109
|
+
|
|
110
|
+
Envolve uma operação assíncrona com limite de tempo. Lança `TimeoutException` se exceder.
|
|
111
|
+
|
|
112
|
+
**Assinatura:**
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
async function timeout<ReturnType>(options: {
|
|
116
|
+
name?: string;
|
|
117
|
+
timeout?: number;
|
|
118
|
+
callback(): Promise<ReturnType> | ReturnType;
|
|
119
|
+
}): Promise<ReturnType>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Parâmetros:**
|
|
123
|
+
|
|
124
|
+
| Parâmetro | Tipo | Obrigatório | Descrição |
|
|
125
|
+
|---|---|---|---|
|
|
126
|
+
| `name` | `string` | Não | Nome da operação (incluído na mensagem de `TimeoutException`) |
|
|
127
|
+
| `timeout` | `number` | Não | Limite em milissegundos |
|
|
128
|
+
| `callback` | `() => T` | Sim | Operação a ser executada com limite de tempo |
|
|
129
|
+
|
|
130
|
+
**Comportamento:**
|
|
131
|
+
|
|
132
|
+
- Se callback completa antes do limite → retorna resultado
|
|
133
|
+
- Se excede limite → lança `TimeoutException` com nome da operação (se fornecido)
|
|
134
|
+
|
|
135
|
+
**Exemplo:**
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const result = await timeout({
|
|
139
|
+
name: "fetchData",
|
|
140
|
+
timeout: 5000,
|
|
141
|
+
callback: async () => {
|
|
142
|
+
return await longRunningOperation();
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
See also: `tests/vitest/helpers/timeout.test.ts` para exemplos com timeout.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### `throwIf(condition, exception)`
|
|
152
|
+
|
|
153
|
+
Lança exceção condicionalmente com tipagem estrita — `never` quando condition é `true`.
|
|
154
|
+
|
|
155
|
+
**Assinatura:**
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
function throwIf(condition: true, exception: () => Exception): never;
|
|
159
|
+
function throwIf(condition: false, exception: () => Exception): void;
|
|
160
|
+
function throwIf(condition: boolean, exception: () => Exception): never | void;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Parâmetros:**
|
|
164
|
+
|
|
165
|
+
| Parâmetro | Tipo | Obrigatório | Descrição |
|
|
166
|
+
|---|---|---|---|
|
|
167
|
+
| `condition` | `boolean` | Sim | Se `true`, lança a exceção |
|
|
168
|
+
| `exception` | `() => Exception` | Sim | Factory que cria a exceção (lazy — só chamada se `condition: true`) |
|
|
169
|
+
|
|
170
|
+
**Exemplo:**
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
throwIf(!user, () => new InvalidArgumentException("User is required"));
|
|
174
|
+
// Após esta linha, TypeScript sabe que `user` existe (type narrowing via `never`)
|
|
175
|
+
|
|
176
|
+
throwIf(amount < 0, () => new InvalidArgumentException("Amount must be positive"));
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
See also: `tests/vitest/helpers/throw-if.test.ts` para padrões de validação.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### Common Patterns
|
|
184
|
+
|
|
185
|
+
**Retry com exponential backoff:**
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
let delay = 500;
|
|
189
|
+
const result = await retry({
|
|
190
|
+
times: 5,
|
|
191
|
+
sleep: delay,
|
|
192
|
+
callback: async (attempt) => {
|
|
193
|
+
delay = 500 * Math.pow(2, attempt - 1); // 500, 1000, 2000, 4000, 8000
|
|
194
|
+
return await unstableApi();
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Retry com timeout por tentativa:**
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
const result = await retry({
|
|
203
|
+
times: 3,
|
|
204
|
+
sleep: 1000,
|
|
205
|
+
callback: async (attempt) => {
|
|
206
|
+
return await timeout({
|
|
207
|
+
name: `attempt-${attempt}`,
|
|
208
|
+
timeout: 5000,
|
|
209
|
+
callback: () => fetchData(),
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Validação com throwIf encadeado:**
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
throwIf(!config.url, () => new InvalidArgumentException("URL is required"));
|
|
219
|
+
throwIf(config.timeout < 0, () => new InvalidArgumentException("Timeout must be positive"));
|
|
220
|
+
// config agora está validado com tipagem correta
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
See also: `tests/vitest/helpers/` para todos os testes de helpers.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odg/chemical-x",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Chemical-X Project It's the basis of everything",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -30,7 +30,9 @@
|
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"./dist/",
|
|
33
|
-
"./README.md"
|
|
33
|
+
"./README.md",
|
|
34
|
+
"agents.md",
|
|
35
|
+
"docs/**"
|
|
34
36
|
],
|
|
35
37
|
"author": "Dragons Gamers <https://www.linkedin.com/in/victor-alves-odgodinho>",
|
|
36
38
|
"license": "MIT",
|