react-native-qalink 0.6.1 → 0.7.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 (36) hide show
  1. package/README.md +127 -1
  2. package/dist/core/MiddlewarePipeline.d.ts +37 -0
  3. package/dist/core/MiddlewarePipeline.d.ts.map +1 -0
  4. package/dist/core/MiddlewarePipeline.js +58 -0
  5. package/dist/core/MiddlewarePipeline.js.map +1 -0
  6. package/dist/core/OfflineQueue.d.ts +48 -0
  7. package/dist/core/OfflineQueue.d.ts.map +1 -0
  8. package/dist/core/OfflineQueue.js +145 -0
  9. package/dist/core/OfflineQueue.js.map +1 -0
  10. package/dist/core/session.d.ts +2 -0
  11. package/dist/core/session.d.ts.map +1 -1
  12. package/dist/core/session.js +9 -0
  13. package/dist/core/session.js.map +1 -1
  14. package/dist/index.d.ts +79 -13
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +160 -28
  17. package/dist/index.js.map +1 -1
  18. package/dist/trackers/NavigationLoopTracker.d.ts +31 -0
  19. package/dist/trackers/NavigationLoopTracker.d.ts.map +1 -0
  20. package/dist/trackers/NavigationLoopTracker.js +73 -0
  21. package/dist/trackers/NavigationLoopTracker.js.map +1 -0
  22. package/dist/trackers/RageClickTracker.d.ts +33 -0
  23. package/dist/trackers/RageClickTracker.d.ts.map +1 -0
  24. package/dist/trackers/RageClickTracker.js +56 -0
  25. package/dist/trackers/RageClickTracker.js.map +1 -0
  26. package/dist/trackers/SilentFailureTracker.d.ts +55 -0
  27. package/dist/trackers/SilentFailureTracker.d.ts.map +1 -0
  28. package/dist/trackers/SilentFailureTracker.js +84 -0
  29. package/dist/trackers/SilentFailureTracker.js.map +1 -0
  30. package/dist/transport/websocket.d.ts +18 -9
  31. package/dist/transport/websocket.d.ts.map +1 -1
  32. package/dist/transport/websocket.js +66 -30
  33. package/dist/transport/websocket.js.map +1 -1
  34. package/dist/types/index.d.ts +90 -10
  35. package/dist/types/index.d.ts.map +1 -1
  36. package/package.json +1 -1
