@rejourneyco/react-native 1.0.1 → 1.0.3

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 (65) hide show
  1. package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +72 -391
  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 +3 -26
  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/android/src/newarch/java/com/rejourney/RejourneyModule.kt +7 -0
  15. package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +9 -0
  16. package/ios/Capture/RJCaptureEngine.m +3 -34
  17. package/ios/Capture/RJVideoEncoder.m +0 -26
  18. package/ios/Capture/RJViewHierarchyScanner.m +68 -51
  19. package/ios/Core/RJLifecycleManager.m +0 -14
  20. package/ios/Core/Rejourney.mm +53 -129
  21. package/ios/Network/RJDeviceAuthManager.m +0 -2
  22. package/ios/Network/RJUploadManager.h +8 -0
  23. package/ios/Network/RJUploadManager.m +45 -0
  24. package/ios/Privacy/RJPrivacyMask.m +5 -31
  25. package/ios/Rejourney.h +0 -14
  26. package/ios/Touch/RJTouchInterceptor.m +21 -15
  27. package/ios/Utils/RJEventBuffer.m +57 -69
  28. package/ios/Utils/RJPerfTiming.m +0 -5
  29. package/ios/Utils/RJWindowUtils.m +87 -87
  30. package/lib/commonjs/components/Mask.js +1 -6
  31. package/lib/commonjs/index.js +46 -117
  32. package/lib/commonjs/sdk/autoTracking.js +39 -313
  33. package/lib/commonjs/sdk/constants.js +2 -13
  34. package/lib/commonjs/sdk/errorTracking.js +1 -29
  35. package/lib/commonjs/sdk/metricsTracking.js +3 -24
  36. package/lib/commonjs/sdk/navigation.js +3 -42
  37. package/lib/commonjs/sdk/networkInterceptor.js +7 -60
  38. package/lib/commonjs/sdk/utils.js +73 -19
  39. package/lib/module/components/Mask.js +1 -6
  40. package/lib/module/index.js +45 -121
  41. package/lib/module/sdk/autoTracking.js +39 -314
  42. package/lib/module/sdk/constants.js +2 -13
  43. package/lib/module/sdk/errorTracking.js +1 -29
  44. package/lib/module/sdk/index.js +0 -2
  45. package/lib/module/sdk/metricsTracking.js +3 -24
  46. package/lib/module/sdk/navigation.js +3 -42
  47. package/lib/module/sdk/networkInterceptor.js +7 -60
  48. package/lib/module/sdk/utils.js +73 -19
  49. package/lib/typescript/NativeRejourney.d.ts +1 -0
  50. package/lib/typescript/sdk/autoTracking.d.ts +4 -4
  51. package/lib/typescript/sdk/utils.d.ts +31 -1
  52. package/lib/typescript/types/index.d.ts +0 -1
  53. package/package.json +17 -11
  54. package/src/NativeRejourney.ts +2 -0
  55. package/src/components/Mask.tsx +0 -3
  56. package/src/index.ts +43 -92
  57. package/src/sdk/autoTracking.ts +51 -284
  58. package/src/sdk/constants.ts +13 -13
  59. package/src/sdk/errorTracking.ts +1 -17
  60. package/src/sdk/index.ts +0 -2
  61. package/src/sdk/metricsTracking.ts +5 -33
  62. package/src/sdk/navigation.ts +8 -29
  63. package/src/sdk/networkInterceptor.ts +9 -42
  64. package/src/sdk/utils.ts +76 -19
  65. package/src/types/index.ts +0 -29
@@ -23,111 +23,111 @@
23
23
 
24
24
  @implementation RJWindowUtils
25
25
 
