@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.
Files changed (70) hide show
  1. package/README.md +46 -28
  2. package/dist/cjs/client.d.ts +32 -50
  3. package/dist/cjs/client.d.ts.map +1 -1
  4. package/dist/cjs/client.js +104 -215
  5. package/dist/cjs/client.js.map +1 -1
  6. package/dist/cjs/middleware/common.d.ts +16 -0
  7. package/dist/cjs/middleware/common.d.ts.map +1 -1
  8. package/dist/cjs/middleware/common.js +54 -0
  9. package/dist/cjs/middleware/common.js.map +1 -1
  10. package/dist/cjs/middleware/express.d.ts +10 -5
  11. package/dist/cjs/middleware/express.d.ts.map +1 -1
  12. package/dist/cjs/middleware/express.js +22 -59
  13. package/dist/cjs/middleware/express.js.map +1 -1
  14. package/dist/cjs/middleware/fastify.d.ts +8 -4
  15. package/dist/cjs/middleware/fastify.d.ts.map +1 -1
  16. package/dist/cjs/middleware/fastify.js +25 -45
  17. package/dist/cjs/middleware/fastify.js.map +1 -1
  18. package/dist/cjs/middleware/koa.d.ts +10 -5
  19. package/dist/cjs/middleware/koa.d.ts.map +1 -1
  20. package/dist/cjs/middleware/koa.js +25 -43
  21. package/dist/cjs/middleware/koa.js.map +1 -1
  22. package/dist/cjs/transport-core/core.d.ts +355 -0
  23. package/dist/cjs/transport-core/core.d.ts.map +1 -0
  24. package/dist/cjs/transport-core/core.js +1047 -0
  25. package/dist/cjs/transport-core/core.js.map +1 -0
  26. package/dist/cjs/types.d.ts +82 -46
  27. package/dist/cjs/types.d.ts.map +1 -1
  28. package/dist/esm/client.js +103 -214
  29. package/dist/esm/client.js.map +1 -1
  30. package/dist/esm/middleware/common.js +51 -0
  31. package/dist/esm/middleware/common.js.map +1 -1
  32. package/dist/esm/middleware/express.js +23 -60
  33. package/dist/esm/middleware/express.js.map +1 -1
  34. package/dist/esm/middleware/fastify.js +26 -46
  35. package/dist/esm/middleware/fastify.js.map +1 -1
  36. package/dist/esm/middleware/koa.js +26 -44
  37. package/dist/esm/middleware/koa.js.map +1 -1
  38. package/dist/esm/transport-core/core.js +1038 -0
  39. package/dist/esm/transport-core/core.js.map +1 -0
  40. package/dist/types/client.d.ts +32 -50
  41. package/dist/types/client.d.ts.map +1 -1
  42. package/dist/types/middleware/common.d.ts +16 -0
  43. package/dist/types/middleware/common.d.ts.map +1 -1
  44. package/dist/types/middleware/express.d.ts +10 -5
  45. package/dist/types/middleware/express.d.ts.map +1 -1
  46. package/dist/types/middleware/fastify.d.ts +8 -4
  47. package/dist/types/middleware/fastify.d.ts.map +1 -1
  48. package/dist/types/middleware/koa.d.ts +10 -5
  49. package/dist/types/middleware/koa.d.ts.map +1 -1
  50. package/dist/types/transport-core/core.d.ts +355 -0
  51. package/dist/types/transport-core/core.d.ts.map +1 -0
  52. package/dist/types/types.d.ts +82 -46
  53. package/dist/types/types.d.ts.map +1 -1
  54. package/package.json +1 -1
  55. package/dist/cjs/buffer.d.ts +0 -33
  56. package/dist/cjs/buffer.d.ts.map +0 -1
  57. package/dist/cjs/buffer.js +0 -83
  58. package/dist/cjs/buffer.js.map +0 -1
  59. package/dist/cjs/transport.d.ts +0 -41
  60. package/dist/cjs/transport.d.ts.map +0 -1
  61. package/dist/cjs/transport.js +0 -186
  62. package/dist/cjs/transport.js.map +0 -1
  63. package/dist/esm/buffer.js +0 -79
  64. package/dist/esm/buffer.js.map +0 -1
  65. package/dist/esm/transport.js +0 -182
  66. package/dist/esm/transport.js.map +0 -1
  67. package/dist/types/buffer.d.ts +0 -33
  68. package/dist/types/buffer.d.ts.map +0 -1
  69. package/dist/types/transport.d.ts +0 -41
  70. 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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"}
@@ -1,20 +1,32 @@
1
+ import type { AforoClient } from './client.js';
1
2
  /**
2
- * Why a buffered event was permanently dropped by the SDK.
3
- * - 'overflow': the ring buffer was full — the OLDEST event was evicted to make room.
4
- * - 'retry_exhausted': a batch failed after all transport retries (ingest outage).
5
- * - 'rejected': the ingestor rejected the batch with a non-retryable 4xx, or
6
- * rejected this event individually in a partially accepted batch.
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) and was never buffered or sent.
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 for authentication. */
20
+ /** Aforo API key, sent as X-API-Key. Never logged or shown by inspect(). */
15
21
  apiKey: string;
16
- /** Base URL for the Aforo ingestor service. Defaults to https://api.aforo.ai */
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
- /** Maximum events to buffer before flushing (capped at 1000, the ingestor's batch limit). Default: 50 */
38
+ /** Events per request (capped at 1000, the ingestor's batch limit). Default: 500 */
27
39
  flushCount?: number;
28
- /** Flush interval in milliseconds. Default: 5000 (5 seconds) */
40
+ /** Flush at least this often, in milliseconds. Default: 5000 */
29
41
  flushInterval?: number;
30
- /** Maximum events in the ring buffer. Oldest dropped on overflow. Default: 10000 */
42
+ /** Queue capacity. The oldest event is dropped on overflow. Default: 10000 */
31
43
  maxQueueSize?: number;
32
- /** Maximum retries on 5xx/timeout. Default: 3 */
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 exponential backoff. Default: 1000 */
46
+ /** Base delay in ms for full-jitter backoff. Default: 500 */
35
47
  retryBaseMs?: number;
36
- /** Request timeout in milliseconds. Default: 10000 */
48
+ /** Total deadline per request, in milliseconds. Default: 10000 */
37
49
  timeout?: number;
38
- /** Graceful shutdown timeout in milliseconds. Default: 5000 */
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
- * (buffer overflow, retry exhaustion, non-retryable rejection, or an event
43
- * that failed client-side validation — reason 'invalid'), so the
44
- * app can persist / alert / replay them. Dropped events keep their
45
- * idempotency keys — re-submitting them via track() after recovery is
46
- * dedup-safe. Default: none (drops are still counted in droppedCount and
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
- /** Aforo API key. */
128
- apiKey: string;
129
- /** Base URL for the ingestor. */
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, and one rejected event fails the whole batch it is in.
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
- * Aforo customer id: a fixed value, or a function of the request.
148
- * Default: the authenticated user's id (`req.user.id` / `.sub`), then the
149
- * `X-Customer-Id` header. Requests with no customer are not metered. The
150
- * caller's `X-Api-Key` header is never used -- it is a secret, not an id.
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
- /** Why the batch failed, when failed > 0. Absent on success. */
167
- reason?: DropReason;
168
- /**
169
- * Events the ingestor rejected individually inside a batch it otherwise
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":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aforoai/metering",
3
- "version": "1.1.2",
3
+ "version": "2.0.0",
4
4
  "description": "Aforo usage metering SDK — track API usage events with batching, retry, and framework middleware",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -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
@@ -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"}