react-native-qalink 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,351 +1,483 @@
1
1
  # react-native-qalink 🔍
2
2
 
3
- SDK de captura de errores en tiempo real para React Native. Se instala en la app y transmite al servidor QALink cada request de red, error JS, log de consola y error del runtime — permitiendo al equipo de QA ver en tiempo real si un bug es del **frontend** o del **backend**, sin necesidad de Android Studio ni logs técnicos.
3
+ SDK de captura de errores en tiempo real para React Native. Captura errores, logs, eventos custom, requests HTTP y screenshots — permitiendo al equipo de QA ver en tiempo real qué está pasando en la app, sin necesidad de Android Studio ni logs técnicos.
4
+
5
+ La conexión WebSocket apunta siempre a **wss://ws.airbites.org**.
4
6
 
5
7
  ---
6
8
 
7
- ## ¿Cómo identifica los requests a la API?
9
+ ## 📦 Instalación
8
10
 
9
- La librería usa **dos estrategias de interceptación simultáneas**:
11
+ ```bash
12
+ npm install react-native-qalink
13
+ # o
14
+ yarn add react-native-qalink
15
+ ```
10
16
 
11
- ### 1. Monkey-patch de `fetch` global
12
- Al llamar `QALink.init()`, la librería reemplaza el `fetch` nativo del entorno JavaScript por su propia versión instrumentada. Cualquier llamada a `fetch(...)` en toda la app pasa primero por QALink, que registra el request y la respuesta antes de devolver el control al código original.
17
+ ### Dependencia opcional para capturas de pantalla:
13
18
 
19
+ ```bash
20
+ npm install react-native-view-shot
21
+ cd ios && pod install
14
22
  ```
15
- Tu código → fetch('/api/users')
16
-
17
- QALink intercepta → registra método, URL, tiempo de inicio
18
-
19
- Ejecuta fetch real → espera respuesta del servidor
20
-
21
- QALink registra → status code, body, duración, clasificación
22
-
23
- Devuelve al código → response (sin modificarla)
24
- ```
25
-
26
- ### 2. Interceptores de Axios
27
- Axios expone un sistema oficial de interceptores (`.interceptors.request` y `.interceptors.response`). QALink se engancha en ambos para capturar cada request antes de que salga y cada respuesta antes de que llegue al código de la app. Funciona con la instancia global y con instancias personalizadas.
28
23
 
29
24
  ---
30
25
 
31
- ## ¿Cómo captura los logs de Metro y el runtime de React Native?
26
+ ## 🚀 Inicio rápido
32
27
 
33
- Hay tres capas adicionales que se activan automáticamente con `init()`:
28
+ ```typescript
29
+ import QALink from 'react-native-qalink';
34
30
 
35
- ### 3. Monkey-patch de `console`
36
- QALink reemplaza `console.log`, `console.warn` y `console.error` con versiones instrumentadas. **Metro sigue mostrando todo normalmente** (se llama al original primero), pero cada mensaje se envía también al dashboard. Los mensajes se clasifican automáticamente:
31
+ // 1. Inicializar el SDK
32
+ QALink.init({
33
+ apiKey: 'qlk_your_api_key_here',
34
+ appVersion: '1.0.0',
35
+ environment: 'dev',
36
+ debug: true,
37
+ });
37
38
 
39
+ // 2. Configurar contexto de usuario
40
+ QALink.setUserContext({
41
+ userId: '12345',
42
+ email: 'user@example.com',
43
+ plan: 'premium'
44
+ });
45
+
46
+ // 3. Configurar contexto custom
47
+ QALink.setCustomContext({
48
+ experimentVariant: 'new_checkout_flow',
49
+ featureFlags: { darkMode: true }
50
+ });
51
+
52
+ // 4. Usar los nuevos métodos de logging
53
+ QALink.debug('User opened settings');
54
+ QALink.info('Payment initiated', { amount: 99.99 });
55
+ QALink.warn('Slow API response', { duration: 3500 });
56
+ QALink.error('Payment failed', { code: 'CARD_DECLINED' });
57
+ QALink.critical('App about to crash');
58
+
59
+ // 5. Eventos custom
60
+ QALink.logEvent('checkout_completed', {
61
+ items: 3,
62
+ totalAmount: 299.99,
63
+ paymentMethod: 'credit_card'
64
+ });
65
+
66
+ // 6. Captura de pantalla (requiere react-native-view-shot)
67
+ await QALink.captureScreen('before_payment');
38
68
  ```
39
- console.log('Productos cargados', data) → 🔵 user_log
40
- console.warn('componentWillMount deprecated') → 🟡 rn_warning
41
- console.error('Invariant Violation: ...') → 🔴 rn_error
42
- console.error('Unable to resolve module') → 🔴 rn_error (Metro)
43
- ```
44
69
 
