@zentto/platform-client 0.2.0 → 0.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 +49 -1
- package/dist/auth/client.d.ts +6 -0
- package/dist/auth/client.d.ts.map +1 -1
- package/dist/auth/client.js +32 -0
- package/dist/auth/client.js.map +1 -1
- package/dist/events/client.d.ts +94 -0
- package/dist/events/client.d.ts.map +1 -0
- package/dist/events/client.js +208 -0
- package/dist/events/client.js.map +1 -0
- package/dist/events/envelope.d.ts +28 -0
- package/dist/events/envelope.d.ts.map +1 -0
- package/dist/events/envelope.js +38 -0
- package/dist/events/envelope.js.map +1 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +3 -0
- package/dist/events/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/circuit.d.ts +33 -0
- package/dist/internal/circuit.d.ts.map +1 -0
- package/dist/internal/circuit.js +73 -0
- package/dist/internal/circuit.js.map +1 -0
- package/dist/internal/errors.d.ts +57 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +96 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/http.d.ts +29 -9
- package/dist/internal/http.d.ts.map +1 -1
- package/dist/internal/http.js +41 -20
- package/dist/internal/http.js.map +1 -1
- package/package.json +15 -2
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @zentto/platform-client
|
|
2
2
|
|
|
3
|
-
Cliente oficial tipado para los servicios de plataforma Zentto: **notify**, **auth**, **cache**, **landing**.
|
|
3
|
+
Cliente oficial tipado para los servicios de plataforma Zentto: **notify**, **auth**, **cache**, **landing**, **events**.
|
|
4
|
+
|
|
5
|
+
Incluye circuit breaker, auto-refresh de JWT, errores tipados (AuthError, RateLimitedError, ServiceError, etc.) y event bus sobre Kafka.
|
|
4
6
|
|
|
5
7
|
Úsalo desde el ERP, cualquier vertical (hotel, medical, tickets, rental, education, inmobiliario…) o un sitio externo de un tenant cliente.
|
|
6
8
|
|
|
@@ -67,6 +69,52 @@ const res = await c.gridLayouts.get("invoices-list", { companyId, userId });
|
|
|
67
69
|
// res.data.layout → layout guardado
|
|
68
70
|
```
|
|
69
71
|
|
|
72
|
+
### Events (bus Kafka)
|
|
73
|
+
|
|
74
|
+
Requiere `kafkajs` como peer dependency (opcional):
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm install kafkajs
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { EventBusClient } from "@zentto/platform-client/events";
|
|
82
|
+
|
|
83
|
+
const bus = new EventBusClient({
|
|
84
|
+
brokers: ["kafka:9092"],
|
|
85
|
+
source: "zentto-hotel",
|
|
86
|
+
tenantCode: "ACME",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await bus.connect();
|
|
90
|
+
|
|
91
|
+
// Producer
|
|
92
|
+
await bus.publish({
|
|
93
|
+
eventType: "hotel.reservation.confirmed",
|
|
94
|
+
data: { reservationId: 42, guest: "Juan" },
|
|
95
|
+
correlationId: req.headers["x-request-id"],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Consumer (otro proceso)
|
|
99
|
+
bus.on(/^crm\..+/, async (evt) => {
|
|
100
|
+
console.log("got", evt.eventType, evt.data);
|
|
101
|
+
});
|
|
102
|
+
await bus.start();
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Topic: `zentto.acme.hotel.reservation.confirmed`. Envelope estándar con `eventId` (dedup automática), `timestamp`, `source`, `correlationId`, `version`.
|
|
106
|
+
|
|
107
|
+
### Errores tipados
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { AuthError, RateLimitedError, ServiceError } from "@zentto/platform-client";
|
|
111
|
+
|
|
112
|
+
const r = await notify.email.send(...);
|
|
113
|
+
if (!r.ok && r.errorInstance instanceof RateLimitedError) {
|
|
114
|
+
await wait(r.errorInstance.retryAfterSec ?? 30);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
70
118
|
### Landing (leads de tenants clientes)
|
|
71
119
|
|
|
72
120
|
```ts
|
package/dist/auth/client.d.ts
CHANGED
|
@@ -73,9 +73,15 @@ export declare class AuthClient {
|
|
|
73
73
|
private readonly cfg;
|
|
74
74
|
private readonly serviceKey?;
|
|
75
75
|
private accessToken?;
|
|
76
|
+
private refreshInFlight?;
|
|
76
77
|
constructor(opts: AuthConfig);
|
|
77
78
|
setAccessToken(token: string | undefined): void;
|
|
78
79
|
private bearer;
|
|
80
|
+
/**
|
|
81
|
+
* Refresh coalescido: si varios requests 401 caen a la vez, solo uno
|
|
82
|
+
* llama a /auth/refresh y los demás esperan el mismo resultado.
|
|
83
|
+
*/
|
|
84
|
+
private tryRefresh;
|
|
79
85
|
private service;
|
|
80
86
|
login(params: {
|
|
81
87
|
username: 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;AAEvG,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;CACjC;AAGD,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,GAAG,gBAAgB,CAAC;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IACrC,OAAO,CAAC,WAAW,CAAC,CAAS;
|
|
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
|
@@ -15,12 +15,25 @@ export class AuthClient {
|
|
|
15
15
|
cfg;
|
|
16
16
|
serviceKey;
|
|
17
17
|
accessToken;
|
|
18
|
+
refreshInFlight;
|
|
18
19
|
constructor(opts) {
|
|
19
20
|
this.cfg = defaultHttpConfig({
|
|
20
21
|
baseUrl: opts.baseUrl ?? "https://auth.zentto.net",
|
|
21
22
|
timeoutMs: opts.timeoutMs,
|
|
22
23
|
retries: opts.retries,
|
|
23
24
|
onError: opts.onError,
|
|
25
|
+
// Intercepta 401 → intenta refresh + reintenta UNA vez con el nuevo Bearer.
|
|
26
|
+
// Evita que cada caller tenga que saber manejar expiración de tokens.
|
|
27
|
+
beforeRetry: async (err, ctx) => {
|
|
28
|
+
if (err.name !== "AuthError")
|
|
29
|
+
return { retry: false };
|
|
30
|
+
if (ctx.path === "/auth/refresh")
|
|
31
|
+
return { retry: false }; // no refresh durante refresh
|
|
32
|
+
const newToken = await this.tryRefresh();
|
|
33
|
+
if (!newToken)
|
|
34
|
+
return { retry: false };
|
|
35
|
+
return { retry: true, headers: { Authorization: `Bearer ${newToken}` } };
|
|
36
|
+
},
|
|
24
37
|
});
|
|
25
38
|
this.accessToken = opts.accessToken;
|
|
26
39
|
this.serviceKey = opts.serviceKey;
|
|
@@ -31,6 +44,25 @@ export class AuthClient {
|
|
|
31
44
|
bearer() {
|
|
32
45
|
return this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {};
|
|
33
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Refresh coalescido: si varios requests 401 caen a la vez, solo uno
|
|
49
|
+
* llama a /auth/refresh y los demás esperan el mismo resultado.
|
|
50
|
+
*/
|
|
51
|
+
async tryRefresh() {
|
|
52
|
+
if (!this.refreshInFlight) {
|
|
53
|
+
this.refreshInFlight = (async () => {
|
|
54
|
+
const res = await this.refresh();
|
|
55
|
+
const newToken = res.ok ? res.data?.accessToken : undefined;
|
|
56
|
+
if (newToken)
|
|
57
|
+
this.accessToken = newToken;
|
|
58
|
+
return newToken;
|
|
59
|
+
})().finally(() => {
|
|
60
|
+
// Limpiar tras la resolución (con un tick de margen).
|
|
61
|
+
setTimeout(() => { this.refreshInFlight = undefined; }, 0);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return this.refreshInFlight;
|
|
65
|
+
}
|
|
34
66
|
service() {
|
|
35
67
|
if (!this.serviceKey)
|
|
36
68
|
throw new Error("AuthClient: serviceKey no configurada para este método");
|
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,EAAoC,MAAM,qBAAqB,CAAC;AAsEvG,+EAA+E;AAC/E,MAAM,OAAO,UAAU;IACJ,GAAG,CAAa;IAChB,UAAU,CAAU;IAC7B,WAAW,CAAU;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventBusClient — producer + consumer de eventos Zentto sobre Kafka.
|
|
3
|
+
*
|
|
4
|
+
* `kafkajs` es una dependencia OPCIONAL. El paquete es zero-deps para callers
|
|
5
|
+
* que no usan eventos. Si un caller importa este submódulo sin kafkajs
|
|
6
|
+
* instalado, el constructor lanza con un mensaje claro.
|
|
7
|
+
*
|
|
8
|
+
* Uso:
|
|
9
|
+
* import { EventBusClient } from "@zentto/platform-client/events";
|
|
10
|
+
*
|
|
11
|
+
* const bus = new EventBusClient({
|
|
12
|
+
* brokers: ["kafka:9092"],
|
|
13
|
+
* source: "zentto-hotel",
|
|
14
|
+
* tenantCode: "ACME",
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Producer
|
|
18
|
+
* await bus.connect();
|
|
19
|
+
* await bus.publish({ eventType: "hotel.reservation.confirmed", data: {...} });
|
|
20
|
+
*
|
|
21
|
+
* // Consumer (otro proceso)
|
|
22
|
+
* bus.on("crm.lead.created", async (evt) => { ... });
|
|
23
|
+
* bus.on(/crm\..+/, async (evt) => { ... });
|
|
24
|
+
* await bus.start();
|
|
25
|
+
*/
|
|
26
|
+
import { type EventEnvelope } from "./envelope.js";
|
|
27
|
+
export interface EventBusConfig {
|
|
28
|
+
brokers: string[];
|
|
29
|
+
source: string;
|
|
30
|
+
/** TenantCode por default para `publish`. Override por-llamada con `.publish({ tenantCode })`. */
|
|
31
|
+
tenantCode: string;
|
|
32
|
+
clientId?: string;
|
|
33
|
+
groupId?: string;
|
|
34
|
+
/** Log level: default "warn". */
|
|
35
|
+
logLevel?: "debug" | "info" | "warn" | "error" | "nothing";
|
|
36
|
+
/** Dedup por eventId. Default: en memoria con TTL 10min. */
|
|
37
|
+
dedup?: EventDedup;
|
|
38
|
+
onError?: (err: Error, ctx: {
|
|
39
|
+
where: string;
|
|
40
|
+
topic?: string;
|
|
41
|
+
eventId?: string;
|
|
42
|
+
}) => void;
|
|
43
|
+
}
|
|
44
|
+
export interface EventDedup {
|
|
45
|
+
seen(eventId: string): Promise<boolean>;
|
|
46
|
+
mark(eventId: string): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
type Handler = (evt: EventEnvelope, raw: {
|
|
49
|
+
topic: string;
|
|
50
|
+
partition: number;
|
|
51
|
+
offset: string;
|
|
52
|
+
}) => Promise<void> | void;
|
|
53
|
+
export declare class EventBusClient {
|
|
54
|
+
private readonly cfg;
|
|
55
|
+
private readonly subs;
|
|
56
|
+
private producer;
|
|
57
|
+
private consumer;
|
|
58
|
+
private started;
|
|
59
|
+
private connected;
|
|
60
|
+
constructor(cfg: EventBusConfig);
|
|
61
|
+
connect(): Promise<void>;
|
|
62
|
+
disconnect(): Promise<void>;
|
|
63
|
+
publish<T>(params: {
|
|
64
|
+
eventType: string;
|
|
65
|
+
data: T;
|
|
66
|
+
tenantCode?: string;
|
|
67
|
+
tenantId?: number;
|
|
68
|
+
correlationId?: string;
|
|
69
|
+
version?: number;
|
|
70
|
+
eventId?: string;
|
|
71
|
+
}): Promise<EventEnvelope<T>>;
|
|
72
|
+
on(pattern: string | RegExp, handler: Handler): void;
|
|
73
|
+
start(opts?: {
|
|
74
|
+
fromBeginning?: boolean;
|
|
75
|
+
topics?: (string | RegExp)[];
|
|
76
|
+
}): Promise<void>;
|
|
77
|
+
}
|
|
78
|
+
export declare class InMemoryDedup implements EventDedup {
|
|
79
|
+
private readonly ttlMs;
|
|
80
|
+
private readonly seenAt;
|
|
81
|
+
constructor(ttlMs?: number);
|
|
82
|
+
seen(eventId: string): Promise<boolean>;
|
|
83
|
+
mark(eventId: string): Promise<void>;
|
|
84
|
+
private sweep;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Factory desde env vars:
|
|
88
|
+
* KAFKA_BROKERS — CSV (obligatoria)
|
|
89
|
+
* ZENTTO_SERVICE_NAME — source (obligatoria)
|
|
90
|
+
* ZENTTO_TENANT_CODE — tenantCode default
|
|
91
|
+
*/
|
|
92
|
+
export declare function eventsFromEnv(overrides?: Partial<EventBusConfig>): EventBusClient;
|
|
93
|
+
export {};
|
|
94
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/events/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventBusClient — producer + consumer de eventos Zentto sobre Kafka.
|
|
3
|
+
*
|
|
4
|
+
* `kafkajs` es una dependencia OPCIONAL. El paquete es zero-deps para callers
|
|
5
|
+
* que no usan eventos. Si un caller importa este submódulo sin kafkajs
|
|
6
|
+
* instalado, el constructor lanza con un mensaje claro.
|
|
7
|
+
*
|
|
8
|
+
* Uso:
|
|
9
|
+
* import { EventBusClient } from "@zentto/platform-client/events";
|
|
10
|
+
*
|
|
11
|
+
* const bus = new EventBusClient({
|
|
12
|
+
* brokers: ["kafka:9092"],
|
|
13
|
+
* source: "zentto-hotel",
|
|
14
|
+
* tenantCode: "ACME",
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Producer
|
|
18
|
+
* await bus.connect();
|
|
19
|
+
* await bus.publish({ eventType: "hotel.reservation.confirmed", data: {...} });
|
|
20
|
+
*
|
|
21
|
+
* // Consumer (otro proceso)
|
|
22
|
+
* bus.on("crm.lead.created", async (evt) => { ... });
|
|
23
|
+
* bus.on(/crm\..+/, async (evt) => { ... });
|
|
24
|
+
* await bus.start();
|
|
25
|
+
*/
|
|
26
|
+
import { buildEnvelope, topicName } from "./envelope.js";
|
|
27
|
+
export class EventBusClient {
|
|
28
|
+
cfg;
|
|
29
|
+
subs = [];
|
|
30
|
+
producer;
|
|
31
|
+
consumer;
|
|
32
|
+
started = false;
|
|
33
|
+
connected = false;
|
|
34
|
+
constructor(cfg) {
|
|
35
|
+
this.cfg = {
|
|
36
|
+
clientId: `zentto-${cfg.source}-${process.pid}`,
|
|
37
|
+
groupId: `zentto-${cfg.source}`,
|
|
38
|
+
logLevel: "warn",
|
|
39
|
+
dedup: new InMemoryDedup(),
|
|
40
|
+
onError: () => { },
|
|
41
|
+
...cfg,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// ── Lifecycle ────────────────────────────────────────────────────────────
|
|
45
|
+
async connect() {
|
|
46
|
+
if (this.connected)
|
|
47
|
+
return;
|
|
48
|
+
const { Kafka } = await loadKafka();
|
|
49
|
+
const kafka = new Kafka({
|
|
50
|
+
clientId: this.cfg.clientId,
|
|
51
|
+
brokers: this.cfg.brokers,
|
|
52
|
+
logLevel: mapLogLevel(this.cfg.logLevel),
|
|
53
|
+
retry: { initialRetryTime: 2000, retries: 5 },
|
|
54
|
+
});
|
|
55
|
+
this.producer = kafka.producer({ idempotent: true, maxInFlightRequests: 1 });
|
|
56
|
+
this.consumer = kafka.consumer({ groupId: this.cfg.groupId });
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
|
+
await this.producer.connect();
|
|
59
|
+
this.connected = true;
|
|
60
|
+
}
|
|
61
|
+
async disconnect() {
|
|
62
|
+
if (!this.connected)
|
|
63
|
+
return;
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
if (this.producer)
|
|
66
|
+
await this.producer.disconnect().catch(() => { });
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
if (this.consumer && this.started)
|
|
69
|
+
await this.consumer.disconnect().catch(() => { });
|
|
70
|
+
this.connected = false;
|
|
71
|
+
this.started = false;
|
|
72
|
+
}
|
|
73
|
+
// ── Producer ─────────────────────────────────────────────────────────────
|
|
74
|
+
async publish(params) {
|
|
75
|
+
if (!this.connected)
|
|
76
|
+
await this.connect();
|
|
77
|
+
const tenantCode = (params.tenantCode ?? this.cfg.tenantCode).toUpperCase();
|
|
78
|
+
const envelope = buildEnvelope({
|
|
79
|
+
eventType: params.eventType,
|
|
80
|
+
tenantCode,
|
|
81
|
+
tenantId: params.tenantId,
|
|
82
|
+
source: this.cfg.source,
|
|
83
|
+
data: params.data,
|
|
84
|
+
version: params.version,
|
|
85
|
+
correlationId: params.correlationId,
|
|
86
|
+
eventId: params.eventId,
|
|
87
|
+
});
|
|
88
|
+
const topic = topicName(tenantCode, params.eventType);
|
|
89
|
+
try {
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
91
|
+
await this.producer.send({
|
|
92
|
+
topic,
|
|
93
|
+
messages: [{ key: tenantCode, value: JSON.stringify(envelope) }],
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
this.cfg.onError(err, { where: "publish", topic, eventId: envelope.eventId });
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
return envelope;
|
|
101
|
+
}
|
|
102
|
+
// ── Consumer ─────────────────────────────────────────────────────────────
|
|
103
|
+
on(pattern, handler) {
|
|
104
|
+
this.subs.push({ pattern, handler });
|
|
105
|
+
}
|
|
106
|
+
async start(opts) {
|
|
107
|
+
if (this.started)
|
|
108
|
+
return;
|
|
109
|
+
if (!this.connected)
|
|
110
|
+
await this.connect();
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
112
|
+
const consumer = this.consumer;
|
|
113
|
+
await consumer.connect();
|
|
114
|
+
const topics = opts?.topics ?? [/^zentto\..+/];
|
|
115
|
+
for (const t of topics) {
|
|
116
|
+
await consumer.subscribe({ topic: t, fromBeginning: opts?.fromBeginning ?? false });
|
|
117
|
+
}
|
|
118
|
+
await consumer.run({
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
120
|
+
eachMessage: async ({ topic, partition, message }) => {
|
|
121
|
+
const raw = message.value?.toString("utf-8");
|
|
122
|
+
if (!raw)
|
|
123
|
+
return;
|
|
124
|
+
let envelope;
|
|
125
|
+
try {
|
|
126
|
+
envelope = JSON.parse(raw);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
this.cfg.onError(err, { where: "decode", topic });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
// Dedup
|
|
133
|
+
if (await this.cfg.dedup.seen(envelope.eventId))
|
|
134
|
+
return;
|
|
135
|
+
await this.cfg.dedup.mark(envelope.eventId);
|
|
136
|
+
// Dispatch a handlers que matcheen el eventType o el topic
|
|
137
|
+
for (const sub of this.subs) {
|
|
138
|
+
const ok = typeof sub.pattern === "string"
|
|
139
|
+
? envelope.eventType === sub.pattern || topic === sub.pattern
|
|
140
|
+
: sub.pattern.test(envelope.eventType) || sub.pattern.test(topic);
|
|
141
|
+
if (!ok)
|
|
142
|
+
continue;
|
|
143
|
+
try {
|
|
144
|
+
await sub.handler(envelope, { topic, partition, offset: message.offset });
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
this.cfg.onError(err, { where: "handler", topic, eventId: envelope.eventId });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
this.started = true;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// ── Dedup in-memory (default) ───────────────────────────────────────────────
|
|
156
|
+
export class InMemoryDedup {
|
|
157
|
+
ttlMs;
|
|
158
|
+
seenAt = new Map();
|
|
159
|
+
constructor(ttlMs = 10 * 60 * 1000) {
|
|
160
|
+
this.ttlMs = ttlMs;
|
|
161
|
+
}
|
|
162
|
+
async seen(eventId) {
|
|
163
|
+
this.sweep();
|
|
164
|
+
return this.seenAt.has(eventId);
|
|
165
|
+
}
|
|
166
|
+
async mark(eventId) {
|
|
167
|
+
this.seenAt.set(eventId, Date.now());
|
|
168
|
+
}
|
|
169
|
+
sweep() {
|
|
170
|
+
const cutoff = Date.now() - this.ttlMs;
|
|
171
|
+
for (const [k, t] of this.seenAt) {
|
|
172
|
+
if (t < cutoff)
|
|
173
|
+
this.seenAt.delete(k);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// ── Kafka loading (optional dep) ────────────────────────────────────────────
|
|
178
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
179
|
+
async function loadKafka() {
|
|
180
|
+
try {
|
|
181
|
+
// optional peer dep — resolve dinámico para no requerir tipos/install.
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
183
|
+
const mod = await import(/* @vite-ignore */ "kafkajs");
|
|
184
|
+
return { Kafka: mod.Kafka };
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
throw new Error("EventBusClient requires `kafkajs` to be installed.\n" +
|
|
188
|
+
"Run: npm install kafkajs\n" +
|
|
189
|
+
"(kafkajs es una optional dependency de @zentto/platform-client — se carga solo si importás el submódulo /events)");
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function mapLogLevel(l) {
|
|
193
|
+
// kafkajs logLevel: NOTHING=0, ERROR=1, WARN=2, INFO=4, DEBUG=5
|
|
194
|
+
return { nothing: 0, error: 1, warn: 2, info: 4, debug: 5 }[l] ?? 2;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Factory desde env vars:
|
|
198
|
+
* KAFKA_BROKERS — CSV (obligatoria)
|
|
199
|
+
* ZENTTO_SERVICE_NAME — source (obligatoria)
|
|
200
|
+
* ZENTTO_TENANT_CODE — tenantCode default
|
|
201
|
+
*/
|
|
202
|
+
export function eventsFromEnv(overrides) {
|
|
203
|
+
const brokers = (process.env.KAFKA_BROKERS ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
204
|
+
const source = process.env.ZENTTO_SERVICE_NAME ?? "unknown-service";
|
|
205
|
+
const tenantCode = process.env.ZENTTO_TENANT_CODE ?? "ZENTTO";
|
|
206
|
+
return new EventBusClient({ brokers, source, tenantCode, ...overrides });
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/events/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envelope estándar para eventos del bus Zentto.
|
|
3
|
+
* Ver docs/wiki/15-event-bus.md en zentto-web.
|
|
4
|
+
*/
|
|
5
|
+
export interface EventEnvelope<T = unknown> {
|
|
6
|
+
eventId: string;
|
|
7
|
+
eventType: string;
|
|
8
|
+
tenantCode: string;
|
|
9
|
+
tenantId?: number;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
source: string;
|
|
12
|
+
correlationId?: string;
|
|
13
|
+
data: T;
|
|
14
|
+
version: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildEnvelope<T>(params: {
|
|
17
|
+
eventType: string;
|
|
18
|
+
tenantCode: string;
|
|
19
|
+
tenantId?: number;
|
|
20
|
+
source: string;
|
|
21
|
+
data: T;
|
|
22
|
+
version?: number;
|
|
23
|
+
correlationId?: string;
|
|
24
|
+
eventId?: string;
|
|
25
|
+
timestamp?: string;
|
|
26
|
+
}): EventEnvelope<T>;
|
|
27
|
+
export declare function topicName(tenantCode: string, eventType: string): string;
|
|
28
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/events/envelope.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,EAAE,MAAM,CAAC;CACjB;AAkBD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,aAAa,CAAC,CAAC,CAAC,CAYnB;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envelope estándar para eventos del bus Zentto.
|
|
3
|
+
* Ver docs/wiki/15-event-bus.md en zentto-web.
|
|
4
|
+
*/
|
|
5
|
+
function uuid() {
|
|
6
|
+
// RFC 4122 v4 — sin dependencias
|
|
7
|
+
const bytes = new Uint8Array(16);
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
const g = globalThis;
|
|
10
|
+
if (g.crypto?.getRandomValues) {
|
|
11
|
+
g.crypto.getRandomValues(bytes);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
for (let i = 0; i < 16; i++)
|
|
15
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
16
|
+
}
|
|
17
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
18
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
19
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
20
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
21
|
+
}
|
|
22
|
+
export function buildEnvelope(params) {
|
|
23
|
+
return {
|
|
24
|
+
eventId: params.eventId ?? `evt_${uuid()}`,
|
|
25
|
+
eventType: params.eventType,
|
|
26
|
+
tenantCode: params.tenantCode.toUpperCase(),
|
|
27
|
+
tenantId: params.tenantId,
|
|
28
|
+
timestamp: params.timestamp ?? new Date().toISOString(),
|
|
29
|
+
source: params.source,
|
|
30
|
+
correlationId: params.correlationId,
|
|
31
|
+
data: params.data,
|
|
32
|
+
version: params.version ?? 1,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function topicName(tenantCode, eventType) {
|
|
36
|
+
return `zentto.${tenantCode.toLowerCase()}.${eventType}`;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/events/envelope.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH,SAAS,IAAI;IACX,iCAAiC;IACjC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,8DAA8D;IAC9D,MAAM,CAAC,GAAQ,UAAiB,CAAC;IACjC,IAAI,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC;QAC9B,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE;YAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;IAC1E,CAAC;IACD,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACpC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACpC,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/E,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED,MAAM,UAAU,aAAa,CAAI,MAUhC;IACC,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,OAAO,IAAI,EAAE,EAAE;QAC1C,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE;QAC3C,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACvD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,UAAkB,EAAE,SAAiB;IAC7D,OAAO,UAAU,UAAU,CAAC,WAAW,EAAE,IAAI,SAAS,EAAE,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,6 @@ export * as notify from "./notify/index.js";
|
|
|
2
2
|
export * as auth from "./auth/index.js";
|
|
3
3
|
export * as cache from "./cache/index.js";
|
|
4
4
|
export * as landing from "./landing/index.js";
|
|
5
|
+
export * as events from "./events/index.js";
|
|
6
|
+
export * from "./internal/errors.js";
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAG5C,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,4 +5,7 @@ export * as notify from "./notify/index.js";
|
|
|
5
5
|
export * as auth from "./auth/index.js";
|
|
6
6
|
export * as cache from "./cache/index.js";
|
|
7
7
|
export * as landing from "./landing/index.js";
|
|
8
|
+
export * as events from "./events/index.js";
|
|
9
|
+
// Tipos de error compartidos (útiles para `instanceof` en callers).
|
|
10
|
+
export * from "./internal/errors.js";
|
|
8
11
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,2EAA2E;AAC3E,gDAAgD;AAEhD,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,2EAA2E;AAC3E,gDAAgD;AAEhD,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAE5C,oEAAoE;AACpE,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit breaker minimal — un breaker por (baseUrl, path-prefix).
|
|
3
|
+
*
|
|
4
|
+
* Estados:
|
|
5
|
+
* closed → pasa tráfico. Cuenta fallos consecutivos.
|
|
6
|
+
* open → rechaza inmediato. Despeja tras cooldown.
|
|
7
|
+
* half → deja pasar 1 request de prueba. Si falla, vuelve a open.
|
|
8
|
+
* Si pasa, vuelve a closed.
|
|
9
|
+
*
|
|
10
|
+
* Evita cascade failures cuando un servicio upstream se cae.
|
|
11
|
+
*/
|
|
12
|
+
export interface CircuitOptions {
|
|
13
|
+
/** Fallos consecutivos antes de abrir. Default 5. */
|
|
14
|
+
failureThreshold?: number;
|
|
15
|
+
/** Tiempo en open antes de probar half. Default 30s. */
|
|
16
|
+
cooldownMs?: number;
|
|
17
|
+
}
|
|
18
|
+
type State = "closed" | "open" | "half";
|
|
19
|
+
export declare class CircuitBreaker {
|
|
20
|
+
private readonly failureThreshold;
|
|
21
|
+
private readonly cooldownMs;
|
|
22
|
+
private readonly slots;
|
|
23
|
+
constructor(opts?: CircuitOptions);
|
|
24
|
+
private slot;
|
|
25
|
+
/** Llamado antes de disparar un request. Retorna false si el circuito está abierto. */
|
|
26
|
+
allow(key: string): boolean;
|
|
27
|
+
recordSuccess(key: string): void;
|
|
28
|
+
recordFailure(key: string): void;
|
|
29
|
+
/** Sólo para tests/debug. */
|
|
30
|
+
_state(key: string): State;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=circuit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit.d.ts","sourceRoot":"","sources":["../../src/internal/circuit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,KAAK,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AASxC,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;gBAErC,IAAI,GAAE,cAAmB;IAKrC,OAAO,CAAC,IAAI;IASZ,uFAAuF;IACvF,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAiB3B,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAOhC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAehC,6BAA6B;IAC7B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK;CAG3B"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit breaker minimal — un breaker por (baseUrl, path-prefix).
|
|
3
|
+
*
|
|
4
|
+
* Estados:
|
|
5
|
+
* closed → pasa tráfico. Cuenta fallos consecutivos.
|
|
6
|
+
* open → rechaza inmediato. Despeja tras cooldown.
|
|
7
|
+
* half → deja pasar 1 request de prueba. Si falla, vuelve a open.
|
|
8
|
+
* Si pasa, vuelve a closed.
|
|
9
|
+
*
|
|
10
|
+
* Evita cascade failures cuando un servicio upstream se cae.
|
|
11
|
+
*/
|
|
12
|
+
export class CircuitBreaker {
|
|
13
|
+
failureThreshold;
|
|
14
|
+
cooldownMs;
|
|
15
|
+
slots = new Map();
|
|
16
|
+
constructor(opts = {}) {
|
|
17
|
+
this.failureThreshold = Math.max(1, opts.failureThreshold ?? 5);
|
|
18
|
+
this.cooldownMs = Math.max(1000, opts.cooldownMs ?? 30_000);
|
|
19
|
+
}
|
|
20
|
+
slot(key) {
|
|
21
|
+
let s = this.slots.get(key);
|
|
22
|
+
if (!s) {
|
|
23
|
+
s = { state: "closed", consecutiveFailures: 0, openedAt: 0, halfInFlight: false };
|
|
24
|
+
this.slots.set(key, s);
|
|
25
|
+
}
|
|
26
|
+
return s;
|
|
27
|
+
}
|
|
28
|
+
/** Llamado antes de disparar un request. Retorna false si el circuito está abierto. */
|
|
29
|
+
allow(key) {
|
|
30
|
+
const s = this.slot(key);
|
|
31
|
+
if (s.state === "closed")
|
|
32
|
+
return true;
|
|
33
|
+
if (s.state === "open") {
|
|
34
|
+
if (Date.now() - s.openedAt >= this.cooldownMs) {
|
|
35
|
+
s.state = "half";
|
|
36
|
+
s.halfInFlight = false;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// half: solo 1 in-flight a la vez
|
|
43
|
+
if (s.halfInFlight)
|
|
44
|
+
return false;
|
|
45
|
+
s.halfInFlight = true;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
recordSuccess(key) {
|
|
49
|
+
const s = this.slot(key);
|
|
50
|
+
s.consecutiveFailures = 0;
|
|
51
|
+
s.halfInFlight = false;
|
|
52
|
+
s.state = "closed";
|
|
53
|
+
}
|
|
54
|
+
recordFailure(key) {
|
|
55
|
+
const s = this.slot(key);
|
|
56
|
+
s.consecutiveFailures++;
|
|
57
|
+
s.halfInFlight = false;
|
|
58
|
+
if (s.state === "half") {
|
|
59
|
+
s.state = "open";
|
|
60
|
+
s.openedAt = Date.now();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (s.consecutiveFailures >= this.failureThreshold) {
|
|
64
|
+
s.state = "open";
|
|
65
|
+
s.openedAt = Date.now();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Sólo para tests/debug. */
|
|
69
|
+
_state(key) {
|
|
70
|
+
return this.slot(key).state;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=circuit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit.js","sourceRoot":"","sources":["../../src/internal/circuit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkBH,MAAM,OAAO,cAAc;IACR,gBAAgB,CAAS;IACzB,UAAU,CAAS;IACnB,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IAEjD,YAAY,OAAuB,EAAE;QACnC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,CAAC;IAC9D,CAAC;IAEO,IAAI,CAAC,GAAW;QACtB,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,mBAAmB,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;YAClF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,uFAAuF;IACvF,KAAK,CAAC,GAAW;QACf,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACtC,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YACvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC/C,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC;gBACjB,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,kCAAkC;QAClC,IAAI,CAAC,CAAC,YAAY;YAAE,OAAO,KAAK,CAAC;QACjC,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,aAAa,CAAC,GAAW;QACvB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC,mBAAmB,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC;QACvB,CAAC,CAAC,KAAK,GAAG,QAAQ,CAAC;IACrB,CAAC;IAED,aAAa,CAAC,GAAW;QACvB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC,mBAAmB,EAAE,CAAC;QACxB,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YACvB,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC;YACjB,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,CAAC,mBAAmB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACnD,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC;YACjB,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,6BAA6B;IAC7B,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jerarquía de errores tipados del SDK.
|
|
3
|
+
*
|
|
4
|
+
* El SDK NO lanza por default (mantiene shape best-effort `{ ok, error }`).
|
|
5
|
+
* Estos errores se usan:
|
|
6
|
+
* a) En `result.errorInstance` para callers que quieran `instanceof`.
|
|
7
|
+
* b) Opcionalmente en modo `throwOnError: true` (futuro).
|
|
8
|
+
*
|
|
9
|
+
* La jerarquía permite reaccionar fino:
|
|
10
|
+
* if (err instanceof RateLimitedError) backoff();
|
|
11
|
+
* if (err instanceof AuthError) redirectToLogin();
|
|
12
|
+
*/
|
|
13
|
+
export declare class PlatformError extends Error {
|
|
14
|
+
readonly status?: number;
|
|
15
|
+
readonly path?: string;
|
|
16
|
+
readonly attempt?: number;
|
|
17
|
+
constructor(message: string, opts?: {
|
|
18
|
+
status?: number;
|
|
19
|
+
path?: string;
|
|
20
|
+
attempt?: number;
|
|
21
|
+
cause?: unknown;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** 4xx 401/403 — token inválido/expirado, scope faltante. */
|
|
25
|
+
export declare class AuthError extends PlatformError {
|
|
26
|
+
constructor(message: string, opts?: ConstructorParameters<typeof PlatformError>[1]);
|
|
27
|
+
}
|
|
28
|
+
/** 4xx 400/422 — body mal formado, campos faltantes. */
|
|
29
|
+
export declare class ValidationError extends PlatformError {
|
|
30
|
+
constructor(message: string, opts?: ConstructorParameters<typeof PlatformError>[1]);
|
|
31
|
+
}
|
|
32
|
+
/** 4xx 404 — recurso no existe. */
|
|
33
|
+
export declare class NotFoundError extends PlatformError {
|
|
34
|
+
constructor(message: string, opts?: ConstructorParameters<typeof PlatformError>[1]);
|
|
35
|
+
}
|
|
36
|
+
/** 4xx 429 — rate limited upstream. */
|
|
37
|
+
export declare class RateLimitedError extends PlatformError {
|
|
38
|
+
readonly retryAfterSec?: number;
|
|
39
|
+
constructor(message: string, opts?: ConstructorParameters<typeof PlatformError>[1] & {
|
|
40
|
+
retryAfterSec?: number;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** 5xx — error del servicio upstream. Normalmente reintentable. */
|
|
44
|
+
export declare class ServiceError extends PlatformError {
|
|
45
|
+
constructor(message: string, opts?: ConstructorParameters<typeof PlatformError>[1]);
|
|
46
|
+
}
|
|
47
|
+
/** Errores de red (timeout, DNS, connection reset). Reintentables. */
|
|
48
|
+
export declare class NetworkError extends PlatformError {
|
|
49
|
+
constructor(message: string, opts?: ConstructorParameters<typeof PlatformError>[1]);
|
|
50
|
+
}
|
|
51
|
+
/** Circuit breaker abierto — upstream fallando demasiado. */
|
|
52
|
+
export declare class CircuitOpenError extends PlatformError {
|
|
53
|
+
constructor(message: string, opts?: ConstructorParameters<typeof PlatformError>[1]);
|
|
54
|
+
}
|
|
55
|
+
/** Mapea HTTP status + contexto a un error tipado. */
|
|
56
|
+
export declare function mapHttpError(status: number | undefined, body: Record<string, unknown>, path: string, attempt: number): PlatformError;
|
|
57
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/internal/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAQ1G;AAED,6DAA6D;AAC7D,qBAAa,SAAU,SAAQ,aAAa;gBAC9B,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;CAInF;AAED,wDAAwD;AACxD,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;CAInF;AAED,mCAAmC;AACnC,qBAAa,aAAc,SAAQ,aAAa;gBAClC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;CAInF;AAED,uCAAuC;AACvC,qBAAa,gBAAiB,SAAQ,aAAa;IACjD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;gBACpB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE;CAKhH;AAED,mEAAmE;AACnE,qBAAa,YAAa,SAAQ,aAAa;gBACjC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;CAInF;AAED,sEAAsE;AACtE,qBAAa,YAAa,SAAQ,aAAa;gBACjC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;CAInF;AAED,6DAA6D;AAC7D,qBAAa,gBAAiB,SAAQ,aAAa;gBACrC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;CAInF;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAYpI"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jerarquía de errores tipados del SDK.
|
|
3
|
+
*
|
|
4
|
+
* El SDK NO lanza por default (mantiene shape best-effort `{ ok, error }`).
|
|
5
|
+
* Estos errores se usan:
|
|
6
|
+
* a) En `result.errorInstance` para callers que quieran `instanceof`.
|
|
7
|
+
* b) Opcionalmente en modo `throwOnError: true` (futuro).
|
|
8
|
+
*
|
|
9
|
+
* La jerarquía permite reaccionar fino:
|
|
10
|
+
* if (err instanceof RateLimitedError) backoff();
|
|
11
|
+
* if (err instanceof AuthError) redirectToLogin();
|
|
12
|
+
*/
|
|
13
|
+
export class PlatformError extends Error {
|
|
14
|
+
status;
|
|
15
|
+
path;
|
|
16
|
+
attempt;
|
|
17
|
+
constructor(message, opts) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "PlatformError";
|
|
20
|
+
this.status = opts?.status;
|
|
21
|
+
this.path = opts?.path;
|
|
22
|
+
this.attempt = opts?.attempt;
|
|
23
|
+
if (opts?.cause !== undefined)
|
|
24
|
+
this.cause = opts.cause;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** 4xx 401/403 — token inválido/expirado, scope faltante. */
|
|
28
|
+
export class AuthError extends PlatformError {
|
|
29
|
+
constructor(message, opts) {
|
|
30
|
+
super(message, opts);
|
|
31
|
+
this.name = "AuthError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** 4xx 400/422 — body mal formado, campos faltantes. */
|
|
35
|
+
export class ValidationError extends PlatformError {
|
|
36
|
+
constructor(message, opts) {
|
|
37
|
+
super(message, opts);
|
|
38
|
+
this.name = "ValidationError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** 4xx 404 — recurso no existe. */
|
|
42
|
+
export class NotFoundError extends PlatformError {
|
|
43
|
+
constructor(message, opts) {
|
|
44
|
+
super(message, opts);
|
|
45
|
+
this.name = "NotFoundError";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** 4xx 429 — rate limited upstream. */
|
|
49
|
+
export class RateLimitedError extends PlatformError {
|
|
50
|
+
retryAfterSec;
|
|
51
|
+
constructor(message, opts) {
|
|
52
|
+
super(message, opts);
|
|
53
|
+
this.name = "RateLimitedError";
|
|
54
|
+
this.retryAfterSec = opts?.retryAfterSec;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** 5xx — error del servicio upstream. Normalmente reintentable. */
|
|
58
|
+
export class ServiceError extends PlatformError {
|
|
59
|
+
constructor(message, opts) {
|
|
60
|
+
super(message, opts);
|
|
61
|
+
this.name = "ServiceError";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Errores de red (timeout, DNS, connection reset). Reintentables. */
|
|
65
|
+
export class NetworkError extends PlatformError {
|
|
66
|
+
constructor(message, opts) {
|
|
67
|
+
super(message, opts);
|
|
68
|
+
this.name = "NetworkError";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Circuit breaker abierto — upstream fallando demasiado. */
|
|
72
|
+
export class CircuitOpenError extends PlatformError {
|
|
73
|
+
constructor(message, opts) {
|
|
74
|
+
super(message, opts);
|
|
75
|
+
this.name = "CircuitOpenError";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** Mapea HTTP status + contexto a un error tipado. */
|
|
79
|
+
export function mapHttpError(status, body, path, attempt) {
|
|
80
|
+
const msg = body.error ?? body.message ?? (status ? `HTTP ${status}` : "unknown error");
|
|
81
|
+
const opts = { status, path, attempt };
|
|
82
|
+
if (status === 401 || status === 403)
|
|
83
|
+
return new AuthError(msg, opts);
|
|
84
|
+
if (status === 404)
|
|
85
|
+
return new NotFoundError(msg, opts);
|
|
86
|
+
if (status === 429) {
|
|
87
|
+
const retryAfterSec = typeof body.retryAfter === "number" ? body.retryAfter : undefined;
|
|
88
|
+
return new RateLimitedError(msg, { ...opts, retryAfterSec });
|
|
89
|
+
}
|
|
90
|
+
if (status && status >= 400 && status < 500)
|
|
91
|
+
return new ValidationError(msg, opts);
|
|
92
|
+
if (status && status >= 500)
|
|
93
|
+
return new ServiceError(msg, opts);
|
|
94
|
+
return new NetworkError(msg, opts);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/internal/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/internal/http.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* HTTP helper compartido entre submódulos.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Retries con backoff exponencial ante errores de red o 5xx.
|
|
6
|
+
* - Sin retry en 4xx (es error del caller).
|
|
7
|
+
* - Timeout por request.
|
|
8
|
+
* - Circuit breaker por (baseUrl): evita cascade cuando upstream cae.
|
|
9
|
+
* - Errores tipados (AuthError, RateLimitedError, ServiceError, etc.) en `errorInstance`.
|
|
10
|
+
* - Hook `beforeRetry` (ej. AuthClient lo usa para auto-refresh del JWT).
|
|
11
|
+
* - No lanza: siempre retorna Result<T> (ok/error).
|
|
10
12
|
*/
|
|
13
|
+
import { CircuitBreaker, type CircuitOptions } from "./circuit.js";
|
|
14
|
+
import { type PlatformError } from "./errors.js";
|
|
11
15
|
export interface HttpConfig {
|
|
12
16
|
baseUrl: string;
|
|
13
17
|
timeoutMs: number;
|
|
@@ -16,12 +20,23 @@ export interface HttpConfig {
|
|
|
16
20
|
path: string;
|
|
17
21
|
attempt: number;
|
|
18
22
|
}) => void;
|
|
23
|
+
/** Opcional: permite al AuthClient interceptar 401 para refresh + retry. */
|
|
24
|
+
beforeRetry?: (err: PlatformError, ctx: {
|
|
25
|
+
path: string;
|
|
26
|
+
attempt: number;
|
|
27
|
+
}) => Promise<{
|
|
28
|
+
retry: boolean;
|
|
29
|
+
headers?: Record<string, string>;
|
|
30
|
+
}>;
|
|
31
|
+
/** Circuit breaker compartido entre requests del mismo cliente. */
|
|
32
|
+
breaker: CircuitBreaker;
|
|
19
33
|
}
|
|
20
34
|
export interface HttpResult<T = unknown> {
|
|
21
35
|
ok: boolean;
|
|
22
36
|
status?: number;
|
|
23
37
|
data?: T;
|
|
24
38
|
error?: string;
|
|
39
|
+
errorInstance?: PlatformError;
|
|
25
40
|
}
|
|
26
41
|
export interface RequestOptions {
|
|
27
42
|
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
@@ -29,11 +44,16 @@ export interface RequestOptions {
|
|
|
29
44
|
body?: object;
|
|
30
45
|
headers?: Record<string, string>;
|
|
31
46
|
query?: Record<string, string | number | undefined | null>;
|
|
32
|
-
/** Enviar cookies (para endpoints que usan cookie httpOnly). */
|
|
33
47
|
credentials?: "include" | "omit";
|
|
34
48
|
}
|
|
35
49
|
export declare function httpRequest<T = unknown>(cfg: HttpConfig, opts: RequestOptions): Promise<HttpResult<T>>;
|
|
36
|
-
export
|
|
50
|
+
export interface HttpConfigInput {
|
|
37
51
|
baseUrl: string;
|
|
38
|
-
|
|
52
|
+
timeoutMs?: number;
|
|
53
|
+
retries?: number;
|
|
54
|
+
onError?: HttpConfig["onError"];
|
|
55
|
+
circuit?: CircuitOptions;
|
|
56
|
+
beforeRetry?: HttpConfig["beforeRetry"];
|
|
57
|
+
}
|
|
58
|
+
export declare function defaultHttpConfig(overrides: HttpConfigInput): HttpConfig;
|
|
39
59
|
//# sourceMappingURL=http.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"AAAA
|
|
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;AAE/F,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;CACzB;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,CA+DxB;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;CACzC;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,GAAG,UAAU,CASxE"}
|
package/dist/internal/http.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* HTTP helper compartido entre submódulos.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Retries con backoff exponencial ante errores de red o 5xx.
|
|
6
|
+
* - Sin retry en 4xx (es error del caller).
|
|
7
|
+
* - Timeout por request.
|
|
8
|
+
* - Circuit breaker por (baseUrl): evita cascade cuando upstream cae.
|
|
9
|
+
* - Errores tipados (AuthError, RateLimitedError, ServiceError, etc.) en `errorInstance`.
|
|
10
|
+
* - Hook `beforeRetry` (ej. AuthClient lo usa para auto-refresh del JWT).
|
|
11
|
+
* - No lanza: siempre retorna Result<T> (ok/error).
|
|
10
12
|
*/
|
|
13
|
+
import { CircuitBreaker } from "./circuit.js";
|
|
14
|
+
import { CircuitOpenError, NetworkError, mapHttpError } from "./errors.js";
|
|
11
15
|
function buildUrl(baseUrl, path, query) {
|
|
12
16
|
const url = `${baseUrl.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
13
17
|
if (!query)
|
|
@@ -23,10 +27,13 @@ function buildUrl(baseUrl, path, query) {
|
|
|
23
27
|
}
|
|
24
28
|
export async function httpRequest(cfg, opts) {
|
|
25
29
|
const url = buildUrl(cfg.baseUrl, opts.path, opts.query);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
const breakerKey = cfg.baseUrl;
|
|
31
|
+
if (!cfg.breaker.allow(breakerKey)) {
|
|
32
|
+
const err = new CircuitOpenError(`Circuit open for ${cfg.baseUrl}`, { path: opts.path, attempt: 0 });
|
|
33
|
+
cfg.onError(err, { path: opts.path, attempt: 0 });
|
|
34
|
+
return { ok: false, error: err.message, errorInstance: err };
|
|
35
|
+
}
|
|
36
|
+
let headers = { "Content-Type": "application/json", ...opts.headers };
|
|
30
37
|
let lastErr;
|
|
31
38
|
for (let attempt = 0; attempt <= cfg.retries; attempt++) {
|
|
32
39
|
try {
|
|
@@ -39,29 +46,41 @@ export async function httpRequest(cfg, opts) {
|
|
|
39
46
|
});
|
|
40
47
|
const json = (await res.json().catch(() => ({})));
|
|
41
48
|
if (res.ok) {
|
|
49
|
+
cfg.breaker.recordSuccess(breakerKey);
|
|
42
50
|
return { ok: true, status: res.status, data: json };
|
|
43
51
|
}
|
|
44
|
-
|
|
52
|
+
const err = mapHttpError(res.status, json, opts.path, attempt);
|
|
53
|
+
lastErr = err;
|
|
54
|
+
// 4xx: sin retry por default. Pero beforeRetry puede pedir retry
|
|
55
|
+
// (ej. AuthClient refresca token y reintenta 401 una vez).
|
|
45
56
|
if (res.status >= 400 && res.status < 500) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
const shouldRetry = cfg.beforeRetry && attempt < cfg.retries
|
|
58
|
+
? await cfg.beforeRetry(err, { path: opts.path, attempt })
|
|
59
|
+
: { retry: false };
|
|
60
|
+
if (!shouldRetry.retry) {
|
|
61
|
+
// 4xx → NO toca el breaker (es error del caller, no del servicio).
|
|
62
|
+
return { ok: false, status: res.status, error: err.message, errorInstance: err };
|
|
63
|
+
}
|
|
64
|
+
if (shouldRetry.headers)
|
|
65
|
+
headers = { ...headers, ...shouldRetry.headers };
|
|
66
|
+
continue;
|
|
51
67
|
}
|
|
52
|
-
|
|
68
|
+
// 5xx → cuenta para el breaker
|
|
69
|
+
cfg.breaker.recordFailure(breakerKey);
|
|
53
70
|
}
|
|
54
|
-
catch (
|
|
71
|
+
catch (netErr) {
|
|
72
|
+
const err = new NetworkError(netErr.message, { path: opts.path, attempt, cause: netErr });
|
|
55
73
|
lastErr = err;
|
|
74
|
+
cfg.breaker.recordFailure(breakerKey);
|
|
56
75
|
}
|
|
57
76
|
if (attempt < cfg.retries) {
|
|
58
77
|
cfg.onError(lastErr, { path: opts.path, attempt });
|
|
59
78
|
await new Promise((r) => setTimeout(r, 250 * Math.pow(2, attempt)));
|
|
60
79
|
}
|
|
61
80
|
}
|
|
62
|
-
const err = lastErr ?? new
|
|
81
|
+
const err = lastErr ?? new NetworkError("unknown error", { path: opts.path, attempt: cfg.retries });
|
|
63
82
|
cfg.onError(err, { path: opts.path, attempt: cfg.retries });
|
|
64
|
-
return { ok: false, error: err.message };
|
|
83
|
+
return { ok: false, error: err.message, errorInstance: err };
|
|
65
84
|
}
|
|
66
85
|
export function defaultHttpConfig(overrides) {
|
|
67
86
|
return {
|
|
@@ -69,6 +88,8 @@ export function defaultHttpConfig(overrides) {
|
|
|
69
88
|
timeoutMs: overrides.timeoutMs ?? 10_000,
|
|
70
89
|
retries: Math.max(0, overrides.retries ?? 1),
|
|
71
90
|
onError: overrides.onError ?? (() => { }),
|
|
91
|
+
beforeRetry: overrides.beforeRetry,
|
|
92
|
+
breaker: new CircuitBreaker(overrides.circuit ?? {}),
|
|
72
93
|
};
|
|
73
94
|
}
|
|
74
95
|
//# sourceMappingURL=http.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/internal/http.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zentto/platform-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Cliente tipado para los servicios de plataforma Zentto (notify, cache, auth, landing). Uso oficial en ERP, verticals y sitios de tenants clientes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,8 +25,18 @@
|
|
|
25
25
|
"./landing": {
|
|
26
26
|
"types": "./dist/landing/index.d.ts",
|
|
27
27
|
"import": "./dist/landing/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./events": {
|
|
30
|
+
"types": "./dist/events/index.d.ts",
|
|
31
|
+
"import": "./dist/events/index.js"
|
|
28
32
|
}
|
|
29
33
|
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"kafkajs": { "optional": true }
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"kafkajs": "^2.2.4"
|
|
39
|
+
},
|
|
30
40
|
"files": [
|
|
31
41
|
"dist",
|
|
32
42
|
"README.md",
|
|
@@ -35,6 +45,8 @@
|
|
|
35
45
|
"scripts": {
|
|
36
46
|
"build": "tsc",
|
|
37
47
|
"dev": "tsc --watch",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"test:watch": "vitest",
|
|
38
50
|
"clean": "rm -rf dist",
|
|
39
51
|
"prepublishOnly": "npm run clean && npm run build"
|
|
40
52
|
},
|
|
@@ -59,7 +71,8 @@
|
|
|
59
71
|
},
|
|
60
72
|
"devDependencies": {
|
|
61
73
|
"@types/node": "^25.6.0",
|
|
62
|
-
"typescript": "^5.7.0"
|
|
74
|
+
"typescript": "^5.7.0",
|
|
75
|
+
"vitest": "^3.2.4"
|
|
63
76
|
},
|
|
64
77
|
"engines": {
|
|
65
78
|
"node": ">=20"
|