@rejourneyco/react-native 1.0.2 → 1.0.4

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 (43) hide show
  1. package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +38 -363
  2. package/android/src/main/java/com/rejourney/capture/CaptureEngine.kt +11 -113
  3. package/android/src/main/java/com/rejourney/capture/SegmentUploader.kt +1 -15
  4. package/android/src/main/java/com/rejourney/capture/VideoEncoder.kt +1 -61
  5. package/android/src/main/java/com/rejourney/capture/ViewHierarchyScanner.kt +3 -1
  6. package/android/src/main/java/com/rejourney/lifecycle/SessionLifecycleService.kt +1 -22
  7. package/android/src/main/java/com/rejourney/network/DeviceAuthManager.kt +14 -27
  8. package/android/src/main/java/com/rejourney/network/NetworkMonitor.kt +0 -2
  9. package/android/src/main/java/com/rejourney/network/UploadManager.kt +7 -93
  10. package/android/src/main/java/com/rejourney/network/UploadWorker.kt +5 -41
  11. package/android/src/main/java/com/rejourney/privacy/PrivacyMask.kt +2 -58
  12. package/android/src/main/java/com/rejourney/touch/TouchInterceptor.kt +4 -4
  13. package/android/src/main/java/com/rejourney/utils/EventBuffer.kt +36 -7
  14. package/ios/Capture/RJCaptureEngine.m +9 -61
  15. package/ios/Capture/RJViewHierarchyScanner.m +68 -51
  16. package/ios/Core/RJLifecycleManager.m +0 -14
  17. package/ios/Core/Rejourney.mm +24 -37
  18. package/ios/Network/RJDeviceAuthManager.m +0 -2
  19. package/ios/Network/RJUploadManager.h +8 -0
  20. package/ios/Network/RJUploadManager.m +45 -0
  21. package/ios/Privacy/RJPrivacyMask.m +5 -31
  22. package/ios/Rejourney.h +0 -14
  23. package/ios/Touch/RJTouchInterceptor.m +21 -15
  24. package/ios/Utils/RJEventBuffer.m +57 -69
  25. package/ios/Utils/RJWindowUtils.m +87 -86
  26. package/lib/commonjs/index.js +44 -31
  27. package/lib/commonjs/sdk/autoTracking.js +0 -3
  28. package/lib/commonjs/sdk/constants.js +1 -1
  29. package/lib/commonjs/sdk/networkInterceptor.js +0 -11
  30. package/lib/commonjs/sdk/utils.js +73 -14
  31. package/lib/module/index.js +44 -31
  32. package/lib/module/sdk/autoTracking.js +0 -3
  33. package/lib/module/sdk/constants.js +1 -1
  34. package/lib/module/sdk/networkInterceptor.js +0 -11
  35. package/lib/module/sdk/utils.js +73 -14
  36. package/lib/typescript/sdk/constants.d.ts +1 -1
  37. package/lib/typescript/sdk/utils.d.ts +31 -1
  38. package/package.json +16 -4
  39. package/src/index.ts +42 -20
  40. package/src/sdk/autoTracking.ts +0 -2
  41. package/src/sdk/constants.ts +14 -14
  42. package/src/sdk/networkInterceptor.ts +0 -9
  43. package/src/sdk/utils.ts +76 -14
