@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
@@ -14,35 +14,25 @@ const SDK_VERSION = exports.SDK_VERSION = '1.0.0';
14
14
  const DEFAULT_CONFIG = exports.DEFAULT_CONFIG = {
15
15
  enabled: true,
16
16
  captureFPS: 0.5,
17
- // Every 2 seconds (only used in timer mode)
18
17
  captureOnEvents: true,
19
- // Event-driven capture (not time-based)
20
18
  maxSessionDuration: 10 * 60 * 1000,
21
- // 10 minutes (project-level configurable, clamped 1–10)
22
19
  maxStorageSize: 50 * 1024 * 1024,
23
- // 50MB
24
20
  autoScreenTracking: true,
25
21
  autoGestureTracking: true,
26
22
  privacyOcclusion: true,
27
23
  enableCompression: true,
28
24
  inactivityThreshold: 5000,
29
- // 5 seconds
30
25
  disableInDev: false,
31
26
  detectRageTaps: true,
32
27
  rageTapThreshold: 3,
33
28
  rageTapTimeWindow: 1000,
34
- // 1 second
35
29
  debug: false,
36
30
  autoStartRecording: true,
37
31
  collectDeviceInfo: true,
38
- // Collect detailed device information
39
32
  collectGeoLocation: true,
40
- // Collect IP address and geolocation
41
33
  postNavigationDelay: 300,
42
- // 300ms - allow navigation animations to complete
43
34
  postGestureDelay: 200,
44
- // 200ms - show result of taps, not animations
45
- postModalDelay: 400 // 400ms - ensure modals/alerts are fully rendered
35
+ postModalDelay: 400
46
36
  };
47
37
 
48
38
  /** Event type constants */
@@ -78,8 +68,7 @@ const CAPTURE_SETTINGS = exports.CAPTURE_SETTINGS = {
78
68
  MIN_FPS: 0.1,
79
69
  MAX_FPS: 2,
80
70
  CAPTURE_SCALE: 0.25,
81
- // 25% resolution for video segments
82
- MIN_CAPTURE_DELTA_TIME: 0.5 // Minimum 0.5s between captures (rate limiting)
71
+ MIN_CAPTURE_DELTA_TIME: 0.5
83
72
  };
84
73
 
85
74
  /** Memory management settings */
@@ -15,20 +15,11 @@ exports.setupErrorTracking = setupErrorTracking;
15
15
  * Split from autoTracking.ts for better code organization.
16
16
  */
17
17
 
18
- // Type declarations for browser globals (only used in hybrid apps where DOM is available)
19
-
20
- // Cast globalThis to work with both RN and hybrid scenarios
21
18
  const _globalThis = globalThis;
22
-
23
- // Original error handlers (for restoration)
24
19
  let originalErrorHandler;
25
20
  let originalOnError = null;
26
21
  let originalOnUnhandledRejection = null;
27
-
28
- // Callbacks
29
22
  let onErrorCallback = null;
30
-
31
- // Metrics
32
23
  let errorCount = 0;
33
24
 
34
25
  /**
@@ -37,18 +28,12 @@ let errorCount = 0;
37
28
  function setupErrorTracking(config, onError) {
38
29
  onErrorCallback = onError;
39
30
  errorCount = 0;
40
-
41
- // Track React Native errors
42
31
  if (config.trackReactNativeErrors !== false) {
43
32
  setupReactNativeErrorHandler();
44
33
  }
45
-
46
- // Track JavaScript errors (only works in web/debug)
47
34
  if (config.trackJSErrors !== false && typeof _globalThis !== 'undefined') {
48
35
  setupJSErrorHandler();
49
36
  }
50
-
51
- // Track unhandled promise rejections
52
37
  if (config.trackPromiseRejections !== false && typeof _globalThis !== 'undefined') {
53
38
  setupPromiseRejectionHandler();
54
39
  }
@@ -58,7 +43,6 @@ function setupErrorTracking(config, onError) {
58
43
  * Cleanup error tracking and restore original handlers
59
44
  */