45
- ### 4. `ErrorUtils.setGlobalHandler` — Pantalla roja (Red Screen)
46
- React Native expone `ErrorUtils` para capturar errores **antes** de que la app crashee y muestre la pantalla roja. QALink se registra ahí para enviar el error al dashboard con todo el stack trace, y luego llama al handler original para que RN siga comportándose normalmente.
70
+ ---
71
+
72
+ ## 🔧 Configuración HTTP avanzada
47
73
 
74
+ El SDK captura automáticamente todas las peticiones HTTP (fetch y axios). Puedes configurar qué capturar:
75
+
76
+ ```typescript
77
+ QALink.init({
78
+ apiKey: 'qlk_xxx',
79
+ appVersion: '1.0.0',
80
+ httpConfig: {
81
+ // Captura requests y responses
82
+ captureRequests: true,
83
+ captureResponses: true,
84
+
85
+ // Filtrar por URL
86
+ includeUrls: ['/api/payment', '/api/checkout'],
87
+ excludeUrls: ['/api/analytics', '/health'],
88
+
89
+ // Filtrar por método HTTP
90
+ methods: ['POST', 'PUT', 'DELETE'], // ignorar GETs
91
+
92
+ // Sanitización de datos sensibles
93
+ sanitizeHeaders: ['Authorization', 'X-API-Key'],
94
+ sanitizeRequestBody: ['password', 'creditCard', 'cvv'],
95
+ sanitizeResponseBody: ['token', 'secret'],
96
+
97
+ // Capturar solo errores HTTP (4xx, 5xx)
98
+ captureOnlyErrors: true,
99
+ minStatusCode: 400,
100
+
101
+ // Límite de tamaño de body
102
+ maxBodySize: 5000, // bytes
103
+
104
+ // Performance monitoring
105
+ captureTimings: true,
106
+ slowRequestThreshold: 2000, // marcar requests > 2s como lentos
107
+ }
108
+ });
48
109
  ```
49
- Error fatal en JS
50
-
51
- QALink captura → envía al dashboard con stack trace completo
52
-
53
- ErrorUtils original → React Native muestra la pantalla roja
110
+
111
+ ### Actualizar configuración HTTP en runtime:
112
+
113
+ ```typescript
114
+ QALink.configureHTTP({
115
+ captureOnlyErrors: true,
116
+ slowRequestThreshold: 1000
117
+ });
54
118
  ```
55
119
 
56
- ### 5. LogBox — Cajas amarillas (Yellow Box)
57
- En React Native ≥ 0.64, los warnings se manejan internamente via `LogBox`. QALink se engancha al método interno `__warn` de LogBox para capturar cada warning antes de que aparezca en pantalla.
120
+ ---
121
+
122
+ ## 📝 API de Logging
123
+
124
+ Todos los métodos de logging hacen **console.log nativo** (visible en Metro) **Y** envían al servidor QALink:
125
+
126
+ ```typescript
127
+ // Acepta múltiples argumentos como console.log
128
+ QALink.debug('User action', { screen: 'Settings' }, 'Extra data');
129
+
130
+ QALink.info('API call started', {
131
+ endpoint: '/api/users',
132
+ method: 'GET'
133
+ });
134
+
135
+ QALink.warn('Memory warning', {
136
+ available: '50MB',
137
+ threshold: '100MB'
138
+ });
139
+
140
+ QALink.error('Validation failed', {
141
+ field: 'email',
142
+ reason: 'Invalid format'
143
+ });
58
144
 
59
- ### Clasificación de errores de runtime
145
+ QALink.critical('Unrecoverable error', {
146
+ code: 'FATAL_001',
147
+ message: 'Cannot connect to database'
148
+ });
149
+ ```
60
150
 
