@zentto/platform-client 0.4.0 → 0.5.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/dist/auth/client.d.ts +8 -1
- package/dist/auth/client.d.ts.map +1 -1
- package/dist/auth/client.js +17 -1
- package/dist/auth/client.js.map +1 -1
- package/dist/internal/cache.d.ts +41 -0
- package/dist/internal/cache.d.ts.map +1 -0
- package/dist/internal/cache.js +84 -0
- package/dist/internal/cache.js.map +1 -0
- package/dist/internal/http.d.ts +5 -0
- package/dist/internal/http.d.ts.map +1 -1
- package/dist/internal/http.js +6 -0
- package/dist/internal/http.js.map +1 -1
- package/dist/internal/ratelimit.d.ts +36 -0
- package/dist/internal/ratelimit.d.ts.map +1 -0
- package/dist/internal/ratelimit.js +67 -0
- package/dist/internal/ratelimit.js.map +1 -0
- package/package.json +1 -1
package/dist/auth/client.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* setPassword es público (magic-link consumo), no requiere auth.
|
|
11
11
|
*/
|
|
12
|
-
import { type HttpConfig, type HttpResult } from "../internal/http.js";
|
|
12
|
+
import { type HttpConfig, type HttpConfigInput, type HttpResult } from "../internal/http.js";
|
|
13
13
|
export interface AuthConfig {
|
|
14
14
|
baseUrl?: string;
|
|
15
15
|
/** Bearer JWT para llamadas user-facing. Opcional — algunos métodos no requieren. */
|
|
@@ -19,6 +19,10 @@ export interface AuthConfig {
|
|
|
19
19
|
timeoutMs?: number;
|
|
20
20
|
retries?: number;
|
|
21
21
|
onError?: HttpConfig["onError"];
|
|
22
|
+
/** TTL del cache de `me()`. Default 15s. Pasar 0 para desactivar. */
|
|
23
|
+
meCacheTtlMs?: number;
|
|
24
|
+
/** Rate limit client-side (opcional). */
|
|
25
|
+
rateLimit?: HttpConfigInput["rateLimit"];
|
|
22
26
|
}
|
|
23
27
|
export interface AuthUser {
|
|
24
28
|
userId?: number;
|
|
@@ -74,6 +78,7 @@ export declare class AuthClient {
|
|
|
74
78
|
private readonly serviceKey?;
|
|
75
79
|
private accessToken?;
|
|
76
80
|
private refreshInFlight?;
|
|
81
|
+
private readonly meCache;
|
|
77
82
|
constructor(opts: AuthConfig);
|
|
78
83
|
setAccessToken(token: string | undefined): void;
|
|
79
84
|
private bearer;
|
|
@@ -104,6 +109,8 @@ export declare class AuthClient {
|
|
|
104
109
|
ok: boolean;
|
|
105
110
|
}>>;
|
|
106
111
|
me(appId?: string): Promise<HttpResult<MeResponse>>;
|
|
112
|
+
/** Purga manualmente el cache de `me()`. Útil tras cambios de permisos. */
|
|
113
|
+
invalidateMeCache(): void;
|
|
107
114
|
registerForApp(params: {
|
|
108
115
|
email: string;
|
|
109
116
|
password: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAkC,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/client.js
CHANGED
|
@@ -10,18 +10,21 @@
|
|
|
10
10
|
* setPassword es público (magic-link consumo), no requiere auth.
|
|
11
11
|
*/
|
|
12
12
|
import { defaultHttpConfig, httpRequest } from "../internal/http.js";
|
|
13
|
+
import { TtlCache, memoAsync } from "../internal/cache.js";
|
|
13
14
|
// ── Client ──────────────────────────────────────────────────────────────────
|
|
14
15
|
export class AuthClient {
|
|
15
16
|
cfg;
|
|
16
17
|
serviceKey;
|
|
17
18
|
accessToken;
|
|
18
19
|
refreshInFlight;
|
|
20
|
+
meCache;
|
|
19
21
|
constructor(opts) {
|
|
20
22
|
this.cfg = defaultHttpConfig({
|
|
21
23
|
baseUrl: opts.baseUrl ?? "https://auth.zentto.net",
|
|
22
24
|
timeoutMs: opts.timeoutMs,
|
|
23
25
|
retries: opts.retries,
|
|
24
26
|
onError: opts.onError,
|
|
27
|
+
rateLimit: opts.rateLimit,
|
|
25
28
|
// Intercepta 401 → intenta refresh + reintenta UNA vez con el nuevo Bearer.
|
|
26
29
|
// Evita que cada caller tenga que saber manejar expiración de tokens.
|
|
27
30
|
beforeRetry: async (err, ctx) => {
|
|
@@ -32,11 +35,15 @@ export class AuthClient {
|
|
|
32
35
|
const newToken = await this.tryRefresh();
|
|
33
36
|
if (!newToken)
|
|
34
37
|
return { retry: false };
|
|
38
|
+
// Invalidate me cache on token change (identity may have changed).
|
|
39
|
+
this.meCache?.clear();
|
|
35
40
|
return { retry: true, headers: { Authorization: `Bearer ${newToken}` } };
|
|
36
41
|
},
|
|
37
42
|
});
|
|
38
43
|
this.accessToken = opts.accessToken;
|
|
39
44
|
this.serviceKey = opts.serviceKey;
|
|
45
|
+
const ttl = opts.meCacheTtlMs ?? 15_000;
|
|
46
|
+
this.meCache = ttl > 0 ? new TtlCache({ ttlMs: ttl, maxEntries: 16 }) : null;
|
|
40
47
|
}
|
|
41
48
|
setAccessToken(token) {
|
|
42
49
|
this.accessToken = token;
|
|
@@ -105,13 +112,22 @@ export class AuthClient {
|
|
|
105
112
|
});
|
|
106
113
|
}
|
|
107
114
|
async me(appId) {
|
|
108
|
-
|
|
115
|
+
const fn = () => httpRequest(this.cfg, {
|
|
109
116
|
method: "GET",
|
|
110
117
|
path: "/auth/me",
|
|
111
118
|
query: { appId },
|
|
112
119
|
headers: this.bearer(),
|
|
113
120
|
credentials: "include",
|
|
114
121
|
});
|
|
122
|
+
if (!this.meCache)
|
|
123
|
+
return fn();
|
|
124
|
+
// key = token + appId — cambios de cualquiera invalidan la entrada.
|
|
125
|
+
const key = `${this.accessToken ?? "anon"}:${appId ?? ""}`;
|
|
126
|
+
return memoAsync(this.meCache, key, fn);
|
|
127
|
+
}
|
|
128
|
+
/** Purga manualmente el cache de `me()`. Útil tras cambios de permisos. */
|
|
129
|
+
invalidateMeCache() {
|
|
130
|
+
this.meCache?.clear();
|
|
115
131
|
}
|
|
116
132
|
async registerForApp(params) {
|
|
117
133
|
return httpRequest(this.cfg, {
|
package/dist/auth/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,iBAAiB,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTL cache en memoria + wrapper `memoAsync` para memoizar resultados
|
|
3
|
+
* positivos de funciones async.
|
|
4
|
+
*
|
|
5
|
+
* Uso típico:
|
|
6
|
+
* const cache = new TtlCache<MeResponse>({ ttlMs: 15_000 });
|
|
7
|
+
* const me = await memoAsync(cache, "me", () => client.me());
|
|
8
|
+
*
|
|
9
|
+
* Sólo cachea resultados "ok" (`{ ok: true }`). Los errores se propagan
|
|
10
|
+
* sin guardarse — así los callers reintentan en la siguiente llamada.
|
|
11
|
+
*/
|
|
12
|
+
export interface TtlCacheOptions {
|
|
13
|
+
/** TTL default por entrada. Default 15s. */
|
|
14
|
+
ttlMs?: number;
|
|
15
|
+
/** Límite de entradas; al exceder se evicta por FIFO. Default 200. */
|
|
16
|
+
maxEntries?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare class TtlCache<T> {
|
|
19
|
+
private readonly ttlMs;
|
|
20
|
+
private readonly maxEntries;
|
|
21
|
+
private readonly data;
|
|
22
|
+
constructor(opts?: TtlCacheOptions);
|
|
23
|
+
get(key: string): T | undefined;
|
|
24
|
+
set(key: string, value: T, ttlMsOverride?: number): void;
|
|
25
|
+
delete(key: string): void;
|
|
26
|
+
clear(): void;
|
|
27
|
+
size(): number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Memoiza una función async por `key`. Si ya hay un resultado cacheado no
|
|
31
|
+
* expirado, lo devuelve sin llamar a fn. Si múltiples callers piden la
|
|
32
|
+
* misma key simultáneamente, se coalesce en una sola llamada (single-flight).
|
|
33
|
+
*
|
|
34
|
+
* Sólo guarda resultados donde `shouldCache(r)` sea true (default: r?.ok ===
|
|
35
|
+
* true, para compatibilidad con el shape Result<T> del SDK).
|
|
36
|
+
*/
|
|
37
|
+
export declare function memoAsync<T>(cache: TtlCache<T>, key: string, fn: () => Promise<T>, opts?: {
|
|
38
|
+
ttlMsOverride?: number;
|
|
39
|
+
shouldCache?: (r: T) => boolean;
|
|
40
|
+
}): Promise<T>;
|
|
41
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/internal/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;gBAExC,IAAI,GAAE,eAAoB;IAKtC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAU/B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI;IAYxD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,MAAM;CAGf;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAClB,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;CAAE,GACjE,OAAO,CAAC,CAAC,CAAC,CAqBZ"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTL cache en memoria + wrapper `memoAsync` para memoizar resultados
|
|
3
|
+
* positivos de funciones async.
|
|
4
|
+
*
|
|
5
|
+
* Uso típico:
|
|
6
|
+
* const cache = new TtlCache<MeResponse>({ ttlMs: 15_000 });
|
|
7
|
+
* const me = await memoAsync(cache, "me", () => client.me());
|
|
8
|
+
*
|
|
9
|
+
* Sólo cachea resultados "ok" (`{ ok: true }`). Los errores se propagan
|
|
10
|
+
* sin guardarse — así los callers reintentan en la siguiente llamada.
|
|
11
|
+
*/
|
|
12
|
+
export class TtlCache {
|
|
13
|
+
ttlMs;
|
|
14
|
+
maxEntries;
|
|
15
|
+
data = new Map();
|
|
16
|
+
constructor(opts = {}) {
|
|
17
|
+
this.ttlMs = opts.ttlMs ?? 15_000;
|
|
18
|
+
this.maxEntries = Math.max(1, opts.maxEntries ?? 200);
|
|
19
|
+
}
|
|
20
|
+
get(key) {
|
|
21
|
+
const e = this.data.get(key);
|
|
22
|
+
if (!e)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (e.expiresAt <= Date.now()) {
|
|
25
|
+
this.data.delete(key);
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return e.value;
|
|
29
|
+
}
|
|
30
|
+
set(key, value, ttlMsOverride) {
|
|
31
|
+
if (this.data.size >= this.maxEntries && !this.data.has(key)) {
|
|
32
|
+
// FIFO evict
|
|
33
|
+
const oldest = this.data.keys().next().value;
|
|
34
|
+
if (oldest !== undefined)
|
|
35
|
+
this.data.delete(oldest);
|
|
36
|
+
}
|
|
37
|
+
this.data.set(key, {
|
|
38
|
+
value,
|
|
39
|
+
expiresAt: Date.now() + (ttlMsOverride ?? this.ttlMs),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
delete(key) {
|
|
43
|
+
this.data.delete(key);
|
|
44
|
+
}
|
|
45
|
+
clear() {
|
|
46
|
+
this.data.clear();
|
|
47
|
+
}
|
|
48
|
+
size() {
|
|
49
|
+
return this.data.size;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Memoiza una función async por `key`. Si ya hay un resultado cacheado no
|
|
54
|
+
* expirado, lo devuelve sin llamar a fn. Si múltiples callers piden la
|
|
55
|
+
* misma key simultáneamente, se coalesce en una sola llamada (single-flight).
|
|
56
|
+
*
|
|
57
|
+
* Sólo guarda resultados donde `shouldCache(r)` sea true (default: r?.ok ===
|
|
58
|
+
* true, para compatibilidad con el shape Result<T> del SDK).
|
|
59
|
+
*/
|
|
60
|
+
export function memoAsync(cache, key, fn, opts) {
|
|
61
|
+
const cached = cache.get(key);
|
|
62
|
+
if (cached !== undefined)
|
|
63
|
+
return Promise.resolve(cached);
|
|
64
|
+
const inflight = cache._inflight
|
|
65
|
+
?? ((cache._inflight = new Map()));
|
|
66
|
+
const existing = inflight.get(key);
|
|
67
|
+
if (existing)
|
|
68
|
+
return existing;
|
|
69
|
+
const p = (async () => {
|
|
70
|
+
const shouldCache = opts?.shouldCache ?? ((r) => r?.ok === true);
|
|
71
|
+
try {
|
|
72
|
+
const r = await fn();
|
|
73
|
+
if (shouldCache(r))
|
|
74
|
+
cache.set(key, r, opts?.ttlMsOverride);
|
|
75
|
+
return r;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
inflight.delete(key);
|
|
79
|
+
}
|
|
80
|
+
})();
|
|
81
|
+
inflight.set(key, p);
|
|
82
|
+
return p;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/internal/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/internal/http.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { CircuitBreaker, type CircuitOptions } from "./circuit.js";
|
|
14
14
|
import { type PlatformError } from "./errors.js";
|
|
15
|
+
import { TokenBucket, type TokenBucketOptions } from "./ratelimit.js";
|
|
15
16
|
export interface HttpConfig {
|
|
16
17
|
baseUrl: string;
|
|
17
18
|
timeoutMs: number;
|
|
@@ -30,6 +31,8 @@ export interface HttpConfig {
|
|
|
30
31
|
}>;
|
|
31
32
|
/** Circuit breaker compartido entre requests del mismo cliente. */
|
|
32
33
|
breaker: CircuitBreaker;
|
|
34
|
+
/** Rate limiter opcional — bloquea antes del fetch si no hay tokens. */
|
|
35
|
+
rateLimiter?: TokenBucket;
|
|
33
36
|
}
|
|
34
37
|
export interface HttpResult<T = unknown> {
|
|
35
38
|
ok: boolean;
|
|
@@ -54,6 +57,8 @@ export interface HttpConfigInput {
|
|
|
54
57
|
onError?: HttpConfig["onError"];
|
|
55
58
|
circuit?: CircuitOptions;
|
|
56
59
|
beforeRetry?: HttpConfig["beforeRetry"];
|
|
60
|
+
/** Si se pasa, activa rate limit client-side (token bucket). */
|
|
61
|
+
rateLimit?: TokenBucketOptions;
|
|
57
62
|
}
|
|
58
63
|
export declare function defaultHttpConfig(overrides: HttpConfigInput): HttpConfig;
|
|
59
64
|
//# sourceMappingURL=http.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAgD,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAgD,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACtE,4EAA4E;IAC5E,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;IAC5I,mEAAmE;IACnE,OAAO,EAAE,cAAc,CAAC;IACxB,wEAAwE;IACxE,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,OAAO;IACrC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC;IAC3D,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAClC;AAcD,wBAAsB,WAAW,CAAC,CAAC,GAAG,OAAO,EAC3C,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAoExB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,WAAW,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;IACxC,gEAAgE;IAChE,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,GAAG,UAAU,CAUxE"}
|
package/dist/internal/http.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { CircuitBreaker } from "./circuit.js";
|
|
14
14
|
import { CircuitOpenError, NetworkError, mapHttpError } from "./errors.js";
|
|
15
|
+
import { TokenBucket } from "./ratelimit.js";
|
|
15
16
|
function buildUrl(baseUrl, path, query) {
|
|
16
17
|
const url = `${baseUrl.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
17
18
|
if (!query)
|
|
@@ -33,6 +34,10 @@ export async function httpRequest(cfg, opts) {
|
|
|
33
34
|
cfg.onError(err, { path: opts.path, attempt: 0 });
|
|
34
35
|
return { ok: false, error: err.message, errorInstance: err };
|
|
35
36
|
}
|
|
37
|
+
// Rate limit cliente (token bucket). Bloquea hasta tener tokens.
|
|
38
|
+
if (cfg.rateLimiter) {
|
|
39
|
+
await cfg.rateLimiter.take();
|
|
40
|
+
}
|
|
36
41
|
let headers = { "Content-Type": "application/json", ...opts.headers };
|
|
37
42
|
let lastErr;
|
|
38
43
|
for (let attempt = 0; attempt <= cfg.retries; attempt++) {
|
|
@@ -90,6 +95,7 @@ export function defaultHttpConfig(overrides) {
|
|
|
90
95
|
onError: overrides.onError ?? (() => { }),
|
|
91
96
|
beforeRetry: overrides.beforeRetry,
|
|
92
97
|
breaker: new CircuitBreaker(overrides.circuit ?? {}),
|
|
98
|
+
rateLimiter: overrides.rateLimit ? new TokenBucket(overrides.rateLimit) : undefined,
|
|
93
99
|
};
|
|
94
100
|
}
|
|
95
101
|
//# sourceMappingURL=http.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,cAAc,EAAuB,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token bucket client-side.
|
|
3
|
+
*
|
|
4
|
+
* Cada cliente HTTP puede configurar un rate limiter que bloquea (awaits)
|
|
5
|
+
* si se agotaron los tokens, hasta que se refilen. Previene que el SDK
|
|
6
|
+
* dispare ráfagas a servicios upstream con políticas estrictas y el server
|
|
7
|
+
* empiece a 429.
|
|
8
|
+
*
|
|
9
|
+
* Ejemplo:
|
|
10
|
+
* const rl = new TokenBucket({ capacity: 60, refillPerSec: 10 });
|
|
11
|
+
* await rl.take(); // bloquea si no hay tokens
|
|
12
|
+
*/
|
|
13
|
+
export interface TokenBucketOptions {
|
|
14
|
+
/** Tokens máximos en el bucket (ráfaga máx). */
|
|
15
|
+
capacity: number;
|
|
16
|
+
/** Tokens añadidos por segundo (tasa sostenida). */
|
|
17
|
+
refillPerSec: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class TokenBucket {
|
|
20
|
+
private readonly capacity;
|
|
21
|
+
private readonly refillPerMs;
|
|
22
|
+
private tokens;
|
|
23
|
+
private lastRefill;
|
|
24
|
+
constructor(opts: TokenBucketOptions);
|
|
25
|
+
/** Mide tokens disponibles ahora (sin consumir). */
|
|
26
|
+
available(): number;
|
|
27
|
+
/**
|
|
28
|
+
* Toma 1 token. Si no hay disponibles, espera hasta que haya.
|
|
29
|
+
* Resuelve inmediatamente si hay tokens.
|
|
30
|
+
*/
|
|
31
|
+
take(count?: number): Promise<void>;
|
|
32
|
+
/** Reset manual (útil para tests). */
|
|
33
|
+
reset(): void;
|
|
34
|
+
private refill;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=ratelimit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ratelimit.d.ts","sourceRoot":"","sources":["../../src/internal/ratelimit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;gBAEf,IAAI,EAAE,kBAAkB;IASpC,oDAAoD;IACpD,SAAS,IAAI,MAAM;IAKnB;;;OAGG;IACG,IAAI,CAAC,KAAK,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAepC,sCAAsC;IACtC,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,MAAM;CAQf"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token bucket client-side.
|
|
3
|
+
*
|
|
4
|
+
* Cada cliente HTTP puede configurar un rate limiter que bloquea (awaits)
|
|
5
|
+
* si se agotaron los tokens, hasta que se refilen. Previene que el SDK
|
|
6
|
+
* dispare ráfagas a servicios upstream con políticas estrictas y el server
|
|
7
|
+
* empiece a 429.
|
|
8
|
+
*
|
|
9
|
+
* Ejemplo:
|
|
10
|
+
* const rl = new TokenBucket({ capacity: 60, refillPerSec: 10 });
|
|
11
|
+
* await rl.take(); // bloquea si no hay tokens
|
|
12
|
+
*/
|
|
13
|
+
export class TokenBucket {
|
|
14
|
+
capacity;
|
|
15
|
+
refillPerMs;
|
|
16
|
+
tokens;
|
|
17
|
+
lastRefill;
|
|
18
|
+
constructor(opts) {
|
|
19
|
+
if (opts.capacity <= 0)
|
|
20
|
+
throw new Error("capacity must be > 0");
|
|
21
|
+
if (opts.refillPerSec <= 0)
|
|
22
|
+
throw new Error("refillPerSec must be > 0");
|
|
23
|
+
this.capacity = opts.capacity;
|
|
24
|
+
this.refillPerMs = opts.refillPerSec / 1000;
|
|
25
|
+
this.tokens = opts.capacity;
|
|
26
|
+
this.lastRefill = Date.now();
|
|
27
|
+
}
|
|
28
|
+
/** Mide tokens disponibles ahora (sin consumir). */
|
|
29
|
+
available() {
|
|
30
|
+
this.refill();
|
|
31
|
+
return this.tokens;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Toma 1 token. Si no hay disponibles, espera hasta que haya.
|
|
35
|
+
* Resuelve inmediatamente si hay tokens.
|
|
36
|
+
*/
|
|
37
|
+
async take(count = 1) {
|
|
38
|
+
if (count <= 0)
|
|
39
|
+
return;
|
|
40
|
+
while (true) {
|
|
41
|
+
this.refill();
|
|
42
|
+
if (this.tokens >= count) {
|
|
43
|
+
this.tokens -= count;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Tiempo para acumular `count` tokens
|
|
47
|
+
const needed = count - this.tokens;
|
|
48
|
+
const waitMs = Math.ceil(needed / this.refillPerMs);
|
|
49
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Reset manual (útil para tests). */
|
|
53
|
+
reset() {
|
|
54
|
+
this.tokens = this.capacity;
|
|
55
|
+
this.lastRefill = Date.now();
|
|
56
|
+
}
|
|
57
|
+
refill() {
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
const elapsed = now - this.lastRefill;
|
|
60
|
+
if (elapsed <= 0)
|
|
61
|
+
return;
|
|
62
|
+
const add = elapsed * this.refillPerMs;
|
|
63
|
+
this.tokens = Math.min(this.capacity, this.tokens + add);
|
|
64
|
+
this.lastRefill = now;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=ratelimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ratelimit.js","sourceRoot":"","sources":["../../src/internal/ratelimit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,MAAM,OAAO,WAAW;IACL,QAAQ,CAAS;IACjB,WAAW,CAAS;IAC7B,MAAM,CAAS;IACf,UAAU,CAAS;IAE3B,YAAY,IAAwB;QAClC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAChE,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACxE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC/B,CAAC;IAED,oDAAoD;IACpD,SAAS;QACP,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC;QAClB,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO;QACvB,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;gBACrB,OAAO;YACT,CAAC;YACD,sCAAsC;YACtC,MAAM,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;YACnC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;YACpD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,sCAAsC;IACtC,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC/B,CAAC;IAEO,MAAM;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;QACtC,IAAI,OAAO,IAAI,CAAC;YAAE,OAAO;QACzB,MAAM,GAAG,GAAG,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;IACxB,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zentto/platform-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Cliente tipado para los servicios de plataforma Zentto (notify, auth, cache, landing, events, webhooks). Uso oficial en ERP, verticals y sitios de tenants clientes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|