@aforoai/metering 1.1.2 → 2.0.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 +46 -28
- package/dist/cjs/client.d.ts +32 -50
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +104 -215
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/middleware/common.d.ts +16 -0
- package/dist/cjs/middleware/common.d.ts.map +1 -1
- package/dist/cjs/middleware/common.js +54 -0
- package/dist/cjs/middleware/common.js.map +1 -1
- package/dist/cjs/middleware/express.d.ts +10 -5
- package/dist/cjs/middleware/express.d.ts.map +1 -1
- package/dist/cjs/middleware/express.js +22 -59
- package/dist/cjs/middleware/express.js.map +1 -1
- package/dist/cjs/middleware/fastify.d.ts +8 -4
- package/dist/cjs/middleware/fastify.d.ts.map +1 -1
- package/dist/cjs/middleware/fastify.js +25 -45
- package/dist/cjs/middleware/fastify.js.map +1 -1
- package/dist/cjs/middleware/koa.d.ts +10 -5
- package/dist/cjs/middleware/koa.d.ts.map +1 -1
- package/dist/cjs/middleware/koa.js +25 -43
- package/dist/cjs/middleware/koa.js.map +1 -1
- package/dist/cjs/transport-core/core.d.ts +355 -0
- package/dist/cjs/transport-core/core.d.ts.map +1 -0
- package/dist/cjs/transport-core/core.js +1047 -0
- package/dist/cjs/transport-core/core.js.map +1 -0
- package/dist/cjs/types.d.ts +82 -46
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/esm/client.js +103 -214
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/middleware/common.js +51 -0
- package/dist/esm/middleware/common.js.map +1 -1
- package/dist/esm/middleware/express.js +23 -60
- package/dist/esm/middleware/express.js.map +1 -1
- package/dist/esm/middleware/fastify.js +26 -46
- package/dist/esm/middleware/fastify.js.map +1 -1
- package/dist/esm/middleware/koa.js +26 -44
- package/dist/esm/middleware/koa.js.map +1 -1
- package/dist/esm/transport-core/core.js +1038 -0
- package/dist/esm/transport-core/core.js.map +1 -0
- package/dist/types/client.d.ts +32 -50
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/middleware/common.d.ts +16 -0
- package/dist/types/middleware/common.d.ts.map +1 -1
- package/dist/types/middleware/express.d.ts +10 -5
- package/dist/types/middleware/express.d.ts.map +1 -1
- package/dist/types/middleware/fastify.d.ts +8 -4
- package/dist/types/middleware/fastify.d.ts.map +1 -1
- package/dist/types/middleware/koa.d.ts +10 -5
- package/dist/types/middleware/koa.d.ts.map +1 -1
- package/dist/types/transport-core/core.d.ts +355 -0
- package/dist/types/transport-core/core.d.ts.map +1 -0
- package/dist/types/types.d.ts +82 -46
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/buffer.d.ts +0 -33
- package/dist/cjs/buffer.d.ts.map +0 -1
- package/dist/cjs/buffer.js +0 -83
- package/dist/cjs/buffer.js.map +0 -1
- package/dist/cjs/transport.d.ts +0 -41
- package/dist/cjs/transport.d.ts.map +0 -1
- package/dist/cjs/transport.js +0 -186
- package/dist/cjs/transport.js.map +0 -1
- package/dist/esm/buffer.js +0 -79
- package/dist/esm/buffer.js.map +0 -1
- package/dist/esm/transport.js +0 -182
- package/dist/esm/transport.js.map +0 -1
- package/dist/types/buffer.d.ts +0 -33
- package/dist/types/buffer.d.ts.map +0 -1
- package/dist/types/transport.d.ts +0 -41
- package/dist/types/transport.d.ts.map +0 -1
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aforo Node transport core (wave 5, contract v2).
|
|
3
|
+
*
|
|
4
|
+
* THE ONE PLACE TO EDIT. This file lives in `node/src/transport-core/` and is
|
|
5
|
+
* copied, byte for byte, into every Node variant (`node-ws`, `node-mqtt`,
|
|
6
|
+
* `node-grpc`, `node-graphql`, `node-mcp`, `node-agent`, `mcp-proxy`) by
|
|
7
|
+
* `scripts/sync-transport.sh node`. Edit it here, then run the sync; CI fails
|
|
8
|
+
* when a copy differs. Normative behaviour: `contract/TRANSPORT-SPEC.md`.
|
|
9
|
+
*
|
|
10
|
+
* Self-contained on purpose: no imports (not even relative ones, so every
|
|
11
|
+
* module format and test runner that receives the copy can load it), only
|
|
12
|
+
* Node built-ins reached through globals (`fetch`, `AbortSignal`, `Buffer`,
|
|
13
|
+
* timers). Target ES2020.
|
|
14
|
+
*
|
|
15
|
+
* What it does, per client:
|
|
16
|
+
* - one bounded FIFO queue (evict-oldest, reported as 'overflow');
|
|
17
|
+
* - one long-lived flusher: `enqueue()` never sends, it only wakes the
|
|
18
|
+
* flusher at `flushCount`; `flush()` hands work to the flusher and waits;
|
|
19
|
+
* at most one ingest request is ever in flight;
|
|
20
|
+
* - full-jitter retries, Retry-After in both forms (capped), a total
|
|
21
|
+
* deadline per request that also covers reading the response body;
|
|
22
|
+
* - redirects are never followed (the API key must not reach another
|
|
23
|
+
* host): a 3xx keeps the batch queued and opens the breaker;
|
|
24
|
+
* - each event is serialized once, at enqueue: an event JSON cannot
|
|
25
|
+
* represent (BigInt, a cycle, NaN) is dropped there as 'invalid';
|
|
26
|
+
* - 413 splits the batch, 2xx per-event `retryable` failures are requeued,
|
|
27
|
+
* other 4xx are dropped as 'rejected';
|
|
28
|
+
* - after the last retry (or on 401/403) the batch goes back to the front
|
|
29
|
+
* of the queue with its keys and a breaker pauses the flusher;
|
|
30
|
+
* - `shutdown()` drains until a deadline and reports leftovers as
|
|
31
|
+
* 'shutdown'; `enqueue()` after close reports 'closed';
|
|
32
|
+
* - no signal handlers: a process `beforeExit` hook flushes within the
|
|
33
|
+
* shutdown deadline. Apps call `shutdown()` from their own SIGTERM handler;
|
|
34
|
+
* - `onAccepted(body, events)` sees the parsed 2xx body of every accepted
|
|
35
|
+
* batch (for fields such as `killedSessionIds`); `onError` receives a
|
|
36
|
+
* `CoreTransportError` whose `kind` says what happened.
|
|
37
|
+
*/
|
|
38
|
+
/** Why events were permanently dropped. See TRANSPORT-SPEC.md "Drop reasons". */
|
|
39
|
+
export type CoreDropReason = 'overflow' | 'rejected' | 'invalid' | 'shutdown' | 'closed' | 'retry_exhausted';
|
|
40
|
+
/**
|
|
41
|
+
* What an onError report is about. `outage` and `auth` keep the events queued
|
|
42
|
+
* (`willRetry` true); the others describe events that are gone.
|
|
43
|
+
* - outage: network errors, timeouts, 408/429/5xx after every retry, or
|
|
44
|
+
* per-event `retryable` failures that never cleared
|
|
45
|
+
* - auth: HTTP 401/403, the API key is wrong or revoked
|
|
46
|
+
* - rejected: the ingestor refused the events (other 4xx, 2xx per-event errors, a single event still 413)
|
|
47
|
+
* - shutdown: still queued when the shutdown deadline passed
|
|
48
|
+
* - closed: tracked after shutdown (reported for the first, then every 1000th)
|
|
49
|
+
*/
|
|
50
|
+
export type CoreErrorKind = 'outage' | 'auth' | 'rejected' | 'shutdown' | 'closed';
|
|
51
|
+
/**
|
|
52
|
+
* The error every onError report receives. `message` is for people; branch on
|
|
53
|
+
* `kind`. `events` are the events concerned: the queued ones for outage/auth,
|
|
54
|
+
* the dropped ones otherwise (empty when the ingestor did not name them).
|
|
55
|
+
*/
|
|
56
|
+
export declare class CoreTransportError<E = CoreEvent> extends Error {
|
|
57
|
+
readonly kind: CoreErrorKind;
|
|
58
|
+
readonly events: E[];
|
|
59
|
+
/** HTTP status of the answer that caused the report, when there was one. */
|
|
60
|
+
readonly status?: number;
|
|
61
|
+
/** True when the events are still queued and will be re-sent. */
|
|
62
|
+
readonly willRetry: boolean;
|
|
63
|
+
constructor(kind: CoreErrorKind, message: string, events: E[], options?: {
|
|
64
|
+
status?: number;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** Every event the core sends carries the key the ingestor deduplicates on. */
|
|
68
|
+
export interface CoreEvent {
|
|
69
|
+
idempotencyKey: string;
|
|
70
|
+
}
|
|
71
|
+
/** The subset of a fetch Response the core reads. */
|
|
72
|
+
export interface CoreResponse {
|
|
73
|
+
status: number;
|
|
74
|
+
ok?: boolean;
|
|
75
|
+
headers: {
|
|
76
|
+
get(name: string): string | null;
|
|
77
|
+
};
|
|
78
|
+
text?(): Promise<string>;
|
|
79
|
+
json?(): Promise<unknown>;
|
|
80
|
+
}
|
|
81
|
+
/** The subset of fetch the core calls. Injectable for tests. */
|
|
82
|
+
export type CoreFetch = (url: string, init: {
|
|
83
|
+
method: string;
|
|
84
|
+
headers: Record<string, string>;
|
|
85
|
+
body: string;
|
|
86
|
+
signal: AbortSignal;
|
|
87
|
+
redirect: 'manual';
|
|
88
|
+
}) => Promise<CoreResponse>;
|
|
89
|
+
/** Sleep that ends early (resolving) when `signal` aborts. Injectable for tests. */
|
|
90
|
+
export type CoreSleep = (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
91
|
+
export interface CoreLogger {
|
|
92
|
+
debug(message: string): void;
|
|
93
|
+
warn(message: string): void;
|
|
94
|
+
error(message: string): void;
|
|
95
|
+
}
|
|
96
|
+
export interface TransportCoreOptions<E extends CoreEvent> {
|
|
97
|
+
/** Ingestor base URL. Must be https:// (plain http only for localhost, 127.0.0.1, ::1, or with allowInsecureHttp). */
|
|
98
|
+
baseUrl: string;
|
|
99
|
+
/** Tenant API key, sent only as X-API-Key. Never logged, never in an error or onDrop payload. */
|
|
100
|
+
apiKey: string;
|
|
101
|
+
/** Allow plain http:// to a non-local host. Default false. */
|
|
102
|
+
allowInsecureHttp?: boolean;
|
|
103
|
+
/** Path appended to baseUrl. Default '/v1/ingest/batch'. */
|
|
104
|
+
path?: string;
|
|
105
|
+
/** Sent as User-Agent, e.g. 'aforo-node/2.0.0'. */
|
|
106
|
+
userAgent?: string;
|
|
107
|
+
/** Extra request headers (e.g. X-Tenant-Id). Content-Type, X-API-Key and Content-Encoding cannot be overridden. */
|
|
108
|
+
headers?: Record<string, string>;
|
|
109
|
+
/** Events per request. Default 500, clamped to 1..1000. */
|
|
110
|
+
flushCount?: number;
|
|
111
|
+
/** Flush at least this often, in ms. Default 5000. */
|
|
112
|
+
flushIntervalMs?: number;
|
|
113
|
+
/** Queue capacity. Default 10 000. Overflow evicts the oldest event. */
|
|
114
|
+
maxQueueSize?: number;
|
|
115
|
+
/** Retries per batch before the breaker opens. Default 3. */
|
|
116
|
+
maxRetries?: number;
|
|
117
|
+
/** Backoff base in ms. Default 500. */
|
|
118
|
+
retryBaseMs?: number;
|
|
119
|
+
/** Backoff cap in ms. Default 30 000. */
|
|
120
|
+
retryMaxDelayMs?: number;
|
|
121
|
+
/** Retry-After cap in ms. Default 60 000. */
|
|
122
|
+
retryAfterMaxMs?: number;
|
|
123
|
+
/** First breaker cooldown in ms. Default 5000 (doubles, full jitter). */
|
|
124
|
+
breakerInitialMs?: number;
|
|
125
|
+
/** Breaker cooldown cap in ms. Default 300 000. */
|
|
126
|
+
breakerMaxMs?: number;
|
|
127
|
+
/** Total deadline per request in ms. Default 10 000. */
|
|
128
|
+
timeoutMs?: number;
|
|
129
|
+
/** shutdown() deadline in ms. Default 5000. */
|
|
130
|
+
shutdownTimeoutMs?: number;
|
|
131
|
+
/** Split a batch whose JSON body exceeds this many bytes. Default 4 MiB. */
|
|
132
|
+
targetRequestBodyBytes?: number;
|
|
133
|
+
/** Flush on the process 'beforeExit' event (within shutdownTimeoutMs). Default true. */
|
|
134
|
+
flushOnExit?: boolean;
|
|
135
|
+
/** Receives events that are lost for good. A throw is caught and logged. */
|
|
136
|
+
onDrop?: (events: E[], reason: CoreDropReason, detail?: string) => void;
|
|
137
|
+
/**
|
|
138
|
+
* Receives failures worth surfacing: breaker openings (`outage`, `auth`),
|
|
139
|
+
* rejections, shutdown leftovers and post-close tracking. Branch on
|
|
140
|
+
* `error.kind`, never on the message. A throw is caught and logged.
|
|
141
|
+
*/
|
|
142
|
+
onError?: (error: CoreTransportError<E>) => void;
|
|
143
|
+
/**
|
|
144
|
+
* Called after every accepted (2xx) batch with the response body, the
|
|
145
|
+
* `{success, data}` envelope already unwrapped (`undefined` when the body was
|
|
146
|
+
* empty or not JSON), and the events of that batch. Use it to read fields
|
|
147
|
+
* such as `killedSessionIds`. A throw is caught and logged.
|
|
148
|
+
*/
|
|
149
|
+
onAccepted?: (body: unknown, events: E[]) => void;
|
|
150
|
+
/** Log sink. Default: console with `logPrefix` (debug lines only when AFORO_DEBUG is set). */
|
|
151
|
+
logger?: CoreLogger;
|
|
152
|
+
/** Prefix for default log lines. Default '[aforo]'. */
|
|
153
|
+
logPrefix?: string;
|
|
154
|
+
/** Injectable for tests. Default: the global fetch, looked up on every request. */
|
|
155
|
+
fetch?: CoreFetch;
|
|
156
|
+
/** Injectable for tests. Default Date.now. */
|
|
157
|
+
clock?: () => number;
|
|
158
|
+
/** Injectable for tests. Default: an unref'd timer that ends when the signal aborts. */
|
|
159
|
+
sleep?: CoreSleep;
|
|
160
|
+
/** Injectable for tests. Default Math.random. */
|
|
161
|
+
random?: () => number;
|
|
162
|
+
}
|
|
163
|
+
/** What one flush cycle did. */
|
|
164
|
+
export interface CoreFlushResult {
|
|
165
|
+
/** Events the ingestor accepted (including duplicates it already had). */
|
|
166
|
+
sent: number;
|
|
167
|
+
/** Events dropped for good in this cycle. */
|
|
168
|
+
failed: number;
|
|
169
|
+
/** Events put back on the queue (outage or per-event retryable). */
|
|
170
|
+
requeued: number;
|
|
171
|
+
/** Events still queued when the cycle ended. */
|
|
172
|
+
queued: number;
|
|
173
|
+
}
|
|
174
|
+
/** What shutdown() did. */
|
|
175
|
+
export interface CoreShutdownResult extends CoreFlushResult {
|
|
176
|
+
/** Events still queued at the deadline, reported as 'shutdown'. */
|
|
177
|
+
leftover: number;
|
|
178
|
+
/** True when the deadline passed before the queue was empty. */
|
|
179
|
+
timedOut: boolean;
|
|
180
|
+
}
|
|
181
|
+
export declare const CORE_DEFAULTS: Readonly<{
|
|
182
|
+
path: "/v1/ingest/batch";
|
|
183
|
+
flushCount: 500;
|
|
184
|
+
maxBatchEvents: 1000;
|
|
185
|
+
flushIntervalMs: 5000;
|
|
186
|
+
maxQueueSize: 10000;
|
|
187
|
+
maxRetries: 3;
|
|
188
|
+
retryBaseMs: 500;
|
|
189
|
+
retryMaxDelayMs: 30000;
|
|
190
|
+
retryAfterMaxMs: 60000;
|
|
191
|
+
breakerInitialMs: 5000;
|
|
192
|
+
breakerMaxMs: 300000;
|
|
193
|
+
timeoutMs: 10000;
|
|
194
|
+
shutdownTimeoutMs: 5000;
|
|
195
|
+
targetRequestBodyBytes: number;
|
|
196
|
+
}>;
|
|
197
|
+
declare const INSPECT: unique symbol;
|
|
198
|
+
/**
|
|
199
|
+
* Throws when `baseUrl` is not https:// (plain http only for a local host or
|
|
200
|
+
* with `allowInsecureHttp`). Returns the URL without trailing slashes.
|
|
201
|
+
*/
|
|
202
|
+
export declare function checkBaseUrl(baseUrl: string, allowInsecureHttp?: boolean): string;
|
|
203
|
+
/** Full-jitter backoff: random(0, min(maxDelay, base * 2^attempt)). */
|
|
204
|
+
export declare function fullJitter(attempt: number, baseMs: number, maxMs: number, random: () => number): number;
|
|
205
|
+
/**
|
|
206
|
+
* Retry-After in ms: delta-seconds or an HTTP-date, capped at `maxMs`.
|
|
207
|
+
* Undefined when absent or unreadable (the caller then uses its own delay).
|
|
208
|
+
*/
|
|
209
|
+
export declare function parseRetryAfter(value: string | null | undefined, now: number, maxMs: number): number | undefined;
|
|
210
|
+
/** Sleep on an unref'd timer; resolves early when `signal` aborts. */
|
|
211
|
+
export declare const defaultSleep: CoreSleep;
|
|
212
|
+
/**
|
|
213
|
+
* The Node transport core. One instance per SDK client.
|
|
214
|
+
*
|
|
215
|
+
* ```ts
|
|
216
|
+
* const core = new TransportCore<MyEvent>({ baseUrl, apiKey, onDrop });
|
|
217
|
+
* core.enqueue(event); // never sends, never throws
|
|
218
|
+
* await core.flush(); // waits for the flusher to drain the queue
|
|
219
|
+
* await core.shutdown(); // drains until shutdownTimeoutMs, reports leftovers
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
export declare class TransportCore<E extends CoreEvent> {
|
|
223
|
+
private readonly url;
|
|
224
|
+
private readonly headers;
|
|
225
|
+
private readonly flushCount;
|
|
226
|
+
private readonly flushIntervalMs;
|
|
227
|
+
private readonly maxRetries;
|
|
228
|
+
private readonly retryBaseMs;
|
|
229
|
+
private readonly retryMaxDelayMs;
|
|
230
|
+
private readonly retryAfterMaxMs;
|
|
231
|
+
private readonly breakerInitialMs;
|
|
232
|
+
private readonly breakerMaxMs;
|
|
233
|
+
private readonly timeoutMs;
|
|
234
|
+
private readonly shutdownTimeoutMs;
|
|
235
|
+
private readonly targetBytes;
|
|
236
|
+
private readonly fetchFn;
|
|
237
|
+
private readonly clock;
|
|
238
|
+
private readonly sleepFn;
|
|
239
|
+
private readonly random;
|
|
240
|
+
private readonly logger;
|
|
241
|
+
private readonly onDrop?;
|
|
242
|
+
private readonly onError?;
|
|
243
|
+
private readonly onAccepted?;
|
|
244
|
+
private readonly queue;
|
|
245
|
+
private dropped;
|
|
246
|
+
private overflowDrops;
|
|
247
|
+
private invalidDrops;
|
|
248
|
+
private closedDrops;
|
|
249
|
+
private sentTotal;
|
|
250
|
+
private inFlight;
|
|
251
|
+
private closedFlag;
|
|
252
|
+
private deadline;
|
|
253
|
+
private readonly stopController;
|
|
254
|
+
/** Aborted to wake the flusher from its idle wait (replaced after each wake). */
|
|
255
|
+
private idleWake;
|
|
256
|
+
/** Aborted to cut a breaker wait short (explicit flush / shutdown). */
|
|
257
|
+
private breakerWake;
|
|
258
|
+
private breakerOpens;
|
|
259
|
+
private breakerOpen;
|
|
260
|
+
/** ERROR line for this breaker opening (401/403 or a redirect) already written. */
|
|
261
|
+
private configErrorLogged;
|
|
262
|
+
private flushWaiters;
|
|
263
|
+
private readonly loop;
|
|
264
|
+
private shutdownPromise;
|
|
265
|
+
private readonly closingTotals;
|
|
266
|
+
private deadlineTimer;
|
|
267
|
+
/** Per-event retryable failures seen so far, keyed by event object. */
|
|
268
|
+
private readonly perEventRetries;
|
|
269
|
+
/** Highest per-event retry count in the last requeue, for the backoff before the resend. */
|
|
270
|
+
private perEventAttempt;
|
|
271
|
+
/** Each queued event's JSON, taken at enqueue. */
|
|
272
|
+
private readonly serialized;
|
|
273
|
+
/** Events taken off the queue that are being sent or waiting for a retry. */
|
|
274
|
+
private eventsInHand;
|
|
275
|
+
private shutdownSettled;
|
|
276
|
+
private exitKeepAlive;
|
|
277
|
+
constructor(options: TransportCoreOptions<E>);
|
|
278
|
+
/**
|
|
279
|
+
* Queue an event. Never sends and never throws. The event is serialized
|
|
280
|
+
* now, so later changes to the object are not sent; one JSON cannot
|
|
281
|
+
* represent is reported through onDrop(…, 'invalid'). After shutdown the
|
|
282
|
+
* event is reported through onDrop(…, 'closed'). Returns false in both cases.
|
|
283
|
+
*/
|
|
284
|
+
enqueue(event: E): boolean;
|
|
285
|
+
/** Count and report events the caller rejected before queueing (reason 'invalid' or another). */
|
|
286
|
+
reportDrop(events: E[], reason: CoreDropReason, detail?: string): void;
|
|
287
|
+
/**
|
|
288
|
+
* Hand the queue to the flusher and wait for one drain cycle. Never runs a
|
|
289
|
+
* second concurrent send. While the breaker is open this makes one attempt
|
|
290
|
+
* now instead of waiting for the cooldown.
|
|
291
|
+
*/
|
|
292
|
+
flush(): Promise<CoreFlushResult>;
|
|
293
|
+
/**
|
|
294
|
+
* Stop accepting events and drain until `shutdownTimeoutMs`. Each request
|
|
295
|
+
* in that window uses min(timeoutMs, time left). Events still queued at the
|
|
296
|
+
* deadline are reported through onDrop(…, 'shutdown'). Idempotent.
|
|
297
|
+
*/
|
|
298
|
+
shutdown(): Promise<CoreShutdownResult>;
|
|
299
|
+
/** Events waiting in the queue. */
|
|
300
|
+
get queued(): number;
|
|
301
|
+
/** Events lost for good since creation (every reason, including unattributed per-event rejections). */
|
|
302
|
+
get droppedCount(): number;
|
|
303
|
+
/** Events the ingestor accepted since creation. */
|
|
304
|
+
get sentCount(): number;
|
|
305
|
+
/** True after shutdown() was called. */
|
|
306
|
+
get closed(): boolean;
|
|
307
|
+
/** True while the breaker pauses the flusher after an outage. */
|
|
308
|
+
get isBreakerOpen(): boolean;
|
|
309
|
+
/** Ingest requests in flight right now (0 or 1). */
|
|
310
|
+
get inFlightRequests(): number;
|
|
311
|
+
/** True while events are queued or a taken batch is being sent / retried. */
|
|
312
|
+
get busy(): boolean;
|
|
313
|
+
/**
|
|
314
|
+
* @internal Called from the process 'beforeExit' hook. When this core still
|
|
315
|
+
* holds events (or a shutdown is already running), it shuts down and holds
|
|
316
|
+
* the event loop open with one timer until the shutdown settles. Never
|
|
317
|
+
* longer than the shutdown deadline plus a second.
|
|
318
|
+
*/
|
|
319
|
+
flushForExit(): void;
|
|
320
|
+
/** @internal Debug log, used by the exit hook. */
|
|
321
|
+
logDebug(message: string): void;
|
|
322
|
+
toJSON(): Record<string, unknown>;
|
|
323
|
+
[INSPECT](): string;
|
|
324
|
+
private wakeIdle;
|
|
325
|
+
private wakeBreaker;
|
|
326
|
+
private get pastDeadline();
|
|
327
|
+
private run;
|
|
328
|
+
private waitBackoff;
|
|
329
|
+
private waitIdle;
|
|
330
|
+
private waitBreaker;
|
|
331
|
+
/** Send everything queued, one request at a time. Stops on outage or deadline. */
|
|
332
|
+
private drainCycle;
|
|
333
|
+
/**
|
|
334
|
+
* Send one batch (splitting it when the body is too large or the ingestor
|
|
335
|
+
* answers 413). Returns true when the cycle must stop (outage or deadline);
|
|
336
|
+
* unsent events are already back at the front of the queue then.
|
|
337
|
+
*/
|
|
338
|
+
private sendBatch;
|
|
339
|
+
/** Request body from the JSON taken at enqueue. */
|
|
340
|
+
private bodyFor;
|
|
341
|
+
private requeue;
|
|
342
|
+
/** `kept` are the events just put back on the queue (named in the onError report). */
|
|
343
|
+
private openBreaker;
|
|
344
|
+
private closeBreaker;
|
|
345
|
+
/** One chunk, with retries. Never throws. */
|
|
346
|
+
private sendWithRetry;
|
|
347
|
+
private post;
|
|
348
|
+
private handleAccepted;
|
|
349
|
+
private discardBody;
|
|
350
|
+
private readProblem;
|
|
351
|
+
private recordDrop;
|
|
352
|
+
private reportError;
|
|
353
|
+
}
|
|
354
|
+
export {};
|
|
355
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/transport-core/core.ts"],"names":[],"mappings":"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"}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
|
+
import type { AforoClient } from './client.js';
|
|
1
2
|
/**
|
|
2
|
-
* Why
|
|
3
|
-
*
|
|
4
|
-
* - '
|
|
5
|
-
* - 'rejected': the ingestor
|
|
6
|
-
*
|
|
3
|
+
* Why events were permanently lost. Every dropped event keeps its
|
|
4
|
+
* idempotency key, so re-tracking it after recovery is dedup-safe.
|
|
5
|
+
* - 'overflow': the queue was full — the OLDEST event was evicted to make room.
|
|
6
|
+
* - 'rejected': the ingestor refused the event (a non-retryable 4xx, a
|
|
7
|
+
* per-event rejection inside an accepted batch, or 413 on a single event).
|
|
7
8
|
* - 'invalid': the event failed a client-side check at track() (blank
|
|
8
9
|
* customerId/metricName, quantity <= 0, a field over the ingestor's size
|
|
9
|
-
* limit, a malformed occurredAt)
|
|
10
|
+
* limit, a malformed occurredAt), or a middleware customer resolver
|
|
11
|
+
* returned nothing. It was never queued or sent.
|
|
12
|
+
* - 'shutdown': still queued when the shutdown deadline passed.
|
|
13
|
+
* - 'closed': track() was called after shutdown().
|
|
14
|
+
* - 'retry_exhausted': kept for compatibility; not produced by 2.x (an outage
|
|
15
|
+
* requeues the batch behind a breaker instead of dropping it).
|
|
10
16
|
*/
|
|
11
|
-
export type DropReason = 'overflow' | 'retry_exhausted' | 'rejected' | 'invalid';
|
|
17
|
+
export type DropReason = 'overflow' | 'retry_exhausted' | 'rejected' | 'invalid' | 'shutdown' | 'closed';
|
|
12
18
|
/** Options for creating an AforoClient instance. */
|
|
13
19
|
export interface AforoOptions {
|
|
14
|
-
/** Aforo API key
|
|
20
|
+
/** Aforo API key, sent as X-API-Key. Never logged or shown by inspect(). */
|
|
15
21
|
apiKey: string;
|
|
16
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Base URL for the Aforo ingestor. Default https://api.aforo.ai.
|
|
24
|
+
* Must be https:// — plain http:// is accepted only for localhost,
|
|
25
|
+
* 127.0.0.1 and ::1, or with `allowInsecureHttp: true`.
|
|
26
|
+
*/
|
|
17
27
|
baseUrl?: string;
|
|
28
|
+
/** Allow a plain http:// baseUrl on a non-local host. Default false. */
|
|
29
|
+
allowInsecureHttp?: boolean;
|
|
18
30
|
/**
|
|
19
31
|
* Default product type stamped on every event (top-level `productType`).
|
|
20
32
|
* Required by the Aforo ingestor in production. One of API, AGENTIC_API,
|
|
@@ -23,29 +35,34 @@ export interface AforoOptions {
|
|
|
23
35
|
* A per-event `productType` on `track()` overrides this.
|
|
24
36
|
*/
|
|
25
37
|
productType?: string;
|
|
26
|
-
/**
|
|
38
|
+
/** Events per request (capped at 1000, the ingestor's batch limit). Default: 500 */
|
|
27
39
|
flushCount?: number;
|
|
28
|
-
/** Flush
|
|
40
|
+
/** Flush at least this often, in milliseconds. Default: 5000 */
|
|
29
41
|
flushInterval?: number;
|
|
30
|
-
/**
|
|
42
|
+
/** Queue capacity. The oldest event is dropped on overflow. Default: 10000 */
|
|
31
43
|
maxQueueSize?: number;
|
|
32
|
-
/**
|
|
44
|
+
/** Retries per batch on network errors, timeouts, 408, 429 and 5xx before the breaker opens. Default: 3 */
|
|
33
45
|
maxRetries?: number;
|
|
34
|
-
/** Base delay in ms for
|
|
46
|
+
/** Base delay in ms for full-jitter backoff. Default: 500 */
|
|
35
47
|
retryBaseMs?: number;
|
|
36
|
-
/**
|
|
48
|
+
/** Total deadline per request, in milliseconds. Default: 10000 */
|
|
37
49
|
timeout?: number;
|
|
38
|
-
/**
|
|
50
|
+
/** How long shutdown() keeps sending, in milliseconds. Default: 5000 */
|
|
39
51
|
shutdownTimeoutMs?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Flush queued events when the process is about to exit naturally
|
|
54
|
+
* (`beforeExit`), within shutdownTimeoutMs. Default true. The SDK installs
|
|
55
|
+
* no signal handlers: call `await client.shutdown()` from your own SIGTERM
|
|
56
|
+
* handler before exiting.
|
|
57
|
+
*/
|
|
58
|
+
flushOnExit?: boolean;
|
|
40
59
|
/**
|
|
41
60
|
* OPT-IN hook invoked with events the SDK is about to lose permanently
|
|
42
|
-
* (
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* WARN-logged). Exceptions thrown by the hook are swallowed — a hook bug
|
|
48
|
-
* can never break flushing.
|
|
61
|
+
* (see DropReason), so the app can persist / alert / replay them. Dropped
|
|
62
|
+
* events keep their idempotency keys — re-submitting them via track() after
|
|
63
|
+
* recovery is dedup-safe. Default: none (drops are still counted in
|
|
64
|
+
* droppedCount and WARN-logged). An exception thrown by the hook is caught
|
|
65
|
+
* and logged; it never breaks flushing.
|
|
49
66
|
*/
|
|
50
67
|
onDrop?: (events: ResolvedEvent[], reason: DropReason) => void;
|
|
51
68
|
}
|
|
@@ -119,14 +136,22 @@ export interface BatchResponse {
|
|
|
119
136
|
errors: Array<{
|
|
120
137
|
index: number;
|
|
121
138
|
message: string;
|
|
139
|
+
retryable?: boolean;
|
|
122
140
|
}>;
|
|
123
141
|
killedSessionIds?: string[];
|
|
124
142
|
}
|
|
125
143
|
/** Options for Express/Koa/Fastify middleware. */
|
|
126
144
|
export interface MiddlewareOptions {
|
|
127
|
-
/**
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
/**
|
|
146
|
+
* An AforoClient the app owns (recommended): the app can flush it, read
|
|
147
|
+
* droppedCount and call shutdown() from its SIGTERM handler. When omitted,
|
|
148
|
+
* the middleware creates one from apiKey/baseUrl/clientOptions and exposes
|
|
149
|
+
* it as `middleware.client`.
|
|
150
|
+
*/
|
|
151
|
+
client?: AforoClient;
|
|
152
|
+
/** Aforo API key (only when `client` is not given). */
|
|
153
|
+
apiKey?: string;
|
|
154
|
+
/** Base URL for the ingestor (only when `client` is not given). */
|
|
130
155
|
baseUrl?: string;
|
|
131
156
|
/**
|
|
132
157
|
* Product type stamped on every metered request (top-level `productType`).
|
|
@@ -138,43 +163,54 @@ export interface MiddlewareOptions {
|
|
|
138
163
|
* request/response. Default: `"api_calls"` (DEFAULT_METRIC_NAME).
|
|
139
164
|
*
|
|
140
165
|
* Must name a metric that exists in your Aforo catalog. The ingestor rejects
|
|
141
|
-
* unknown metrics
|
|
166
|
+
* unknown metrics.
|
|
142
167
|
*/
|
|
143
168
|
metricName?: string | ((req: any, res: any) => string);
|
|
144
169
|
/** Static quantity or function to derive from request/response. Requests with quantity <= 0 are not metered. */
|
|
145
170
|
quantity?: number | ((req: any, res: any) => number);
|
|
146
171
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* `
|
|
150
|
-
*
|
|
172
|
+
* Who is billed for a request, from identity your app authenticated (the
|
|
173
|
+
* session, a verified JWT subject, an API-key lookup). Required unless
|
|
174
|
+
* `trustCustomerHeader` is true. Return null/undefined/'' when the request
|
|
175
|
+
* has no billable customer: the event is dropped as 'invalid' and counted;
|
|
176
|
+
* the request itself is never blocked.
|
|
177
|
+
*/
|
|
178
|
+
customerResolver?: (req: any) => string | null | undefined;
|
|
179
|
+
/**
|
|
180
|
+
* @deprecated Use `customerResolver`. A function is used as the resolver; a
|
|
181
|
+
* fixed string bills every request to that customer.
|
|
151
182
|
*/
|
|
152
|
-
customerId?: string | ((req: any) => string | null);
|
|
183
|
+
customerId?: string | ((req: any) => string | null | undefined);
|
|
184
|
+
/**
|
|
185
|
+
* Read the customer from the `X-Customer-Id` request header. That header is
|
|
186
|
+
* set by whoever calls your API, so only turn this on when a trusted proxy
|
|
187
|
+
* in front of the app sets it and strips any client copy. Default false.
|
|
188
|
+
*/
|
|
189
|
+
trustCustomerHeader?: boolean;
|
|
190
|
+
/**
|
|
191
|
+
* Collapse dynamic path segments before sending `endpointPath`
|
|
192
|
+
* (`/users/123` → `/users/:id`; the framework's route template wins when
|
|
193
|
+
* there is one). Default true, so per-id paths do not create unbounded
|
|
194
|
+
* label cardinality. Pass a function to normalize yourself, or false to send
|
|
195
|
+
* the raw path.
|
|
196
|
+
*/
|
|
197
|
+
normalizePath?: boolean | ((path: string, req: any) => string);
|
|
153
198
|
/** Paths to exclude from metering. Default: ["/health", "/ready", "/metrics", "/favicon.ico"] */
|
|
154
199
|
excludePaths?: string[];
|
|
155
200
|
/** Status codes to exclude. Default: none */
|
|
156
201
|
excludeStatusCodes?: number[];
|
|
157
202
|
/** Function to extract metadata from request/response. */
|
|
158
203
|
metadata?: (req: any, res: any) => Record<string, string | number | boolean>;
|
|
159
|
-
/** AforoClient options (flushCount, flushInterval, etc.) */
|
|
204
|
+
/** AforoClient options (flushCount, flushInterval, etc.) when the middleware creates the client. */
|
|
160
205
|
clientOptions?: Omit<AforoOptions, 'apiKey' | 'baseUrl'>;
|
|
161
206
|
}
|
|
162
207
|
/** Flush result for internal tracking. */
|
|
163
208
|
export interface FlushResult {
|
|
164
209
|
sent: number;
|
|
165
210
|
failed: number;
|
|
166
|
-
/**
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
|
|
170
|
-
* accepted (per-event `errors[]` in the response). `index` is the position
|
|
171
|
-
* in the sent batch. Present only when the response identified them.
|
|
172
|
-
*/
|
|
173
|
-
rejected?: Array<{
|
|
174
|
-
index: number;
|
|
175
|
-
message: string;
|
|
176
|
-
}>;
|
|
177
|
-
/** Server-provided explanation for a failed batch, when one was returned. */
|
|
178
|
-
message?: string;
|
|
211
|
+
/** Events put back on the queue (ingestor outage or a per-event retryable failure). */
|
|
212
|
+
requeued: number;
|
|
213
|
+
/** Events still queued after the flush. */
|
|
214
|
+
queued: number;
|
|
179
215
|
}
|
|
180
216
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/dist/cjs/buffer.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { ResolvedEvent } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Bounded ring buffer for usage events.
|
|
4
|
-
* Thread-safe for Node.js single-threaded event loop.
|
|
5
|
-
* When full, the oldest event is dropped (FIFO overflow).
|
|
6
|
-
*/
|
|
7
|
-
export declare class RingBuffer {
|
|
8
|
-
private readonly items;
|
|
9
|
-
private readonly capacity;
|
|
10
|
-
private head;
|
|
11
|
-
private tail;
|
|
12
|
-
private count;
|
|
13
|
-
constructor(capacity?: number);
|
|
14
|
-
/** Add an event to the buffer. Returns true if added, false if overflow (oldest dropped). */
|
|
15
|
-
push(event: ResolvedEvent): boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Add an event to the buffer. On overflow, returns the evicted OLDEST
|
|
18
|
-
* event so the caller can surface the drop; returns null when no
|
|
19
|
-
* eviction occurred.
|
|
20
|
-
*/
|
|
21
|
-
pushEvict(event: ResolvedEvent): ResolvedEvent | null;
|
|
22
|
-
/** Drain all events from the buffer. Returns a new array and clears the buffer. */
|
|
23
|
-
drain(): ResolvedEvent[];
|
|
24
|
-
/** Drain up to `max` events from the front of the buffer. */
|
|
25
|
-
drainUpTo(max: number): ResolvedEvent[];
|
|
26
|
-
/** Current number of events in the buffer. */
|
|
27
|
-
get size(): number;
|
|
28
|
-
/** Whether the buffer is empty. */
|
|
29
|
-
get isEmpty(): boolean;
|
|
30
|
-
/** Whether the buffer is at capacity. */
|
|
31
|
-
get isFull(): boolean;
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=buffer.d.ts.map
|
package/dist/cjs/buffer.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../src/buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAK;gBAEN,QAAQ,GAAE,MAAe;IAMrC,6FAA6F;IAC7F,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAInC;;;;OAIG;IACH,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,GAAG,IAAI;IAiBrD,mFAAmF;IACnF,KAAK,IAAI,aAAa,EAAE;IAgBxB,6DAA6D;IAC7D,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE;IAgBvC,8CAA8C;IAC9C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,mCAAmC;IACnC,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,yCAAyC;IACzC,IAAI,MAAM,IAAI,OAAO,CAEpB;CACF"}
|