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