package/README.md CHANGED
@@ -351,6 +351,122 @@ QALink.init({
351
351
 
352
352
  ---
353
353
 
354
+ ## 🧠 Advanced QA Features (v0.7.0)
355
+
356
+ ### Rage Click Detection
357
+
358
+ Detects when a user taps the same element multiple times rapidly — a strong frustration signal.
359
+
360
+ ```typescript
361
+ // 1. Enable (once, after init)
362
+ QALink.enableRageClickDetection({ threshold: 3, windowMs: 600 });
363
+
364
+ // 2. Call from any onPress handler
365
+ <Button
366
+ onPress={() => {
367
+ QALink.trackUIInteraction('checkout-submit-btn');
368
+ handleSubmit();
369
+ }}
370
+ />
371
+ ```
372
+
373
+ A `rage_click` event fires in the dashboard when the threshold is hit.
374
+
375
+ ---
376
+
377
+ ### Navigation Loop Detection
378
+
379
+ Detects when the user bounces back and forth between the same two screens (A→B→A→B…). Signals broken back navigation or an unresolved error state.
380
+
381
+ ```typescript
382
+ // Enable (once, after init)
383
+ QALink.enableNavigationLoopDetection(3); // fires after 3 alternations
384
+
385
+ // Automatically triggered by setScreen() and startPackage()
386
+ QALink.setScreen('CheckoutScreen');
387
+ ```
388
+
389
+ A `navigation_loop` event fires in the dashboard with the full navigation pattern.
390
+
391
+ ---
392
+
393
+ ### Silent Failure Detection
394
+
395
+ The hardest QA bug: API returns 200 OK but the data is null/empty. No error, no crash — the app just silently breaks.
396
+
397
+ ```typescript
398
+ const orders = await fetchOrders(userId); // 200 OK
399
+
400
+ QALink.trackDataState({
401
+ context: 'orders_list',
402
+ expected: Array.isArray(orders) && orders.length > 0,
403
+ actual: orders,
404
+ statusCode: 200,
405
+ url: '/api/orders',
406
+ });
407
+ // If orders is [] → fires a silent_failure event in the dashboard
408
+ ```
409
+
410
+ Returns `true` if the check passes, `false` if a failure was detected.
411
+
412
+ ---
413
+
414
+ ### Middleware (Event Processing Pipeline)
415
+
416
+ Intercept, enrich, filter, or transform any event before it's sent.
417
+
418
+ ```typescript
419
+ // Drop noisy console_log events in production
420
+ QALink.use((event, next) => {
421
+ if (event.type === 'console_log') return; // drop
422
+ next(event);
423
+ });
424
+
425
+ // Add a custom tag to every event
426
+ QALink.use((event, next) => {
427
+ next({ ...event, _release: '2.1.0' } as typeof event);
428
+ });
429
+
430
+ // Log every event locally for debugging
431
+ QALink.use((event, next) => {
432
+ console.log('[QALink middleware]', event.type);
433
+ next(event);
434
+ });
435
+ ```
436
+
437
+ Middlewares run in insertion order. Calling `next` is optional — skipping it drops the event.
438
+
439
+ ---
440
+
441
+ ### Offline-First Queue
442
+
443
+ Events are buffered automatically when the connection drops. Auto-flush triggers:
444
+
445
+ ```typescript
446
+ QALink.init({
447
+ apiKey: 'qlk_...',
448
+ appVersion: '1.0.0',
449
+ offlineQueue: {
450
+ maxSize: 500, // max buffered events (drops oldest when full)
451
+ flushOnCount: 20, // auto-flush when 20 events are buffered
452
+ flushIntervalMs: 30_000, // auto-flush every 30s
453
+ },
454
+ });
455
+
456
+ // Manual flush (e.g. before app goes to background)
457
+ QALink.flush();
458
+ ```
459
+
460
+ If `@react-native-async-storage/async-storage` is installed, events also persist across app restarts.
461
+
462
+ ---
463
+
464
+ ### Sequence Numbers
465
+
466
+ Every envelope sent to the dashboard now includes a `sequenceNumber` — a monotonically increasing counter per session. The dashboard can use it to detect out-of-order or missing events.
467
+
468
+ ---
469
+
354
470
  ## 📦 Event Packages (v0.6.0)
355
471
 
356
472
  Los **Event Packages** agrupan **todos los eventos** de una pantalla en un solo payload que se envía cuando el usuario sale de ella. Incluyen métricas pre-calculadas y el historial completo de eventos.
@@ -421,6 +537,9 @@ El SDK captura automáticamente:
421
537
  |------|-------------|
422
538
  | `session_start` | Inicio de sesión |
423
539
  | `event_package` | Batch de eventos de una pantalla (v0.6.0) |
540
+ | `rage_click` | Usuario tapeó el mismo elemento N veces (v0.7.0) |
541
+ | `navigation_loop` | Usuario rebotando entre mismas pantallas (v0.7.0) |
542
+ | `silent_failure` | API 200 OK con datos inválidos/vacíos (v0.7.0) |
424
543
  | `http_request` | Request HTTP (fetch/axios) |
425
544
  | `user_log` | Logs con debug/info/warn/error/critical |
426
545
  | `custom_event` | Eventos custom con logEvent() |
@@ -550,6 +669,7 @@ import { QALink } from 'react-native-qalink';
550
669
  |--------|-------------|
551
670
  | **`init(config)`** | Inicializa el SDK. Requerido antes de todo. |
552
671
  | **`interceptAxios(instance)`** | Registra una instancia de Axios. |
672
+ | **`use(middleware)`** | Agrega un middleware al pipeline de eventos. |
553
673
  | **`setUserContext(ctx)`** | Adjunta datos del usuario a todos los eventos. |
554
674
  | **`setCustomContext(ctx)`** | Adjunta datos custom a todos los eventos. |
555
675
  | **`clearContext()`** | Limpia usuario y contexto custom. |
@@ -561,14 +681,20 @@ import { QALink } from 'react-native-qalink';
561
681
  | **`logEvent(name, data?)`** | Evento custom de negocio. |
562
682
  | **`addBreadcrumb(action, data?)`** | Breadcrumb manual. |
563
683
  | **`logRequest(options)`** | Registra request de red manualmente. |
564
- | **`setScreen(name)`** | Cambia la pantalla actual (solo breadcrumb). |
684
+ | **`setScreen(name)`** | Cambia la pantalla actual + breadcrumb + loop detection. |
565
685
  | **`startPackage(screenName)`** | Inicia un Event Package para esa pantalla. |
566
686
  | **`endPackage()`** | Cierra el package activo y lo envía. |
687
+ | **`flush()`** | Envía inmediatamente todos los eventos en cola offline. |
688
+ | **`enableRageClickDetection(options?)`** | Activa detección de rage clicks. |
689
+ | **`trackUIInteraction(target)`** | Registra tap para rage click. |
690
+ | **`enableNavigationLoopDetection(threshold?)`** | Activa detección de loops de navegación. |
691
+ | **`trackDataState(check)`** | Detecta silent failures (API 200 con datos inválidos). |
567
692
  | **`captureScreen(label?)`** | Captura la pantalla completa. |
568
693
  | **`captureRef(ref, label?)`** | Captura un componente específico. |
569
694
  | **`configureHTTP(config)`** | Actualiza config HTTP en runtime. |
570
695
  | **`getDeviceId()`** | Devuelve el deviceId de la sesión. |
571
696
  | **`getStatus()`** | Estado de la conexión WebSocket. |
697
+ | **`getQueueSize()`** | Número de eventos en cola offline. |
572
698
  | **`destroy()`** | Limpia interceptores y desconecta. |
573
699
 
574
700
  **Hook:**
@@ -0,0 +1,37 @@
1
+ /**
2
+ * MiddlewarePipeline — chain of event processors applied before sending.
3
+ *
4
+ * Each middleware receives an event and a `next` callback:
5
+ * - Call `next(event)` to pass the (optionally modified) event forward.
6
+ * - Don't call `next` to drop the event entirely.
7
+ * - Mutate or replace the event to enrich/transform it.
8
+ *
9
+ * @example
10
+ * pipeline.use((event, next) => {
11
+ * // Drop noisy console logs in production
12
+ * if (event.type === 'console_log') return;
13
+ * next(event);
14
+ * });
15
+ *
16
+ * @example
17
+ * pipeline.use((event, next) => {
18
+ * // Enrich every event with a custom tag
19
+ * next({ ...event, _tag: 'v2' } as typeof event);
20
+ * });
21
+ */
22
+ import type { QALinkEvent } from '../types';
23
+ export type EventMiddleware = (event: QALinkEvent, next: (event: QALinkEvent) => void) => void;
24
+ export declare class MiddlewarePipeline {
25
+ private readonly middlewares;
26
+ /** Register a middleware. Middlewares run in insertion order. */
27
+ use(middleware: EventMiddleware): this;
28
+ /** Clear all registered middlewares. */
29
+ clear(): void;
30
+ get count(): number;
31
+ /**
32
+ * Run `event` through the full middleware chain.
33
+ * `finalHandler` is called only if every middleware calls `next`.
34
+ */
35
+ process(event: QALinkEvent, finalHandler: (event: QALinkEvent) => void): void;
36
+ }
37
+ //# sourceMappingURL=MiddlewarePipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MiddlewarePipeline.d.ts","sourceRoot":"","sources":["../../src/core/MiddlewarePipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,MAAM,MAAM,eAAe,GAAG,CAC5B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,KAC/B,IAAI,CAAC;AAEV,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyB;IAErD,iEAAiE;IACjE,GAAG,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI;IAKtC,wCAAwC;IACxC,KAAK,IAAI,IAAI;IAIb,IAAI,KAAK,IAAI,MAAM,CAElB;IAED;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;CAa9E"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ /**
3
+ * MiddlewarePipeline — chain of event processors applied before sending.
4
+ *
5
+ * Each middleware receives an event and a `next` callback:
6
+ * - Call `next(event)` to pass the (optionally modified) event forward.
7
+ * - Don't call `next` to drop the event entirely.
8
+ * - Mutate or replace the event to enrich/transform it.
9
+ *
10
+ * @example
11
+ * pipeline.use((event, next) => {
12
+ * // Drop noisy console logs in production
13
+ * if (event.type === 'console_log') return;
14
+ * next(event);
15
+ * });
16
+ *
17
+ * @example
18
+ * pipeline.use((event, next) => {
19
+ * // Enrich every event with a custom tag
20
+ * next({ ...event, _tag: 'v2' } as typeof event);
21
+ * });
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.MiddlewarePipeline = void 0;
25
+ class MiddlewarePipeline {
26
+ constructor() {
27
+ this.middlewares = [];
28
+ }
29
+ /** Register a middleware. Middlewares run in insertion order. */
30
+ use(middleware) {
31
+ this.middlewares.push(middleware);
32
+ return this;
33
+ }
34
+ /** Clear all registered middlewares. */
35
+ clear() {
36
+ this.middlewares.length = 0;
37
+ }
38
+ get count() {
39
+ return this.middlewares.length;
40
+ }
41
+ /**
42
+ * Run `event` through the full middleware chain.
43
+ * `finalHandler` is called only if every middleware calls `next`.
44
+ */
45
+ process(event, finalHandler) {
46
+ const chain = this.middlewares;
47
+ const run = (index, current) => {
48
+ if (index >= chain.length) {
49
+ finalHandler(current);
50
+ return;
51
+ }
52
+ chain[index](current, (next) => run(index + 1, next));
53
+ };
54
+ run(0, event);
55
+ }
56
+ }
57
+ exports.MiddlewarePipeline = MiddlewarePipeline;
58
+ //# sourceMappingURL=MiddlewarePipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MiddlewarePipeline.js","sourceRoot":"","sources":["../../src/core/MiddlewarePipeline.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AASH,MAAa,kBAAkB;IAA/B;QACmB,gBAAW,GAAsB,EAAE,CAAC;IAkCvD,CAAC;IAhCC,iEAAiE;IACjE,GAAG,CAAC,UAA2B;QAC7B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wCAAwC;IACxC,KAAK;QACH,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,KAAkB,EAAE,YAA0C;QACpE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC;QAE/B,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,OAAoB,EAAQ,EAAE;YACxD,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC1B,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,OAAO;YACT,CAAC;YACD,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC;QAEF,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAChB,CAAC;CACF;AAnCD,gDAmCC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * OfflineQueue — FIFO event queue with optional AsyncStorage persistence.
3
+ *
4
+ * - Falls back to pure in-memory when AsyncStorage is not installed.
5
+ * - Respects a max-size limit (drops oldest event when full).
6
+ * - Supports two auto-flush triggers:
7
+ * · count-based: flush when queue reaches `flushOnCount` events.
8
+ * · time-based: flush every `flushIntervalMs` milliseconds.
9
+ * - Persists across app restarts when AsyncStorage is available.
10
+ */
11
+ import type { QALinkEvent } from '../types';
12
+ export interface OfflineQueueConfig {
13
+ maxSize?: number;
14
+ /** Trigger flush when this many events are buffered. @default 20 */
15
+ flushOnCount?: number;
16
+ /** Trigger flush every N milliseconds. @default 30000 */
17
+ flushIntervalMs?: number;
18
+ debug?: boolean;
19
+ }
20
+ type FlushCallback = (events: QALinkEvent[]) => void;
21
+ export declare class OfflineQueue {
22
+ private memory;
23
+ private readonly maxSize;
24
+ private readonly flushOnCount;
25
+ private readonly flushIntervalMs;
26
+ private readonly debug;
27
+ private flushTimer;
28
+ private onFlush;
29
+ private storage;
30
+ constructor(config?: OfflineQueueConfig);
31
+ private tryBindAsyncStorage;
32
+ setFlushCallback(cb: FlushCallback): void;
33
+ startAutoFlush(): void;
34
+ stopAutoFlush(): void;
35
+ push(event: QALinkEvent): Promise<void>;
36
+ /** Remove and return all buffered events. Clears persistence. */
37
+ drain(): QALinkEvent[];
38
+ peek(): readonly QALinkEvent[];
39
+ get size(): number;
40
+ /** Load events persisted from a previous session and merge into current queue. */
41
+ loadPersisted(): Promise<void>;
42
+ private persist;
43
+ private clearPersisted;
44
+ private triggerFlush;
45
+ private log;
46
+ }
47
+ export {};
48
+ //# sourceMappingURL=OfflineQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OfflineQueue.d.ts","sourceRoot":"","sources":["../../src/core/OfflineQueue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAO5C,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,KAAK,aAAa,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;AAQrD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;IAChC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAoC;gBAEvC,MAAM,GAAE,kBAAuB;IAU3C,OAAO,CAAC,mBAAmB;IAa3B,gBAAgB,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI;IAMzC,cAAc,IAAI,IAAI;IAUtB,aAAa,IAAI,IAAI;IASf,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAc7C,iEAAiE;IACjE,KAAK,IAAI,WAAW,EAAE;IAOtB,IAAI,IAAI,SAAS,WAAW,EAAE;IAI9B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAID,kFAAkF;IAC5E,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;YAwBtB,OAAO;IASrB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,GAAG;CAGZ"}
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ /**
3
+ * OfflineQueue — FIFO event queue with optional AsyncStorage persistence.
4
+ *
5
+ * - Falls back to pure in-memory when AsyncStorage is not installed.
6
+ * - Respects a max-size limit (drops oldest event when full).
7
+ * - Supports two auto-flush triggers:
8
+ * · count-based: flush when queue reaches `flushOnCount` events.
9
+ * · time-based: flush every `flushIntervalMs` milliseconds.
10
+ * - Persists across app restarts when AsyncStorage is available.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.OfflineQueue = void 0;
14
+ const STORAGE_KEY = '__qalink_offline_queue__';
15
+ const DEFAULT_MAX_SIZE = 500;
16
+ const DEFAULT_FLUSH_COUNT = 20;
17
+ const DEFAULT_FLUSH_INTERVAL_MS = 30000;
18
+ class OfflineQueue {
19
+ constructor(config = {}) {
20
+ var _a, _b, _c, _d;
21
+ this.memory = [];
22
+ this.flushTimer = null;
23
+ this.onFlush = null;
24
+ this.storage = null;
25
+ this.maxSize = (_a = config.maxSize) !== null && _a !== void 0 ? _a : DEFAULT_MAX_SIZE;
26
+ this.flushOnCount = (_b = config.flushOnCount) !== null && _b !== void 0 ? _b : DEFAULT_FLUSH_COUNT;
27
+ this.flushIntervalMs = (_c = config.flushIntervalMs) !== null && _c !== void 0 ? _c : DEFAULT_FLUSH_INTERVAL_MS;
28
+ this.debug = (_d = config.debug) !== null && _d !== void 0 ? _d : false;
29
+ this.tryBindAsyncStorage();
30
+ }
31
+ // ─── Setup ─────────────────────────────────────────────────────────────────
32
+ tryBindAsyncStorage() {
33
+ try {
34
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
35
+ const AS = require('@react-native-async-storage/async-storage').default;
36
+ if (AS && typeof AS.getItem === 'function') {
37
+ this.storage = AS;
38
+ this.log('AsyncStorage persistence enabled');
39
+ }
40
+ }
41
+ catch (_a) {
42
+ this.log('AsyncStorage unavailable — in-memory queue only');
43
+ }
44
+ }
45
+ setFlushCallback(cb) {
46
+ this.onFlush = cb;
47
+ }
48
+ // ─── Auto-flush lifecycle ──────────────────────────────────────────────────
49
+ startAutoFlush() {
50
+ if (this.flushTimer)
51
+ return;
52
+ this.flushTimer = setInterval(() => {
53
+ if (this.memory.length > 0) {
54
+ this.log(`Auto-flush (time) — ${this.memory.length} events`);
55
+ this.triggerFlush();
56
+ }
57
+ }, this.flushIntervalMs);
58
+ }
59
+ stopAutoFlush() {
60
+ if (this.flushTimer) {
61
+ clearInterval(this.flushTimer);
62
+ this.flushTimer = null;
63
+ }
64
+ }
65
+ // ─── Queue operations ──────────────────────────────────────────────────────
66
+ async push(event) {
67
+ if (this.memory.length >= this.maxSize) {
68
+ this.memory.shift();
69
+ this.log('Queue full — dropped oldest event');
70
+ }
71
+ this.memory.push(event);
72
+ await this.persist();
73
+ if (this.memory.length >= this.flushOnCount) {
74
+ this.log(`Auto-flush (count) — ${this.memory.length} events`);
75
+ this.triggerFlush();
76
+ }
77
+ }
78
+ /** Remove and return all buffered events. Clears persistence. */
79
+ drain() {
80
+ const events = [...this.memory];
81
+ this.memory = [];
82
+ this.clearPersisted();
83
+ return events;
84
+ }
85
+ peek() {
86
+ return this.memory;
87
+ }
88
+ get size() {
89
+ return this.memory.length;
90
+ }
91
+ // ─── Persistence ───────────────────────────────────────────────────────────
92
+ /** Load events persisted from a previous session and merge into current queue. */
93
+ async loadPersisted() {
94
+ if (!this.storage)
95
+ return;
96
+ try {
97
+ const raw = await this.storage.getItem(STORAGE_KEY);
98
+ if (!raw)
99
+ return;
100
+ const parsed = JSON.parse(raw);
101
+ if (!Array.isArray(parsed))
102
+ return;
103
+ const existingIds = new Set(this.memory.map((e) => e.id).filter(Boolean));
104
+ for (const ev of parsed) {
105
+ const id = ev.id;
106
+ if (!id || !existingIds.has(id)) {
107
+ this.memory.push(ev);
108
+ }
109
+ }
110
+ this.log(`Loaded ${parsed.length} persisted events from previous session`);
111
+ }
112
+ catch (_a) {
113
+ this.log('Failed to load persisted queue — starting fresh');
114
+ }
115
+ }
116
+ async persist() {
117
+ if (!this.storage)
118
+ return;
119
+ try {
120
+ await this.storage.setItem(STORAGE_KEY, JSON.stringify(this.memory));
121
+ }
122
+ catch (_a) {
123
+ // Ignore silently — persistence is best-effort
124
+ }
125
+ }
126
+ clearPersisted() {
127
+ var _a;
128
+ (_a = this.storage) === null || _a === void 0 ? void 0 : _a.removeItem(STORAGE_KEY).catch(() => { });
129
+ }
130
+ // ─── Flush trigger ─────────────────────────────────────────────────────────
131
+ triggerFlush() {
132
+ if (!this.onFlush)
133
+ return;
134
+ const events = this.drain();
135
+ if (events.length > 0)
136
+ this.onFlush(events);
137
+ }
138
+ // ─── Helpers ───────────────────────────────────────────────────────────────
139
+ log(...args) {
140
+ if (this.debug)
141
+ console.log('[QALink OfflineQueue]', ...args);
142
+ }
143
+ }
144
+ exports.OfflineQueue = OfflineQueue;
145
+ //# sourceMappingURL=OfflineQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OfflineQueue.js","sourceRoot":"","sources":["../../src/core/OfflineQueue.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,8 @@ import { DeviceInfo } from '../types';
2
2
  export declare function generateId(): string;
3
3
  export declare function getSessionId(): string;
4
4
  export declare function resetSession(): string;
5
+ export declare function nextSequenceNumber(): number;
6
+ export declare function resetSequenceCounter(): void;
5
7
  export declare function getDeviceInfo(appVersion: string): Promise<DeviceInfo>;
6
8
  export declare function sanitizeBody(body: unknown, logBodies: boolean): unknown;
7
9
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAItC,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAmB3E;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAGvE"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAKtC,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAmB3E;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAGvE"}
@@ -3,9 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateId = generateId;
4
4
  exports.getSessionId = getSessionId;