61
- | Tipo | Categoría | Ejemplo |
62
- |--------------------------|----------------|----------------------------------------------|
63
- | Error fatal | `red_screen` | `Invariant Violation`, `undefined is not...` |
64
- | Warning de RN | `yellow_box` | `componentWillMount is deprecated` |
65
- | Módulo nativo | `native_module`| `NativeModule X is null` |
66
- | Bridge JS↔Native | `bridge` | `RCTBridge error` |
67
- | Promise sin .catch() | `unknown` | `Unhandled Promise Rejection` |
68
- | Error de Metro/bundler | `rn_error` | `Unable to resolve module`, `SyntaxError` |
151
+ **Niveles de log:**
152
+ - `debug` → desarrollo y debugging
153
+ - `info` información general
154
+ - `warn` advertencias y problemas no críticos
155
+ - `error` errores recuperables
156
+ - `critical` errores fatales que pueden causar crash
69
157
 
70
158
  ---
71
159
 
72
- ## Instalación
160
+ ## 🎯 Eventos Custom
73
161
 
74
- ```bash
75
- npm install react-native-qalink
76
- # o
77
- yarn add react-native-qalink
162
+ Registra eventos de negocio importantes:
163
+
164
+ ```typescript
165
+ // Evento simple
166
+ QALink.logEvent('user_login');
167
+
168
+ // Evento con datos
169
+ QALink.logEvent('purchase_completed', {
170
+ productId: 'SKU-123',
171
+ price: 29.99,
172
+ currency: 'USD',
173
+ quantity: 2
174
+ });
175
+
176
+ QALink.logEvent('feature_used', {
177
+ featureName: 'dark_mode',
178
+ enabled: true,
179
+ timestamp: Date.now()
180
+ });
78
181
  ```
79
182
 
183
+ **Los eventos incluyen automáticamente:**
184
+ - User context (userId, email, etc.)
185
+ - Custom context (feature flags, experiments)
186
+ - Screen actual
187
+ - Session ID
188
+ - Device ID
189
+ - Timestamp
190
+
80
191
  ---
81
192
 
82
- ## Ejemplos de uso
193
+ ## 👤 Context API
83
194
 
84
- ### Ejemplo 1 — Setup básico con captura de consola
195
+ ### User Context
196
+ Información del usuario que se adjunta a **todos** los eventos:
85
197
 
86
- ```tsx
87
- // App.tsx
88
- import { useEffect } from 'react';
89
- import { QALink } from 'react-native-qalink';
90
- import axios from 'axios';
198
+ ```typescript
199
+ QALink.setUserContext({
200
+ userId: '12345',
201
+ email: 'john@example.com',
202
+ username: 'john_doe',
203
+ plan: 'premium',
204
+ region: 'LATAM'
205
+ });
91
206
 
92
- export default function App() {
93
- useEffect(() => {
94
- QALink.init({
95
- serverUrl: 'wss://qalink-server-production.up.railway.app',
96
- apiKey: 'qlk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
97
- appVersion: '1.2.3',
98
- captureRuntimeErrors: true, // pantalla roja, yellow box
99
- console: {
100
- captureLogs: true, // console.log
101
- captureWarnings: true, // console.warn
102
- captureErrors: true, // console.error + errores de Metro
103
- },
104
- debug: __DEV__,
105
- });
106
-
107
- QALink.interceptAxios(axios);
108
- }, []);
109
-
110
- return <RootNavigator />;
111
- }
207
+ // Actualizar parcialmente
208
+ QALink.setUserContext({ plan: 'enterprise' });
209
+
210
+ // Limpiar
211
+ QALink.clearContext();
212
+ ```
213
+
214
+ ### Custom Context
215
+ Datos custom que se adjuntan a todos los eventos:
216
+
217
+ ```typescript
218
+ QALink.setCustomContext({
219
+ experimentVariant: 'new_ui_v2',
220
+ featureFlags: {
221
+ darkMode: true,
222
+ newCheckout: false
223
+ },
224
+ build: 'staging-142'
225
+ });
112
226
  ```
113
227
 
114
228
  ---
115
229
 
