@qurvo/sdk-core 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fetch-transport.d.ts +23 -0
- package/dist/fetch-transport.d.ts.map +1 -1
- package/dist/fetch-transport.js +23 -0
- package/dist/fetch-transport.js.map +1 -1
- package/dist/queue.d.ts +79 -0
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +86 -2
- package/dist/queue.js.map +1 -1
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/queue.test.d.ts +0 -2
- package/dist/queue.test.d.ts.map +0 -1
- package/dist/queue.test.js +0 -187
- package/dist/queue.test.js.map +0 -1
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
import type { Transport, SendOptions, CompressFn } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Default {@link Transport} implementation using the Fetch API.
|
|
4
|
+
*
|
|
5
|
+
* Sends event batches as HTTP POST requests with optional gzip
|
|
6
|
+
* compression. Compression is skipped for `keepalive` requests
|
|
7
|
+
* (browser unload) because the Compression Streams API may not
|
|
8
|
+
* complete before the page is destroyed.
|
|
9
|
+
*
|
|
10
|
+
* **Error classification**:
|
|
11
|
+
* - 2xx / 202: success.
|
|
12
|
+
* - 429 with `quota_limited` body: throws {@link QuotaExceededError}.
|
|
13
|
+
* - Other 4xx: throws {@link NonRetryableError} (batch should be dropped).
|
|
14
|
+
* - 5xx: throws a plain {@link Error} (batch should be retried by the queue).
|
|
15
|
+
*/
|
|
2
16
|
export declare class FetchTransport implements Transport {
|
|
3
17
|
private readonly compress?;
|
|
18
|
+
/** @param compress - Optional gzip function (e.g. `compressGzip` from sdk-browser). */
|
|
4
19
|
constructor(compress?: CompressFn | undefined);
|
|
20
|
+
/**
|
|
21
|
+
* Send a JSON-serialized payload to the ingest endpoint.
|
|
22
|
+
*
|
|
23
|
+
* @returns `true` on 2xx/202 (accepted).
|
|
24
|
+
* @throws {@link QuotaExceededError} on 429 + `quota_limited`.
|
|
25
|
+
* @throws {@link NonRetryableError} on 4xx client errors.
|
|
26
|
+
* @throws {@link Error} on 5xx server errors.
|
|
27
|
+
*/
|
|
5
28
|
send(endpoint: string, apiKey: string, payload: unknown, options?: SendOptions): Promise<boolean>;
|
|
6
29
|
}
|
|
7
30
|
//# sourceMappingURL=fetch-transport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-transport.d.ts","sourceRoot":"","sources":["../src/fetch-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGlE,qBAAa,cAAe,YAAW,SAAS;
|
|
1
|
+
{"version":3,"file":"fetch-transport.d.ts","sourceRoot":"","sources":["../src/fetch-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGlE;;;;;;;;;;;;;GAaG;AACH,qBAAa,cAAe,YAAW,SAAS;IAElC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IADtC,uFAAuF;gBAC1D,QAAQ,CAAC,EAAE,UAAU,YAAA;IAElD;;;;;;;OAOG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CA2CxG"}
|
package/dist/fetch-transport.js
CHANGED
|
@@ -2,11 +2,34 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FetchTransport = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
|
+
/**
|
|
6
|
+
* Default {@link Transport} implementation using the Fetch API.
|
|
7
|
+
*
|
|
8
|
+
* Sends event batches as HTTP POST requests with optional gzip
|
|
9
|
+
* compression. Compression is skipped for `keepalive` requests
|
|
10
|
+
* (browser unload) because the Compression Streams API may not
|
|
11
|
+
* complete before the page is destroyed.
|
|
12
|
+
*
|
|
13
|
+
* **Error classification**:
|
|
14
|
+
* - 2xx / 202: success.
|
|
15
|
+
* - 429 with `quota_limited` body: throws {@link QuotaExceededError}.
|
|
16
|
+
* - Other 4xx: throws {@link NonRetryableError} (batch should be dropped).
|
|
17
|
+
* - 5xx: throws a plain {@link Error} (batch should be retried by the queue).
|
|
18
|
+
*/
|
|
5
19
|
class FetchTransport {
|
|
6
20
|
compress;
|
|
21
|
+
/** @param compress - Optional gzip function (e.g. `compressGzip` from sdk-browser). */
|
|
7
22
|
constructor(compress) {
|
|
8
23
|
this.compress = compress;
|
|
9
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Send a JSON-serialized payload to the ingest endpoint.
|
|
27
|
+
*
|
|
28
|
+
* @returns `true` on 2xx/202 (accepted).
|
|
29
|
+
* @throws {@link QuotaExceededError} on 429 + `quota_limited`.
|
|
30
|
+
* @throws {@link NonRetryableError} on 4xx client errors.
|
|
31
|
+
* @throws {@link Error} on 5xx server errors.
|
|
32
|
+
*/
|
|
10
33
|
async send(endpoint, apiKey, payload, options) {
|
|
11
34
|
const json = JSON.stringify(payload);
|
|
12
35
|
const headers = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-transport.js","sourceRoot":"","sources":["../src/fetch-transport.ts"],"names":[],"mappings":";;;AACA,mCAAgE;AAEhE,MAAa,cAAc;
|
|
1
|
+
{"version":3,"file":"fetch-transport.js","sourceRoot":"","sources":["../src/fetch-transport.ts"],"names":[],"mappings":";;;AACA,mCAAgE;AAEhE;;;;;;;;;;;;;GAaG;AACH,MAAa,cAAc;IAEI;IAD7B,uFAAuF;IACvF,YAA6B,QAAqB;QAArB,aAAQ,GAAR,QAAQ,CAAa;IAAG,CAAC;IAEtD;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI,CAAC,QAAgB,EAAE,MAAc,EAAE,OAAgB,EAAE,OAAqB;QAClF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,OAAO,GAA2B;YACtC,WAAW,EAAE,MAAM;SACpB,CAAC;QAEF,IAAI,IAAc,CAAC;QACnB,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;YACzC,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjC,OAAO,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC;YACvC,OAAO,CAAC,kBAAkB,CAAC,GAAG,MAAM,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,IAAI,CAAC;YACZ,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QAC/C,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI;YACJ,SAAS,EAAE,OAAO,EAAE,SAAS;YAC7B,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAExD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7D,IAAI,YAAY,EAAE,aAAa,EAAE,CAAC;gBAChC,MAAM,IAAI,0BAAkB,EAAE,CAAC;YACjC,CAAC;QACH,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAE3D,uEAAuE;QACvE,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACpD,MAAM,IAAI,yBAAiB,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,QAAQ,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC,CAAC;QAC3F,CAAC;QAED,gCAAgC;QAChC,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC,CAAC;IAC9D,CAAC;CACF;AAvDD,wCAuDC"}
|
package/dist/queue.d.ts
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import type { Transport, LogFn, QueuePersistence } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Buffered event queue with automatic flushing, exponential backoff, and
|
|
4
|
+
* optional persistence.
|
|
5
|
+
*
|
|
6
|
+
* **Lifecycle**: events are added via {@link enqueue}, accumulated in an
|
|
7
|
+
* in-memory buffer, and periodically sent to the ingest API by
|
|
8
|
+
* {@link flush}. Flushing is triggered either by a timer ({@link start})
|
|
9
|
+
* or when the buffer reaches `flushSize`.
|
|
10
|
+
*
|
|
11
|
+
* **Error handling**:
|
|
12
|
+
* - 5xx / network errors: the batch is re-queued and delivery retries
|
|
13
|
+
* with exponential backoff (up to 30 s).
|
|
14
|
+
* - 4xx ({@link NonRetryableError}): the batch is dropped permanently.
|
|
15
|
+
* - 429 + quota_limited ({@link QuotaExceededError}): the entire queue
|
|
16
|
+
* is drained and the timer is stopped.
|
|
17
|
+
*
|
|
18
|
+
* **Persistence**: when a {@link QueuePersistence} implementation is
|
|
19
|
+
* provided, the queue is saved to durable storage after every mutation
|
|
20
|
+
* and restored on construction.
|
|
21
|
+
*/
|
|
2
22
|
export declare class EventQueue {
|
|
3
23
|
private readonly transport;
|
|
4
24
|
private readonly endpoint;
|
|
@@ -16,15 +36,74 @@ export declare class EventQueue {
|
|
|
16
36
|
private failureCount;
|
|
17
37
|
private retryAfter;
|
|
18
38
|
private readonly maxBackoffMs;
|
|
39
|
+
/**
|
|
40
|
+
* @param transport - Transport used to deliver batches (e.g. {@link FetchTransport}).
|
|
41
|
+
* @param endpoint - Full URL of the ingest endpoint.
|
|
42
|
+
* @param apiKey - Project API key for authentication.
|
|
43
|
+
* @param flushInterval - Milliseconds between automatic flushes. Default: `5000`.
|
|
44
|
+
* @param flushSize - Batch size that triggers an immediate flush. Default: `20`.
|
|
45
|
+
* @param maxQueueSize - Maximum events held in memory (FIFO eviction). Default: `1000`.
|
|
46
|
+
* @param sendTimeoutMs - Per-request abort timeout in milliseconds. Default: `30000`.
|
|
47
|
+
* @param logger - Optional debug logger.
|
|
48
|
+
* @param persistence - Optional durable storage backing for the queue.
|
|
49
|
+
*/
|
|
19
50
|
constructor(transport: Transport, endpoint: string, apiKey: string, flushInterval?: number, flushSize?: number, maxQueueSize?: number, sendTimeoutMs?: number, logger?: LogFn | undefined, persistence?: QueuePersistence | undefined);
|
|
51
|
+
/**
|
|
52
|
+
* Add an event to the queue.
|
|
53
|
+
*
|
|
54
|
+
* When the buffer is full (`maxQueueSize`), the **oldest** event is
|
|
55
|
+
* dropped (FIFO eviction) to make room. If the buffer reaches
|
|
56
|
+
* `flushSize` after insertion, an immediate {@link flush} is triggered.
|
|
57
|
+
*/
|
|
20
58
|
enqueue(event: unknown): void;
|
|
59
|
+
/** Start the periodic flush timer. No-op if already running. */
|
|
21
60
|
start(): void;
|
|
61
|
+
/** Stop the periodic flush timer. Safe to call when already stopped. */
|
|
22
62
|
stop(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Send the next batch of events to the ingest API.
|
|
65
|
+
*
|
|
66
|
+
* No-op when a flush is already in progress, the queue is empty,
|
|
67
|
+
* or the backoff cooldown has not elapsed.
|
|
68
|
+
*
|
|
69
|
+
* **Retry logic**:
|
|
70
|
+
* - On 5xx or network error the batch is re-queued and delivery is
|
|
71
|
+
* retried with exponential backoff (1 s, 2 s, 4 s, ... up to 30 s).
|
|
72
|
+
* - On 4xx ({@link NonRetryableError}) the batch is **dropped**.
|
|
73
|
+
* - On 429 + quota_limited ({@link QuotaExceededError}) the queue is
|
|
74
|
+
* emptied and the flush timer is stopped.
|
|
75
|
+
*/
|
|
23
76
|
flush(): Promise<void>;
|
|
24
77
|
private scheduleBackoff;
|
|
78
|
+
/**
|
|
79
|
+
* Drain the queue by flushing repeatedly until empty.
|
|
80
|
+
*
|
|
81
|
+
* Resets backoff state before starting so pending retries are not
|
|
82
|
+
* delayed. Stops early if a flush cycle makes no progress (e.g. all
|
|
83
|
+
* events are failing permanently).
|
|
84
|
+
*/
|
|
25
85
|
flushAll(): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Gracefully shut down the queue.
|
|
88
|
+
*
|
|
89
|
+
* Stops the periodic timer and attempts to deliver all remaining
|
|
90
|
+
* events via {@link flushAll}. If delivery does not complete within
|
|
91
|
+
* `timeoutMs`, the promise resolves and outstanding events are lost.
|
|
92
|
+
*
|
|
93
|
+
* @param timeoutMs - Maximum time to wait for delivery. Default: `30000`.
|
|
94
|
+
*/
|
|
26
95
|
shutdown(timeoutMs?: number): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Last-resort flush for page unload (`beforeunload` / `visibilitychange`).
|
|
98
|
+
*
|
|
99
|
+
* Sends all remaining events in a single fire-and-forget request with
|
|
100
|
+
* `keepalive: true` so the browser keeps the connection alive after the
|
|
101
|
+
* page is destroyed. If a regular {@link flush} is already in-flight,
|
|
102
|
+
* only the queued (not yet sent) events are included to avoid
|
|
103
|
+
* double-delivery.
|
|
104
|
+
*/
|
|
27
105
|
flushForUnload(): void;
|
|
106
|
+
/** Total number of events pending delivery (queued + in-flight). */
|
|
28
107
|
get size(): number;
|
|
29
108
|
private persist;
|
|
30
109
|
}
|
package/dist/queue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGlE,qBAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGlE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAU;IAqBnB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IA5B/B,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IAEvC;;;;;;;;;;OAUG;gBAEgB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,aAAa,GAAE,MAAa,EAC5B,SAAS,GAAE,MAAW,EACtB,YAAY,GAAE,MAAa,EAC3B,aAAa,GAAE,MAAe,EAC9B,MAAM,CAAC,EAAE,KAAK,YAAA,EACd,WAAW,CAAC,EAAE,gBAAgB,YAAA;IAejD;;;;;;OAMG;IACH,OAAO,CAAC,KAAK,EAAE,OAAO;IAatB,gEAAgE;IAChE,KAAK;IAKL,wEAAwE;IACxE,IAAI;IAOJ;;;;;;;;;;;;OAYG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD5B,OAAO,CAAC,eAAe;IAMvB;;;;;;OAMG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAU/B;;;;;;;;OAQG;IACG,QAAQ,CAAC,SAAS,GAAE,MAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD;;;;;;;;OAQG;IACH,cAAc,IAAI,IAAI;IAatB,oEAAoE;IACpE,IAAI,IAAI,WAEP;IAED,OAAO,CAAC,OAAO;CAOhB"}
|
package/dist/queue.js
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EventQueue = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
|
+
/**
|
|
6
|
+
* Buffered event queue with automatic flushing, exponential backoff, and
|
|
7
|
+
* optional persistence.
|
|
8
|
+
*
|
|
9
|
+
* **Lifecycle**: events are added via {@link enqueue}, accumulated in an
|
|
10
|
+
* in-memory buffer, and periodically sent to the ingest API by
|
|
11
|
+
* {@link flush}. Flushing is triggered either by a timer ({@link start})
|
|
12
|
+
* or when the buffer reaches `flushSize`.
|
|
13
|
+
*
|
|
14
|
+
* **Error handling**:
|
|
15
|
+
* - 5xx / network errors: the batch is re-queued and delivery retries
|
|
16
|
+
* with exponential backoff (up to 30 s).
|
|
17
|
+
* - 4xx ({@link NonRetryableError}): the batch is dropped permanently.
|
|
18
|
+
* - 429 + quota_limited ({@link QuotaExceededError}): the entire queue
|
|
19
|
+
* is drained and the timer is stopped.
|
|
20
|
+
*
|
|
21
|
+
* **Persistence**: when a {@link QueuePersistence} implementation is
|
|
22
|
+
* provided, the queue is saved to durable storage after every mutation
|
|
23
|
+
* and restored on construction.
|
|
24
|
+
*/
|
|
5
25
|
class EventQueue {
|
|
6
26
|
transport;
|
|
7
27
|
endpoint;
|
|
@@ -19,6 +39,17 @@ class EventQueue {
|
|
|
19
39
|
failureCount = 0;
|
|
20
40
|
retryAfter = 0;
|
|
21
41
|
maxBackoffMs = 30_000;
|
|
42
|
+
/**
|
|
43
|
+
* @param transport - Transport used to deliver batches (e.g. {@link FetchTransport}).
|
|
44
|
+
* @param endpoint - Full URL of the ingest endpoint.
|
|
45
|
+
* @param apiKey - Project API key for authentication.
|
|
46
|
+
* @param flushInterval - Milliseconds between automatic flushes. Default: `5000`.
|
|
47
|
+
* @param flushSize - Batch size that triggers an immediate flush. Default: `20`.
|
|
48
|
+
* @param maxQueueSize - Maximum events held in memory (FIFO eviction). Default: `1000`.
|
|
49
|
+
* @param sendTimeoutMs - Per-request abort timeout in milliseconds. Default: `30000`.
|
|
50
|
+
* @param logger - Optional debug logger.
|
|
51
|
+
* @param persistence - Optional durable storage backing for the queue.
|
|
52
|
+
*/
|
|
22
53
|
constructor(transport, endpoint, apiKey, flushInterval = 5000, flushSize = 20, maxQueueSize = 1000, sendTimeoutMs = 30_000, logger, persistence) {
|
|
23
54
|
this.transport = transport;
|
|
24
55
|
this.endpoint = endpoint;
|
|
@@ -42,6 +73,13 @@ class EventQueue {
|
|
|
42
73
|
}
|
|
43
74
|
}
|
|
44
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Add an event to the queue.
|
|
78
|
+
*
|
|
79
|
+
* When the buffer is full (`maxQueueSize`), the **oldest** event is
|
|
80
|
+
* dropped (FIFO eviction) to make room. If the buffer reaches
|
|
81
|
+
* `flushSize` after insertion, an immediate {@link flush} is triggered.
|
|
82
|
+
*/
|
|
45
83
|
enqueue(event) {
|
|
46
84
|
if (this.queue.length >= this.maxQueueSize) {
|
|
47
85
|
this.queue.shift();
|
|
@@ -53,17 +91,32 @@ class EventQueue {
|
|
|
53
91
|
this.flush();
|
|
54
92
|
}
|
|
55
93
|
}
|
|
94
|
+
/** Start the periodic flush timer. No-op if already running. */
|
|
56
95
|
start() {
|
|
57
96
|
if (this.timer)
|
|
58
97
|
return;
|
|
59
98
|
this.timer = setInterval(() => this.flush(), this.flushInterval);
|
|
60
99
|
}
|
|
100
|
+
/** Stop the periodic flush timer. Safe to call when already stopped. */
|
|
61
101
|
stop() {
|
|
62
102
|
if (this.timer) {
|
|
63
103
|
clearInterval(this.timer);
|
|
64
104
|
this.timer = null;
|
|
65
105
|
}
|
|
66
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Send the next batch of events to the ingest API.
|
|
109
|
+
*
|
|
110
|
+
* No-op when a flush is already in progress, the queue is empty,
|
|
111
|
+
* or the backoff cooldown has not elapsed.
|
|
112
|
+
*
|
|
113
|
+
* **Retry logic**:
|
|
114
|
+
* - On 5xx or network error the batch is re-queued and delivery is
|
|
115
|
+
* retried with exponential backoff (1 s, 2 s, 4 s, ... up to 30 s).
|
|
116
|
+
* - On 4xx ({@link NonRetryableError}) the batch is **dropped**.
|
|
117
|
+
* - On 429 + quota_limited ({@link QuotaExceededError}) the queue is
|
|
118
|
+
* emptied and the flush timer is stopped.
|
|
119
|
+
*/
|
|
67
120
|
async flush() {
|
|
68
121
|
if (this.flushing || this.queue.length === 0)
|
|
69
122
|
return;
|
|
@@ -118,6 +171,13 @@ class EventQueue {
|
|
|
118
171
|
const backoffMs = Math.min(1000 * Math.pow(2, this.failureCount - 1), this.maxBackoffMs);
|
|
119
172
|
this.retryAfter = Date.now() + backoffMs;
|
|
120
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Drain the queue by flushing repeatedly until empty.
|
|
176
|
+
*
|
|
177
|
+
* Resets backoff state before starting so pending retries are not
|
|
178
|
+
* delayed. Stops early if a flush cycle makes no progress (e.g. all
|
|
179
|
+
* events are failing permanently).
|
|
180
|
+
*/
|
|
121
181
|
async flushAll() {
|
|
122
182
|
this.retryAfter = 0;
|
|
123
183
|
this.failureCount = 0;
|
|
@@ -128,6 +188,15 @@ class EventQueue {
|
|
|
128
188
|
break;
|
|
129
189
|
}
|
|
130
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Gracefully shut down the queue.
|
|
193
|
+
*
|
|
194
|
+
* Stops the periodic timer and attempts to deliver all remaining
|
|
195
|
+
* events via {@link flushAll}. If delivery does not complete within
|
|
196
|
+
* `timeoutMs`, the promise resolves and outstanding events are lost.
|
|
197
|
+
*
|
|
198
|
+
* @param timeoutMs - Maximum time to wait for delivery. Default: `30000`.
|
|
199
|
+
*/
|
|
131
200
|
async shutdown(timeoutMs = 30_000) {
|
|
132
201
|
this.stop();
|
|
133
202
|
if (this.size === 0)
|
|
@@ -137,14 +206,29 @@ class EventQueue {
|
|
|
137
206
|
new Promise((resolve) => setTimeout(resolve, timeoutMs)),
|
|
138
207
|
]);
|
|
139
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Last-resort flush for page unload (`beforeunload` / `visibilitychange`).
|
|
211
|
+
*
|
|
212
|
+
* Sends all remaining events in a single fire-and-forget request with
|
|
213
|
+
* `keepalive: true` so the browser keeps the connection alive after the
|
|
214
|
+
* page is destroyed. If a regular {@link flush} is already in-flight,
|
|
215
|
+
* only the queued (not yet sent) events are included to avoid
|
|
216
|
+
* double-delivery.
|
|
217
|
+
*/
|
|
140
218
|
flushForUnload() {
|
|
141
|
-
|
|
142
|
-
|
|
219
|
+
// If a flush() is already in-flight, don't re-send those events — they are
|
|
220
|
+
// being delivered by the ongoing fetch. Only grab remaining queue items.
|
|
221
|
+
const batch = this.flushing
|
|
222
|
+
? this.queue.splice(0)
|
|
223
|
+
: [...(this.inFlightBatch || []), ...this.queue.splice(0)];
|
|
224
|
+
if (!this.flushing)
|
|
225
|
+
this.inFlightBatch = null;
|
|
143
226
|
this.persist();
|
|
144
227
|
if (batch.length === 0)
|
|
145
228
|
return;
|
|
146
229
|
this.transport.send(this.endpoint, this.apiKey, { events: batch, sent_at: new Date().toISOString() }, { keepalive: true }).catch(() => { });
|
|
147
230
|
}
|
|
231
|
+
/** Total number of events pending delivery (queued + in-flight). */
|
|
148
232
|
get size() {
|
|
149
233
|
return this.queue.length + (this.inFlightBatch?.length || 0);
|
|
150
234
|
}
|
package/dist/queue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":";;;AACA,mCAAgE;AAEhE,MAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the Qurvo SDK.
|
|
3
|
+
*
|
|
4
|
+
* Only `apiKey` is required. All other fields have sensible defaults
|
|
5
|
+
* set by the platform-specific SDK wrapper (sdk-browser / sdk-node).
|
|
6
|
+
*/
|
|
1
7
|
export interface SdkConfig {
|
|
8
|
+
/** Project API key used to authenticate ingest requests (`x-api-key` header). */
|
|
2
9
|
apiKey: string;
|
|
10
|
+
/** Ingest endpoint URL. Defaults to `https://ingest.qurvo.pro/events/batch`. */
|
|
3
11
|
endpoint?: string;
|
|
12
|
+
/** Interval in milliseconds between automatic flushes. Default: `5000`. */
|
|
4
13
|
flushInterval?: number;
|
|
14
|
+
/** Number of events that triggers an immediate flush. Default: `20`. */
|
|
5
15
|
flushSize?: number;
|
|
16
|
+
/** Maximum number of events held in memory. When exceeded, the oldest event is dropped (FIFO). Default: `1000`. */
|
|
6
17
|
maxQueueSize?: number;
|
|
18
|
+
/** Optional logger function for debug output and error reporting. */
|
|
7
19
|
logger?: LogFn;
|
|
8
20
|
}
|
|
9
21
|
export interface EventPayload {
|
|
10
22
|
event: string;
|
|
11
23
|
distinct_id: string;
|
|
12
24
|
anonymous_id?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Event properties. The browser SDK automatically merges UTM parameters
|
|
27
|
+
* (`utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`)
|
|
28
|
+
* from the page URL into this object. Explicitly provided properties
|
|
29
|
+
* take priority over auto-captured UTM values.
|
|
30
|
+
*/
|
|
13
31
|
properties?: Record<string, unknown>;
|
|
14
32
|
user_properties?: Record<string, unknown>;
|
|
15
33
|
context?: EventContext;
|
|
@@ -39,14 +57,49 @@ export interface SendOptions {
|
|
|
39
57
|
signal?: AbortSignal;
|
|
40
58
|
}
|
|
41
59
|
export type LogFn = (message: string, error?: unknown) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Persistence layer for the event queue.
|
|
62
|
+
*
|
|
63
|
+
* Implementations back the in-memory queue with durable storage (e.g.
|
|
64
|
+
* `localStorage` in browsers) so events survive page reloads or crashes.
|
|
65
|
+
* Persistence is best-effort: failures are silently ignored by {@link EventQueue}.
|
|
66
|
+
*/
|
|
42
67
|
export interface QueuePersistence {
|
|
68
|
+
/** Persist the current queue snapshot. Called after every enqueue and flush. */
|
|
43
69
|
save(events: unknown[]): void;
|
|
70
|
+
/** Load previously persisted events. Called once during {@link EventQueue} construction. */
|
|
44
71
|
load(): unknown[];
|
|
45
72
|
}
|
|
46
73
|
export type CompressFn = (data: string) => Promise<Blob>;
|
|
74
|
+
/**
|
|
75
|
+
* Transport contract for sending event batches to the ingest API.
|
|
76
|
+
*
|
|
77
|
+
* The default implementation is {@link FetchTransport}. Custom transports
|
|
78
|
+
* can be provided via SDK configuration for non-standard environments.
|
|
79
|
+
*/
|
|
47
80
|
export interface Transport {
|
|
81
|
+
/**
|
|
82
|
+
* Send a batch payload to the ingest endpoint.
|
|
83
|
+
*
|
|
84
|
+
* @param endpoint - Full URL of the ingest endpoint.
|
|
85
|
+
* @param apiKey - Project API key for the `x-api-key` header.
|
|
86
|
+
* @param payload - Serializable payload (`{ events, sent_at }`).
|
|
87
|
+
* @param options - Optional send options (abort signal, keepalive).
|
|
88
|
+
* @returns `true` if the server accepted the batch (2xx/202),
|
|
89
|
+
* `false` for retryable failures (e.g. network timeout handled internally).
|
|
90
|
+
* @throws {@link QuotaExceededError} when the server responds 429 with `quota_limited`.
|
|
91
|
+
* @throws {@link NonRetryableError} on 4xx client errors (bad data, auth failure).
|
|
92
|
+
* @throws {@link Error} on 5xx server errors (retryable by the queue).
|
|
93
|
+
*/
|
|
48
94
|
send(endpoint: string, apiKey: string, payload: unknown, options?: SendOptions): Promise<boolean>;
|
|
49
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Thrown when the ingest API responds with 429 and `quota_limited: true`,
|
|
98
|
+
* indicating the project has exceeded its monthly event quota.
|
|
99
|
+
*
|
|
100
|
+
* When caught by {@link EventQueue}, the queue is drained and stopped
|
|
101
|
+
* to prevent further network requests until the billing period resets.
|
|
102
|
+
*/
|
|
50
103
|
export declare class QuotaExceededError extends Error {
|
|
51
104
|
constructor();
|
|
52
105
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC9B,IAAI,IAAI,OAAO,EAAE,CAAC;CACnB;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnG;AAED,qBAAa,kBAAmB,SAAQ,KAAK;;CAK5C;AAED,uEAAuE;AACvE,qBAAa,iBAAkB,SAAQ,KAAK;aACd,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAIhE"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mHAAmH;IACnH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAE/D;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC9B,4FAA4F;IAC5F,IAAI,IAAI,OAAO,EAAE,CAAC;CACnB;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnG;AAED;;;;;;GAMG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;;CAK5C;AAED,uEAAuE;AACvE,qBAAa,iBAAkB,SAAQ,KAAK;aACd,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAIhE"}
|
package/dist/types.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NonRetryableError = exports.QuotaExceededError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Thrown when the ingest API responds with 429 and `quota_limited: true`,
|
|
6
|
+
* indicating the project has exceeded its monthly event quota.
|
|
7
|
+
*
|
|
8
|
+
* When caught by {@link EventQueue}, the queue is drained and stopped
|
|
9
|
+
* to prevent further network requests until the billing period resets.
|
|
10
|
+
*/
|
|
4
11
|
class QuotaExceededError extends Error {
|
|
5
12
|
constructor() {
|
|
6
13
|
super('Monthly event limit exceeded');
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAwGA;;;;;;GAMG;AACH,MAAa,kBAAmB,SAAQ,KAAK;IAC3C;QACE,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED,uEAAuE;AACvE,MAAa,iBAAkB,SAAQ,KAAK;IACd;IAA5B,YAA4B,UAAkB,EAAE,OAAe;QAC7D,KAAK,CAAC,OAAO,CAAC,CAAC;QADW,eAAU,GAAV,UAAU,CAAQ;QAE5C,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AALD,8CAKC"}
|
package/package.json
CHANGED
package/dist/queue.test.d.ts
DELETED
package/dist/queue.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"queue.test.d.ts","sourceRoot":"","sources":["../src/queue.test.ts"],"names":[],"mappings":""}
|
package/dist/queue.test.js
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const vitest_1 = require("vitest");
|
|
4
|
-
const queue_1 = require("./queue");
|
|
5
|
-
const types_1 = require("./types");
|
|
6
|
-
function createMockTransport(sendFn) {
|
|
7
|
-
return { send: sendFn ?? vitest_1.vi.fn(async () => true) };
|
|
8
|
-
}
|
|
9
|
-
function createMockPersistence() {
|
|
10
|
-
const store = [];
|
|
11
|
-
return {
|
|
12
|
-
store,
|
|
13
|
-
save: vitest_1.vi.fn((events) => { store.length = 0; store.push(...events); }),
|
|
14
|
-
load: vitest_1.vi.fn(() => [...store]),
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
function createQueue(opts = {}) {
|
|
18
|
-
return new queue_1.EventQueue(opts.transport ?? createMockTransport(), 'https://ingest.test/v1/batch', 'test-key', 60_000, // large flush interval — we flush manually in tests
|
|
19
|
-
opts.flushSize ?? 100, opts.maxQueueSize ?? 1000, 30_000, undefined, opts.persistence);
|
|
20
|
-
}
|
|
21
|
-
(0, vitest_1.describe)('EventQueue', () => {
|
|
22
|
-
(0, vitest_1.beforeEach)(() => {
|
|
23
|
-
vitest_1.vi.restoreAllMocks();
|
|
24
|
-
});
|
|
25
|
-
(0, vitest_1.it)('enqueues events and reports size', () => {
|
|
26
|
-
const q = createQueue();
|
|
27
|
-
q.enqueue({ id: 1 });
|
|
28
|
-
q.enqueue({ id: 2 });
|
|
29
|
-
(0, vitest_1.expect)(q.size).toBe(2);
|
|
30
|
-
});
|
|
31
|
-
(0, vitest_1.it)('flushes events via transport', async () => {
|
|
32
|
-
const send = vitest_1.vi.fn(async () => true);
|
|
33
|
-
const q = createQueue({ transport: createMockTransport(send) });
|
|
34
|
-
q.enqueue({ id: 1 });
|
|
35
|
-
q.enqueue({ id: 2 });
|
|
36
|
-
await q.flush();
|
|
37
|
-
(0, vitest_1.expect)(send).toHaveBeenCalledOnce();
|
|
38
|
-
const payload = send.mock.calls[0][2];
|
|
39
|
-
(0, vitest_1.expect)(payload.events).toHaveLength(2);
|
|
40
|
-
(0, vitest_1.expect)(q.size).toBe(0);
|
|
41
|
-
});
|
|
42
|
-
(0, vitest_1.it)('re-queues events on transport failure (returns false)', async () => {
|
|
43
|
-
const send = vitest_1.vi.fn(async () => false);
|
|
44
|
-
const q = createQueue({ transport: createMockTransport(send) });
|
|
45
|
-
q.enqueue({ id: 1 });
|
|
46
|
-
await q.flush();
|
|
47
|
-
(0, vitest_1.expect)(q.size).toBe(1);
|
|
48
|
-
});
|
|
49
|
-
(0, vitest_1.it)('re-queues events on transport error (network)', async () => {
|
|
50
|
-
const send = vitest_1.vi.fn(async () => { throw new Error('network'); });
|
|
51
|
-
const q = createQueue({ transport: createMockTransport(send) });
|
|
52
|
-
q.enqueue({ id: 1 });
|
|
53
|
-
await q.flush();
|
|
54
|
-
(0, vitest_1.expect)(q.size).toBe(1);
|
|
55
|
-
});
|
|
56
|
-
(0, vitest_1.it)('drops batch on NonRetryableError', async () => {
|
|
57
|
-
const send = vitest_1.vi.fn(async () => { throw new types_1.NonRetryableError(400, 'bad'); });
|
|
58
|
-
const q = createQueue({ transport: createMockTransport(send) });
|
|
59
|
-
q.enqueue({ id: 1 });
|
|
60
|
-
await q.flush();
|
|
61
|
-
(0, vitest_1.expect)(q.size).toBe(0);
|
|
62
|
-
});
|
|
63
|
-
(0, vitest_1.it)('clears queue and stops on QuotaExceededError', async () => {
|
|
64
|
-
const send = vitest_1.vi.fn(async () => { throw new types_1.QuotaExceededError(); });
|
|
65
|
-
const q = createQueue({ transport: createMockTransport(send) });
|
|
66
|
-
q.enqueue({ id: 1 });
|
|
67
|
-
q.enqueue({ id: 2 });
|
|
68
|
-
await q.flush();
|
|
69
|
-
(0, vitest_1.expect)(q.size).toBe(0);
|
|
70
|
-
});
|
|
71
|
-
(0, vitest_1.it)('drops oldest event when maxQueueSize is reached', () => {
|
|
72
|
-
const q = createQueue({ maxQueueSize: 3 });
|
|
73
|
-
q.enqueue({ id: 1 });
|
|
74
|
-
q.enqueue({ id: 2 });
|
|
75
|
-
q.enqueue({ id: 3 });
|
|
76
|
-
q.enqueue({ id: 4 });
|
|
77
|
-
(0, vitest_1.expect)(q.size).toBe(3);
|
|
78
|
-
});
|
|
79
|
-
(0, vitest_1.describe)('flushForUnload — in-flight batch recovery', () => {
|
|
80
|
-
(0, vitest_1.it)('includes in-flight batch in unload flush', async () => {
|
|
81
|
-
let resolveSend;
|
|
82
|
-
const sendPromise = new Promise((r) => { resolveSend = () => r(true); });
|
|
83
|
-
const sendCalls = [];
|
|
84
|
-
const send = vitest_1.vi.fn(async (...args) => {
|
|
85
|
-
sendCalls.push(args);
|
|
86
|
-
if (sendCalls.length === 1)
|
|
87
|
-
return sendPromise; // first call blocks
|
|
88
|
-
return true;
|
|
89
|
-
});
|
|
90
|
-
const q = createQueue({ transport: createMockTransport(send), flushSize: 2 });
|
|
91
|
-
q.enqueue({ id: 1 });
|
|
92
|
-
q.enqueue({ id: 2 });
|
|
93
|
-
q.enqueue({ id: 3 }); // stays in queue
|
|
94
|
-
// Start flush — takes [1, 2] as in-flight, [3] remains
|
|
95
|
-
const flushPromise = q.flush();
|
|
96
|
-
// Before flush completes, simulate page unload
|
|
97
|
-
q.flushForUnload();
|
|
98
|
-
// unload should send ALL events: in-flight [1,2] + queue [3]
|
|
99
|
-
(0, vitest_1.expect)(sendCalls).toHaveLength(2);
|
|
100
|
-
const unloadPayload = sendCalls[1][2];
|
|
101
|
-
(0, vitest_1.expect)(unloadPayload.events).toHaveLength(3);
|
|
102
|
-
(0, vitest_1.expect)(unloadPayload.events.map((e) => e.id)).toEqual([1, 2, 3]);
|
|
103
|
-
// Let the original flush complete
|
|
104
|
-
resolveSend();
|
|
105
|
-
await flushPromise;
|
|
106
|
-
});
|
|
107
|
-
(0, vitest_1.it)('sends only queue events when no in-flight batch', () => {
|
|
108
|
-
const send = vitest_1.vi.fn(async () => true);
|
|
109
|
-
const q = createQueue({ transport: createMockTransport(send) });
|
|
110
|
-
q.enqueue({ id: 1 });
|
|
111
|
-
q.flushForUnload();
|
|
112
|
-
(0, vitest_1.expect)(send).toHaveBeenCalledOnce();
|
|
113
|
-
const payload = send.mock.calls[0][2];
|
|
114
|
-
(0, vitest_1.expect)(payload.events).toHaveLength(1);
|
|
115
|
-
(0, vitest_1.expect)(q.size).toBe(0);
|
|
116
|
-
});
|
|
117
|
-
(0, vitest_1.it)('does nothing when queue and in-flight are empty', () => {
|
|
118
|
-
const send = vitest_1.vi.fn(async () => true);
|
|
119
|
-
const q = createQueue({ transport: createMockTransport(send) });
|
|
120
|
-
q.flushForUnload();
|
|
121
|
-
(0, vitest_1.expect)(send).not.toHaveBeenCalled();
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
(0, vitest_1.describe)('persistence', () => {
|
|
125
|
-
(0, vitest_1.it)('saves queue to persistence on enqueue', () => {
|
|
126
|
-
const persistence = createMockPersistence();
|
|
127
|
-
const q = createQueue({ persistence });
|
|
128
|
-
q.enqueue({ id: 1 });
|
|
129
|
-
(0, vitest_1.expect)(persistence.save).toHaveBeenCalled();
|
|
130
|
-
(0, vitest_1.expect)(persistence.store).toEqual([{ id: 1 }]);
|
|
131
|
-
});
|
|
132
|
-
(0, vitest_1.it)('restores events from persistence on construction', () => {
|
|
133
|
-
const persistence = createMockPersistence();
|
|
134
|
-
persistence.store.push({ id: 'old1' }, { id: 'old2' });
|
|
135
|
-
const q = createQueue({ persistence });
|
|
136
|
-
(0, vitest_1.expect)(q.size).toBe(2);
|
|
137
|
-
});
|
|
138
|
-
(0, vitest_1.it)('clears persistence after successful flush', async () => {
|
|
139
|
-
const persistence = createMockPersistence();
|
|
140
|
-
const q = createQueue({ persistence });
|
|
141
|
-
q.enqueue({ id: 1 });
|
|
142
|
-
await q.flush();
|
|
143
|
-
(0, vitest_1.expect)(persistence.store).toEqual([]);
|
|
144
|
-
});
|
|
145
|
-
(0, vitest_1.it)('persists remaining events after partial flush', async () => {
|
|
146
|
-
const persistence = createMockPersistence();
|
|
147
|
-
const q = createQueue({ persistence, flushSize: 1 });
|
|
148
|
-
q.enqueue({ id: 1 });
|
|
149
|
-
q.enqueue({ id: 2 });
|
|
150
|
-
await q.flush(); // sends first, keeps second
|
|
151
|
-
(0, vitest_1.expect)(persistence.store).toEqual([{ id: 2 }]);
|
|
152
|
-
});
|
|
153
|
-
(0, vitest_1.it)('persists on flushForUnload (clears queue)', () => {
|
|
154
|
-
const persistence = createMockPersistence();
|
|
155
|
-
const q = createQueue({ persistence });
|
|
156
|
-
q.enqueue({ id: 1 });
|
|
157
|
-
q.flushForUnload();
|
|
158
|
-
// queue should be empty after unload flush
|
|
159
|
-
(0, vitest_1.expect)(persistence.store).toEqual([]);
|
|
160
|
-
});
|
|
161
|
-
(0, vitest_1.it)('handles persistence load failure gracefully', () => {
|
|
162
|
-
const persistence = {
|
|
163
|
-
save: vitest_1.vi.fn(),
|
|
164
|
-
load: vitest_1.vi.fn(() => { throw new Error('corrupt'); }),
|
|
165
|
-
};
|
|
166
|
-
const q = createQueue({ persistence });
|
|
167
|
-
(0, vitest_1.expect)(q.size).toBe(0);
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
(0, vitest_1.describe)('size', () => {
|
|
171
|
-
(0, vitest_1.it)('includes in-flight batch during flush', async () => {
|
|
172
|
-
let resolveSend;
|
|
173
|
-
const send = vitest_1.vi.fn(() => new Promise((r) => { resolveSend = () => r(true); }));
|
|
174
|
-
const q = createQueue({ transport: createMockTransport(send) });
|
|
175
|
-
q.enqueue({ id: 1 });
|
|
176
|
-
q.enqueue({ id: 2 });
|
|
177
|
-
(0, vitest_1.expect)(q.size).toBe(2);
|
|
178
|
-
// Start flush manually — events move to inFlightBatch
|
|
179
|
-
const flushPromise = q.flush();
|
|
180
|
-
(0, vitest_1.expect)(q.size).toBe(2); // 2 in-flight, 0 in queue
|
|
181
|
-
resolveSend();
|
|
182
|
-
await flushPromise;
|
|
183
|
-
(0, vitest_1.expect)(q.size).toBe(0); // all sent
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
//# sourceMappingURL=queue.test.js.map
|
package/dist/queue.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"queue.test.js","sourceRoot":"","sources":["../src/queue.test.ts"],"names":[],"mappings":"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"}
|