@eusilvio/cep-lookup 2.4.0 → 2.6.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/LICENSE +1 -47
- package/README.md +109 -210
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/providers/index.cjs +1 -1
- package/dist/providers/index.mjs +1 -1
- package/dist/src/cache/index.d.ts +14 -17
- package/dist/src/cache/index.js +35 -20
- package/dist/src/data/ddd-by-state.d.ts +2 -0
- package/dist/src/data/ddd-by-state.js +12 -0
- package/dist/src/errors.d.ts +35 -0
- package/dist/src/errors.js +82 -0
- package/dist/src/index.d.ts +24 -19
- package/dist/src/index.js +198 -38
- package/dist/src/providers/index.d.ts +1 -0
- package/dist/src/providers/index.js +1 -0
- package/dist/src/providers/opencep.d.ts +10 -0
- package/dist/src/providers/opencep.js +32 -0
- package/dist/src/providers/viacep.js +2 -0
- package/dist/src/types.d.ts +41 -2
- package/package.json +3 -2
package/LICENSE
CHANGED
|
@@ -1,24 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
This project was developed with the philosophy that knowledge and tools should be accessible to all. I believe that by sharing our work freely, we can empower other creators to build incredible things.
|
|
4
|
-
|
|
5
|
-
That's why I chose the MIT License for this project. In simple terms, this means you have complete freedom to use, modify, and distribute this code, even for commercial purposes, with a single condition: you must keep the original copyright and license notice included.
|
|
6
|
-
|
|
7
|
-
Thank you for your interest and contributions!
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Licença do Projeto
|
|
12
|
-
|
|
13
|
-
Este projeto foi desenvolvido com a filosofia de que o conhecimento e as ferramentas devem ser acessíveis a todos. Acredito que, ao compartilhar nosso trabalho livremente, podemos capacitar outros criadores a construir coisas incríveis.
|
|
14
|
-
|
|
15
|
-
Por isso, escolhi a Licença MIT para este projeto. Em termos simples, isso significa que você tem total liberdade para usar, modificar e distribuir este código, até mesmo para fins comerciais, com uma única condição: mantenha o aviso de licença e copyright originais.
|
|
16
|
-
|
|
17
|
-
Agradecemos o seu interesse e contribuição!
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
### MIT License
|
|
1
|
+
MIT License
|
|
22
2
|
|
|
23
3
|
Copyright (c) 2025 Silvio Campos
|
|
24
4
|
|
|
@@ -39,29 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
39
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
40
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
41
21
|
SOFTWARE.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
### Tradução para Português (Apenas para referência)
|
|
46
|
-
|
|
47
|
-
_Aviso: Esta é uma tradução não oficial e serve apenas para facilitar o entendimento. A versão em inglês é a que possui validade legal._
|
|
48
|
-
|
|
49
|
-
Copyright (c) 2025 Silvio Campos
|
|
50
|
-
|
|
51
|
-
É concedida permissão, gratuitamente, a qualquer pessoa que obtenha uma cópia
|
|
52
|
-
deste software e dos arquivos de documentação associados (o "Software"), para negociar
|
|
53
|
-
o Software sem restrições, incluindo, sem limitação, os direitos
|
|
54
|
-
de usar, copiar, modificar, mesclar, publicar, distribuir, sublicenciar e/ou vender
|
|
55
|
-
cópias do Software, e permitir que as pessoas a quem o Software é
|
|
56
|
-
fornecido o façam, sujeito às seguintes condições:
|
|
57
|
-
|
|
58
|
-
O aviso de copyright acima e este aviso de permissão devem ser incluídos em todas as
|
|
59
|
-
cópias ou partes substanciais do Software.
|
|
60
|
-
|
|
61
|
-
O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU
|
|
62
|
-
IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO,
|
|
63
|
-
ADEQUAÇÃO A UM FIM ESPECÍFICO E NÃO VIOLAÇÃO. EM NENHUMA CIRCUNSTÂNCIA OS
|
|
64
|
-
AUTORES OU TITULARES DE DIREITOS AUTORAIS SERÃO RESPONSÁVEIS POR QUALQUER REIVINDICAÇÃO, DANOS OU OUTRA
|
|
65
|
-
RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, ILÍCITO CIVIL OU DE OUTRA FORMA, DECORRENTE DE,
|
|
66
|
-
FORA DE OU EM CONEXÃO COM O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES NO
|
|
67
|
-
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,28 +1,10 @@
|
|
|
1
1
|
# @eusilvio/cep-lookup
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@eusilvio/cep-lookup)
|
|
4
|
-
[](https://github.com/eusilvio/cep-lookup/actions)
|
|
4
|
+
[](https://github.com/eusilvio/cep-lookup/actions)
|
|
6
5
|
[](https://opensource.org/licenses/MIT)
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## About
|
|
11
|
-
|
|
12
|
-
`@eusilvio/cep-lookup` was created to solve address lookup from a CEP in a different way. Instead of relying on a single data source, it queries multiple services simultaneously and returns the response from the fastest one.
|
|
13
|
-
|
|
14
|
-
Its agnostic design allows it to be used in any JavaScript environment with any HTTP client, and its powerful "mapper" system allows you to format the data output exactly as you need.
|
|
15
|
-
|
|
16
|
-
## Key Features
|
|
17
|
-
|
|
18
|
-
- **Multiple Providers (Race Strategy)**: Queries multiple CEP APIs at the same time and uses the first valid response.
|
|
19
|
-
- **Class-Based API**: Create a reusable instance with your settings.
|
|
20
|
-
- **Bulk Lookups**: Efficiently look up multiple CEPs with a single method call.
|
|
21
|
-
- **Customizable Return Format**: Provide a `mapper` function to transform the address data into any format your application needs.
|
|
22
|
-
- **HTTP Client Agnostic**: You provide the fetch function, giving you full control over the requests. Defaults to global `fetch` if not provided.
|
|
23
|
-
- **Modular and Extensible Architecture**: Adding a new CEP data source is trivial.
|
|
24
|
-
- **Fully Typed**: Developed with TypeScript to ensure type safety and a great developer experience.
|
|
25
|
-
- **Caching**: Built-in support for caching to avoid repeated requests for the same CEP.
|
|
7
|
+
Core CEP lookup engine with multi-provider race, resilience controls, and metrics.
|
|
26
8
|
|
|
27
9
|
## Installation
|
|
28
10
|
|
|
@@ -30,225 +12,142 @@ Its agnostic design allows it to be used in any JavaScript environment with any
|
|
|
30
12
|
npm install @eusilvio/cep-lookup
|
|
31
13
|
```
|
|
32
14
|
|
|
33
|
-
##
|
|
15
|
+
## Features
|
|
34
16
|
|
|
35
|
-
|
|
17
|
+
- Multi-provider race strategy.
|
|
18
|
+
- Cache and rate limiting.
|
|
19
|
+
- Retry with exponential backoff.
|
|
20
|
+
- Standardized errors with error codes.
|
|
21
|
+
- Circuit breaker per provider.
|
|
22
|
+
- Provider health score and runtime metrics.
|
|
23
|
+
- Event-based observability.
|
|
36
24
|
|
|
37
|
-
|
|
25
|
+
## Basic Usage
|
|
38
26
|
|
|
39
|
-
```
|
|
40
|
-
import { CepLookup
|
|
41
|
-
import {
|
|
42
|
-
viaCepProvider,
|
|
43
|
-
brasilApiProvider,
|
|
44
|
-
} from "@eusilvio/cep-lookup/providers";
|
|
27
|
+
```ts
|
|
28
|
+
import { CepLookup } from "@eusilvio/cep-lookup";
|
|
29
|
+
import { viaCepProvider, brasilApiProvider } from "@eusilvio/cep-lookup/providers";
|
|
45
30
|
|
|
46
|
-
|
|
47
|
-
const cepLookup = new CepLookup({
|
|
31
|
+
const lookup = new CepLookup({
|
|
48
32
|
providers: [viaCepProvider, brasilApiProvider],
|
|
49
33
|
});
|
|
50
34
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
console.log("Address found:", address);
|
|
54
|
-
// Output:
|
|
55
|
-
// {
|
|
56
|
-
// cep: '01001-000',
|
|
57
|
-
// state: 'SP',
|
|
58
|
-
// city: 'São Paulo',
|
|
59
|
-
// neighborhood: 'Sé',
|
|
60
|
-
// street: 'Praça da Sé',
|
|
61
|
-
// service: 'ViaCEP'
|
|
62
|
-
// }
|
|
63
|
-
});
|
|
35
|
+
const address = await lookup.lookup("01001-000");
|
|
36
|
+
console.log(address);
|
|
64
37
|
```
|
|
65
38
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
import { CepLookup, Address } from "@eusilvio/cep-lookup";
|
|
70
|
-
import { viaCepProvider } from "@eusilvio/cep-lookup/providers";
|
|
39
|
+
## Error Handling
|
|
71
40
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
41
|
+
```ts
|
|
42
|
+
import {
|
|
43
|
+
CepLookup,
|
|
44
|
+
CepNotFoundError,
|
|
45
|
+
ProviderTimeoutError,
|
|
46
|
+
RateLimitError,
|
|
47
|
+
AllProvidersFailedError,
|
|
48
|
+
} from "@eusilvio/cep-lookup";
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
await lookup.lookup("01001000");
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error instanceof CepNotFoundError) {
|
|
54
|
+
console.log(error.code); // NOT_FOUND
|
|
55
|
+
} else if (error instanceof ProviderTimeoutError) {
|
|
56
|
+
console.log(error.code); // TIMEOUT
|
|
57
|
+
} else if (error instanceof RateLimitError) {
|
|
58
|
+
console.log(error.code); // RATE_LIMITED
|
|
59
|
+
} else if (error instanceof AllProvidersFailedError) {
|
|
60
|
+
console.log(error.code); // ALL_PROVIDERS_FAILED
|
|
61
|
+
}
|
|
81
62
|
}
|
|
82
|
-
|
|
83
|
-
const myMapper = (address: Address): CustomAddress => {
|
|
84
|
-
return {
|
|
85
|
-
postalCode: address.cep,
|
|
86
|
-
fullAddress: `${address.street}, ${address.neighborhood} - ${address.city}/${address.state}`,
|
|
87
|
-
source: address.service,
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// 2. Look up a CEP with the mapper
|
|
92
|
-
cepLookup.lookup("01001-000", myMapper).then((customAddress: CustomAddress) => {
|
|
93
|
-
console.log("Address found (custom format):", customAddress);
|
|
94
|
-
// Output:
|
|
95
|
-
// {
|
|
96
|
-
// postalCode: '01001-000',
|
|
97
|
-
// fullAddress: 'Praça da Sé, Sé - São Paulo/SP',
|
|
98
|
-
// source: 'ViaCEP'
|
|
99
|
-
// }
|
|
100
|
-
});
|
|
101
63
|
```
|
|
102
64
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
For scenarios where you need to query multiple CEPs at once, you can use the `lookupCeps` method. It processes the CEPs in parallel with a configurable concurrency limit to avoid overwhelming the providers.
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
import { CepLookup, BulkCepResult } from "@eusilvio/cep-lookup";
|
|
109
|
-
import {
|
|
110
|
-
viaCepProvider,
|
|
111
|
-
brasilApiProvider,
|
|
112
|
-
} from "@eusilvio/cep-lookup/providers";
|
|
113
|
-
|
|
114
|
-
const cepsToLookup = ["01001-000", "99999-999", "04538-132"];
|
|
65
|
+
## Circuit Breaker
|
|
115
66
|
|
|
116
|
-
|
|
117
|
-
const
|
|
67
|
+
```ts
|
|
68
|
+
const lookup = new CepLookup({
|
|
118
69
|
providers: [viaCepProvider, brasilApiProvider],
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Output:
|
|
125
|
-
// [
|
|
126
|
-
// {
|
|
127
|
-
// cep: '01001-000',
|
|
128
|
-
// data: { cep: '01001-000', state: 'SP', city: 'São Paulo', ... },
|
|
129
|
-
// provider: 'ViaCEP'
|
|
130
|
-
// },
|
|
131
|
-
// {
|
|
132
|
-
// cep: '99999-999',
|
|
133
|
-
// data: null,
|
|
134
|
-
// error: [Error: All providers failed to find the CEP]
|
|
135
|
-
// },
|
|
136
|
-
// {
|
|
137
|
-
// cep: '04538-132',
|
|
138
|
-
// data: { cep: '04538-132', state: 'SP', city: 'São Paulo', ... },
|
|
139
|
-
// provider: 'BrasilAPI'
|
|
140
|
-
// }
|
|
141
|
-
// ]
|
|
70
|
+
circuitBreaker: {
|
|
71
|
+
enabled: true,
|
|
72
|
+
failureThreshold: 3,
|
|
73
|
+
cooldownMs: 30_000,
|
|
74
|
+
},
|
|
142
75
|
});
|
|
143
76
|
```
|
|
144
77
|
|
|
145
|
-
##
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
78
|
+
## Health and SLA Metrics
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const health = lookup.getProviderHealth();
|
|
82
|
+
/*
|
|
83
|
+
[
|
|
84
|
+
{
|
|
85
|
+
provider: 'ViaCEP',
|
|
86
|
+
score: 0.94,
|
|
87
|
+
isOpen: false,
|
|
88
|
+
successCount: 12,
|
|
89
|
+
failureCount: 1,
|
|
90
|
+
avgLatencyMs: 52.11,
|
|
91
|
+
...
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
const metrics = lookup.getProviderMetrics();
|
|
97
|
+
/*
|
|
98
|
+
[
|
|
99
|
+
{
|
|
100
|
+
provider: 'ViaCEP',
|
|
101
|
+
requests: 13,
|
|
102
|
+
successes: 12,
|
|
103
|
+
failures: 1,
|
|
104
|
+
timeoutErrors: 0,
|
|
105
|
+
notFoundErrors: 1,
|
|
106
|
+
avgLatencyMs: 52.11
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
*/
|
|
110
|
+
```
|
|
176
111
|
|
|
177
|
-
|
|
178
|
-
> Standalone `lookupCep` and `lookupCeps` functions are deprecated and will be removed in a future version. Please use the methods on a `CepLookup` instance instead.
|
|
112
|
+
## Bulk Lookup
|
|
179
113
|
|
|
180
|
-
|
|
114
|
+
```ts
|
|
115
|
+
const results = await lookup.lookupCeps(["01001-000", "99999-999"], 2);
|
|
116
|
+
```
|
|
181
117
|
|
|
182
|
-
|
|
118
|
+
## API Summary
|
|
183
119
|
|
|
184
|
-
|
|
185
|
-
const cepLookup = new CepLookup({ providers: [...] });
|
|
120
|
+
### `new CepLookup(options)`
|
|
186
121
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
122
|
+
- `providers`: required provider list.
|
|
123
|
+
- `fetcher`: optional custom HTTP fetch function.
|
|
124
|
+
- `cache`: optional cache implementation.
|
|
125
|
+
- `rateLimit`: `{ requests, per }`.
|
|
126
|
+
- `staggerDelay`: delay before backup providers.
|
|
127
|
+
- `retries`: retry count after failure.
|
|
128
|
+
- `retryDelay`: base retry delay in ms.
|
|
129
|
+
- `circuitBreaker`: `{ enabled, failureThreshold, cooldownMs }`.
|
|
192
130
|
|
|
193
|
-
|
|
194
|
-
cepLookup.on('failure', ({ provider, cep, error }) => {
|
|
195
|
-
console.error(`[${provider}] Failure for CEP ${cep}: ${error.message}`);
|
|
196
|
-
// myMetrics.increment('cep.failure', { provider });
|
|
197
|
-
});
|
|
131
|
+
### Methods
|
|
198
132
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
133
|
+
- `lookup(cep, mapper?)`
|
|
134
|
+
- `lookupCeps(ceps, concurrency?)`
|
|
135
|
+
- `warmup()`
|
|
136
|
+
- `getProviderHealth()`
|
|
137
|
+
- `getProviderMetrics()`
|
|
138
|
+
- `on(event, listener)` / `off(event, listener)`
|
|
204
139
|
|
|
205
|
-
|
|
206
|
-
cepLookup.lookup("01001-000");
|
|
207
|
-
```
|
|
140
|
+
## Compatibility and support
|
|
208
141
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
You can find more detailed examples in the `examples/` directory:
|
|
212
|
-
|
|
213
|
-
- **Basic Usage**: `examples/example.ts`
|
|
214
|
-
- **Bulk Lookup**: `examples/bulk-example.ts`
|
|
215
|
-
- **Custom Provider**: `examples/custom-provider-example.ts`
|
|
216
|
-
- **Node.js Usage**: `examples/node-example.ts`
|
|
217
|
-
- **React Component**: `examples/react-example.tsx`
|
|
218
|
-
- **React Hook**: `examples/react-hook-example.ts`
|
|
219
|
-
- **Angular Component/Service**: `examples/angular-example.ts`
|
|
220
|
-
- **Cache Usage**: `examples/cache-example.ts`
|
|
221
|
-
|
|
222
|
-
## Creating a Custom Provider
|
|
223
|
-
|
|
224
|
-
Your custom provider must always transform the API response to the library's default `Address` interface. The user's `mapper` will handle the final customization.
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
import { Provider, Address } from "@eusilvio/cep-lookup";
|
|
228
|
-
|
|
229
|
-
const myCustomProvider: Provider = {
|
|
230
|
-
name: "MyCustomAPI",
|
|
231
|
-
buildUrl: (cep: string) => `https://myapi.com/cep/${cep}`,
|
|
232
|
-
transform: (response: any): Address => {
|
|
233
|
-
// Transforms the response from "MyCustomAPI" to the "Address" format
|
|
234
|
-
return {
|
|
235
|
-
cep: response.postal_code,
|
|
236
|
-
state: response.data.state_short,
|
|
237
|
-
city: response.data.city_name,
|
|
238
|
-
neighborhood: response.data.neighborhood,
|
|
239
|
-
street: response.data.street_name,
|
|
240
|
-
service: "MyCustomAPI",
|
|
241
|
-
};
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
```
|
|
142
|
+
- Node.js: `20.x`, `22.x`, `24.x`
|
|
143
|
+
- Maintenance policy: [SUPPORT.md](../../SUPPORT.md)
|
|
245
144
|
|
|
246
|
-
##
|
|
145
|
+
## Production docs
|
|
247
146
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
147
|
+
- [Best Practices](../../docs/BEST_PRACTICES.md)
|
|
148
|
+
- [Migration Guide](../../docs/MIGRATION.md)
|
|
149
|
+
- [Cookbook](../../docs/COOKBOOK.md)
|
|
251
150
|
|
|
252
151
|
## License
|
|
253
152
|
|
|
254
|
-
|
|
153
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var x=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var z=(i,e)=>{for(var t in e)x(i,t,{get:e[t],enumerable:!0})},V=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of q(e))!_.call(i,s)&&s!==t&&x(i,s,{get:()=>e[s],enumerable:!(r=U(e,s))||r.enumerable});return i};var H=i=>V(x({},"__esModule",{value:!0}),i);var G={};z(G,{AllProvidersFailedError:()=>p,CepLookup:()=>O,CepNotFoundError:()=>E,CepValidationError:()=>f,InMemoryCache:()=>A,ProviderTimeoutError:()=>v,ProviderUnavailableError:()=>P,RateLimitError:()=>g});module.exports=H(G);var A=class{constructor(e){this.cache=new Map;this.ttl=e?.ttl??1/0,this.maxSize=e?.maxSize??1/0}get(e){let t=this.cache.get(e);if(t){if(this.ttl!==1/0&&Date.now()-t.timestamp>this.ttl){this.cache.delete(e);return}return t.value}}set(e,t){if(this.cache.has(e)&&this.cache.delete(e),this.cache.size>=this.maxSize){let r=this.cache.keys().next().value;r!==void 0&&this.cache.delete(r)}this.cache.set(e,{value:t,timestamp:Date.now()})}delete(e){this.cache.delete(e)}has(e){if(!this.cache.has(e))return!1;let t=this.cache.get(e);return this.ttl!==1/0&&Date.now()-t.timestamp>this.ttl?(this.cache.delete(e),!1):!0}clear(){this.cache.clear()}};var f=class extends Error{constructor(t){super("Invalid CEP format. Use either NNNNNNNN or NNNNN-NNN.");this.code="INVALID_CEP";this.name="CepValidationError",this.cep=t}},g=class extends Error{constructor(t,r){super(`Rate limit exceeded: ${t} requests per ${r}ms.`);this.code="RATE_LIMITED";this.name="RateLimitError",this.limit=t,this.window=r}},v=class extends Error{constructor(t,r){super(`Timeout from ${t}`);this.code="TIMEOUT";this.name="ProviderTimeoutError",this.provider=t,this.timeout=r}},E=class extends Error{constructor(t,r){super("CEP not found");this.code="NOT_FOUND";this.name="CepNotFoundError",this.cep=t,this.provider=r}},p=class extends Error{constructor(t){super("All providers failed to resolve the CEP.");this.code="ALL_PROVIDERS_FAILED";this.name="AllProvidersFailedError",this.errors=t}},P=class extends Error{constructor(t){super(`Provider ${t} is temporarily unavailable (circuit open).`);this.code="PROVIDER_UNAVAILABLE";this.name="ProviderUnavailableError",this.provider=t}};function F(i,e,t){if(i instanceof Error){if(i instanceof f||i instanceof g||i instanceof v||i instanceof E||i instanceof P||i instanceof p)return i;let r=i.message?.toLowerCase?.()||"";return r.includes("cep not found")||r.includes("not found")||r.includes("status: 404")?new E(e,t):(i.name==="AbortError",i)}return new Error(String(i))}var S={AC:"68",AL:"82",AM:"92",AP:"96",BA:"71",CE:"85",DF:"61",ES:"27",GO:"62",MA:"98",MG:"31",MS:"67",MT:"65",PA:"91",PB:"83",PE:"81",PI:"86",PR:"41",RJ:"21",RN:"84",RO:"69",RR:"95",RS:"51",SC:"48",SE:"79",SP:"11",TO:"63"};var M=class{constructor(){this.listeners={}}on(e,t){this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(t)}off(e,t){let r=this.listeners[e];r&&(this.listeners[e]=r.filter(s=>s!==t))}emit(e,t){let r=this.listeners[e];r&&r.forEach(s=>s(t))}};function $(i){if(!/^(\d{8}|\d{5}-\d{3})$/.test(i))throw new f(i);return i.replace("-","")}function K(i){let e={...i};return Object.keys(e).forEach(t=>{let r=e[t];typeof r=="string"&&(e[t]=r.trim())}),e}function j(i){if(!i.ddd&&i.state){let e=S[i.state];if(e)return{...i,ddd:e}}return i}var O=class{constructor(e){this.requestTimestamps=[];this.providerState=new Map;this.providers=e.providers,this.sortedProviders=[...e.providers],this.emitter=new M,this.fetcher=e.fetcher||(async(t,r)=>{let s=await fetch(t,{signal:r});if(!s.ok)throw new Error(`HTTP error! status: ${s.status}`);return s.json()}),this.cache=e.cache,this.rateLimit=e.rateLimit,this.staggerDelay=e.staggerDelay??100,this.retries=e.retries??0,this.retryDelay=e.retryDelay??1e3,this.logger=e.logger,this.circuitBreakerEnabled=e.circuitBreaker?.enabled??!0,this.circuitFailureThreshold=e.circuitBreaker?.failureThreshold??3,this.circuitCooldownMs=e.circuitBreaker?.cooldownMs??3e4,this.providers.forEach(t=>{this.providerState.set(t.name,{consecutiveFailures:0,successCount:0,failureCount:0,avgLatencyMs:0,requests:0,timeoutErrors:0,notFoundErrors:0})})}log(e,t){this.logger?.debug(e,t)}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}async warmup(){let e="01001000",t=new AbortController,r=this.providers.map(async o=>{let a=Date.now();try{let u=o.buildUrl(e);return await this.fetcher(u,t.signal),{provider:o,duration:Date.now()-a,error:!1}}catch{return{provider:o,duration:1/0,error:!0}}}),c=(await Promise.all(r)).sort((o,a)=>o.duration-a.duration);return this.sortedProviders=c.map(o=>o.provider).filter(o=>!!o),t.abort(),this.sortedProviders}getOrCreateProviderState(e){let t=this.providerState.get(e);if(t)return t;let r={consecutiveFailures:0,successCount:0,failureCount:0,avgLatencyMs:0,requests:0,timeoutErrors:0,notFoundErrors:0};return this.providerState.set(e,r),r}recordProviderSuccess(e,t){let r=this.getOrCreateProviderState(e);r.requests+=1,r.successCount+=1,r.consecutiveFailures=0;let s=r.successCount+r.failureCount;r.avgLatencyMs=s===1?t:(r.avgLatencyMs*(s-1)+t)/s,r.openUntil=void 0}recordProviderFailure(e,t,r){let s=this.getOrCreateProviderState(e);s.requests+=1,s.failureCount+=1,s.consecutiveFailures+=1;let c=s.successCount+s.failureCount;s.avgLatencyMs=c===1?t:(s.avgLatencyMs*(c-1)+t)/c,r instanceof v&&(s.timeoutErrors+=1),r instanceof E&&(s.notFoundErrors+=1),this.circuitBreakerEnabled&&s.consecutiveFailures>=this.circuitFailureThreshold&&(s.openUntil=Date.now()+this.circuitCooldownMs)}isProviderOpen(e){if(!this.circuitBreakerEnabled)return!1;let t=this.getOrCreateProviderState(e);return t.openUntil?Date.now()>=t.openUntil?(t.openUntil=void 0,t.consecutiveFailures=0,!1):!0:!1}scoreProvider(e){let t=this.getOrCreateProviderState(e.name),r=t.successCount+t.failureCount,s=r===0?1:t.successCount/r,c=t.avgLatencyMs>0?Math.min(t.avgLatencyMs/1e3,1):0,o=this.isProviderOpen(e.name)?1:0;return s*.8+(1-c)*.2-o}getProviderHealth(){return this.providers.map(e=>{let t=this.getOrCreateProviderState(e.name);return{provider:e.name,score:Number(this.scoreProvider(e).toFixed(4)),isOpen:this.isProviderOpen(e.name),openUntil:t.openUntil,consecutiveFailures:t.consecutiveFailures,successCount:t.successCount,failureCount:t.failureCount,avgLatencyMs:Number(t.avgLatencyMs.toFixed(2))}}).sort((e,t)=>t.score-e.score)}getProviderMetrics(){return this.providers.map(e=>{let t=this.getOrCreateProviderState(e.name);return{provider:e.name,requests:t.requests,successes:t.successCount,failures:t.failureCount,timeoutErrors:t.timeoutErrors,notFoundErrors:t.notFoundErrors,avgLatencyMs:Number(t.avgLatencyMs.toFixed(2))}})}checkRateLimit(){if(!this.rateLimit)return;let e=Date.now(),t=e-this.rateLimit.per;if(this.requestTimestamps=this.requestTimestamps.filter(r=>r>t),this.requestTimestamps.length>=this.rateLimit.requests)throw new g(this.rateLimit.requests,this.rateLimit.per);this.requestTimestamps.push(e)}async lookup(e,t){this.checkRateLimit();let r=$(e);if(this.log("lookup:start",{cep:r}),this.cache){let o=this.cache.get(r);if(o)return this.log("cache:hit",{cep:r}),this.emitter.emit("cache:hit",{cep:r}),t?t(o):o}let s,c=1+this.retries;for(let o=0;o<c;o++){if(o>0){let a=this.retryDelay*Math.pow(2,o-1);this.log("retry:attempt",{attempt:o,cep:r,delay:a}),await new Promise(u=>setTimeout(u,a))}try{return await this._lookupFromProviders(r,t)}catch(a){if(a instanceof f||a instanceof g)throw a;s=a}}throw s}async _lookupFromProviders(e,t){let r=new AbortController,{signal:s}=r,c=this.sortedProviders.filter(n=>!this.isProviderOpen(n.name)),o=[...c].sort((n,l)=>this.scoreProvider(l)-this.scoreProvider(n)),a=o.length>0?o:[...this.sortedProviders].sort((n,l)=>this.scoreProvider(l)-this.scoreProvider(n));if(a.length===0)throw new p([new P("all")]);if(c.length===0&&this.circuitBreakerEnabled)throw new p(a.map(n=>new P(n.name)));let u=n=>{let l=Date.now(),L=n.buildUrl(e);this.log("provider:start",{provider:n.name,cep:e});let I=new Promise((b,m)=>{if(!n.timeout)return;let d=setTimeout(()=>{s.removeEventListener("abort",R);let N=Date.now()-l,T=new v(n.name,n.timeout);this.recordProviderFailure(n.name,N,T),this.log("provider:failure",{provider:n.name,cep:e,error:T.message}),this.emitter.emit("failure",{provider:n.name,cep:e,duration:N,error:T}),m(T)},n.timeout),R=()=>clearTimeout(d);s.addEventListener("abort",R,{once:!0})}),B=this.fetcher(L,s).then(b=>n.transform(b)).then(b=>{let m=Date.now()-l,d=j(K(b));return this.recordProviderSuccess(n.name,m),this.log("provider:success",{provider:n.name,cep:e,duration:m}),this.emitter.emit("success",{provider:n.name,cep:e,duration:m,address:d}),this.cache&&this.cache.set(e,d),t?t(d):d}).catch(b=>{let m=Date.now()-l,d=F(b,e,n.name);throw d.name!=="AbortError"&&!(d instanceof v)&&(this.recordProviderFailure(n.name,m,d),this.log("provider:failure",{provider:n.name,cep:e,error:d.message}),this.emitter.emit("failure",{provider:n.name,cep:e,duration:m,error:d})),d});return Promise.race([B,I])},y=a[0],h=a.slice(1);if(h.length===0)try{return await u(y)}finally{r.abort()}let w=null,C=null,k=new Promise((n,l)=>{C=()=>{if(w&&clearTimeout(w),s.aborted)return;let L=h.map(u);Promise.any(L).then(n).catch(l)},w=setTimeout(C,this.staggerDelay)}),D=u(y).catch(n=>{throw C&&C(),n});try{return await Promise.any([D,k])}catch(n){let l=n.errors||[n];throw new p(l)}finally{w&&clearTimeout(w),r.abort()}}async lookupCeps(e,t=5,r){if(!e||e.length===0)return[];let s=new Array(e.length),c=0,o=async()=>{for(;c<e.length;){let u=c++;if(u>=e.length)break;let y=e[u];try{let h=await this.lookup(y);if(h)s[u]={cep:y,data:r?r(h):h,provider:h.service};else throw new Error("No address found")}catch(h){s[u]={cep:y,data:null,error:h}}}},a=Array.from({length:Math.min(t,e.length)},()=>o());return await Promise.all(a),s.filter(Boolean)}};
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var L=class{constructor(e){this.cache=new Map;this.ttl=e?.ttl??1/0,this.maxSize=e?.maxSize??1/0}get(e){let t=this.cache.get(e);if(t){if(this.ttl!==1/0&&Date.now()-t.timestamp>this.ttl){this.cache.delete(e);return}return t.value}}set(e,t){if(this.cache.has(e)&&this.cache.delete(e),this.cache.size>=this.maxSize){let r=this.cache.keys().next().value;r!==void 0&&this.cache.delete(r)}this.cache.set(e,{value:t,timestamp:Date.now()})}delete(e){this.cache.delete(e)}has(e){if(!this.cache.has(e))return!1;let t=this.cache.get(e);return this.ttl!==1/0&&Date.now()-t.timestamp>this.ttl?(this.cache.delete(e),!1):!0}clear(){this.cache.clear()}};var E=class extends Error{constructor(t){super("Invalid CEP format. Use either NNNNNNNN or NNNNN-NNN.");this.code="INVALID_CEP";this.name="CepValidationError",this.cep=t}},P=class extends Error{constructor(t,r){super(`Rate limit exceeded: ${t} requests per ${r}ms.`);this.code="RATE_LIMITED";this.name="RateLimitError",this.limit=t,this.window=r}},v=class extends Error{constructor(t,r){super(`Timeout from ${t}`);this.code="TIMEOUT";this.name="ProviderTimeoutError",this.provider=t,this.timeout=r}},y=class extends Error{constructor(t,r){super("CEP not found");this.code="NOT_FOUND";this.name="CepNotFoundError",this.cep=t,this.provider=r}},p=class extends Error{constructor(t){super("All providers failed to resolve the CEP.");this.code="ALL_PROVIDERS_FAILED";this.name="AllProvidersFailedError",this.errors=t}},b=class extends Error{constructor(t){super(`Provider ${t} is temporarily unavailable (circuit open).`);this.code="PROVIDER_UNAVAILABLE";this.name="ProviderUnavailableError",this.provider=t}};function R(i,e,t){if(i instanceof Error){if(i instanceof E||i instanceof P||i instanceof v||i instanceof y||i instanceof b||i instanceof p)return i;let r=i.message?.toLowerCase?.()||"";return r.includes("cep not found")||r.includes("not found")||r.includes("status: 404")?new y(e,t):(i.name==="AbortError",i)}return new Error(String(i))}var N={AC:"68",AL:"82",AM:"92",AP:"96",BA:"71",CE:"85",DF:"61",ES:"27",GO:"62",MA:"98",MG:"31",MS:"67",MT:"65",PA:"91",PB:"83",PE:"81",PI:"86",PR:"41",RJ:"21",RN:"84",RO:"69",RR:"95",RS:"51",SC:"48",SE:"79",SP:"11",TO:"63"};var x=class{constructor(){this.listeners={}}on(e,t){this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(t)}off(e,t){let r=this.listeners[e];r&&(this.listeners[e]=r.filter(s=>s!==t))}emit(e,t){let r=this.listeners[e];r&&r.forEach(s=>s(t))}};function B(i){if(!/^(\d{8}|\d{5}-\d{3})$/.test(i))throw new E(i);return i.replace("-","")}function U(i){let e={...i};return Object.keys(e).forEach(t=>{let r=e[t];typeof r=="string"&&(e[t]=r.trim())}),e}function q(i){if(!i.ddd&&i.state){let e=N[i.state];if(e)return{...i,ddd:e}}return i}var F=class{constructor(e){this.requestTimestamps=[];this.providerState=new Map;this.providers=e.providers,this.sortedProviders=[...e.providers],this.emitter=new x,this.fetcher=e.fetcher||(async(t,r)=>{let s=await fetch(t,{signal:r});if(!s.ok)throw new Error(`HTTP error! status: ${s.status}`);return s.json()}),this.cache=e.cache,this.rateLimit=e.rateLimit,this.staggerDelay=e.staggerDelay??100,this.retries=e.retries??0,this.retryDelay=e.retryDelay??1e3,this.logger=e.logger,this.circuitBreakerEnabled=e.circuitBreaker?.enabled??!0,this.circuitFailureThreshold=e.circuitBreaker?.failureThreshold??3,this.circuitCooldownMs=e.circuitBreaker?.cooldownMs??3e4,this.providers.forEach(t=>{this.providerState.set(t.name,{consecutiveFailures:0,successCount:0,failureCount:0,avgLatencyMs:0,requests:0,timeoutErrors:0,notFoundErrors:0})})}log(e,t){this.logger?.debug(e,t)}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}async warmup(){let e="01001000",t=new AbortController,r=this.providers.map(async o=>{let a=Date.now();try{let u=o.buildUrl(e);return await this.fetcher(u,t.signal),{provider:o,duration:Date.now()-a,error:!1}}catch{return{provider:o,duration:1/0,error:!0}}}),c=(await Promise.all(r)).sort((o,a)=>o.duration-a.duration);return this.sortedProviders=c.map(o=>o.provider).filter(o=>!!o),t.abort(),this.sortedProviders}getOrCreateProviderState(e){let t=this.providerState.get(e);if(t)return t;let r={consecutiveFailures:0,successCount:0,failureCount:0,avgLatencyMs:0,requests:0,timeoutErrors:0,notFoundErrors:0};return this.providerState.set(e,r),r}recordProviderSuccess(e,t){let r=this.getOrCreateProviderState(e);r.requests+=1,r.successCount+=1,r.consecutiveFailures=0;let s=r.successCount+r.failureCount;r.avgLatencyMs=s===1?t:(r.avgLatencyMs*(s-1)+t)/s,r.openUntil=void 0}recordProviderFailure(e,t,r){let s=this.getOrCreateProviderState(e);s.requests+=1,s.failureCount+=1,s.consecutiveFailures+=1;let c=s.successCount+s.failureCount;s.avgLatencyMs=c===1?t:(s.avgLatencyMs*(c-1)+t)/c,r instanceof v&&(s.timeoutErrors+=1),r instanceof y&&(s.notFoundErrors+=1),this.circuitBreakerEnabled&&s.consecutiveFailures>=this.circuitFailureThreshold&&(s.openUntil=Date.now()+this.circuitCooldownMs)}isProviderOpen(e){if(!this.circuitBreakerEnabled)return!1;let t=this.getOrCreateProviderState(e);return t.openUntil?Date.now()>=t.openUntil?(t.openUntil=void 0,t.consecutiveFailures=0,!1):!0:!1}scoreProvider(e){let t=this.getOrCreateProviderState(e.name),r=t.successCount+t.failureCount,s=r===0?1:t.successCount/r,c=t.avgLatencyMs>0?Math.min(t.avgLatencyMs/1e3,1):0,o=this.isProviderOpen(e.name)?1:0;return s*.8+(1-c)*.2-o}getProviderHealth(){return this.providers.map(e=>{let t=this.getOrCreateProviderState(e.name);return{provider:e.name,score:Number(this.scoreProvider(e).toFixed(4)),isOpen:this.isProviderOpen(e.name),openUntil:t.openUntil,consecutiveFailures:t.consecutiveFailures,successCount:t.successCount,failureCount:t.failureCount,avgLatencyMs:Number(t.avgLatencyMs.toFixed(2))}}).sort((e,t)=>t.score-e.score)}getProviderMetrics(){return this.providers.map(e=>{let t=this.getOrCreateProviderState(e.name);return{provider:e.name,requests:t.requests,successes:t.successCount,failures:t.failureCount,timeoutErrors:t.timeoutErrors,notFoundErrors:t.notFoundErrors,avgLatencyMs:Number(t.avgLatencyMs.toFixed(2))}})}checkRateLimit(){if(!this.rateLimit)return;let e=Date.now(),t=e-this.rateLimit.per;if(this.requestTimestamps=this.requestTimestamps.filter(r=>r>t),this.requestTimestamps.length>=this.rateLimit.requests)throw new P(this.rateLimit.requests,this.rateLimit.per);this.requestTimestamps.push(e)}async lookup(e,t){this.checkRateLimit();let r=B(e);if(this.log("lookup:start",{cep:r}),this.cache){let o=this.cache.get(r);if(o)return this.log("cache:hit",{cep:r}),this.emitter.emit("cache:hit",{cep:r}),t?t(o):o}let s,c=1+this.retries;for(let o=0;o<c;o++){if(o>0){let a=this.retryDelay*Math.pow(2,o-1);this.log("retry:attempt",{attempt:o,cep:r,delay:a}),await new Promise(u=>setTimeout(u,a))}try{return await this._lookupFromProviders(r,t)}catch(a){if(a instanceof E||a instanceof P)throw a;s=a}}throw s}async _lookupFromProviders(e,t){let r=new AbortController,{signal:s}=r,c=this.sortedProviders.filter(n=>!this.isProviderOpen(n.name)),o=[...c].sort((n,l)=>this.scoreProvider(l)-this.scoreProvider(n)),a=o.length>0?o:[...this.sortedProviders].sort((n,l)=>this.scoreProvider(l)-this.scoreProvider(n));if(a.length===0)throw new p([new b("all")]);if(c.length===0&&this.circuitBreakerEnabled)throw new p(a.map(n=>new b(n.name)));let u=n=>{let l=Date.now(),A=n.buildUrl(e);this.log("provider:start",{provider:n.name,cep:e});let D=new Promise((g,m)=>{if(!n.timeout)return;let d=setTimeout(()=>{s.removeEventListener("abort",M);let O=Date.now()-l,T=new v(n.name,n.timeout);this.recordProviderFailure(n.name,O,T),this.log("provider:failure",{provider:n.name,cep:e,error:T.message}),this.emitter.emit("failure",{provider:n.name,cep:e,duration:O,error:T}),m(T)},n.timeout),M=()=>clearTimeout(d);s.addEventListener("abort",M,{once:!0})}),I=this.fetcher(A,s).then(g=>n.transform(g)).then(g=>{let m=Date.now()-l,d=q(U(g));return this.recordProviderSuccess(n.name,m),this.log("provider:success",{provider:n.name,cep:e,duration:m}),this.emitter.emit("success",{provider:n.name,cep:e,duration:m,address:d}),this.cache&&this.cache.set(e,d),t?t(d):d}).catch(g=>{let m=Date.now()-l,d=R(g,e,n.name);throw d.name!=="AbortError"&&!(d instanceof v)&&(this.recordProviderFailure(n.name,m,d),this.log("provider:failure",{provider:n.name,cep:e,error:d.message}),this.emitter.emit("failure",{provider:n.name,cep:e,duration:m,error:d})),d});return Promise.race([I,D])},f=a[0],h=a.slice(1);if(h.length===0)try{return await u(f)}finally{r.abort()}let w=null,C=null,S=new Promise((n,l)=>{C=()=>{if(w&&clearTimeout(w),s.aborted)return;let A=h.map(u);Promise.any(A).then(n).catch(l)},w=setTimeout(C,this.staggerDelay)}),k=u(f).catch(n=>{throw C&&C(),n});try{return await Promise.any([k,S])}catch(n){let l=n.errors||[n];throw new p(l)}finally{w&&clearTimeout(w),r.abort()}}async lookupCeps(e,t=5,r){if(!e||e.length===0)return[];let s=new Array(e.length),c=0,o=async()=>{for(;c<e.length;){let u=c++;if(u>=e.length)break;let f=e[u];try{let h=await this.lookup(f);if(h)s[u]={cep:f,data:r?r(h):h,provider:h.service};else throw new Error("No address found")}catch(h){s[u]={cep:f,data:null,error:h}}}},a=Array.from({length:Math.min(t,e.length)},()=>o());return await Promise.all(a),s.filter(Boolean)}};export{p as AllProvidersFailedError,F as CepLookup,y as CepNotFoundError,E as CepValidationError,L as InMemoryCache,v as ProviderTimeoutError,b as ProviderUnavailableError,P as RateLimitError};
|
package/dist/providers/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var o=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var f=(r,t)=>{for(var d in t)o(r,d,{get:t[d],enumerable:!0})},P=(r,t,d,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of c(t))!m.call(r,i)&&i!==d&&o(r,i,{get:()=>t[i],enumerable:!(e=a(t,i))||e.enumerable});return r};var l=r=>P(o({},"__esModule",{value:!0}),r);var g={};f(g,{apicepProvider:()=>v,brasilApiProvider:()=>u,openCepProvider:()=>b,viaCepProvider:()=>n});module.exports=l(g);var n={name:"ViaCEP",buildUrl:r=>`https://viacep.com.br/ws/${r}/json/`,transform:r=>{if(!r||r.erro===!0||r.erro==="true")throw new Error("CEP not found");return{cep:(r.cep||"").replace("-",""),state:r.uf||"",city:r.localidade||"",neighborhood:r.bairro||"",street:r.logradouro||"",service:"ViaCEP",ibge:r.ibge||void 0,ddd:r.ddd||void 0}}};var u={name:"BrasilAPI",buildUrl:r=>`https://brasilapi.com.br/api/cep/v1/${r}`,transform:r=>{if(!r||r.errors||r.message)throw new Error(r.message||"CEP not found");return{cep:(r.cep||"").replace("-",""),state:r.state||"",city:r.city||"",neighborhood:r.neighborhood||"",street:r.street||"",service:"BrasilAPI"}}};var v={name:"ApiCEP",buildUrl:r=>`https://cdn.apicep.com/file/apicep/${r}.json`,transform:r=>{if(!r||r.status!==200)throw new Error(r?.message||"CEP not found");return{cep:(r.code||"").replace("-",""),state:r.state||"",city:r.city||"",neighborhood:r.district||"",street:r.address||"",service:"ApiCEP"}}};var b={name:"OpenCEP",buildUrl:r=>`https://opencep.com/v1/${r}`,transform:r=>{if(!r||r.error)throw new Error("CEP not found");return{cep:(r.cep||"").replace("-",""),state:r.uf||"",city:r.localidade||"",neighborhood:r.bairro||"",street:r.logradouro||"",service:"OpenCEP",ibge:r.ibge||void 0}}};
|
package/dist/providers/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var t={name:"ViaCEP",buildUrl:r=>`https://viacep.com.br/ws/${r}/json/`,transform:r=>{if(!r||r.erro===!0||r.erro==="true")throw new Error("CEP not found");return{cep:(r.cep||"").replace("-",""),state:r.uf||"",city:r.localidade||"",neighborhood:r.bairro||"",street:r.logradouro||"",service:"ViaCEP"}}};var
|
|
1
|
+
var t={name:"ViaCEP",buildUrl:r=>`https://viacep.com.br/ws/${r}/json/`,transform:r=>{if(!r||r.erro===!0||r.erro==="true")throw new Error("CEP not found");return{cep:(r.cep||"").replace("-",""),state:r.uf||"",city:r.localidade||"",neighborhood:r.bairro||"",street:r.logradouro||"",service:"ViaCEP",ibge:r.ibge||void 0,ddd:r.ddd||void 0}}};var d={name:"BrasilAPI",buildUrl:r=>`https://brasilapi.com.br/api/cep/v1/${r}`,transform:r=>{if(!r||r.errors||r.message)throw new Error(r.message||"CEP not found");return{cep:(r.cep||"").replace("-",""),state:r.state||"",city:r.city||"",neighborhood:r.neighborhood||"",street:r.street||"",service:"BrasilAPI"}}};var e={name:"ApiCEP",buildUrl:r=>`https://cdn.apicep.com/file/apicep/${r}.json`,transform:r=>{if(!r||r.status!==200)throw new Error(r?.message||"CEP not found");return{cep:(r.code||"").replace("-",""),state:r.state||"",city:r.city||"",neighborhood:r.district||"",street:r.address||"",service:"ApiCEP"}}};var c={name:"OpenCEP",buildUrl:r=>`https://opencep.com/v1/${r}`,transform:r=>{if(!r||r.error)throw new Error("CEP not found");return{cep:(r.cep||"").replace("-",""),state:r.uf||"",city:r.localidade||"",neighborhood:r.bairro||"",street:r.logradouro||"",service:"OpenCEP",ibge:r.ibge||void 0}}};export{e as apicepProvider,d as brasilApiProvider,c as openCepProvider,t as viaCepProvider};
|
|
@@ -7,30 +7,27 @@ export interface Cache {
|
|
|
7
7
|
get(key: string): Address | undefined;
|
|
8
8
|
set(key: string, value: Address): void;
|
|
9
9
|
clear(): void;
|
|
10
|
+
delete?(key: string): void;
|
|
11
|
+
has?(key: string): boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface InMemoryCacheOptions {
|
|
14
|
+
/** Time-to-live in milliseconds. Default: Infinity (no expiry) */
|
|
15
|
+
ttl?: number;
|
|
16
|
+
/** Maximum number of entries. Default: Infinity (no limit) */
|
|
17
|
+
maxSize?: number;
|
|
10
18
|
}
|
|
11
19
|
/**
|
|
12
20
|
* @class InMemoryCache
|
|
13
|
-
* @description
|
|
21
|
+
* @description In-memory cache with optional TTL and size limit.
|
|
14
22
|
*/
|
|
15
23
|
export declare class InMemoryCache implements Cache {
|
|
16
24
|
private cache;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* @param {string} key - The CEP to look up.
|
|
21
|
-
* @returns {Address | undefined} The cached address or undefined if not found.
|
|
22
|
-
*/
|
|
25
|
+
private ttl;
|
|
26
|
+
private maxSize;
|
|
27
|
+
constructor(options?: InMemoryCacheOptions);
|
|
23
28
|
get(key: string): Address | undefined;
|
|
24
|
-
/**
|
|
25
|
-
* @method set
|
|
26
|
-
* @description Stores an address in the cache.
|
|
27
|
-
* @param {string} key - The CEP to use as the cache key.
|
|
28
|
-
* @param {Address} value - The address to store.
|
|
29
|
-
*/
|
|
30
29
|
set(key: string, value: Address): void;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* @description Clears the entire cache.
|
|
34
|
-
*/
|
|
30
|
+
delete(key: string): void;
|
|
31
|
+
has(key: string): boolean;
|
|
35
32
|
clear(): void;
|
|
36
33
|
}
|