116
- ### Ejemplo 2 — Filtrar logs muy verbosos de librerías
230
+ ## 📸 Captura de Pantalla
231
+
232
+ **Requisito:** `react-native-view-shot`
233
+
234
+ ```typescript
235
+ // Capturar pantalla completa
236
+ await QALink.captureScreen('before_payment');
237
+ await QALink.captureScreen('error_state');
117
238
 
118
- Si usas librerías que loguean mucho (react-query, redux, etc.), puedes filtrarlas
119
- para que el dashboard no se llene de ruido.
239
+ // Capturar componente específico
240
+ import { useRef } from 'react';
120
241
 
121
- ```tsx
242
+ const MyComponent = () => {
243
+ const viewRef = useRef(null);
244
+
245
+ const handleCapture = async () => {
246
+ await QALink.captureRef(viewRef, 'form_error');
247
+ };
248
+
249
+ return (
250
+ <View ref={viewRef}>
251
+ {/* contenido */}
252
+ </View>
253
+ );
254
+ };
255
+ ```
256
+
257
+ **Configuración:**
258
+
259
+ ```typescript
122
260
  QALink.init({
123
- serverUrl: 'wss://qalink-server-production.up.railway.app',
124
- apiKey: 'qlk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
125
- appVersion: '1.2.3',
126
- console: {
127
- captureLogs: true,
128
- captureWarnings: true,
129
- captureErrors: true,
130
- // Ignorar logs de estas librerías
131
- ignorePatterns: [
132
- '[react-query]',
133
- '[redux]',
134
- 'Reanimated',
135
- 'Gesture Handler',
136
- '[MMKV]',
137
- ],
138
- },
261
+ apiKey: 'qlk_xxx',
262
+ appVersion: '1.0.0',
263
+ enableScreenCapture: true, // ← activar
264
+ });
265
+ ```
266
+
267
+ ---
268
+
269
+ ## 🔌 Interceptores HTTP
270
+
271
+ ### Fetch (automático)
272
+ El SDK intercepta **todos** los `fetch()` automáticamente. No necesitas hacer nada.
273
+
274
+ ### Axios
275
+ Si usas Axios, puedes interceptar instancias específicas:
276
+
277
+ ```typescript
278
+ import axios from 'axios';
279
+ import QALink from 'react-native-qalink';
280
+
281
+ const apiClient = axios.create({
282
+ baseURL: 'https://api.example.com'
139
283
  });
284
+
285
+ // Interceptar esta instancia de Axios
286
+ QALink.interceptAxios(apiClient);
140
287
  ```
141
288
 
142
289
  ---
143
290
 
144
- ### Ejemplo 3 — Capturar solo logs relevantes para QA
291
+ ## 🛠️ Configuración completa
145
292
 
146
- Si quieres que el QA vea únicamente los logs que tú marcas explícitamente:
293
+ ```typescript
294
+ import QALink from 'react-native-qalink';
147
295
 
148
- ```tsx
149
296
  QALink.init({
150
- serverUrl: 'ws://192.168.1.100:3000',
151
- apiKey: 'qlk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
297
+ // ── Requerido ──────────────────────────────────
298
+ apiKey: 'qlk_your_64_char_hex_key',
152
299
  appVersion: '1.2.3',
300
+
301
+ // ── Básico ─────────────────────────────────────
302
+ enabled: true, // habilitar/deshabilitar SDK
303
+ environment: 'dev', // 'dev' | 'prod'
304
+ debug: true, // logs de debug en consola
305
+
306
+ // ── HTTP Interceptors ──────────────────────────
307
+ httpConfig: {
308
+ captureRequests: true,
309
+ captureResponses: true,
310
+ includeUrls: ['/api/'],
311
+ excludeUrls: ['/health', '/metrics'],
312
+ methods: ['POST', 'PUT', 'DELETE'],
313
+ sanitizeHeaders: ['Authorization'],
314
+ sanitizeRequestBody: ['password', 'token', 'creditCard'],
315
+ sanitizeResponseBody: ['secret', 'apiKey'],
316
+ captureOnlyErrors: false,
317
+ minStatusCode: 200,
318
+ maxBodySize: 5000,
319
+ captureTimings: true,
320
+ slowRequestThreshold: 2000,
321
+ },
322
+
323
+ // ── Legacy Network (compatibilidad) ────────────
324
+ logNetworkBodies: false,
325
+ sensitiveHeaders: ['Authorization'],
326
+ sensitiveUrlPatterns: ['/auth/', '/login'],
327
+ sensitiveBodyFields: ['password', 'token'],
328
+
329
+ // ── Console ─────────────────────────────────────
153
330
  console: {
154
331
  captureLogs: true,
155
332
  captureWarnings: true,
156
333
  captureErrors: true,
157
- // Solo capturar logs que contengan estas palabras
158
- includePatterns: ['[QA]', '[FLOW]', '[ERROR]'],
334
+ ignorePatterns: ['Ignore this'],
335
+ includePatterns: [],
159
336
  },
160
- });
161
-
162
- // En tu código, prefija los logs importantes:
163
- console.log('[QA] Usuario llegó al checkout', { userId, cartTotal });
164
- console.log('[FLOW] Pago procesado', { orderId });
165
- console.error('[ERROR] Falló validación', { campo, valor });
166
- ```
167
-
168
- ---
169
337
 