5
5
  exports.resetSession = resetSession;
6
+ exports.nextSequenceNumber = nextSequenceNumber;
7
+ exports.resetSequenceCounter = resetSequenceCounter;
6
8
  exports.getDeviceInfo = getDeviceInfo;
7
9
  exports.sanitizeBody = sanitizeBody;
8
10
  let currentSessionId = null;
11
+ let sequenceCounter = 0;
9
12
  function generateId() {
10
13
  return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
11
14
  }
@@ -19,6 +22,12 @@ function resetSession() {
19
22
  currentSessionId = generateId();
20
23
  return currentSessionId;
21
24
  }
25
+ function nextSequenceNumber() {
26
+ return ++sequenceCounter;
27
+ }
28
+ function resetSequenceCounter() {
29
+ sequenceCounter = 0;
30
+ }
22
31
  async function getDeviceInfo(appVersion) {
23
32
  var _a, _b;
24
33
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":";;AAIA,gCAEC;AAED,oCAKC;AAED,oCAGC;AAED,sCAmBC;AAED,oCAGC;AA1CD,IAAI,gBAAgB,GAAkB,IAAI,CAAC;AAE3C,SAAgB,UAAU;IACxB,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC;AAED,SAAgB,YAAY;IAC1B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,gBAAgB,GAAG,UAAU,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAgB,YAAY;IAC1B,gBAAgB,GAAG,UAAU,EAAE,CAAC;IAChC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,UAAkB;;IACpD,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;QAC7C,OAAO;YACL,QAAQ,EAAE,QAAQ,CAAC,EAAuB;YAC1C,SAAS,EAAE,MAAA,MAAA,QAAQ,CAAC,OAAO,0CAAE,QAAQ,EAAE,mCAAI,SAAS;YACpD,UAAU;YACV,WAAW,EAAE,SAAS;YACtB,SAAS,EAAE,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;SAC3E,CAAC;IACJ,CAAC;IAAC,WAAM,CAAC;QACP,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,SAAS,EAAE,SAAS;YACpB,UAAU;YACV,WAAW,EAAE,SAAS;YACtB,SAAS,EAAE,SAAS;SACrB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,IAAa,EAAE,SAAkB;IAC5D,IAAI,CAAC,SAAS;QAAE,OAAO,0CAA0C,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":";;AAKA,gCAEC;AAED,oCAKC;AAED,oCAGC;AAED,gDAEC;AAED,oDAEC;AAED,sCAmBC;AAED,oCAGC;AAnDD,IAAI,gBAAgB,GAAkB,IAAI,CAAC;AAC3C,IAAI,eAAe,GAAG,CAAC,CAAC;AAExB,SAAgB,UAAU;IACxB,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC;AAED,SAAgB,YAAY;IAC1B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,gBAAgB,GAAG,UAAU,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAgB,YAAY;IAC1B,gBAAgB,GAAG,UAAU,EAAE,CAAC;IAChC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAgB,kBAAkB;IAChC,OAAO,EAAE,eAAe,CAAC;AAC3B,CAAC;AAED,SAAgB,oBAAoB;IAClC,eAAe,GAAG,CAAC,CAAC;AACtB,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,UAAkB;;IACpD,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;QAC7C,OAAO;YACL,QAAQ,EAAE,QAAQ,CAAC,EAAuB;YAC1C,SAAS,EAAE,MAAA,MAAA,QAAQ,CAAC,OAAO,0CAAE,QAAQ,EAAE,mCAAI,SAAS;YACpD,UAAU;YACV,WAAW,EAAE,SAAS;YACtB,SAAS,EAAE,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;SAC3E,CAAC;IACJ,CAAC;IAAC,WAAM,CAAC;QACP,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,SAAS,EAAE,SAAS;YACpB,UAAU;YACV,WAAW,EAAE,SAAS;YACtB,SAAS,EAAE,SAAS;SACrB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,IAAa,EAAE,SAAkB;IAC5D,IAAI,CAAC,SAAS;QAAE,OAAO,0CAA0C,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- import { QALinkConfig, LogRequestOptions, UserContext, CustomContext, HTTPInterceptorConfig } from './types';
1
+ import { QALinkConfig, LogRequestOptions, UserContext, CustomContext, HTTPInterceptorConfig, DataStateCheck } from './types';
2
+ import { EventMiddleware } from './core/MiddlewarePipeline';
3
+ import { RageClickOptions } from './trackers/RageClickTracker';
2
4
  declare class QALinkSDK {
3
5
  private transport;
4
6
  private config;
@@ -10,36 +12,98 @@ declare class QALinkSDK {
10
12
  private logger;
11
13
  private eventManager;
12
14
  private screenCapture;
15
+ private rageClickTracker;
16
+ private navigationLoopTracker;
17
+ private silentFailureTracker;
13
18
  init(config: QALinkConfig): Promise<void>;
14
- interceptAxios(axiosInstance: any): void;
19
+ interceptAxios(axiosInstance: unknown): void;
20
+ /**
21
+ * Add an event middleware. Each middleware runs before an event is sent.
22
+ *
23
+ * @example — Drop console_log events in production:
24
+ * QALink.use((event, next) => {
25
+ * if (event.type === 'console_log') return; // drop
26
+ * next(event);
27
+ * });
28
+ *
29
+ * @example — Tag every event with a release ID:
30
+ * QALink.use((event, next) => next({ ...event, _release: '1.2.3' } as typeof event));
31
+ */
32
+ use(middleware: EventMiddleware): void;
15
33
  setUserContext(context: UserContext): void;
16
34
  setCustomContext(context: CustomContext): void;
17
35
  clearContext(): void;
18
- debug(...args: any[]): void;
19
- info(...args: any[]): void;
20
- warn(...args: any[]): void;
21
- error(...args: any[]): void;
22
- critical(...args: any[]): void;
23
- logEvent(eventName: string, data?: any): void;
36
+ debug(...args: unknown[]): void;
37
+ info(...args: unknown[]): void;
38
+ warn(...args: unknown[]): void;
39
+ error(...args: unknown[]): void;
40
+ critical(...args: unknown[]): void;
41
+ logEvent(eventName: string, data?: unknown): void;
24
42
  captureScreen(label?: string): Promise<void>;
25
- captureRef(viewRef: any, label?: string): Promise<void>;
43
+ captureRef(viewRef: unknown, label?: string): Promise<void>;
26
44
  configureHTTP(httpConfig: Partial<HTTPInterceptorConfig>): void;
45
+ /**
46
+ * Manually flush all buffered offline events.
47
+ * Useful before the user puts the app in background.
48
+ */
49
+ flush(): void;
50
+ /**
51
+ * Enable rage-click detection.
52
+ * After enabling, call `QALink.trackUIInteraction(target)` from any onPress handler.
53
+ *
54
+ * @example
55
+ * QALink.enableRageClickDetection({ threshold: 3, windowMs: 600 });
56
+ * // then in a component:
57
+ * <Button onPress={() => { QALink.trackUIInteraction('submit-btn'); ... }} />
58
+ */
59
+ enableRageClickDetection(options?: RageClickOptions): void;
60
+ /**
61
+ * Record a UI interaction (tap/press) for rage-click detection.
62
+ * Has no effect if `enableRageClickDetection()` was not called.
63
+ *
64
+ * @param target - Component label, testID, or any string that identifies the element.
65
+ */
66
+ trackUIInteraction(target: string): void;
67
+ /**
68
+ * Enable navigation-loop detection.
69
+ * Automatically active when you call `setScreen()` or `startPackage()`.
70
+ *
71
+ * @param loopThreshold - How many back-and-forth alternations trigger the alert. @default 3
72
+ */
73
+ enableNavigationLoopDetection(loopThreshold?: number): void;
74
+ /**
75
+ * Assert that API data meets expectations. Fires a `silent_failure` event
76
+ * when an API call succeeds (2xx) but returns invalid/empty/unexpected data.
77
+ *
78
+ * Returns `true` if the check passes, `false` if a silent failure was detected.
79
+ *
80
+ * @example
81
+ * const users = await fetchUsers(); // 200 OK
82
+ * QALink.trackDataState({
83
+ * context: 'users_list',
84
+ * expected: Array.isArray(users) && users.length > 0,
85
+ * actual: users,
86
+ * statusCode: 200,
87
+ * url: '/api/users',
88
+ * });
89
+ */
90
+ trackDataState(check: DataStateCheck): boolean;
27
91
  addBreadcrumb(action: string, data?: Record<string, unknown>): void;
28
92
  logRequest(options: LogRequestOptions): void;
29
93
  setScreen(screenName: string): void;
30
94
  /**
31
95
  * Start grouping all subsequent events for `screenName` into an in-memory package.
32
- * Call this when a screen mounts. Pair with endPackage() on unmount.
33
- * Using `useTrackedScreen(screenName)` does both automatically.
96
+ * Call when a screen mounts. Pair with endPackage() on unmount.
97
+ * `useTrackedScreen(screenName)` does both automatically.
34
98
  */
35
99
  startPackage(screenName: string): void;
36
100
  /**
37
- * Close the active package, compute metrics and send it as a single EventPackage event.
38
- * All buffered events are included; nothing is lost.
101
+ * Close the active package, compute metrics, and send as a single EventPackage event.
39
102
  */
40
103
  endPackage(): void;
41
104
  getDeviceId(): string;
42
105
  getStatus(): string;
106
+ getQueueSize(): number;
43
107
  destroy(): void;
44
108
  private log;
45
109
  private validateRequiredConfig;
@@ -47,6 +111,8 @@ declare class QALinkSDK {
47
111
  }
48
112
  export declare const QALink: QALinkSDK;
49
113
  export * from './types';
114
+ export type { EventMiddleware } from './core/MiddlewarePipeline';
115
+ export type { RageClickOptions } from './trackers/RageClickTracker';
50
116
  export { getSourceLabel } from './core/classifier';
51
117
  export { useTrackedScreen } from './hooks/useTrackedScreen';
52
118
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAGZ,iBAAiB,EAGjB,WAAW,EACX,aAAa,EACb,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAoBjB,cAAM,SAAS;IACb,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,SAAS,CAAqB;IAGtC,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,aAAa,CAA8B;IAE7C,IAAI,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA2I/C,cAAc,CAAC,aAAa,EAAE,GAAG,GAAG,IAAI;IAwBxC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAQ1C,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAQ9C,YAAY,IAAI,IAAI;IAMpB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAQ3B,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAQ1B,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAQ1B,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAQ3B,QAAQ,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAU9B,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAUvC,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU7D,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAkB/D,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAgBnE,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAiD5C,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAQnC;;;;OAIG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAOtC;;;OAGG;IACH,UAAU,IAAI,IAAI;IASlB,WAAW,IAAI,MAAM;IAIrB,SAAS,IAAI,MAAM;IAInB,OAAO,IAAI,IAAI;IAef,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,kBAAkB;CAS3B;AAED,eAAO,MAAM,MAAM,WAAkB,CAAC;AAEtC,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}