@rejourneyco/react-native 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/android/build.gradle.kts +135 -0
  2. package/android/consumer-rules.pro +10 -0
  3. package/android/proguard-rules.pro +1 -0
  4. package/android/src/main/AndroidManifest.xml +15 -0
  5. package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +2981 -0
  6. package/android/src/main/java/com/rejourney/capture/ANRHandler.kt +206 -0
  7. package/android/src/main/java/com/rejourney/capture/ActivityTracker.kt +98 -0
  8. package/android/src/main/java/com/rejourney/capture/CaptureEngine.kt +1553 -0
  9. package/android/src/main/java/com/rejourney/capture/CaptureHeuristics.kt +375 -0
  10. package/android/src/main/java/com/rejourney/capture/CrashHandler.kt +153 -0
  11. package/android/src/main/java/com/rejourney/capture/MotionEvent.kt +215 -0
  12. package/android/src/main/java/com/rejourney/capture/SegmentUploader.kt +512 -0
  13. package/android/src/main/java/com/rejourney/capture/VideoEncoder.kt +773 -0
  14. package/android/src/main/java/com/rejourney/capture/ViewHierarchyScanner.kt +633 -0
  15. package/android/src/main/java/com/rejourney/capture/ViewSerializer.kt +286 -0
  16. package/android/src/main/java/com/rejourney/core/Constants.kt +117 -0
  17. package/android/src/main/java/com/rejourney/core/Logger.kt +93 -0
  18. package/android/src/main/java/com/rejourney/core/Types.kt +124 -0
  19. package/android/src/main/java/com/rejourney/lifecycle/SessionLifecycleService.kt +162 -0
  20. package/android/src/main/java/com/rejourney/network/DeviceAuthManager.kt +747 -0
  21. package/android/src/main/java/com/rejourney/network/HttpClientProvider.kt +16 -0
  22. package/android/src/main/java/com/rejourney/network/NetworkMonitor.kt +272 -0
  23. package/android/src/main/java/com/rejourney/network/UploadManager.kt +1363 -0
  24. package/android/src/main/java/com/rejourney/network/UploadWorker.kt +492 -0
  25. package/android/src/main/java/com/rejourney/privacy/PrivacyMask.kt +645 -0
  26. package/android/src/main/java/com/rejourney/touch/GestureClassifier.kt +233 -0
  27. package/android/src/main/java/com/rejourney/touch/KeyboardTracker.kt +158 -0
  28. package/android/src/main/java/com/rejourney/touch/TextInputTracker.kt +181 -0
  29. package/android/src/main/java/com/rejourney/touch/TouchInterceptor.kt +591 -0
  30. package/android/src/main/java/com/rejourney/utils/EventBuffer.kt +284 -0
  31. package/android/src/main/java/com/rejourney/utils/OEMDetector.kt +154 -0
  32. package/android/src/main/java/com/rejourney/utils/PerfTiming.kt +235 -0
  33. package/android/src/main/java/com/rejourney/utils/Telemetry.kt +297 -0
  34. package/android/src/main/java/com/rejourney/utils/WindowUtils.kt +84 -0
  35. package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +187 -0
  36. package/android/src/newarch/java/com/rejourney/RejourneyPackage.kt +40 -0
  37. package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +218 -0
  38. package/android/src/oldarch/java/com/rejourney/RejourneyPackage.kt +23 -0
  39. package/ios/Capture/RJANRHandler.h +42 -0
  40. package/ios/Capture/RJANRHandler.m +328 -0
  41. package/ios/Capture/RJCaptureEngine.h +275 -0
  42. package/ios/Capture/RJCaptureEngine.m +2062 -0
  43. package/ios/Capture/RJCaptureHeuristics.h +80 -0
  44. package/ios/Capture/RJCaptureHeuristics.m +903 -0
  45. package/ios/Capture/RJCrashHandler.h +46 -0
  46. package/ios/Capture/RJCrashHandler.m +313 -0
  47. package/ios/Capture/RJMotionEvent.h +183 -0
  48. package/ios/Capture/RJMotionEvent.m +183 -0
  49. package/ios/Capture/RJPerformanceManager.h +100 -0
  50. package/ios/Capture/RJPerformanceManager.m +373 -0
  51. package/ios/Capture/RJPixelBufferDownscaler.h +42 -0
  52. package/ios/Capture/RJPixelBufferDownscaler.m +85 -0
  53. package/ios/Capture/RJSegmentUploader.h +146 -0
  54. package/ios/Capture/RJSegmentUploader.m +778 -0
  55. package/ios/Capture/RJVideoEncoder.h +247 -0
  56. package/ios/Capture/RJVideoEncoder.m +1036 -0
  57. package/ios/Capture/RJViewControllerTracker.h +73 -0
  58. package/ios/Capture/RJViewControllerTracker.m +508 -0
  59. package/ios/Capture/RJViewHierarchyScanner.h +215 -0
  60. package/ios/Capture/RJViewHierarchyScanner.m +1464 -0
  61. package/ios/Capture/RJViewSerializer.h +119 -0
  62. package/ios/Capture/RJViewSerializer.m +498 -0
  63. package/ios/Core/RJConstants.h +124 -0
  64. package/ios/Core/RJConstants.m +88 -0
  65. package/ios/Core/RJLifecycleManager.h +85 -0
  66. package/ios/Core/RJLifecycleManager.m +308 -0
  67. package/ios/Core/RJLogger.h +61 -0
  68. package/ios/Core/RJLogger.m +211 -0
  69. package/ios/Core/RJTypes.h +176 -0
  70. package/ios/Core/RJTypes.m +66 -0
  71. package/ios/Core/Rejourney.h +64 -0
  72. package/ios/Core/Rejourney.mm +2495 -0
  73. package/ios/Network/RJDeviceAuthManager.h +94 -0
  74. package/ios/Network/RJDeviceAuthManager.m +967 -0
  75. package/ios/Network/RJNetworkMonitor.h +68 -0
  76. package/ios/Network/RJNetworkMonitor.m +267 -0
  77. package/ios/Network/RJRetryManager.h +73 -0
  78. package/ios/Network/RJRetryManager.m +325 -0
  79. package/ios/Network/RJUploadManager.h +267 -0
  80. package/ios/Network/RJUploadManager.m +2296 -0
  81. package/ios/Privacy/RJPrivacyMask.h +163 -0
  82. package/ios/Privacy/RJPrivacyMask.m +922 -0
  83. package/ios/Rejourney.h +63 -0
  84. package/ios/Touch/RJGestureClassifier.h +130 -0
  85. package/ios/Touch/RJGestureClassifier.m +333 -0
  86. package/ios/Touch/RJTouchInterceptor.h +169 -0
  87. package/ios/Touch/RJTouchInterceptor.m +772 -0
  88. package/ios/Utils/RJEventBuffer.h +112 -0
  89. package/ios/Utils/RJEventBuffer.m +358 -0
  90. package/ios/Utils/RJGzipUtils.h +33 -0
  91. package/ios/Utils/RJGzipUtils.m +89 -0
  92. package/ios/Utils/RJKeychainManager.h +48 -0
  93. package/ios/Utils/RJKeychainManager.m +111 -0
  94. package/ios/Utils/RJPerfTiming.h +209 -0
  95. package/ios/Utils/RJPerfTiming.m +264 -0
  96. package/ios/Utils/RJTelemetry.h +92 -0
  97. package/ios/Utils/RJTelemetry.m +320 -0
  98. package/ios/Utils/RJWindowUtils.h +66 -0
  99. package/ios/Utils/RJWindowUtils.m +133 -0
  100. package/lib/commonjs/NativeRejourney.js +40 -0
  101. package/lib/commonjs/components/Mask.js +79 -0
  102. package/lib/commonjs/index.js +1381 -0
  103. package/lib/commonjs/sdk/autoTracking.js +1259 -0
  104. package/lib/commonjs/sdk/constants.js +151 -0
  105. package/lib/commonjs/sdk/errorTracking.js +199 -0
  106. package/lib/commonjs/sdk/index.js +50 -0
  107. package/lib/commonjs/sdk/metricsTracking.js +204 -0
  108. package/lib/commonjs/sdk/navigation.js +151 -0
  109. package/lib/commonjs/sdk/networkInterceptor.js +412 -0
  110. package/lib/commonjs/sdk/utils.js +363 -0
  111. package/lib/commonjs/types/expo-router.d.js +2 -0
  112. package/lib/commonjs/types/index.js +2 -0
  113. package/lib/module/NativeRejourney.js +38 -0
  114. package/lib/module/components/Mask.js +72 -0
  115. package/lib/module/index.js +1284 -0
  116. package/lib/module/sdk/autoTracking.js +1233 -0
  117. package/lib/module/sdk/constants.js +145 -0
  118. package/lib/module/sdk/errorTracking.js +189 -0
  119. package/lib/module/sdk/index.js +12 -0
  120. package/lib/module/sdk/metricsTracking.js +187 -0
  121. package/lib/module/sdk/navigation.js +143 -0
  122. package/lib/module/sdk/networkInterceptor.js +401 -0
  123. package/lib/module/sdk/utils.js +342 -0
  124. package/lib/module/types/expo-router.d.js +2 -0
  125. package/lib/module/types/index.js +2 -0
  126. package/lib/typescript/NativeRejourney.d.ts +147 -0
  127. package/lib/typescript/components/Mask.d.ts +39 -0
  128. package/lib/typescript/index.d.ts +117 -0
  129. package/lib/typescript/sdk/autoTracking.d.ts +204 -0
  130. package/lib/typescript/sdk/constants.d.ts +120 -0
  131. package/lib/typescript/sdk/errorTracking.d.ts +32 -0
  132. package/lib/typescript/sdk/index.d.ts +9 -0
  133. package/lib/typescript/sdk/metricsTracking.d.ts +58 -0
  134. package/lib/typescript/sdk/navigation.d.ts +33 -0
  135. package/lib/typescript/sdk/networkInterceptor.d.ts +47 -0
  136. package/lib/typescript/sdk/utils.d.ts +148 -0
  137. package/lib/typescript/types/index.d.ts +624 -0
  138. package/package.json +102 -0
  139. package/rejourney.podspec +21 -0
  140. package/src/NativeRejourney.ts +165 -0
  141. package/src/components/Mask.tsx +80 -0
  142. package/src/index.ts +1459 -0
  143. package/src/sdk/autoTracking.ts +1373 -0
  144. package/src/sdk/constants.ts +134 -0
  145. package/src/sdk/errorTracking.ts +231 -0
  146. package/src/sdk/index.ts +11 -0
  147. package/src/sdk/metricsTracking.ts +232 -0
  148. package/src/sdk/navigation.ts +157 -0
  149. package/src/sdk/networkInterceptor.ts +440 -0
  150. package/src/sdk/utils.ts +369 -0
  151. package/src/types/expo-router.d.ts +7 -0
  152. package/src/types/index.ts +739 -0
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getCurrentRouteFromState = getCurrentRouteFromState;
7
+ exports.getScreenNameFromPath = getScreenNameFromPath;
8
+ exports.normalizeScreenName = normalizeScreenName;
9
+ /**
10
+ * Rejourney Navigation Utilities
11
+ *
12
+ * Helper functions for extracting human-readable screen names from
13
+ * React Navigation / Expo Router state.
14
+ *
15
+ * These functions are used internally by the SDK's automatic navigation
16
+ * detection. You don't need to import or use these directly.
17
+ */
18
+
19
+ /**
20
+ * Normalize a screen name to be human-readable
21
+ * Handles common patterns from React Native / Expo Router
22
+ *
23
+ * @param raw - Raw screen name to normalize
24
+ * @returns Cleaned, human-readable screen name
25
+ */
26
+ function normalizeScreenName(raw) {
27
+ if (!raw) return 'Unknown';
28
+ let name = raw;
29
+
30
+ // 1. Remove non-printable characters and weird symbols (often from icons)
31
+ name = name.replace(/[^\x20-\x7E\s]/g, '');
32
+
33
+ // 2. Handle hyphens: my-recipes -> My Recipes
34
+ name = name.split(/[-_]/).map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
35
+
36
+ // 3. Remove common suffixes
37
+ const suffixes = ['Screen', 'Page', 'View', 'Controller', 'ViewController', 'VC'];
38
+ for (const suffix of suffixes) {
39
+ if (name.endsWith(suffix) && name.length > suffix.length) {
40
+ name = name.slice(0, -suffix.length).trim();
41
+ }
42
+ }
43
+
44
+ // 4. Remove common prefixes (React Native internals)
45
+ const prefixes = ['RNS', 'RCT', 'RN', 'UI'];
46
+ for (const prefix of prefixes) {
47
+ if (name.startsWith(prefix) && name.length > prefix.length + 2) {
48
+ name = name.slice(prefix.length).trim();
49
+ }
50
+ }
51
+
52
+ // 5. Handle dynamic route params: [id] -> (omit), [userId] -> "User"
53
+ name = name.replace(/\[([a-zA-Z]+)(?:Id)?\]/g, (_, param) => {
54
+ const clean = param.replace(/Id$/i, '');
55
+ if (clean.length < 2) return '';
56
+ return clean.charAt(0).toUpperCase() + clean.slice(1);
57
+ });
58
+
59
+ // 6. Remove leftover brackets
60
+ name = name.replace(/\[\]/g, '');
61
+
62
+ // 7. Convert camelCase/PascalCase to Title Case with spaces
63
+ name = name.replace(/([a-z])([A-Z])/g, '$1 $2');
64
+
65
+ // 8. Clean up multiple spaces and trim
66
+ name = name.replace(/\s+/g, ' ').trim();
67
+
68
+ // 9. Capitalize first letter
69
+ if (name.length > 0) {
70
+ name = name.charAt(0).toUpperCase() + name.slice(1);
71
+ }
72
+ return name || 'Unknown';
73
+ }
74
+
75
+ /**
76
+ * Get a human-readable screen name from Expo Router path and segments
77
+ *
78
+ * @param pathname - The current route pathname
79
+ * @param segments - Route segments from useSegments()
80
+ * @returns Human-readable screen name
81
+ */
82
+ function getScreenNameFromPath(pathname, segments) {
83
+ // Use segments for cleaner names if available
84
+ if (segments.length > 0) {
85
+ // Filter out group markers like (tabs), (auth), etc.
86
+ const cleanSegments = segments.filter(s => !s.startsWith('(') && !s.endsWith(')'));
87
+ if (cleanSegments.length > 0) {
88
+ // Process each segment
89
+ const processedSegments = cleanSegments.map(s => {
90
+ // Handle dynamic params like [id]
91
+ if (s.startsWith('[') && s.endsWith(']')) {
92
+ const param = s.slice(1, -1);
93
+ // Skip pure ID params, keep meaningful ones
94
+ if (param === 'id' || param === 'slug') return null;
95
+ // Extract meaningful part: userId -> User
96
+ const clean = param.replace(/Id$/i, '');
97
+ return clean.charAt(0).toUpperCase() + clean.slice(1);
98
+ }
99
+ // Regular segment - capitalize
100
+ return s.charAt(0).toUpperCase() + s.slice(1);
101
+ }).filter(Boolean);
102
+ if (processedSegments.length > 0) {
103
+ return processedSegments.join(' > ');
104
+ }
105
+ }
106
+ }
107
+
108
+ // Fall back to pathname
109
+ if (!pathname || pathname === '/') {
110
+ return 'Home';
111
+ }
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
118
+ if (param === 'id' || param === 'slug') return '';
119
+ const clean = param.replace(/Id$/i, '');
120
+ 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();
126
+ if (!cleanPath) {
127
+ return 'Home';
128
+ }
129
+
130
+ // Capitalize first letter of each word
131
+ return cleanPath.split(' > ').map(s => s.charAt(0).toUpperCase() + s.slice(1)).filter(s => s.length > 0).join(' > ') || 'Home';
132
+ }
133
+
134
+ /**
135
+ * Get the current route name from a navigation state object
136
+ *
137
+ * @param state - React Navigation state object
138
+ * @returns Current route name or null
139
+ */
140
+ function getCurrentRouteFromState(state) {
141
+ if (!state || !state.routes) return null;
142
+ const route = state.routes[state.index ?? state.routes.length - 1];
143
+ if (!route) return null;
144
+
145
+ // If nested state, recurse
146
+ if (route.state) {
147
+ return getCurrentRouteFromState(route.state);
148
+ }
149
+ return route.name || null;
150
+ }
151
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1,412 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.disableNetworkInterceptor = disableNetworkInterceptor;
7
+ exports.enableNetworkInterceptor = enableNetworkInterceptor;
8
+ exports.flushNetworkRequests = flushNetworkRequests;
9
+ exports.getNetworkInterceptorStats = getNetworkInterceptorStats;
10
+ exports.initNetworkInterceptor = initNetworkInterceptor;
11
+ exports.restoreNetworkInterceptor = restoreNetworkInterceptor;
12
+ /**
13
+ * Network Interceptor for Rejourney - Optimized Version
14
+ *
15
+ * Automatically intercepts fetch() and XMLHttpRequest to log API calls.
16
+ *
17
+ * PERFORMANCE OPTIMIZATIONS:
18
+ * - Minimal synchronous overhead (just captures timing, no processing)
19
+ * - Batched async logging (doesn't block requests)
20
+ * - Circular buffer with max size limit
21
+ * - Sampling for high-frequency endpoints
22
+ * - No string allocations in hot path
23
+ * - Lazy URL parsing
24
+ * - PII Scrubbing for query parameters
25
+ */
26
+
27
+ // Store original implementations
28
+ let originalFetch = null;
29
+ let originalXHROpen = null;
30
+ let originalXHRSend = null;
31
+
32
+ // Callback to log network requests (called asynchronously)
33
+ let logCallback = null;
34
+
35
+ // Pending requests buffer (circular buffer for memory efficiency)
36
+ const MAX_PENDING_REQUESTS = 100;
37
+ const pendingRequests = new Array(MAX_PENDING_REQUESTS).fill(null);
38
+ let pendingHead = 0;
39
+ let pendingTail = 0;
40
+ let pendingCount = 0;
41
+
42
+ // Flush timer
43
+ let flushTimer = null;
44
+ const FLUSH_INTERVAL = 500; // Flush every 500ms
45
+
46
+ // Sampling for high-frequency endpoints
47
+ 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
52
+ const config = {
53
+ enabled: true,
54
+ ignorePatterns: [],
55
+ // Simple string patterns for fast matching
56
+ maxUrlLength: 300,
57
+ // Shorter for efficiency
58
+ captureSizes: false // Disabled by default for performance
59
+ };
60
+
61
+ // PII Scrubbing - Sensitive keys to look for in query params
62
+ const SENSITIVE_KEYS = ['token', 'key', 'secret', 'password', 'auth', 'access_token', 'api_key'];
63
+
64
+ /**
65
+ * Scrub sensitive data from URL
66
+ */
67
+ function scrubUrl(url) {
68
+ try {
69
+ // Fast check if URL might contain params
70
+ if (url.indexOf('?') === -1) return url;
71
+ const urlObj = new URL(url);
72
+ let modified = false;
73
+ SENSITIVE_KEYS.forEach(key => {
74
+ if (urlObj.searchParams.has(key)) {
75
+ urlObj.searchParams.set(key, '[REDACTED]');
76
+ modified = true;
77
+ }
78
+ });
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
+ return modified ? urlObj.toString() : url;
84
+ } catch {
85
+ // If URL parsing fails (relative URL?), try primitive replacement
86
+ let scrubbed = url;
87
+ SENSITIVE_KEYS.forEach(key => {
88
+ const regex = new RegExp(`([?&])${key}=[^&]*`, 'gi');
89
+ scrubbed = scrubbed.replace(regex, `$1${key}=[REDACTED]`);
90
+ });
91
+ return scrubbed;
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Fast check if URL should be ignored (no regex for speed)
97
+ */
98
+ function shouldIgnoreUrl(url) {
99
+ const patterns = config.ignorePatterns;
100
+ for (let i = 0; i < patterns.length; i++) {
101
+ const pattern = patterns[i];
102
+ if (pattern && url.indexOf(pattern) !== -1) return true;
103
+ }
104
+ return false;
105
+ }
106
+
107
+ /**
108
+ * Check if we should sample this request (rate limiting per endpoint)
109
+ */
110
+ function shouldSampleRequest(urlPath) {
111
+ const now = Date.now();
112
+ let entry = endpointCounts.get(urlPath);
113
+ if (!entry || now - entry.lastReset > SAMPLE_WINDOW) {
114
+ entry = {
115
+ count: 0,
116
+ lastReset: now
117
+ };
118
+ endpointCounts.set(urlPath, entry);
119
+ }
120
+ entry.count++;
121
+ return entry.count <= MAX_PER_ENDPOINT;
122
+ }
123
+
124
+ /**
125
+ * Add request to pending buffer (non-blocking)
126
+ */
127
+ function queueRequest(request) {
128
+ if (pendingCount >= MAX_PENDING_REQUESTS) {
129
+ // Buffer full, drop oldest
130
+ pendingHead = (pendingHead + 1) % MAX_PENDING_REQUESTS;
131
+ pendingCount--;
132
+ }
133
+
134
+ // Scrub URL before queuing
135
+ request.url = scrubUrl(request.url);
136
+ pendingRequests[pendingTail] = request;
137
+ pendingTail = (pendingTail + 1) % MAX_PENDING_REQUESTS;
138
+ pendingCount++;
139
+
140
+ // Schedule flush if not already scheduled
141
+ if (!flushTimer) {
142
+ flushTimer = setTimeout(flushPendingRequests, FLUSH_INTERVAL);
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Flush pending requests to callback
148
+ */
149
+ function flushPendingRequests() {
150
+ flushTimer = null;
151
+ if (!logCallback || pendingCount === 0) return;
152
+
153
+ // Process all pending requests
154
+ while (pendingCount > 0) {
155
+ const request = pendingRequests[pendingHead];
156
+ pendingRequests[pendingHead] = null; // Allow GC
157
+ pendingHead = (pendingHead + 1) % MAX_PENDING_REQUESTS;
158
+ pendingCount--;
159
+ if (request) {
160
+ try {
161
+ logCallback(request);
162
+ } catch {
163
+ // Ignore logging errors
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Parse URL efficiently (only extract what we need)
171
+ */
172
+ function parseUrlFast(url) {
173
+ // Fast path for common patterns
174
+ let hostEnd = -1;
175
+ let pathStart = -1;
176
+
177
+ // Find ://
178
+ const protoEnd = url.indexOf('://');
179
+ if (protoEnd !== -1) {
180
+ const afterProto = protoEnd + 3;
181
+ // Find end of host (first / after ://)
182
+ const slashPos = url.indexOf('/', afterProto);
183
+ if (slashPos !== -1) {
184
+ hostEnd = slashPos;
185
+ pathStart = slashPos;
186
+ } else {
187
+ hostEnd = url.length;
188
+ pathStart = url.length;
189
+ }
190
+ return {
191
+ host: url.substring(afterProto, hostEnd),
192
+ path: pathStart < url.length ? url.substring(pathStart) : '/'
193
+ };
194
+ }
195
+
196
+ // Relative URL
197
+ return {
198
+ host: '',
199
+ path: url
200
+ };
201
+ }
202
+
203
+ /**
204
+ * Intercept fetch - minimal overhead version
205
+ */
206
+ function interceptFetch() {
207
+ if (typeof globalThis.fetch === 'undefined') return;
208
+ if (originalFetch) return;
209
+ originalFetch = globalThis.fetch;
210
+ globalThis.fetch = function optimizedFetch(input, init) {
211
+ // Fast path: if disabled or no callback, skip entirely
212
+ if (!config.enabled || !logCallback) {
213
+ return originalFetch(input, init);
214
+ }
215
+
216
+ // Extract URL string (minimal work)
217
+ const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
218
+
219
+ // Fast ignore check
220
+ if (shouldIgnoreUrl(url)) {
221
+ return originalFetch(input, init);
222
+ }
223
+
224
+ // Parse URL and check sampling
225
+ const {
226
+ path
227
+ } = parseUrlFast(url);
228
+ if (!shouldSampleRequest(path)) {
229
+ return originalFetch(input, init);
230
+ }
231
+
232
+ // Capture start time (only synchronous work)
233
+ const startTime = Date.now();
234
+ const method = (init?.method || 'GET').toUpperCase();
235
+
236
+ // Call original fetch
237
+ return originalFetch(input, init).then(response => {
238
+ // Success - queue the log asynchronously
239
+ queueRequest({
240
+ requestId: `f${startTime}`,
241
+ method,
242
+ url: url.length > config.maxUrlLength ? url.substring(0, config.maxUrlLength) : url,
243
+ statusCode: response.status,
244
+ duration: Date.now() - startTime,
245
+ startTimestamp: startTime,
246
+ endTimestamp: Date.now(),
247
+ success: response.ok
248
+ });
249
+ return response;
250
+ }, error => {
251
+ // Error - queue the log asynchronously
252
+ queueRequest({
253
+ requestId: `f${startTime}`,
254
+ method,
255
+ url: url.length > config.maxUrlLength ? url.substring(0, config.maxUrlLength) : url,
256
+ statusCode: 0,
257
+ duration: Date.now() - startTime,
258
+ startTimestamp: startTime,
259
+ endTimestamp: Date.now(),
260
+ success: false,
261
+ errorMessage: error?.message || 'Network error'
262
+ });
263
+ throw error;
264
+ });
265
+ };
266
+ }
267
+
268
+ /**
269
+ * Intercept XMLHttpRequest - minimal overhead version
270
+ */
271
+ function interceptXHR() {
272
+ if (typeof XMLHttpRequest === 'undefined') return;
273
+ if (originalXHROpen) return;
274
+ originalXHROpen = XMLHttpRequest.prototype.open;
275
+ originalXHRSend = XMLHttpRequest.prototype.send;
276
+ XMLHttpRequest.prototype.open = function (method, url, async = true, username, password) {
277
+ const urlString = typeof url === 'string' ? url : url.toString();
278
+
279
+ // Store minimal info
280
+ this.__rj = {
281
+ m: method.toUpperCase(),
282
+ u: urlString,
283
+ t: 0
284
+ };
285
+ return originalXHROpen.call(this, method, urlString, async, username, password);
286
+ };
287
+ XMLHttpRequest.prototype.send = function (body) {
288
+ const data = this.__rj;
289
+ if (!config.enabled || !logCallback || !data || shouldIgnoreUrl(data.u)) {
290
+ return originalXHRSend.call(this, body);
291
+ }
292
+
293
+ // Check sampling
294
+ const {
295
+ path
296
+ } = parseUrlFast(data.u);
297
+ if (!shouldSampleRequest(path)) {
298
+ return originalXHRSend.call(this, body);
299
+ }
300
+ data.t = Date.now();
301
+ const onComplete = () => {
302
+ const endTime = Date.now();
303
+ queueRequest({
304
+ requestId: `x${data.t}`,
305
+ method: data.m,
306
+ url: data.u.length > config.maxUrlLength ? data.u.substring(0, config.maxUrlLength) : data.u,
307
+ statusCode: this.status,
308
+ duration: endTime - data.t,
309
+ startTimestamp: data.t,
310
+ endTimestamp: endTime,
311
+ success: this.status >= 200 && this.status < 400,
312
+ errorMessage: this.status === 0 ? 'Network error' : undefined
313
+ });
314
+ };
315
+
316
+ // Use load/error events (more efficient than readystatechange)
317
+ // Note: We use basic addEventListener without options for RN compatibility
318
+ this.addEventListener('load', onComplete);
319
+ this.addEventListener('error', onComplete);
320
+ this.addEventListener('abort', onComplete);
321
+ return originalXHRSend.call(this, body);
322
+ };
323
+ }
324
+
325
+ /**
326
+ * Initialize network interception
327
+ */
328
+ function initNetworkInterceptor(callback, options) {
329
+ logCallback = callback;
330
+
331
+ // Convert patterns to simple strings for fast matching
332
+ if (options?.ignoreUrls) {
333
+ config.ignorePatterns = options.ignoreUrls.filter(p => typeof p === 'string');
334
+ // Note: RegExp patterns are not supported in optimized version for performance
335
+ }
336
+ if (options?.captureSizes !== undefined) {
337
+ config.captureSizes = options.captureSizes;
338
+ }
339
+ interceptFetch();
340
+ interceptXHR();
341
+ }
342
+
343
+ /**
344
+ * Disable network interception
345
+ */
346
+ function disableNetworkInterceptor() {
347
+ config.enabled = false;
348
+
349
+ // Flush any pending requests
350
+ if (flushTimer) {
351
+ clearTimeout(flushTimer);
352
+ flushTimer = null;
353
+ }
354
+ flushPendingRequests();
355
+ }
356
+
357
+ /**
358
+ * Re-enable network interception
359
+ */
360
+ function enableNetworkInterceptor() {
361
+ config.enabled = true;
362
+ }
363
+
364
+ /**
365
+ * Force flush pending requests (call before app termination)
366
+ */
367
+ function flushNetworkRequests() {
368
+ if (flushTimer) {
369
+ clearTimeout(flushTimer);
370
+ flushTimer = null;
371
+ }
372
+ flushPendingRequests();
373
+ }
374
+
375
+ /**
376
+ * Restore original fetch and XHR
377
+ */
378
+ function restoreNetworkInterceptor() {
379
+ if (originalFetch) {
380
+ globalThis.fetch = originalFetch;
381
+ originalFetch = null;
382
+ }
383
+ if (originalXHROpen && originalXHRSend) {
384
+ XMLHttpRequest.prototype.open = originalXHROpen;
385
+ XMLHttpRequest.prototype.send = originalXHRSend;
386
+ originalXHROpen = null;
387
+ originalXHRSend = null;
388
+ }
389
+ logCallback = null;
390
+
391
+ // Clear state
392
+ pendingHead = 0;
393
+ pendingTail = 0;
394
+ pendingCount = 0;
395
+ endpointCounts.clear();
396
+ if (flushTimer) {
397
+ clearTimeout(flushTimer);
398
+ flushTimer = null;
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Get stats for debugging
404
+ */
405
+ function getNetworkInterceptorStats() {
406
+ return {
407
+ pendingCount,
408
+ endpointCount: endpointCounts.size,
409
+ enabled: config.enabled
410
+ };
411
+ }
412
+ //# sourceMappingURL=networkInterceptor.js.map