170
- ### Ejemplo 4 — App con múltiples instancias de Axios
338
+ // ── Errors ──────────────────────────────────────
339
+ captureRuntimeErrors: true, // red screen / yellow box
340
+ captureMetroErrors: true, // bundler errors
171
341
 
172
- ```tsx
173
- // services/api.ts
174
- export const apiPrincipal = axios.create({ baseURL: 'https://api.miapp.com/v1' });
175
- export const apiPagos = axios.create({ baseURL: 'https://pagos.miapp.com' });
342
+ // ── Screen Capture ──────────────────────────────
343
+ enableScreenCapture: true, // requiere react-native-view-shot
176
344
 
177
- // App.tsx
178
- await QALink.init({
179
- serverUrl: 'ws://192.168.1.100:3000',
180
- apiKey: 'qlk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
181
- appVersion: '1.2.3',
345
+ // ── Callbacks ───────────────────────────────────
346
+ onEvent: (event) => {
347
+ console.log('Event sent:', event.type);
348
+ }
182
349
  });
183
-
184
- QALink.interceptAxios(apiPrincipal);
185
- QALink.interceptAxios(apiPagos);
186
- // fetch nativo ya se intercepta automáticamente con init()
187
350
  ```
188
351
 
189
352
  ---
190
353
 
191
- ### Ejemplo 5 Integración con React Navigation
192
-
193
- ```tsx
194
- <NavigationContainer
195
- ref={navigationRef}
196
- onStateChange={() => {
197
- const routeName = navigationRef.current?.getCurrentRoute()?.name ?? '';
198
- QALink.setScreen(routeName);
199
- // Genera automáticamente: breadcrumb "NAVIGATE CheckoutScreen"
200
- }}
201
- >
202
- ```
354
+ ## 📊 Tipos de eventos capturados
355
+
356
+ El SDK captura automáticamente:
357
+
358
+ | Tipo | Descripción |
359
+ |------|-------------|
360
+ | `session_start` | Inicio de sesión |
361
+ | `http_request` | Request HTTP (fetch/axios) |
362
+ | `user_log` | Logs con debug/info/warn/error/critical |
363
+ | `custom_event` | Eventos custom con logEvent() |
364
+ | `console_log` | console.log |
365
+ | `console_warn` | console.warn |
366
+ | `console_error` | console.error |
367
+ | `runtime_error` | Red screen / Yellow box |
368
+ | `metro_error` | Errores de Metro Bundler |
369
+ | `js_error` | Errores de JavaScript |
370
+ | `breadcrumb` | Navegación y acciones |
371
+ | `screen_capture` | Screenshots |
203
372
 
204
373
  ---
205
374
 
206
- ### Ejemplo 6 Breadcrumbs en acciones críticas
375
+ ## 🔐 Compatibilidad con fetch-blob
207
376
 
208
- Los breadcrumbs + logs de consola juntos dan la línea de tiempo completa al QA:
377
+ El interceptor de fetch es **100% compatible** con `fetch-blob`:
209
378
 
210
- ```tsx
211
- const handleConfirmarCompra = async () => {
212
- QALink.addBreadcrumb('TAP → Confirmar Compra', {
213
- cartId: cart.id,
214
- items: cart.items.length,
215
- total: cart.total,
216
- });
379
+ ```typescript
380
+ import { fetch, Blob } from 'react-native-fetch-blob';
217
381
 