26
+ static __weak UIWindow *_cachedKeyWindow = nil;
27
+ static NSTimeInterval _lastCacheTime = 0;
28
+ static const NSTimeInterval kKeyWindowCacheTTL = 0.5; // Cache for 500ms
29
+
26
30
  + (UIWindow *)keyWindow {
27
- if (@available(iOS 13.0, *)) {
28
- // IMPORTANT:
29
- // "Key window" can temporarily become a system window such as:
30
- // - UITextEffectsWindow
31
- // - UIRemoteKeyboardWindow / UIInputWindowController-hosted windows
32
- // Capturing those can trigger keyboard autolayout warnings/spikes even if the
33
- // user never focused a text field. Prefer a normal-level app window.
34
- //
35
- // ALSO IMPORTANT:
36
- // Some frameworks (including React Native/Expo modals/overlays) may present
37
- // content in a separate UIWindow with a windowLevel > UIWindowLevelNormal.
38
- // If we only consider "normal" level, we may capture the wrong window and
39
- // miss TextInputs entirely (privacy masking failure).
40
- //
41
- // We therefore prefer the TOP-MOST visible non-system window, while still
42
- // excluding keyboard/text-effects windows.
43
-
44
- UIWindow *bestKeyApp = nil;
45
- CGFloat bestKeyAppLevel = -CGFLOAT_MAX;
46
- UIWindow *bestApp = nil;
47
- CGFloat bestAppLevel = -CGFLOAT_MAX;
48
- UIWindow *anyKey = nil;
49
-
50
- for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
51
- if (![scene isKindOfClass:[UIWindowScene class]]) {
52
- continue;
53
- }
54
- UIWindowScene *windowScene = (UIWindowScene *)scene;
55
- if (windowScene.activationState != UISceneActivationStateForegroundActive) {
56
- continue;
57
- }
58
-
59
- for (UIWindow *window in windowScene.windows) {
60
- if (!window || window.isHidden || window.alpha <= 0.01) {
61
- continue;
62
- }
63
-
64
- NSString *cls = NSStringFromClass([window class]);
65
- BOOL isSystemInputWindow =
66
- ([cls containsString:@"Keyboard"] ||
67
- [cls containsString:@"TextEffects"] ||
68
- [cls containsString:@"InputWindow"] ||
69
- [cls containsString:@"RemoteKeyboard"]);
70
-
71
- BOOL hasRoot = (window.rootViewController != nil);
72
- BOOL isAppCandidate = (!isSystemInputWindow && hasRoot);
73
- CGFloat level = window.windowLevel;
74
-
75
- if (window.isKeyWindow) {
76
- // Keep as a last-ditch fallback (even if it's a system window).
77
- if (!anyKey) {
78
- anyKey = window;
79
- }
80
- if (isAppCandidate && level > bestKeyAppLevel) {
81
- bestKeyAppLevel = level;
82
- bestKeyApp = window;
83
- }
84
- }
85
-
86
- if (isAppCandidate && level > bestAppLevel) {
87
- bestAppLevel = level;
88
- bestApp = window;
89
- }
90
- }
91
- }
31
+ NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
32
+ if (_cachedKeyWindow && (now - _lastCacheTime < kKeyWindowCacheTTL)) {
33
+ return _cachedKeyWindow;
34
+ }
35
+
36
+ UIWindow *window = [self findKeyWindowInternal];
37
+ _cachedKeyWindow = window;
38
+ _lastCacheTime = now;
39
+ return window;
40
+ }
41
+
42
+ + (UIWindow *)findKeyWindowInternal {
43
+ if (@available(iOS 13.0, *)) {
44
+ UIWindow *bestKeyApp = nil;
45
+ CGFloat bestKeyAppLevel = -CGFLOAT_MAX;
46
+ UIWindow *bestApp = nil;
47
+ CGFloat bestAppLevel = -CGFLOAT_MAX;
48
+ UIWindow *anyKey = nil;
92
49
 
93
- if (bestKeyApp) {
94
- return bestKeyApp;
50
+ for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
51
+ if (![scene isKindOfClass:[UIWindowScene class]]) {
52
+ continue;
53
+ }
54
+ UIWindowScene *windowScene = (UIWindowScene *)scene;
55
+ if (windowScene.activationState !=
56
+ UISceneActivationStateForegroundActive) {
57
+ continue;
58
+ }
59
+
60
+ for (UIWindow *window in windowScene.windows) {
61
+ if (!window || window.isHidden || window.alpha <= 0.01) {
62
+ continue;
95
63
  }
96
- if (bestApp) {
97
- return bestApp;
64
+
65
+ NSString *cls = NSStringFromClass([window class]);
66
+ BOOL isSystemInputWindow = ([cls containsString:@"Keyboard"] ||
67
+ [cls containsString:@"TextEffects"] ||
68
+ [cls containsString:@"InputWindow"] ||
69
+ [cls containsString:@"RemoteKeyboard"]);
70
+
71
+ BOOL hasRoot = (window.rootViewController != nil);
72
+ BOOL isAppCandidate = (!isSystemInputWindow && hasRoot);
73
+ CGFloat level = window.windowLevel;
74
+
75
+ if (window.isKeyWindow) {
76
+ if (!anyKey) {
77
+ anyKey = window;
78
+ }
79
+ if (isAppCandidate && level > bestKeyAppLevel) {
80
+ bestKeyAppLevel = level;
81
+ bestKeyApp = window;
82
+ }
98
83
  }
99
- if (anyKey) {
100
- return anyKey;
84
+
85
+ if (isAppCandidate && level > bestAppLevel) {
86
+ bestAppLevel = level;
87
+ bestApp = window;
101
88
  }
102
- } else {
89
+ }
90
+ }
91
+
92
+ if (bestKeyApp) {
93
+ return bestKeyApp;
94
+ }
95
+ if (bestApp) {
96
+ return bestApp;
97
+ }
98
+ if (anyKey) {
99
+ return anyKey;
100
+ }
101
+ } else {
103
102
  #pragma clang diagnostic push
104
103
  #pragma clang diagnostic ignored "-Wdeprecated-declarations"
105
- return [UIApplication sharedApplication].keyWindow;
104
+ return [UIApplication sharedApplication].keyWindow;
106
105
  #pragma clang diagnostic pop
107
- }
108
- return nil;
106
+ }
107
+ return nil;
109
108
  }
110
109
 
111
110
  + (NSString *)accessibilityLabelForView:(UIView *)view {
112
- UIView *current = view;
113
- while (current) {
114
- if (current.accessibilityLabel.length > 0) {
115
- return current.accessibilityLabel;
116
- }
117
- current = current.superview;
111
+ UIView *current = view;
112
+ while (current) {
113
+ if (current.accessibilityLabel.length > 0) {
114
+ return current.accessibilityLabel;
118
115
  }
119
- return nil;
116
+ current = current.superview;
117
+ }
118
+ return nil;
120
119
  }
121
120
 
122
121
  + (NSString *)generateSessionId {
123
- NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970];
124
- NSString *timestampStr = [NSString stringWithFormat:@"%.0f", timestamp * 1000];
125
- NSString *randomHex = [NSString stringWithFormat:@"%08X", arc4random()];
126
- return [NSString stringWithFormat:@"session_%@_%@", timestampStr, randomHex];
122
+ NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970];
123
+ NSString *timestampStr =
124
+ [NSString stringWithFormat:@"%.0f", timestamp * 1000];
125
+ NSString *randomHex = [NSString stringWithFormat:@"%08X", arc4random()];
126
+ return [NSString stringWithFormat:@"session_%@_%@", timestampStr, randomHex];
127
127
  }