60
45
  function cleanupErrorTracking() {
61
- // Restore React Native handler
62
46
  if (originalErrorHandler) {
63
47
  try {
64
48
  const ErrorUtils = _globalThis.ErrorUtils;
@@ -70,14 +54,10 @@ function cleanupErrorTracking() {
70
54
  }
71
55
  originalErrorHandler = undefined;
72
56
  }
73
-
74
- // Restore global onerror
75
57
  if (originalOnError !== null) {
76
58
  _globalThis.onerror = originalOnError;
77
59
  originalOnError = null;
78
60
  }
79
-
80
- // Remove promise rejection handler
81
61
  if (originalOnUnhandledRejection && typeof _globalThis.removeEventListener !== 'undefined') {
82
62
  _globalThis.removeEventListener('unhandledrejection', originalOnUnhandledRejection);
83
63
  originalOnUnhandledRejection = null;
@@ -129,11 +109,7 @@ function setupReactNativeErrorHandler() {
129
109
  try {
130
110
  const ErrorUtils = _globalThis.ErrorUtils;
131
111
  if (!ErrorUtils) return;
132
-
133
- // Store original handler
134
112
  originalErrorHandler = ErrorUtils.getGlobalHandler();
135
-
136
- // Set new handler
137
113
  ErrorUtils.setGlobalHandler((error, isFatal) => {
138
114
  trackError({
139
115
  type: 'error',
@@ -142,14 +118,12 @@ function setupReactNativeErrorHandler() {
142
118
  stack: error.stack,
143
119
  name: error.name || 'Error'
144
120
  });
145
-
146
- // Call original handler
147
121
  if (originalErrorHandler) {
148
122
  originalErrorHandler(error, isFatal);
149
123
  }
150
124
  });
151
125
  } catch {
152
- // ErrorUtils not available
126
+ // Ignore
153
127
  }
154
128
  }
155
129
 
@@ -167,8 +141,6 @@ function setupJSErrorHandler() {
167
141
  stack: error?.stack || `${source}:${lineno}:${colno}`,
168
142
  name: error?.name || 'Error'
169
143
  });
170
-
171
- // Call original handler
172
144
  if (originalOnError) {
173
145
  return originalOnError(message, source, lineno, colno, error);
174
146
  }
@@ -27,10 +27,9 @@ exports.trackAPIMetrics = trackAPIMetrics;
27
27
  * Session metrics structure
28
28
  */
29
29
 
30
- // Metrics state
31
30
  let metrics = createEmptyMetrics();
32
31
  let sessionStartTime = 0;
33
- let maxSessionDurationMs = 10 * 60 * 1000; // 10 minutes default
32
+ let maxSessionDurationMs = 10 * 60 * 1000;
34
33
 
35
34
  /**
36
35
  * Create empty metrics object
@@ -78,11 +77,8 @@ function initMetrics() {
78
77
  * Get current session metrics with calculated scores
79
78
  */
80
79
  function getSessionMetrics() {
81
- // Calculate duration, clamped to max session duration
82
80
  const rawDuration = Date.now() - sessionStartTime;
83
81
  const durationMs = Math.min(rawDuration, maxSessionDurationMs);
84
-
85
- // Calculate scores
86
82
  const interactionScore = calculateInteractionScore(durationMs);
87
83
  const explorationScore = calculateExplorationScore();
88
84
  const uxScore = calculateUXScore();
@@ -104,9 +100,6 @@ function setMaxSessionDurationMinutes(minutes) {
104
100
  maxSessionDurationMs = clampedMinutes * 60 * 1000;
105
101
  }
106
102
  }
107
-
108
- // ==================== Metric Increment Methods ====================
109
-
110
103
  function incrementTouchCount() {
111
104
  metrics.touchCount++;
112
105
  metrics.totalEvents++;
@@ -146,8 +139,6 @@ function trackAPIMetrics(success, durationMs = 0, responseBytes = 0) {
146
139
  }
147
140
  }
148
141
 
149
- // ==================== Score Calculations ====================
150
-
151
142
  /**
152
143
  * Calculate interaction score based on engagement with app
153
144
  * Higher = more engaged (more interactions per minute)
@@ -156,16 +147,12 @@ function calculateInteractionScore(durationMs) {
156
147
  if (durationMs <= 0) return 100;
157
148
  const durationMinutes = durationMs / 60000;
158
149
  const interactionsPerMinute = metrics.touchCount / Math.max(0.5, durationMinutes);
159
-
160
- // Ideal: 10-30 interactions per minute
161
- // Low (< 5): user passive/confused
162
- // Very high (> 60): rage tapping
163
150
  if (interactionsPerMinute < 2) return 20;
164
151
  if (interactionsPerMinute < 5) return 50;
165
152
  if (interactionsPerMinute < 10) return 70;
166
153
  if (interactionsPerMinute <= 30) return 100;
167
154
  if (interactionsPerMinute <= 60) return 80;
168
- return 50; // Very high might indicate frustration
155
+ return 50;
169
156
  }
170
157
 
171
158
  /**
@@ -174,14 +161,12 @@ function calculateInteractionScore(durationMs) {
174
161
  */
175
162
  function calculateExplorationScore() {
176
163
  const uniqueScreens = metrics.uniqueScreensCount;
177
-
178
- // More unique screens = better exploration
179
164
  if (uniqueScreens >= 10) return 100;
180
165
  if (uniqueScreens >= 7) return 90;
181
166
  if (uniqueScreens >= 5) return 80;
182
167
  if (uniqueScreens >= 3) return 60;
183
168
  if (uniqueScreens >= 2) return 40;
184
- return 20; // Single screen visit
169
+ return 20;
185
170
  }
186
171
 
187
172
  /**
@@ -190,14 +175,8 @@ function calculateExplorationScore() {
190
175
  */
191
176
  function calculateUXScore() {
192
177
  let score = 100;
193
-
194
- // Deduct for errors
195
178
  score -= metrics.errorCount * 10;
196
-
197
- // Deduct heavily for rage taps
198
179
  score -= metrics.rageTapCount * 20;
199
-
200
- // Deduct for API errors (less severe)
201
180
  score -= metrics.apiErrorCount * 5;
202
181
  return Math.max(0, Math.min(100, score));
203
182
  }
@@ -26,46 +26,28 @@ exports.normalizeScreenName = normalizeScreenName;
26
26
  function normalizeScreenName(raw) {
27
27
  if (!raw) return 'Unknown';
28
28
  let name = raw;
29
-
30
- // 1. Remove non-printable characters and weird symbols (often from icons)
31
29
  name = name.replace(/[^\x20-\x7E\s]/g, '');
32
-
33
- // 2. Handle hyphens: my-recipes -> My Recipes
34
30
  name = name.split(/[-_]/).map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
35
-
36
- // 3. Remove common suffixes
37
31
  const suffixes = ['Screen', 'Page', 'View', 'Controller', 'ViewController', 'VC'];
38
32
  for (const suffix of suffixes) {
39
33
  if (name.endsWith(suffix) && name.length > suffix.length) {
40
34
  name = name.slice(0, -suffix.length).trim();
41
35
  }
42
36
  }
43
-
44
- // 4. Remove common prefixes (React Native internals)
45
37
  const prefixes = ['RNS', 'RCT', 'RN', 'UI'];
46
38
  for (const prefix of prefixes) {
47
39
  if (name.startsWith(prefix) && name.length > prefix.length + 2) {
48
40
  name = name.slice(prefix.length).trim();
49
41
  }
50
42
  }
51
-
52
- // 5. Handle dynamic route params: [id] -> (omit), [userId] -> "User"
53
43
  name = name.replace(/\[([a-zA-Z]+)(?:Id)?\]/g, (_, param) => {
54
44
  const clean = param.replace(/Id$/i, '');
55
45
  if (clean.length < 2) return '';
56
46
  return clean.charAt(0).toUpperCase() + clean.slice(1);
57
47
  });
58
-
59
- // 6. Remove leftover brackets
60
48
  name = name.replace(/\[\]/g, '');
61
-
62
- // 7. Convert camelCase/PascalCase to Title Case with spaces
63
49
  name = name.replace(/([a-z])([A-Z])/g, '$1 $2');
64
-
65
- // 8. Clean up multiple spaces and trim
66
50
  name = name.replace(/\s+/g, ' ').trim();
67
-
68
- // 9. Capitalize first letter
69
51
  if (name.length > 0) {
70
52
  name = name.charAt(0).toUpperCase() + name.slice(1);
71
53
  }
@@ -80,23 +62,17 @@ function normalizeScreenName(raw) {
80
62
  * @returns Human-readable screen name
81
63
  */
82
64
  function getScreenNameFromPath(pathname, segments) {
83
- // Use segments for cleaner names if available
84
65
  if (segments.length > 0) {
85
- // Filter out group markers like (tabs), (auth), etc.
86
66
  const cleanSegments = segments.filter(s => !s.startsWith('(') && !s.endsWith(')'));
87
67
  if (cleanSegments.length > 0) {
88
- // Process each segment
89
68
  const processedSegments = cleanSegments.map(s => {
90
- // Handle dynamic params like [id]
91
69
  if (s.startsWith('[') && s.endsWith(']')) {
92
70
  const param = s.slice(1, -1);
93
- // Skip pure ID params, keep meaningful ones
94
71
  if (param === 'id' || param === 'slug') return null;
95
- // Extract meaningful part: userId -> User
72
+ if (param === 'id' || param === 'slug') return null;
96
73
  const clean = param.replace(/Id$/i, '');
97
74
  return clean.charAt(0).toUpperCase() + clean.slice(1);
98
75
  }
99
- // Regular segment - capitalize
100
76
  return s.charAt(0).toUpperCase() + s.slice(1);
101
77
  }).filter(Boolean);
102
78
  if (processedSegments.length > 0) {
@@ -104,30 +80,17 @@ function getScreenNameFromPath(pathname, segments) {
104
80
  }
105
81
  }
106
82
  }
107
-
108
- // Fall back to pathname
109
83
  if (!pathname || pathname === '/') {
110
84
  return 'Home';
111
85
  }
112
-
113
- // Clean up the path
114
- let cleanPath = pathname.replace(/^\/(tabs)?/, '') // Remove leading slash and (tabs)
115
- .replace(/\([^)]+\)/g, '') // Remove all group markers like (settings)
116
- .replace(/\[([^\]]+)\]/g, (_, param) => {
117
- // Handle dynamic params in path
86
+ const cleanPath = pathname.replace(/^\/(tabs)?/, '').replace(/\([^)]+\)/g, '').replace(/\[([^\]]+)\]/g, (_, param) => {
118
87
  if (param === 'id' || param === 'slug') return '';
119
88
  const clean = param.replace(/Id$/i, '');
120
89
  return clean.charAt(0).toUpperCase() + clean.slice(1);
121
- }).replace(/\/+/g, '/') // Collapse multiple slashes
122
- .replace(/^\//, '') // Remove leading slash
123
- .replace(/\/$/, '') // Remove trailing slash
124
- .replace(/\//g, ' > ') // Replace slashes with arrows
125
- .trim();
90
+ }).replace(/\/+/g, '/').replace(/^\//, '').replace(/\/$/, '').replace(/\//g, ' > ').trim();
126
91
  if (!cleanPath) {
127
92
  return 'Home';
128
93
  }
129
-
130
- // Capitalize first letter of each word
131
94
  return cleanPath.split(' > ').map(s => s.charAt(0).toUpperCase() + s.slice(1)).filter(s => s.length > 0).join(' > ') || 'Home';
132
95
  }
133
96
 
@@ -141,8 +104,6 @@ function getCurrentRouteFromState(state) {
141
104
  if (!state || !state.routes) return null;
142
105
  const route = state.routes[state.index ?? state.routes.length - 1];
143
106
  if (!route) return null;
144
-
145
- // If nested state, recurse
146
107
  if (route.state) {
147
108
  return getCurrentRouteFromState(route.state);
148
109
  }
@@ -24,41 +24,26 @@ exports.restoreNetworkInterceptor = restoreNetworkInterceptor;
24
24
  * - PII Scrubbing for query parameters
25
25
  */
26
26
 
27
- // Store original implementations
28
27
  let originalFetch = null;
29
28
  let originalXHROpen = null;
30
29
  let originalXHRSend = null;
31
-
32
- // Callback to log network requests (called asynchronously)
33
30
  let logCallback = null;
34
-
35
- // Pending requests buffer (circular buffer for memory efficiency)
36
31
  const MAX_PENDING_REQUESTS = 100;
37
32
  const pendingRequests = new Array(MAX_PENDING_REQUESTS).fill(null);
38
33
  let pendingHead = 0;
39
34
  let pendingTail = 0;
40
35
  let pendingCount = 0;
41
-
42
- // Flush timer
43
36
  let flushTimer = null;
44
- const FLUSH_INTERVAL = 500; // Flush every 500ms
45
-
46
- // Sampling for high-frequency endpoints
37
+ const FLUSH_INTERVAL = 500;
47
38
  const endpointCounts = new Map();
48
- const SAMPLE_WINDOW = 10000; // 10 second window
49
- const MAX_PER_ENDPOINT = 20; // Max 20 requests per endpoint per window
50
-
51
- // Configuration
39
+ const SAMPLE_WINDOW = 10000;
40
+ const MAX_PER_ENDPOINT = 20;
52
41
  const config = {
53
42
  enabled: true,
54
43
  ignorePatterns: [],
55
- // Simple string patterns for fast matching
56
44
  maxUrlLength: 300,
57
- // Shorter for efficiency
58
- captureSizes: false // Disabled by default for performance
45
+ captureSizes: false
59
46
  };
60
-
61
- // PII Scrubbing - Sensitive keys to look for in query params
62
47
  const SENSITIVE_KEYS = ['token', 'key', 'secret', 'password', 'auth', 'access_token', 'api_key'];
63
48
 
64
49
  /**
@@ -66,7 +51,6 @@ const SENSITIVE_KEYS = ['token', 'key', 'secret', 'password', 'auth', 'access_to
66
51
  */
67
52
  function scrubUrl(url) {
68
53
  try {
69
- // Fast check if URL might contain params
70
54
  if (url.indexOf('?') === -1) return url;
71
55
  const urlObj = new URL(url);
72
56
  let modified = false;
@@ -76,13 +60,10 @@ function scrubUrl(url) {
76
60
  modified = true;
77
61
  }
78
62
  });
79
-
80
- // Also scan for partial matches (case-insensitive) if strict scrubbing needed
81
- // But for performance, we stick to exact keys or common variations
82
-
83
63
  return modified ? urlObj.toString() : url;
84
64
  } catch {
85
- // If URL parsing fails (relative URL?), try primitive replacement
65
+ // Ignore error, fallback to primitive scrubbing
66
+
86
67
  let scrubbed = url;
87
68
  SENSITIVE_KEYS.forEach(key => {
88
69
  const regex = new RegExp(`([?&])${key}=[^&]*`, 'gi');
@@ -130,14 +111,10 @@ function queueRequest(request) {
130
111
  pendingHead = (pendingHead + 1) % MAX_PENDING_REQUESTS;
131
112
  pendingCount--;
132
113
  }
133
-
134
- // Scrub URL before queuing
135
114
  request.url = scrubUrl(request.url);
136
115
  pendingRequests[pendingTail] = request;
137
116
  pendingTail = (pendingTail + 1) % MAX_PENDING_REQUESTS;
138
117
  pendingCount++;
139
-
140
- // Schedule flush if not already scheduled
141
118
  if (!flushTimer) {
142
119
  flushTimer = setTimeout(flushPendingRequests, FLUSH_INTERVAL);
143
120
  }
@@ -149,8 +126,6 @@ function queueRequest(request) {
149
126
  function flushPendingRequests() {
150
127
  flushTimer = null;
151
128
  if (!logCallback || pendingCount === 0) return;
152
-
153
- // Process all pending requests
154
129
  while (pendingCount > 0) {
155
130
  const request = pendingRequests[pendingHead];
156
131
  pendingRequests[pendingHead] = null; // Allow GC
@@ -160,7 +135,7 @@ function flushPendingRequests() {
160
135
  try {
161
136
  logCallback(request);
162
137
  } catch {
163
- // Ignore logging errors
138
+ // Ignore
164
139
  }
165
140
  }
166
141
  }
@@ -173,12 +148,9 @@ function parseUrlFast(url) {
173
148
  // Fast path for common patterns
174
149
  let hostEnd = -1;
175
150
  let pathStart = -1;
176
-
177
- // Find ://
178
151
  const protoEnd = url.indexOf('://');
179
152
  if (protoEnd !== -1) {
180
153
  const afterProto = protoEnd + 3;
181
- // Find end of host (first / after ://)
182
154
  const slashPos = url.indexOf('/', afterProto);
183
155
  if (slashPos !== -1) {
184
156
  hostEnd = slashPos;
@@ -192,8 +164,6 @@ function parseUrlFast(url) {
192
164
  path: pathStart < url.length ? url.substring(pathStart) : '/'
193
165
  };
194
166
  }
195
-
196
- // Relative URL
197
167
  return {
198
168
  host: '',
199
169
  path: url
@@ -208,15 +178,10 @@ function interceptFetch() {
208
178
  if (originalFetch) return;
209
179
  originalFetch = globalThis.fetch;
210
180
  globalThis.fetch = function optimizedFetch(input, init) {
211
- // Fast path: if disabled or no callback, skip entirely
212
181
  if (!config.enabled || !logCallback) {
213
182
  return originalFetch(input, init);
214
183
  }
215
-
216
- // Extract URL string (minimal work)
217
184
  const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
218
-
219
- // Fast ignore check
220
185
  if (shouldIgnoreUrl(url)) {
221
186
  return originalFetch(input, init);
222
187
  }
@@ -228,14 +193,9 @@ function interceptFetch() {
228
193
  if (!shouldSampleRequest(path)) {
229
194
  return originalFetch(input, init);
230
195
  }
231
-
232
- // Capture start time (only synchronous work)
233
196
  const startTime = Date.now();
234
197
  const method = (init?.method || 'GET').toUpperCase();
235
-
236
- // Call original fetch
237
198
  return originalFetch(input, init).then(response => {
238
- // Success - queue the log asynchronously
239
199
  queueRequest({
240
200
  requestId: `f${startTime}`,
241
201
  method,
@@ -248,7 +208,6 @@ function interceptFetch() {
248
208
  });
249
209
  return response;
250
210
  }, error => {
251
- // Error - queue the log asynchronously
252
211
  queueRequest({
253
212
  requestId: `f${startTime}`,
254
213
  method,
@@ -275,8 +234,6 @@ function interceptXHR() {
275
234
  originalXHRSend = XMLHttpRequest.prototype.send;
276
235
  XMLHttpRequest.prototype.open = function (method, url, async = true, username, password) {
277
236
  const urlString = typeof url === 'string' ? url : url.toString();
278
-
279
- // Store minimal info
280
237
  this.__rj = {
281
238
  m: method.toUpperCase(),
282
239
  u: urlString,
@@ -289,8 +246,6 @@ function interceptXHR() {
289
246
  if (!config.enabled || !logCallback || !data || shouldIgnoreUrl(data.u)) {
290
247
  return originalXHRSend.call(this, body);
291
248
  }
292
-
293
- // Check sampling
294
249
  const {
295
250
  path
296
251
  } = parseUrlFast(data.u);
@@ -312,9 +267,6 @@ function interceptXHR() {
312
267
  errorMessage: this.status === 0 ? 'Network error' : undefined
313
268
  });
314
269
  };
315
-
316
- // Use load/error events (more efficient than readystatechange)
317
- // Note: We use basic addEventListener without options for RN compatibility
318
270
  this.addEventListener('load', onComplete);
319
271
  this.addEventListener('error', onComplete);
320
272
  this.addEventListener('abort', onComplete);
@@ -327,11 +279,8 @@ function interceptXHR() {
327
279
  */
328
280
  function initNetworkInterceptor(callback, options) {
329
281
  logCallback = callback;
330
-
331
- // Convert patterns to simple strings for fast matching
332
282
  if (options?.ignoreUrls) {
333
283
  config.ignorePatterns = options.ignoreUrls.filter(p => typeof p === 'string');
334
- // Note: RegExp patterns are not supported in optimized version for performance
335
284
  }
336
285
  if (options?.captureSizes !== undefined) {
337
286
  config.captureSizes = options.captureSizes;
@@ -345,8 +294,6 @@ function initNetworkInterceptor(callback, options) {
345
294
  */
346
295
  function disableNetworkInterceptor() {
347
296
  config.enabled = false;
348
-
349
- // Flush any pending requests
350
297
  if (flushTimer) {
351
298
  clearTimeout(flushTimer);
352
299
  flushTimer = null;