218
- console.log('[QA] Iniciando checkout', { cartId: cart.id });
382
+ // QALink detecta automáticamente Blobs y no intenta serializarlos
383
+ const blob = new Blob([...], { type: 'image/jpeg' });
219
384
 
220
- try {
221
- const result = await apiPagos.post('/checkout', { cartId: cart.id });
222
- console.log('[QA] Checkout exitoso', { orderId: result.data.orderId });
223
- } catch (error) {
224
- // QALink ya capturó el error de red automáticamente
225
- // console.error aquí también se envía al dashboard
226
- console.error('[QA] Checkout falló', error);
227
- }
228
- };
229
- ```
385
+ await fetch('https://api.example.com/upload', {
386
+ method: 'POST',
387
+ body: blob
388
+ });
230
389
 
231
- El QA verá en el dashboard esta línea de tiempo completa:
232
- ```
233
- 14:33:40 NAVIGATE → CheckoutScreen
234
- 14:33:55 TAP → Confirmar Compra { cartId: "abc", items: 3, total: 150 }
235
- 14:33:55 🔵 [QA] Iniciando checkout { cartId: "abc" }
236
- 14:33:55 ❌ POST /checkout → 500 🔴 ERROR DE BACKEND
237
- 14:33:55 🔴 [QA] Checkout falló Error: Internal Server Error
390
+ // En el dashboard verás:
391
+ // body: { _type: 'Blob', size: 12345, type: 'image/jpeg' }
238
392
  ```
239
393
 
240
394
  ---
241
395
 
242
- ### Ejemplo 7 — Configuración para build de QA (sin exponer en producción)
243
-
244
- ```tsx
245
- // config/qalink.ts
246
- import Config from 'react-native-config';
247
-
248
- export async function initQALink() {
249
- if (Config.QALINK_ENABLED !== 'true') return;
250
-
251
- await QALink.init({
252
- serverUrl: Config.QALINK_SERVER,
253
- apiKey: Config.QALINK_API_KEY,
254
- appVersion: Config.VERSION_NAME ?? '0.0.0',
255
- logNetworkBodies: true,
256
- captureRuntimeErrors: true,
257
- console: {
258
- captureLogs: true,
259
- captureWarnings: true,
260
- captureErrors: true,
261
- ignorePatterns: ['[react-query]'],
262
- },
263
- sensitiveHeaders: ['Authorization'],
264
- sensitiveUrlPatterns: ['/auth/refresh'],
265
- });
396
+ ## 🎯 Casos de uso
397
+
398
+ ### 1. Tracking de flujo de checkout
399
+ ```typescript
400
+ QALink.setUserContext({ userId: user.id, email: user.email });
401
+
402
+ QALink.logEvent('checkout_started', { cartTotal: 299.99 });
403
+ QALink.info('Loading payment methods');
266
404
 
267
- QALink.interceptAxios(axios);
405
+ // ... usuario selecciona método de pago ...
406
+ QALink.logEvent('payment_method_selected', { method: 'credit_card' });
407
+
408
+ try {
409
+ const response = await processPayment();
410
+ QALink.logEvent('payment_success', {
411
+ orderId: response.orderId,
412
+ amount: 299.99
413
+ });
414
+ } catch (error) {
415
+ QALink.error('Payment failed', {
416
+ reason: error.message,
417
+ code: error.code
418
+ });
419
+ await QALink.captureScreen('payment_error');
268
420
  }
269
421
  ```
270
422
 
271
- ---
423
+ ### 2. Debugging de API lenta
424
+ ```typescript
425
+ QALink.configureHTTP({
426
+ captureTimings: true,
427
+ slowRequestThreshold: 1500, // 1.5s
428
+ });
272
429
 
273
- ### Ejemplo 8 Verificar estado de conexión
430
+ // Los requests > 1.5s aparecerán marcados en el dashboard
431
+ ```
274
432
 
275
- ```tsx
276
- function QAStatusBadge() {
277
- if (QALink.getStatus() !== 'connected') return null;
433
+ ### 3. Tracking de experimentos A/B
434
+ ```typescript
435
+ const variant = getExperimentVariant('new_ui');
278
436
 
279
- return (
280
- <View style={styles.badge}>
281
- <Text>🔴 QALink grabando</Text>
282
- </View>
283
- );
284
- }
437
+ QALink.setCustomContext({
438
+ experiment: 'new_ui',
439
+ variant: variant, // 'A' or 'B'
440
+ });
441
+
442
+ QALink.logEvent('experiment_viewed', {
443
+ experiment: 'new_ui',
444
+ variant
445
+ });
285
446
  ```
286
447
 
287
448
  ---
288
449
 
289
- ## Qué ve el QA en el dashboard
450
+ ## 🚨 Troubleshooting
290
451
 
291
- Cada sesión incluye una línea de tiempo unificada con todos los eventos:
452
+ ### Los logs no aparecen en el dashboard
453
+ - Verifica que `apiKey` sea correcto (formato: `qlk_<64 hex>`)
454
+ - Verifica que `enabled: true`
455
+ - Revisa la consola: `QALink.getStatus()` debe ser `'connected'`
292
456
 
293
- | Ícono | Tipo | Fuente |
294
- |-------|-------------------|---------------------|
295
- | ✅ | Request exitoso | fetch / axios |
296
- | ❌ | Error de red | fetch / axios |
297
- | 🔴 | Error fatal (RN) | ErrorUtils / LogBox |
298
- | 🟡 | Warning (RN) | LogBox / console |
299
- | 🔵 | Log de consola | console.log |
300
- | 📍 | Breadcrumb | QALink.addBreadcrumb|
301
- | 📱 | Pantalla | QALink.setScreen |
457
+ ### Screen capture no funciona
458
+ - Instala: `npm install react-native-view-shot`
459
+ - Habilita: `enableScreenCapture: true` en config
460
+ - iOS: `cd ios && pod install`
461
+
462
+ ### Axios no se intercepta
463
+ - Llama `QALink.interceptAxios(axiosInstance)` **después** de `QALink.init()`
302
464
 
303
465
  ---
304
466
 
305
- ## Configuración completa
467
+ ## 📖 Recursos
306
468
 
307
- ```ts
308
- QALink.init({
309
- // Requeridos —
310
- serverUrl: 'ws://192.168.1.100:3000',
311
- apiKey: 'qlk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
312
- appVersion: '1.0.0',
469
+ - **Dashboard:** https://qalink.airbites.org
470
+ - **Documentación completa:** (próximamente)
471
+ - **GitHub:** (próximamente)
313
472
 
314
- // — Red —
315
- logNetworkBodies: false,
316
- sensitiveHeaders: ['Authorization'],
317
- sensitiveUrlPatterns: ['/auth/refresh'],
473
+ ---
318
474
 
319
- // Runtime de React Native —
320
- captureRuntimeErrors: true, // pantalla roja, yellow box, promises
475
+ ## 📄 Licencia
321
476
 
322
- // — Consola y Metro —
323
- console: {
324
- captureLogs: true,
325
- captureWarnings: true,
326
- captureErrors: true,
327
- ignorePatterns: ['[redux]'], // patrones a ignorar
328
- includePatterns: [], // si se define, solo captura estos
329
- },
330
-
331
- // — General —
332
- enabled: true,
333
- debug: false,
334
- onEvent: (event) => {
335
- console.log(event.type, event);
336
- },
337
- });
338
- ```
477
+ MIT
339
478
 
340
479
  ---
341
480
 
342
- ## API completa
481
+ ## 🤝 Contribuir
343
482
 
344
- | Método | Descripción |
345
- |---------------------------------|-----------------------------------------------------------|
346
- | `QALink.init(config)` | Inicializa el SDK, intercepta fetch, consola y runtime |
347
- | `QALink.interceptAxios(instance)`| Registra una instancia de axios |
348
- | `QALink.setScreen(name)` | Registra la pantalla actual (genera breadcrumb) |
349
- | `QALink.addBreadcrumb(action, data?)` | Registra una acción del usuario |
350
- | `QALink.getStatus()` | Estado de la conexión WS |
351
- | `QALink.destroy()` | Limpia interceptores y desconecta |
483
+ Pull requests son bienvenidos. Para cambios mayores, abre primero un issue.