128
128
 
129
129
  + (NSTimeInterval)currentTimestampMillis {
130
- return [[NSDate date] timeIntervalSince1970] * 1000;
130
+ return [[NSDate date] timeIntervalSince1970] * 1000;
131
131
  }
132
132
 
133
133
  @end
@@ -30,7 +30,6 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
30
30
  * </Mask>
31
31
  * ```
32
32
  */
33
- // Lazy-loaded React Native modules
34
33
  let _RN = null;
35
34
  function getRN() {
36
35
  if (_RN) return _RN;
@@ -54,8 +53,6 @@ const Mask = ({
54
53
  ...props
55
54
  }) => {
56
55
  const RN = getRN();
57
-
58
- // If RN isn't loaded yet (shouldn't happen in practice), render children directly
59
56
  if (!RN) {
60
57
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, children);
61
58
  }
@@ -64,9 +61,7 @@ const Mask = ({
64
61
  StyleSheet
65
62
  } = RN;
66
63
  const styles = StyleSheet.create({
67
- container: {
68
- // Minimal container style - doesn't affect layout
69
- }
64
+ container: {}
70
65
  });
71
66
  return /*#__PURE__*/_react.default.createElement(View, _extends({}, props, {
72
67
  style: [styles.container, style],
@@ -175,13 +175,10 @@ function getReactNative() {
175
175
  return null;
176
176
  }
177
177
  }
178
-
179
- // Lazy-loaded logger
180
178
  let _logger = null;
181
179
  function getLogger() {
182
180
  if (_logger) return _logger;
183
181
  if (_sdkDisabled) {
184
- // Return a no-op logger if SDK is disabled
185
182
  return {
186
183
  debug: () => {},
187
184
  info: console.log.bind(console, '[Rejourney]'),
@@ -197,7 +194,12 @@ function getLogger() {
197
194
  logRecordingStart: () => {},
198
195
  logRecordingRemoteDisabled: () => {},
199
196
  logInvalidProjectKey: () => {},
200
- logPackageMismatch: () => {}
197
+ logPackageMismatch: () => {},
198
+ logNetworkRequest: () => {},
199
+ logFrustration: () => {},
200
+ logError: () => {},
201
+ logUploadStats: () => {},
202
+ logLifecycleEvent: () => {}
201
203
  };
202
204
  }
203
205
  try {
@@ -222,7 +224,12 @@ function getLogger() {
222
224
  logRecordingStart: () => {},
223
225
  logRecordingRemoteDisabled: () => {},
224
226
  logInvalidProjectKey: () => {},
225
- logPackageMismatch: () => {}
227
+ logPackageMismatch: () => {},
228
+ logNetworkRequest: () => {},
229
+ logFrustration: () => {},
230
+ logError: () => {},
231
+ logUploadStats: () => {},
232
+ logLifecycleEvent: () => {}
226
233
  };
227
234
  }
228
235
  }
@@ -260,7 +267,7 @@ const noopAutoTracking = {
260
267
  notifyStateChange: () => {},
261
268
  getSessionMetrics: () => ({}),
262
269
  resetMetrics: () => {},
263
- collectDeviceInfo: () => ({}),
270
+ collectDeviceInfo: async () => ({}),
264
271
  ensurePersistentAnonymousId: async () => 'anonymous'
265
272
  };
266
273
  function getAutoTracking() {
@@ -279,6 +286,7 @@ function getAutoTracking() {
279
286
  let _isInitialized = false;
280
287
  let _isRecording = false;
281
288
  let _initializationFailed = false;
289
+ let _metricsInterval = null;
282
290
  let _appStateSubscription = null;
283
291
  let _authErrorSubscription = null;
284
292
  let _currentAppState = 'active'; // Default to active, will be updated on init
@@ -301,7 +309,7 @@ async function loadPersistedUserIdentity() {
301
309
 
302
310
  // NATIVE STORAGE: Read directly from SharedPreferences/NSUserDefaults
303
311
  return await nativeModule.getUserIdentity();
304
- } catch (e) {
312
+ } catch {
305
313
  return null;
306
314
  }
307
315
  }
@@ -321,9 +329,7 @@ let _runtimeReady = false;
321
329
  function isRuntimeReady() {
322
330
  if (_runtimeReady) return true;
323
331
  try {
324
- // Try to access a core module to verify runtime is ready
325
332
  const RN = require('react-native');
326
- // If we can access NativeModules without error, runtime is ready
327
333
  if (RN.NativeModules) {
328
334
  _runtimeReady = true;
329
335
  return true;
@@ -406,12 +412,9 @@ function getRejourneyNative() {
406
412
  }
407
413
  }
408
414
  } catch (error) {
409
- // If any access fails, log and return null
410
415
  getLogger().warn('Rejourney: Failed to access native modules:', error);
411
416
  _rejourneyNative = null;
412
417
  }
413
-
414
- // Ensure we never return undefined - convert to null
415
418
  if (_rejourneyNative === undefined) {
416
419
  _rejourneyNative = null;
417
420
  }
@@ -486,18 +489,12 @@ const Rejourney = {
486
489
  const apiUrl = _storedConfig.apiUrl || 'https://api.rejourney.co';
487
490
  const publicKey = _storedConfig.publicRouteKey || '';
488
491
  getLogger().debug(`Calling native startSession (apiUrl=${apiUrl})`);
489
-
490
- // Use user identity if set, otherwise use anonymous device ID
491
492
  const deviceId = await getAutoTracking().ensurePersistentAnonymousId();
492
-
493
- // Try to load persisted user identity if not already set in memory
494
493
  if (!_userIdentity) {
495
494
  _userIdentity = await loadPersistedUserIdentity();
496
495
  }
497
496
  const userId = _userIdentity || deviceId;
498
497
  getLogger().debug(`userId=${userId.substring(0, 8)}...`);
499
-
500
- // Start native session
501
498
  const result = await nativeModule.startSession(userId, apiUrl, publicKey);
502
499
  getLogger().debug('Native startSession returned:', JSON.stringify(result));
503
500
  if (!result?.success) {
@@ -510,10 +507,27 @@ const Rejourney = {
510
507
  }
511
508
  _isRecording = true;
512
509
  getLogger().debug(`✅ Session started: ${result.sessionId}`);
513
- // Use lifecycle log for session start - only shown in dev builds
514
510
  getLogger().logSessionStart(result.sessionId);
515
-
516
- // Initialize auto tracking features
511
+ // Start polling for upload stats in dev mode
512
+ if (__DEV__) {
513
+ _metricsInterval = setInterval(async () => {
514
+ if (!_isRecording) {
515
+ if (_metricsInterval) clearInterval(_metricsInterval);
516
+ return;
517
+ }
518
+ try {
519
+ const native = getRejourneyNative();
520
+ if (native) {
521
+ const metrics = await native.getSDKMetrics();
522
+ if (metrics) {
523
+ getLogger().logUploadStats(metrics);
524
+ }
525
+ }
526
+ } catch (e) {
527
+ getLogger().debug('Failed to fetch metrics:', e);
528
+ }
529
+ }, 10000); // Poll more frequently in dev (10s) for better feedback
530
+ }
517
531
  getAutoTracking().initAutoTracking({
518
532
  rageTapThreshold: _storedConfig?.rageTapThreshold ?? 3,
519
533
  rageTapTimeWindow: _storedConfig?.rageTapTimeWindow ?? 500,
@@ -531,7 +545,7 @@ const Rejourney = {
531
545
  x,
532
546
  y
533
547
  });
534
- // logger.debug(`Rage tap detected: ${count} taps at (${x}, ${y})`);
548
+ getLogger().logFrustration(`Rage tap (${count} taps)`);
535
549
  },
536
550
  // Error callback - log as error event
537
551
  onError: error => {
@@ -540,46 +554,31 @@ const Rejourney = {
540
554
  stack: error.stack,
541
555
  name: error.name
542
556
  });
543
- // logger.debug(`Error captured: ${error.message}`);
557
+ getLogger().logError(error.message);
544
558
  },
545
- // Screen change callback - log screen change
546
- onScreen: (_screenName, _previousScreen) => {
547
- // Native module already handles screen changes
548
- // This is just for metrics tracking
549
- // logger.debug(`Screen changed: ${previousScreen} -> ${screenName}`);
550
- }
559
+ onScreen: (_screenName, _previousScreen) => {}
551
560
  });
552
-
553
- // Collect and log device info
554
561
  if (_storedConfig?.collectDeviceInfo !== false) {
555
562
  try {
556
- const deviceInfo = getAutoTracking().collectDeviceInfo();
563
+ const deviceInfo = await getAutoTracking().collectDeviceInfo();
557
564
  this.logEvent('device_info', deviceInfo);
558
565
  } catch (deviceError) {
559
566
  getLogger().warn('Failed to collect device info:', deviceError);
560
567
  }
561
568
  }
562
-
563
- // Setup automatic network interception
564
569
  if (_storedConfig?.autoTrackNetwork !== false) {
565
570
  try {
566
571
  const ignoreUrls = [apiUrl, '/api/ingest/presign', '/api/ingest/batch/complete', '/api/ingest/session/end', ...(_storedConfig?.networkIgnoreUrls || [])];
567
572
  getNetworkInterceptor().initNetworkInterceptor(request => {
568
- this.logNetworkRequest(request);
569
573
  getAutoTracking().trackAPIRequest(request.success || false, request.statusCode, request.duration || 0, request.responseBodySize || 0);
570
574
  }, {
571
575
  ignoreUrls,
572
576
  captureSizes: _storedConfig?.networkCaptureSizes !== false
573
577
  });
574
-
575
- // logger.debug('Network interception enabled');
576
578
  } catch (networkError) {
577
579
  getLogger().warn('Failed to setup network interception:', networkError);
578
580
  }
579
581
  }
580
-
581
- // logger.debug('Auto tracking enabled');
582
-
583
582
  return true;
584
583
  } catch (error) {
585
584
  getLogger().error('Failed to start recording:', error);
@@ -596,17 +595,17 @@ const Rejourney = {
596
595
  return;
597
596
  }
598
597
  try {
599
- // Get session metrics before stopping
600
598
  const metrics = getAutoTracking().getSessionMetrics();
601
599
  this.logEvent('session_metrics', metrics);
602
-
603
- // Cleanup
604
600
  getNetworkInterceptor().disableNetworkInterceptor();
605
601
  getAutoTracking().cleanupAutoTracking();
606
602
  getAutoTracking().resetMetrics();
607
603
  await safeNativeCall('stopSession', () => getRejourneyNative().stopSession(), undefined);
604
+ if (_metricsInterval) {
605
+ clearInterval(_metricsInterval);
606
+ _metricsInterval = null;
607
+ }
608
608
  _isRecording = false;
609
- // Use lifecycle log for session end - only shown in dev builds
610
609
  getLogger().logSessionEnd('current');
611
610
  } catch (error) {
612
611
  getLogger().error('Failed to stop recording:', error);
@@ -622,7 +621,6 @@ const Rejourney = {
622
621
  */
623
622
  logEvent(name, properties) {
624
623
  safeNativeCallSync('logEvent', () => {
625
- // Fire and forget - don't await
626
624
  getRejourneyNative().logEvent(name, properties || {}).catch(() => {});
627
625
  }, undefined);
628
626
  },
@@ -638,9 +636,6 @@ const Rejourney = {
638
636
  setUserIdentity(userId) {
639
637
  _userIdentity = userId;
640
638
  persistUserIdentity(userId).catch(() => {});
641
- // logger.debug(`User identity set: ${userId}`);
642
-
643
- // If recording is active, update the native module immediately
644
639
  if (_isRecording && getRejourneyNative()) {
645
640
  safeNativeCallSync('setUserIdentity', () => {
646
641
  getRejourneyNative().setUserIdentity(userId).catch(() => {});
@@ -654,9 +649,6 @@ const Rejourney = {
654
649
  clearUserIdentity() {
655
650
  _userIdentity = null;
656
651
  persistUserIdentity(null).catch(() => {});
657
- // logger.debug('User identity cleared');
658
-
659
- // If recording is active, update the native module immediately
660
652
  if (_isRecording && getRejourneyNative()) {
661
653
  safeNativeCallSync('setUserIdentity', () => {
662
654
  getRejourneyNative().setUserIdentity('anonymous').catch(() => {});
@@ -670,10 +662,7 @@ const Rejourney = {
670
662
  * @param params - Optional screen parameters
671
663
  */
672
664
  tagScreen(screenName, _params) {
673
- // Track screen for metrics and funnel tracking
674
665
  getAutoTracking().trackScreen(screenName);
675
-
676
- // Notify state change (kept for API compatibility)
677
666
  getAutoTracking().notifyStateChange();
678
667
  safeNativeCallSync('tagScreen', () => {
679
668
  getRejourneyNative().screenChanged(screenName).catch(() => {});
@@ -759,7 +748,6 @@ const Rejourney = {
759
748
  * @returns Path to export file (not implemented)
760
749
  */
761
750
  async exportSession(_sessionId) {
762
- // Return empty string - actual export should be done from dashboard server
763
751
  getLogger().warn('exportSession not implemented - export from dashboard server');
764
752
  return '';
765
753
  },
@@ -851,10 +839,6 @@ const Rejourney = {
851
839
  getAutoTracking().trackScroll();
852
840
  await safeNativeCall('onScroll', () => getRejourneyNative().onScroll(scrollOffset), undefined);
853
841
  },
854
- // ========================================================================
855
- // OAuth / External URL Tracking
856
- // ========================================================================
857
-
858
842
  /**
859
843
  * Notify the SDK that an OAuth flow is starting
860
844
  *
@@ -985,15 +969,9 @@ const Rejourney = {
985
969
  errorMessage: request.errorMessage,
986
970
  cached: request.cached
987
971
  };
988
-
989
- // Fire and forget - don't await, this is low priority
990
972
  getRejourneyNative().logEvent('network_request', networkEvent).catch(() => {});
991
973
  }, undefined);
992
974
  },
993
- // ========================================================================
994
- // SDK Telemetry / Observability
995
- // ========================================================================
996
-
997
975
  /**
998
976
  * Get SDK telemetry metrics for observability
999
977
  *
@@ -1041,10 +1019,6 @@ const Rejourney = {
1041
1019
  getLogger().warn('debugTriggerANR is only available in development mode');
1042
1020
  }
1043
1021
  },
1044
- // ========================================================================
1045
- // Privacy / View Masking
1046
- // ========================================================================
1047
-
1048
1022
  /**
1049
1023
  * Mask a view by its nativeID prop (will be occluded in recordings)
1050
1024
  *
@@ -1080,10 +1054,6 @@ const Rejourney = {
1080
1054
  }
1081
1055
  };
1082
1056
 
1083
- // =============================================================================
1084
- // Automatic Lifecycle Management
1085
- // =============================================================================
1086
-
1087
1057
  /**
1088
1058
  * Handle app state changes for automatic session management
1089
1059
  * - Pauses recording when app goes to background
@@ -1095,10 +1065,10 @@ function handleAppStateChange(nextAppState) {
1095
1065
  try {
1096
1066
  if (_currentAppState.match(/active/) && nextAppState === 'background') {
1097
1067
  // App going to background - native module handles this automatically
1098
- getLogger().debug('App moving to background');
1068
+ getLogger().logLifecycleEvent('App moving to background');
1099
1069
  } else if (_currentAppState.match(/inactive|background/) && nextAppState === 'active') {
1100
1070
  // App coming back to foreground
1101
- getLogger().debug('App returning to foreground');
1071
+ getLogger().logLifecycleEvent('App returning to foreground');
1102
1072
  }
1103
1073
  _currentAppState = nextAppState;
1104
1074
  } catch (error) {
@@ -1114,20 +1084,13 @@ function setupLifecycleManagement() {
1114
1084
  if (_sdkDisabled) return;
1115
1085
  const RN = getReactNative();
1116
1086
  if (!RN) return;
1117
-
1118
- // Remove any existing subscription
1119
1087
  if (_appStateSubscription) {
1120
1088
  _appStateSubscription.remove();
1121
1089
  _appStateSubscription = null;
1122
1090
  }
1123
1091
  try {
1124
- // Get current app state
1125
1092
  _currentAppState = RN.AppState.currentState || 'active';
1126
-
1127
- // Subscribe to app state changes
1128
1093
  _appStateSubscription = RN.AppState.addEventListener('change', handleAppStateChange);
1129
-
1130
- // Setup auth error listener from native module
1131
1094
  setupAuthErrorListener();
1132
1095
  getLogger().debug('Lifecycle management enabled');
1133
1096
  } catch (error) {
@@ -1150,9 +1113,6 @@ function setupAuthErrorListener() {
1150
1113
  try {
1151
1114
  const nativeModule = getRejourneyNative();
1152
1115
  if (nativeModule) {
1153
- // RN warns if a non-null module is passed without addListener/removeListeners.
1154
- // Our native module may not implement these no-op methods yet, so only pass
1155
- // the module when those hooks exist; otherwise use the global emitter.
1156
1116
  const maybeAny = nativeModule;
1157
1117
  const hasEventEmitterHooks = typeof maybeAny?.addListener === 'function' && typeof maybeAny?.removeListeners === 'function';
1158
1118
  const eventEmitter = hasEventEmitterHooks ? new RN.NativeEventEmitter(maybeAny) : new RN.NativeEventEmitter();
@@ -1163,11 +1123,7 @@ function setupAuthErrorListener() {
1163
1123
  } else if (error?.code === 404) {
1164
1124
  getLogger().logInvalidProjectKey();
1165
1125
  }
1166
-
1167
- // Update SDK state - recording has been stopped by native
1168
1126
  _isRecording = false;
1169
-
1170
- // Call user's error handler if provided
1171
1127
  if (_storedConfig?.onAuthError) {
1172
1128
  try {
1173
1129
  _storedConfig.onAuthError(error);
@@ -1178,7 +1134,6 @@ function setupAuthErrorListener() {
1178
1134
  });
1179
1135
  }
1180
1136
  } catch (error) {
1181
- // Event emitter not available on this platform - that's OK
1182
1137
  getLogger().debug('Auth error listener not available:', error);
1183
1138
  }
1184
1139
  }
@@ -1197,10 +1152,6 @@ function cleanupLifecycleManagement() {
1197
1152
  }
1198
1153
  }
1199
1154
 
1200
- // =============================================================================
1201
- // Simple Initialization API
1202
- // =============================================================================
1203
-
1204
1155
  /**
1205
1156
  * Initialize Rejourney SDK - STEP 1 of 3
1206
1157
  *
@@ -1230,14 +1181,11 @@ function cleanupLifecycleManagement() {
1230
1181
  * ```
