@eusilvio/cep-lookup 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 +30 -0
- package/dist/index.d.ts +5 -35
- package/dist/index.js +1 -1
- package/dist/types.d.ts +32 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -149,6 +149,7 @@ Creates a new `CepLookup` instance.
|
|
|
149
149
|
- `providers` (Provider[], **required**): An array of providers that will be queried.
|
|
150
150
|
- `fetcher` (Fetcher, _optional_): Your asynchronous function that fetches data from a URL. Defaults to global `fetch` if not provided.
|
|
151
151
|
- `cache` (Cache, _optional_): An instance of a cache that implements the `Cache` interface. Use `InMemoryCache` for a simple in-memory cache.
|
|
152
|
+
- `rateLimit` ({ requests: number, per: number }, _optional_): Configures an in-memory rate limiter (e.g., `{ requests: 10, per: 1000 }` for 10 requests per second).
|
|
152
153
|
|
|
153
154
|
### `cepLookup.lookup<T = Address>(cep, mapper?): Promise<T>`
|
|
154
155
|
|
|
@@ -168,6 +169,35 @@ Looks up multiple CEPs in bulk. Returns a `Promise` that resolves to an array of
|
|
|
168
169
|
- `fetcher` (Fetcher, _optional_): A custom fetch function.
|
|
169
170
|
- `cache` (Cache, _optional_): A cache instance.
|
|
170
171
|
|
|
172
|
+
### Observability Events API
|
|
173
|
+
|
|
174
|
+
Version 2.0.0 introduced an event-based API to monitor the library's behavior. You can listen to events to gather metrics on provider performance, latency, and errors.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const cepLookup = new CepLookup({ providers: [...] });
|
|
178
|
+
|
|
179
|
+
// Fired for each successful provider response
|
|
180
|
+
cepLookup.on('success', ({ provider, cep, duration }) => {
|
|
181
|
+
console.log(`[${provider}] Success for CEP ${cep} in ${duration}ms`);
|
|
182
|
+
// myMetrics.timing('cep.latency', duration, { provider });
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Fired for each failed provider response
|
|
186
|
+
cepLookup.on('failure', ({ provider, cep, error }) => {
|
|
187
|
+
console.error(`[${provider}] Failure for CEP ${cep}: ${error.message}`);
|
|
188
|
+
// myMetrics.increment('cep.failure', { provider });
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Fired when a CEP is resolved from the cache
|
|
192
|
+
cepLookup.on('cache:hit', ({ cep }) => {
|
|
193
|
+
console.log(`[Cache] CEP ${cep} found in cache.`);
|
|
194
|
+
// myMetrics.increment('cep.cache_hit');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// The lookup call remains the same
|
|
198
|
+
cepLookup.lookup("01001-000");
|
|
199
|
+
```
|
|
200
|
+
|
|
171
201
|
## Examples
|
|
172
202
|
|
|
173
203
|
You can find more detailed examples in the `examples/` directory:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { Address, Fetcher, Provider, CepLookupOptions, BulkCepResult, RateLimitOptions } from "./types";
|
|
1
|
+
import { Address, Fetcher, Provider, CepLookupOptions, BulkCepResult, RateLimitOptions, EventName, EventListener, EventMap } from "./types";
|
|
2
2
|
import { Cache, InMemoryCache } from "./cache";
|
|
3
|
-
export { Address, Fetcher, Provider, CepLookupOptions, Cache, InMemoryCache, BulkCepResult, RateLimitOptions };
|
|
3
|
+
export { Address, Fetcher, Provider, CepLookupOptions, Cache, InMemoryCache, BulkCepResult, RateLimitOptions, EventName, EventListener, EventMap };
|
|
4
4
|
/**
|
|
5
5
|
* @class CepLookup
|
|
6
6
|
* @description A class for looking up Brazilian postal codes (CEPs) using multiple providers.
|
|
7
|
-
* It queries multiple services simultaneously and returns the response from the fastest one.
|
|
8
7
|
*/
|
|
9
8
|
export declare class CepLookup {
|
|
10
9
|
private providers;
|
|
@@ -12,46 +11,17 @@ export declare class CepLookup {
|
|
|
12
11
|
private cache?;
|
|
13
12
|
private rateLimit?;
|
|
14
13
|
private requestTimestamps;
|
|
15
|
-
|
|
16
|
-
* @constructor
|
|
17
|
-
* @param {CepLookupOptions} options - The options for initializing the CepLookup instance.
|
|
18
|
-
*/
|
|
14
|
+
private emitter;
|
|
19
15
|
constructor(options: CepLookupOptions);
|
|
16
|
+
on<T extends EventName>(eventName: T, listener: EventListener<T>): void;
|
|
17
|
+
off<T extends EventName>(eventName: T, listener: EventListener<T>): void;
|
|
20
18
|
private checkRateLimit;
|
|
21
|
-
/**
|
|
22
|
-
* @method lookup
|
|
23
|
-
* @description Looks up an address for a given CEP.
|
|
24
|
-
* @template T - The expected return type, defaults to `Address`.
|
|
25
|
-
* @param {string} cep - The CEP to be queried.
|
|
26
|
-
* @param {(address: Address) => T} [mapper] - An optional function to transform the `Address` object into a custom format `T`.
|
|
27
|
-
* @returns {Promise<T>} A Promise that resolves to the address in the default `Address` format or a custom format `T` if a mapper is provided.
|
|
28
|
-
* @throws {Error} If the CEP is invalid or if all providers fail to find the CEP.
|
|
29
|
-
*/
|
|
30
19
|
lookup<T = Address>(cep: string, mapper?: (address: Address) => T): Promise<T>;
|
|
31
20
|
}
|
|
32
|
-
/**
|
|
33
|
-
* @function lookupCep
|
|
34
|
-
* @description Backward-compatible function for looking up a CEP. Internally creates a `CepLookup` instance.
|
|
35
|
-
* @template T - The expected return type, defaults to `Address`.
|
|
36
|
-
* @param {object} options - Options for the lookup.
|
|
37
|
-
* @param {string} options.cep - The CEP to be queried.
|
|
38
|
-
* @param {Provider[]} options.providers - An array of `Provider` instances.
|
|
39
|
-
* @param {Fetcher} [options.fetcher] - The `Fetcher` function. Defaults to global `fetch` if not provided.
|
|
40
|
-
* @param {Cache} [options.cache] - The `Cache` instance.
|
|
41
|
-
* @param {(address: Address) => T} [options.mapper] - An optional function to transform the `Address` object.
|
|
42
|
-
* @returns {Promise<T>} A Promise that resolves to the address.
|
|
43
|
-
* @throws {Error} If the CEP is invalid or if all providers fail.
|
|
44
|
-
*/
|
|
45
21
|
export declare function lookupCep<T = Address>(options: CepLookupOptions & {
|
|
46
22
|
cep: string;
|
|
47
23
|
mapper?: (address: Address) => T;
|
|
48
24
|
}): Promise<T>;
|
|
49
|
-
/**
|
|
50
|
-
* @function lookupCeps
|
|
51
|
-
* @description Looks up multiple CEPs in bulk with controlled concurrency.
|
|
52
|
-
* @param {CepLookupOptions & { ceps: string[], concurrency?: number }} options - Options for the bulk lookup.
|
|
53
|
-
* @returns {Promise<BulkCepResult[]>} A Promise that resolves to an array of results for each CEP.
|
|
54
|
-
*/
|
|
55
25
|
export declare function lookupCeps(options: CepLookupOptions & {
|
|
56
26
|
ceps: string[];
|
|
57
27
|
concurrency?: number;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var w=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var N=(r,e)=>{for(var t in e)w(r,t,{get:e[t],enumerable:!0})},x=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of A(e))!y.call(r,i)&&i!==t&&w(r,i,{get:()=>e[i],enumerable:!(s=E(e,i))||s.enumerable});return r};var C=r=>x(w({},"__esModule",{value:!0}),r);var O={};N(O,{CepLookup:()=>m,InMemoryCache:()=>l,lookupCep:()=>R,lookupCeps:()=>q});module.exports=C(O);var l=class{constructor(){this.cache=new Map}get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}clear(){this.cache.clear()}};var T=class{constructor(){this.listeners={}}on(e,t){this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(t)}off(e,t){this.listeners[e]&&(this.listeners[e]=this.listeners[e].filter(s=>s!==t))}emit(e,t){this.listeners[e]&&this.listeners[e].forEach(s=>s(t))}};function b(r){if(!/^(\d{8}|\d{5}-\d{3})$/.test(r))throw new Error("Invalid CEP format. Use either NNNNNNNN or NNNNN-NNN.");return r.replace("-","")}function P(r){let e={...r};for(let t in e)typeof e[t]=="string"&&(e[t]=e[t].trim());return e}var m=class{constructor(e){this.requestTimestamps=[];this.providers=e.providers,this.emitter=new T,this.fetcher=e.fetcher||(async(t,s)=>{let i=await fetch(t,{signal:s});if(!i.ok)throw new Error(`HTTP error! status: ${i.status}`);return i.json()}),this.cache=e.cache,this.rateLimit=e.rateLimit}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}checkRateLimit(){if(!this.rateLimit)return;let e=Date.now(),t=e-this.rateLimit.per;if(this.requestTimestamps=this.requestTimestamps.filter(s=>s>t),this.requestTimestamps.length>=this.rateLimit.requests)throw new Error(`Rate limit exceeded: ${this.rateLimit.requests} requests per ${this.rateLimit.per}ms.`);this.requestTimestamps.push(e)}async lookup(e,t){this.checkRateLimit();let s=b(e);if(this.cache){let n=this.cache.get(s);if(n)return this.emitter.emit("cache:hit",{cep:s}),Promise.resolve(t?t(n):n)}let i=new AbortController,{signal:d}=i,h=this.providers.map(n=>{let u=Date.now(),p=n.buildUrl(s),f=new Promise((o,c)=>{if(!n.timeout)return;let a=setTimeout(()=>{d.removeEventListener("abort",g);let k=Date.now()-u,L=new Error(`Timeout from ${n.name}`);this.emitter.emit("failure",{provider:n.name,cep:s,duration:k,error:L}),c(L)},n.timeout),g=()=>clearTimeout(a);d.addEventListener("abort",g,{once:!0})}),v=this.fetcher(p,d).then(o=>n.transform(o)).then(o=>{let c=Date.now()-u,a=P(o);return this.emitter.emit("success",{provider:n.name,cep:s,duration:c,address:a}),this.cache&&this.cache.set(s,a),t?t(a):a}).catch(o=>{let c=Date.now()-u;throw o.message.includes("Timeout from")||this.emitter.emit("failure",{provider:n.name,cep:s,duration:c,error:o}),o});return Promise.race([v,f])});try{return h.length===1?await h[0]:await Promise.any(h)}finally{i.abort()}}};function R(r){let{cep:e,providers:t,fetcher:s,mapper:i,cache:d,rateLimit:h}=r;return new m({providers:t,fetcher:s,cache:d,rateLimit:h}).lookup(e,i)}async function q(r){let{ceps:e,providers:t,fetcher:s,cache:i,concurrency:d=5,rateLimit:h}=r;if(!e||e.length===0)return[];let n=new m({providers:t,fetcher:s,cache:i,rateLimit:h}),u=new Array(e.length),p=0,f=async()=>{for(;p<e.length;){let o=p++;if(o>=e.length)break;let c=e[o];try{let a=await n.lookup(c);if(a)u[o]={cep:c,data:a,provider:a.service};else throw new Error("No address found")}catch(a){u[o]={cep:c,data:null,error:a}}}},v=Array.from({length:Math.min(d,e.length)},()=>f());return await Promise.all(v),u.filter(Boolean)}0&&(module.exports={CepLookup,InMemoryCache,lookupCep,lookupCeps});
|
package/dist/types.d.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
+
import { Cache } from "./cache";
|
|
1
2
|
/**
|
|
2
3
|
* @interface Address
|
|
3
4
|
* @description Represents a standardized address object returned by the CEP lookup.
|
|
4
|
-
* @property {string} cep - The postal code.
|
|
5
|
-
* @property {string} state - The state abbreviation (e.g., 'SP', 'RJ').
|
|
6
|
-
* @property {string} city - The city name.
|
|
7
|
-
* @property {string} neighborhood - The neighborhood name.
|
|
8
|
-
* @property {string} street - The street name.
|
|
9
|
-
* @property {string} service - The name of the service that provided the address (e.g., 'ViaCEP', 'BrasilAPI').
|
|
10
5
|
*/
|
|
11
6
|
export interface Address {
|
|
12
7
|
cep: string;
|
|
@@ -19,9 +14,6 @@ export interface Address {
|
|
|
19
14
|
/**
|
|
20
15
|
* @interface Provider
|
|
21
16
|
* @description Defines the contract for a CEP lookup provider.
|
|
22
|
-
* @property {string} name - The name of the provider.
|
|
23
|
-
* @property {(cep: string) => string} buildUrl - A function that constructs the API URL for a given CEP.
|
|
24
|
-
* @property {(response: any) => Address} transform - A function that transforms the raw API response into a standardized `Address` object.
|
|
25
17
|
*/
|
|
26
18
|
export interface Provider {
|
|
27
19
|
name: string;
|
|
@@ -31,39 +23,30 @@ export interface Provider {
|
|
|
31
23
|
}
|
|
32
24
|
/**
|
|
33
25
|
* @typedef {function(url: string, signal?: AbortSignal): Promise<any>}
|
|
34
|
-
* @description A function that fetches data from a given URL
|
|
26
|
+
* @description A function that fetches data from a given URL.
|
|
35
27
|
*/
|
|
36
28
|
export type Fetcher = (url: string, signal?: AbortSignal) => Promise<any>;
|
|
29
|
+
/**
|
|
30
|
+
* @interface RateLimitOptions
|
|
31
|
+
* @description Options for configuring the internal rate limiter.
|
|
32
|
+
*/
|
|
33
|
+
export interface RateLimitOptions {
|
|
34
|
+
requests: number;
|
|
35
|
+
per: number;
|
|
36
|
+
}
|
|
37
37
|
/**
|
|
38
38
|
* @interface CepLookupOptions
|
|
39
39
|
* @description Options for initializing the `CepLookup` class.
|
|
40
|
-
* @property {Provider[]} providers - An array of `Provider` instances to be used for CEP lookup.
|
|
41
|
-
* @property {Fetcher} [fetcher] - The `Fetcher` function to be used for making HTTP requests. Defaults to global `fetch` if not provided.
|
|
42
40
|
*/
|
|
43
|
-
import { Cache } from "./cache";
|
|
44
41
|
export interface CepLookupOptions {
|
|
45
42
|
providers: Provider[];
|
|
46
43
|
fetcher?: Fetcher;
|
|
47
44
|
cache?: Cache;
|
|
48
45
|
rateLimit?: RateLimitOptions;
|
|
49
46
|
}
|
|
50
|
-
/**
|
|
51
|
-
* @interface RateLimitOptions
|
|
52
|
-
* @description Options for configuring the internal rate limiter.
|
|
53
|
-
* @property {number} requests - The maximum number of requests allowed within the time window.
|
|
54
|
-
* @property {number} per - The time window in milliseconds.
|
|
55
|
-
*/
|
|
56
|
-
export interface RateLimitOptions {
|
|
57
|
-
requests: number;
|
|
58
|
-
per: number;
|
|
59
|
-
}
|
|
60
47
|
/**
|
|
61
48
|
* @interface BulkCepResult
|
|
62
49
|
* @description Represents the result for a single CEP in a bulk lookup operation.
|
|
63
|
-
* @property {string} cep - The original CEP string.
|
|
64
|
-
* @property {Address | null} data - The address data if the lookup was successful, otherwise null.
|
|
65
|
-
* @property {string} [provider] - The name of the provider that successfully resolved the address.
|
|
66
|
-
* @property {Error} [error] - An error object if the lookup failed for this specific CEP.
|
|
67
50
|
*/
|
|
68
51
|
export interface BulkCepResult {
|
|
69
52
|
cep: string;
|
|
@@ -71,3 +54,25 @@ export interface BulkCepResult {
|
|
|
71
54
|
provider?: string;
|
|
72
55
|
error?: Error;
|
|
73
56
|
}
|
|
57
|
+
export type EventName = 'success' | 'failure' | 'cache:hit';
|
|
58
|
+
export interface SuccessPayload {
|
|
59
|
+
provider: string;
|
|
60
|
+
cep: string;
|
|
61
|
+
duration: number;
|
|
62
|
+
address: Address;
|
|
63
|
+
}
|
|
64
|
+
export interface FailurePayload {
|
|
65
|
+
provider: string;
|
|
66
|
+
cep: string;
|
|
67
|
+
duration: number;
|
|
68
|
+
error: Error;
|
|
69
|
+
}
|
|
70
|
+
export interface CacheHitPayload {
|
|
71
|
+
cep: string;
|
|
72
|
+
}
|
|
73
|
+
export interface EventMap {
|
|
74
|
+
success: SuccessPayload;
|
|
75
|
+
failure: FailurePayload;
|
|
76
|
+
'cache:hit': CacheHitPayload;
|
|
77
|
+
}
|
|
78
|
+
export type EventListener<T extends EventName> = (payload: EventMap[T]) => void;
|