@@ -243,7 +243,6 @@ let LogLevel = exports.LogLevel = /*#__PURE__*/function (LogLevel) {
243
243
  */
244
244
  class Logger {
245
245
  prefix = '[Rejourney]';
246
- debugMode = false;
247
246
 
248
247
  /**
249
248
  * Minimum log level to display.
@@ -264,7 +263,6 @@ class Logger {
264
263
  this.minimumLogLevel = level;
265
264
  }
266
265
  setDebugMode(enabled) {
267
- this.debugMode = enabled;
268
266
  this.minimumLogLevel = enabled ? LogLevel.DEBUG : typeof __DEV__ !== 'undefined' && __DEV__ ? LogLevel.ERROR : LogLevel.SILENT;
269
267
  }
270
268
 
@@ -285,14 +283,26 @@ class Logger {
285
283
  /** Log a warning message */
286
284
  warn(...args) {
287
285
  if (this.minimumLogLevel <= LogLevel.WARNING) {
288
- console.warn(this.prefix, ...args);
286
+ if (this.minimumLogLevel <= LogLevel.DEBUG) {
287
+ // Explicit Debug Mode: Show YellowBox
288
+ console.warn(this.prefix, ...args);
289
+ } else {
290
+ // Default Dev Mode: Log to console only, avoid YellowBox
291
+ console.log(this.prefix, '[WARN]', ...args);
292
+ }
289
293
  }
290
294
  }
291
295
 
292
296
  /** Log an error message */
293
297
  error(...args) {
294
298
  if (this.minimumLogLevel <= LogLevel.ERROR) {
295
- console.error(this.prefix, ...args);
299
+ if (this.minimumLogLevel <= LogLevel.DEBUG) {
300
+ // Explicit Debug Mode: Show RedBox
301
+ console.error(this.prefix, ...args);
302
+ } else {
303
+ // Default Dev Mode: Log to console only, avoid RedBox
304
+ console.log(this.prefix, '[ERROR]', ...args);
305
+ }
296
306
  }
297
307
  }
298
308
  notice(...args) {
@@ -306,9 +316,7 @@ class Logger {
306
316
  * Only shown in development builds - this is the minimal "SDK started" log.
307
317
  */
308
318
  logInitSuccess(version) {
309
- if (this.debugMode) {
310
- this.info(`✓ SDK initialized (v${version})`);
311
- }
319
+ this.notice(`✓ SDK initialized (v${version})`);
312
320
  }
313
321
 
314
322
  /**
@@ -324,9 +332,7 @@ class Logger {
324
332
  * Only shown in development builds.
325
333
  */
326
334
  logSessionStart(sessionId) {
327
- if (this.debugMode) {
328
- this.info(`Session started: ${sessionId}`);
329
- }
335
+ this.notice(`Session started: ${sessionId}`);
330
336
  }
331
337
 
332
338
  /**
@@ -334,12 +340,10 @@ class Logger {
334
340
  * Only shown in development builds.
335
341
  */
336
342
  logSessionEnd(sessionId) {
337
- if (this.debugMode) {
338
- this.info(`Session ended: ${sessionId}`);
339
- }
343
+ this.notice(`Session ended: ${sessionId}`);
340
344
  }
341
345
  logObservabilityStart() {
342
- this.notice('Starting Rejourney observability');
346
+ this.notice('💧 Starting Rejourney observability');
343
347
  }
344
348
  logRecordingStart() {
345
349
  this.notice('Starting recording');
@@ -353,6 +357,61 @@ class Logger {
353
357
  logPackageMismatch() {
354
358
  this.notice('Bundle ID / package name mismatch');
355
359
  }
360
+
361
+ /**
362
+ * Log network request details
363
+ */
364
+ logNetworkRequest(request) {
365
+ const statusIcon = request.error || request.statusCode && request.statusCode >= 400 ? '🔴' : '🟢';
366
+ const method = request.method || 'GET';
367
+ // Shorten URL to just path if possible
368
+ let url = request.url || '';
369
+ try {
370
+ if (url.startsWith('http')) {
371
+ const urlObj = new URL(url);
372
+ url = urlObj.pathname;
373
+ }
374
+ } catch {
375
+ // Keep full URL if parsing fails
376
+ }
377
+ const duration = request.duration ? `(${Math.round(request.duration)}ms)` : '';
378
+ const status = request.statusCode ? `${request.statusCode}` : 'ERR';
379
+ this.notice(`${statusIcon} [NET] ${status} ${method} ${url} ${duration} ${request.error ? `Error: ${request.error}` : ''}`);
380
+ }
381
+
382
+ /**
383
+ * Log frustration event (rage taps, etc)
384
+ */
385
+ logFrustration(kind) {
386
+ this.notice(`🤬 Frustration detected: ${kind}`);
387
+ }
388
+
389
+ /**
390
+ * Log error captured by SDK
391
+ */
392
+ logError(message) {
393
+ this.notice(`X Error captured: ${message}`);
394
+ }
395
+
396
+ /**
397
+ * Log lifecycle event (Background/Foreground)
398
+ * Visible in development builds.
399
+ */
400
+ logLifecycleEvent(event) {
401
+ this.notice(`🔄 Lifecycle: ${event}`);
402
+ }
403
+
404
+ /**
405
+ * Log upload statistics
406
+ */
407
+ logUploadStats(metrics) {
408
+ const success = metrics.uploadSuccessCount;
409
+ const failed = metrics.uploadFailureCount;
410
+ const bytes = formatBytes(metrics.totalBytesUploaded);
411
+
412
+ // Always show in dev mode for reassurance, even if 0
413
+ this.notice(`📡 Upload Stats: ${success} success, ${failed} failed (${bytes} uploaded)`);
414
+ }
356
415
  }
357
416
  const logger = exports.logger = new Logger();
358
417
  //# sourceMappingURL=utils.js.map
@@ -86,7 +86,12 @@ function getLogger() {
86
86
  logRecordingStart: () => {},
87
87
  logRecordingRemoteDisabled: () => {},
88
88
  logInvalidProjectKey: () => {},
89
- logPackageMismatch: () => {}
89
+ logPackageMismatch: () => {},
90
+ logNetworkRequest: () => {},
91
+ logFrustration: () => {},
92
+ logError: () => {},
93
+ logUploadStats: () => {},
94
+ logLifecycleEvent: () => {}
90
95
  };
91
96
  }
92
97
  try {
@@ -111,7 +116,12 @@ function getLogger() {
111
116
  logRecordingStart: () => {},
112
117
  logRecordingRemoteDisabled: () => {},
113
118
  logInvalidProjectKey: () => {},
114
- logPackageMismatch: () => {}
119
+ logPackageMismatch: () => {},
120
+ logNetworkRequest: () => {},
121
+ logFrustration: () => {},
122
+ logError: () => {},
123
+ logUploadStats: () => {},
124
+ logLifecycleEvent: () => {}
115
125
  };
116
126
  }
117
127
  }
@@ -168,6 +178,7 @@ function getAutoTracking() {
168
178
  let _isInitialized = false;
169
179
  let _isRecording = false;
170
180
  let _initializationFailed = false;
181
+ let _metricsInterval = null;
171
182
  let _appStateSubscription = null;
172
183
  let _authErrorSubscription = null;
173
184
  let _currentAppState = 'active'; // Default to active, will be updated on init
@@ -370,18 +381,12 @@ const Rejourney = {
370
381
  const apiUrl = _storedConfig.apiUrl || 'https://api.rejourney.co';
371
382
  const publicKey = _storedConfig.publicRouteKey || '';
372
383
  getLogger().debug(`Calling native startSession (apiUrl=${apiUrl})`);
373
-
374
- // Use user identity if set, otherwise use anonymous device ID
375
384
  const deviceId = await getAutoTracking().ensurePersistentAnonymousId();
376
-
377
- // Try to load persisted user identity if not already set in memory
378
385
  if (!_userIdentity) {
379
386
  _userIdentity = await loadPersistedUserIdentity();
380
387
  }
381
388
  const userId = _userIdentity || deviceId;
382
389
  getLogger().debug(`userId=${userId.substring(0, 8)}...`);
383
-
384
- // Start native session
385
390
  const result = await nativeModule.startSession(userId, apiUrl, publicKey);
386
391
  getLogger().debug('Native startSession returned:', JSON.stringify(result));
387
392
  if (!result?.success) {
@@ -394,10 +399,27 @@ const Rejourney = {
394
399
  }
395
400
  _isRecording = true;
396
401
  getLogger().debug(`✅ Session started: ${result.sessionId}`);
397
- // Use lifecycle log for session start - only shown in dev builds
398
402
  getLogger().logSessionStart(result.sessionId);
399
-
400
- // Initialize auto tracking features
403
+ // Start polling for upload stats in dev mode
404
+ if (__DEV__) {
405
+ _metricsInterval = setInterval(async () => {
406
+ if (!_isRecording) {
407
+ if (_metricsInterval) clearInterval(_metricsInterval);
408
+ return;
409
+ }
410
+ try {
411
+ const native = getRejourneyNative();
412
+ if (native) {
413
+ const metrics = await native.getSDKMetrics();
414
+ if (metrics) {
415
+ getLogger().logUploadStats(metrics);
416
+ }
417
+ }
418
+ } catch (e) {
419
+ getLogger().debug('Failed to fetch metrics:', e);
420
+ }
421
+ }, 10000); // Poll more frequently in dev (10s) for better feedback
422
+ }
401
423
  getAutoTracking().initAutoTracking({
402
424
  rageTapThreshold: _storedConfig?.rageTapThreshold ?? 3,
403
425
  rageTapTimeWindow: _storedConfig?.rageTapTimeWindow ?? 500,
@@ -415,7 +437,7 @@ const Rejourney = {
415
437
  x,
416
438
  y
417
439
  });
418
- // logger.debug(`Rage tap detected: ${count} taps at (${x}, ${y})`);
440
+ getLogger().logFrustration(`Rage tap (${count} taps)`);
419
441
  },
420
442
  // Error callback - log as error event
421
443
  onError: error => {
@@ -424,17 +446,10 @@ const Rejourney = {
424
446
  stack: error.stack,
425
447
  name: error.name
426
448
  });
427
- // logger.debug(`Error captured: ${error.message}`);
449
+ getLogger().logError(error.message);
428
450
  },
429
- // Screen change callback - log screen change
430
- onScreen: (_screenName, _previousScreen) => {
431
- // Native module already handles screen changes
432
- // This is just for metrics tracking
433
- // logger.debug(`Screen changed: ${previousScreen} -> ${screenName}`);
434
- }
451
+ onScreen: (_screenName, _previousScreen) => {}
435
452
  });
436
-
437
- // Collect and log device info
438
453
  if (_storedConfig?.collectDeviceInfo !== false) {
439
454
  try {
440
455
  const deviceInfo = await getAutoTracking().collectDeviceInfo();
@@ -443,14 +458,12 @@ const Rejourney = {
443
458
  getLogger().warn('Failed to collect device info:', deviceError);
444
459
  }
445
460
  }
446
-
447
- // Setup automatic network interception
448
461
  if (_storedConfig?.autoTrackNetwork !== false) {
449
462
  try {
450
463
  const ignoreUrls = [apiUrl, '/api/ingest/presign', '/api/ingest/batch/complete', '/api/ingest/session/end', ...(_storedConfig?.networkIgnoreUrls || [])];
451
464
  getNetworkInterceptor().initNetworkInterceptor(request => {
452
- this.logNetworkRequest(request);
453
465
  getAutoTracking().trackAPIRequest(request.success || false, request.statusCode, request.duration || 0, request.responseBodySize || 0);
466
+ Rejourney.logNetworkRequest(request);
454
467
  }, {
455
468
  ignoreUrls,
456
469
  captureSizes: _storedConfig?.networkCaptureSizes !== false
@@ -481,6 +494,10 @@ const Rejourney = {
481
494
  getAutoTracking().cleanupAutoTracking();
482
495
  getAutoTracking().resetMetrics();
483
496
  await safeNativeCall('stopSession', () => getRejourneyNative().stopSession(), undefined);
497
+ if (_metricsInterval) {
498
+ clearInterval(_metricsInterval);
499
+ _metricsInterval = null;
500
+ }
484
501
  _isRecording = false;
485
502
  getLogger().logSessionEnd('current');
486
503
  } catch (error) {
@@ -497,7 +514,6 @@ const Rejourney = {
497
514
  */
498
515
  logEvent(name, properties) {
499
516
  safeNativeCallSync('logEvent', () => {
500
- // Fire and forget - don't await
501
517
  getRejourneyNative().logEvent(name, properties || {}).catch(() => {});
502
518
  }, undefined);
503
519
  },
@@ -598,7 +614,7 @@ const Rejourney = {
598
614
  eventCount: 0,
599
615
  videoSegmentCount: 0,
600
616
  storageSize: 0,
601
- sdkVersion: '1.0.0',
617
+ sdkVersion: SDK_VERSION,
602
618
  isComplete: false
603
619
  },
604
620
  events: []
@@ -625,7 +641,6 @@ const Rejourney = {
625
641
  * @returns Path to export file (not implemented)
626
642
  */
627
643
  async exportSession(_sessionId) {
628
- // Return empty string - actual export should be done from dashboard server
629
644
  getLogger().warn('exportSession not implemented - export from dashboard server');
630
645
  return '';
631
646
  },
@@ -847,8 +862,6 @@ const Rejourney = {
847
862
  errorMessage: request.errorMessage,
848
863
  cached: request.cached
849
864
  };
850
-
851
- // Fire and forget - don't await, this is low priority
852
865
  getRejourneyNative().logEvent('network_request', networkEvent).catch(() => {});
853
866
  }, undefined);
854
867
  },
@@ -945,10 +958,10 @@ function handleAppStateChange(nextAppState) {
945
958
  try {
946
959
  if (_currentAppState.match(/active/) && nextAppState === 'background') {
947
960
  // App going to background - native module handles this automatically
948
- getLogger().debug('App moving to background');
961
+ getLogger().logLifecycleEvent('App moving to background');
949
962
  } else if (_currentAppState.match(/inactive|background/) && nextAppState === 'active') {
950
963
  // App coming back to foreground
951
- getLogger().debug('App returning to foreground');
964
+ getLogger().logLifecycleEvent('App returning to foreground');
952
965
  }
953
966
  _currentAppState = nextAppState;
954
967
  } catch (error) {
@@ -452,9 +452,6 @@ function setupNavigationTracking() {
452
452
  if (__DEV__) {
453
453
  logger.debug('Setting up navigation tracking...');
454
454
  }
455
-
456
- // Delay to ensure navigation is initialized - Expo Router needs more time
457
- // We retry a few times with increasing delays
458
455
  let attempts = 0;
459
456
  const maxAttempts = 5;
460
457
  const trySetup = () => {
@@ -2,7 +2,7 @@
2
2
  * Rejourney SDK Constants
3
3
  */
4
4
 
5
- export const SDK_VERSION = '1.0.0';
5
+ export const SDK_VERSION = '1.0.3';
6
6
 
7
7
  /** Default configuration values */
8
8
  export const DEFAULT_CONFIG = {
@@ -115,8 +115,6 @@ function queueRequest(request) {
115
115
  function flushPendingRequests() {
116
116
  flushTimer = null;
117
117
  if (!logCallback || pendingCount === 0) return;
118
-
119
- // Process all pending requests
120
118
  while (pendingCount > 0) {
121
119
  const request = pendingRequests[pendingHead];
122
120
  pendingRequests[pendingHead] = null; // Allow GC
@@ -184,14 +182,9 @@ function interceptFetch() {
184
182
  if (!shouldSampleRequest(path)) {
185
183
  return originalFetch(input, init);
186
184
  }
187
-
188
- // Capture start time (only synchronous work)
189
185
  const startTime = Date.now();
190
186
  const method = (init?.method || 'GET').toUpperCase();
191
-
192
- // Call original fetch
193
187
  return originalFetch(input, init).then(response => {
194
- // Success - queue the log asynchronously
195
188
  queueRequest({
196
189
  requestId: `f${startTime}`,
197
190
  method,
@@ -242,8 +235,6 @@ function interceptXHR() {
242
235
  if (!config.enabled || !logCallback || !data || shouldIgnoreUrl(data.u)) {
243
236
  return originalXHRSend.call(this, body);
244
237
  }
245
-
246
- // Check sampling
247
238
  const {
248
239
  path
249
240
  } = parseUrlFast(data.u);
@@ -292,8 +283,6 @@ export function initNetworkInterceptor(callback, options) {
292
283
  */
293
284
  export function disableNetworkInterceptor() {
294
285
  config.enabled = false;
295
-
296
- // Flush any pending requests
297
286
  if (flushTimer) {
298
287
  clearTimeout(flushTimer);
299
288
  flushTimer = null;
@@ -222,7 +222,6 @@ export let LogLevel = /*#__PURE__*/function (LogLevel) {
222
222
  */
223
223
  class Logger {
224
224
  prefix = '[Rejourney]';
225
- debugMode = false;
226
225
 
227
226
  /**
228
227
  * Minimum log level to display.
@@ -243,7 +242,6 @@ class Logger {
243
242
  this.minimumLogLevel = level;
244
243
  }
245
244
  setDebugMode(enabled) {
246
- this.debugMode = enabled;
247
245
  this.minimumLogLevel = enabled ? LogLevel.DEBUG : typeof __DEV__ !== 'undefined' && __DEV__ ? LogLevel.ERROR : LogLevel.SILENT;
248
246
  }
249
247
 
@@ -264,14 +262,26 @@ class Logger {
264
262
  /** Log a warning message */
265
263
  warn(...args) {
266
264
  if (this.minimumLogLevel <= LogLevel.WARNING) {
267
- console.warn(this.prefix, ...args);
265
+ if (this.minimumLogLevel <= LogLevel.DEBUG) {
266
+ // Explicit Debug Mode: Show YellowBox
267
+ console.warn(this.prefix, ...args);
268
+ } else {
269
+ // Default Dev Mode: Log to console only, avoid YellowBox
270
+ console.log(this.prefix, '[WARN]', ...args);
271
+ }
268
272
  }
269
273
  }
270
274
 
271
275
  /** Log an error message */
272
276
  error(...args) {
273
277
  if (this.minimumLogLevel <= LogLevel.ERROR) {
274
- console.error(this.prefix, ...args);
278
+ if (this.minimumLogLevel <= LogLevel.DEBUG) {
279
+ // Explicit Debug Mode: Show RedBox
280
+ console.error(this.prefix, ...args);
281
+ } else {
282
+ // Default Dev Mode: Log to console only, avoid RedBox
283
+ console.log(this.prefix, '[ERROR]', ...args);
284
+ }
275
285
  }
276
286
  }
277
287
  notice(...args) {
@@ -285,9 +295,7 @@ class Logger {
285
295
  * Only shown in development builds - this is the minimal "SDK started" log.
286
296
  */
287
297
  logInitSuccess(version) {
288
- if (this.debugMode) {
289
- this.info(`✓ SDK initialized (v${version})`);
290
- }
298
+ this.notice(`✓ SDK initialized (v${version})`);
291
299
  }
292
300
 
293
301
  /**
@@ -303,9 +311,7 @@ class Logger {
303
311
  * Only shown in development builds.
304
312
  */
305
313
  logSessionStart(sessionId) {
306
- if (this.debugMode) {
307
- this.info(`Session started: ${sessionId}`);
308
- }
314
+ this.notice(`Session started: ${sessionId}`);
309
315
  }
310
316
 
311
317
  /**
@@ -313,12 +319,10 @@ class Logger {
313
319
  * Only shown in development builds.
314
320
  */
315
321
  logSessionEnd(sessionId) {
316
- if (this.debugMode) {
317
- this.info(`Session ended: ${sessionId}`);
318
- }
322
+ this.notice(`Session ended: ${sessionId}`);
319
323
  }
320
324
  logObservabilityStart() {
321
- this.notice('Starting Rejourney observability');
325
+ this.notice('💧 Starting Rejourney observability');
322
326
  }
323
327
  logRecordingStart() {
324
328
  this.notice('Starting recording');
@@ -332,6 +336,61 @@ class Logger {
332
336
  logPackageMismatch() {
333
337
  this.notice('Bundle ID / package name mismatch');
334
338
  }
339
+
340
+ /**
341
+ * Log network request details
342
+ */
343
+ logNetworkRequest(request) {
344
+ const statusIcon = request.error || request.statusCode && request.statusCode >= 400 ? '🔴' : '🟢';
345
+ const method = request.method || 'GET';
346
+ // Shorten URL to just path if possible
347
+ let url = request.url || '';
348
+ try {
349
+ if (url.startsWith('http')) {
350
+ const urlObj = new URL(url);
351
+ url = urlObj.pathname;
352
+ }
353
+ } catch {
354
+ // Keep full URL if parsing fails
355
+ }
356
+ const duration = request.duration ? `(${Math.round(request.duration)}ms)` : '';
357
+ const status = request.statusCode ? `${request.statusCode}` : 'ERR';
358
+ this.notice(`${statusIcon} [NET] ${status} ${method} ${url} ${duration} ${request.error ? `Error: ${request.error}` : ''}`);
359
+ }
360
+
361
+ /**
362
+ * Log frustration event (rage taps, etc)
363
+ */
364
+ logFrustration(kind) {
365
+ this.notice(`🤬 Frustration detected: ${kind}`);
366
+ }
367
+
368
+ /**
369
+ * Log error captured by SDK
370
+ */
371
+ logError(message) {
372
+ this.notice(`X Error captured: ${message}`);
373
+ }
374
+
375
+ /**
376
+ * Log lifecycle event (Background/Foreground)
377
+ * Visible in development builds.
378
+ */
379
+ logLifecycleEvent(event) {
380
+ this.notice(`🔄 Lifecycle: ${event}`);
381
+ }
382
+
383
+ /**
384
+ * Log upload statistics
385
+ */
386
+ logUploadStats(metrics) {
387
+ const success = metrics.uploadSuccessCount;
388
+ const failed = metrics.uploadFailureCount;
389
+ const bytes = formatBytes(metrics.totalBytesUploaded);
390
+
391
+ // Always show in dev mode for reassurance, even if 0
392
+ this.notice(`📡 Upload Stats: ${success} success, ${failed} failed (${bytes} uploaded)`);
393
+ }
335
394
  }
336
395
  export const logger = new Logger();
337
396
  //# sourceMappingURL=utils.js.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Rejourney SDK Constants
3
3
  */
4
- export declare const SDK_VERSION = "1.0.0";
4
+ export declare const SDK_VERSION = "1.0.3";
5
5
  /** Default configuration values */
6
6
  export declare const DEFAULT_CONFIG: {
7
7
  readonly enabled: true;
@@ -91,7 +91,6 @@ export declare enum LogLevel {
91
91
  */
92
92
  declare class Logger {
93
93
  private prefix;
94
- private debugMode;
95
94
  /**
96
95
  * Minimum log level to display.
97
96
  *
@@ -142,6 +141,37 @@ declare class Logger {
142
141
  logRecordingRemoteDisabled(): void;
143
142
  logInvalidProjectKey(): void;
144
143
  logPackageMismatch(): void;
144
+ /**
145
+ * Log network request details
146
+ */
147
+ logNetworkRequest(request: {
148
+ method?: string;
149
+ url?: string;
150
+ statusCode?: number;
151
+ duration?: number;
152
+ error?: string;
153
+ }): void;
154
+ /**
155
+ * Log frustration event (rage taps, etc)
156
+ */
157
+ logFrustration(kind: string): void;
158
+ /**
159
+ * Log error captured by SDK
160
+ */
161
+ logError(message: string): void;
162
+ /**
163
+ * Log lifecycle event (Background/Foreground)
164
+ * Visible in development builds.
165
+ */
166
+ logLifecycleEvent(event: string): void;
167
+ /**
168
+ * Log upload statistics
169
+ */
170
+ logUploadStats(metrics: {
171
+ uploadSuccessCount: number;
172
+ uploadFailureCount: number;
173
+ totalBytesUploaded: number;
174
+ }): void;
145
175
  }
146
176
  export declare const logger: Logger;
147
177
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rejourneyco/react-native",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Rejourney Session Recording SDK for React Native",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -47,9 +47,21 @@
47
47
  },
48
48
  "keywords": [
49
49
  "react-native",
50
- "session-recording",
51
- "analytics",
52
- "replay"
50
+ "session-replay",
51
+ "observability",
52
+ "error-tracking",
53
+ "crash-reporting",
54
+ "anr-reporting",
55
+ "api-monitoring",
56
+ "alerting",
57
+ "mobile-analytics",
58
+ "mobile-observability",
59
+ "mobile-error-tracking",
60
+ "mobile-crash-reporting",
61
+ "mobile-anr-reporting",
62
+ "mobile-api-monitoring",
63
+ "mobile-performance-monitoring",
64
+ "mobile-user-behavior-analytics"
53
65
  ],
54
66
  "repository": {
55
67
  "type": "git",