1231
1182
  */
1232
1183
  function initRejourney(publicRouteKey, options) {
1233
- // Validate public route key
1234
1184
  if (!publicRouteKey || typeof publicRouteKey !== 'string') {
1235
1185
  getLogger().warn('Rejourney: Invalid public route key provided. SDK will be disabled.');
1236
1186
  _initializationFailed = true;
1237
1187
  return;
1238
1188
  }
1239
-
1240
- // Store config for later use
1241
1189
  _storedConfig = {
1242
1190
  ...options,
1243
1191
  publicRouteKey
@@ -1291,8 +1239,6 @@ function startRejourney() {
1291
1239
  }
1292
1240
  getLogger().logRecordingStart();
1293
1241
  getLogger().debug('Starting session...');
1294
-
1295
- // Fire and forget - don't block the caller
1296
1242
  (async () => {
1297
1243
  try {
1298
1244
  const started = await Rejourney._startSession();
@@ -1323,12 +1269,7 @@ function stopRejourney() {
1323
1269
  getLogger().warn('Error stopping Rejourney:', error);
1324
1270
  }
1325
1271
  }
1326
- var _default = exports.default = Rejourney; // Export types
1327
- // Export auto tracking utilities for advanced usage
1328
- // These are used internally but can be called manually if needed
1329
- // Navigation
1330
- // Re-export LogLevel enum from utils
1331
- // Note: This is safe because the enum itself doesn't trigger react-native imports
1272
+ var _default = exports.default = Rejourney;
1332
1273
  /**
1333
1274
  * Configure SDK log verbosity.
1334
1275
  *
@@ -1360,16 +1301,4 @@ var _default = exports.default = Rejourney; // Export types
1360
1301
  function setLogLevel(level) {
1361
1302
  getLogger().setLogLevel(level);
1362
1303
  }
1363
-
1364
- // Note: Components and hooks removed in new engine
1365
- // Session replay now handled by dashboard web UI
1366
- // export { RejourneyReplay } from './components/replay/RejourneyReplay';
1367
- // export { GestureTracker } from './components/GestureTracker';
1368
- // export { SessionList } from './components/SessionList';
1369
- // export { useRejourney } from './hooks/useRejourney';
1370
- // export { useReplay } from './hooks/useReplay';
1371
-
1372
- // Note: SDK managers removed in new engine - all functionality handled by native module
1373
-
1374
- // Export Mask component
1375
1304
  //# sourceMappingURL=index.js.map