@rejourneyco/react-native 1.0.7

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 (105) hide show
  1. package/README.md +29 -0
  2. package/android/build.gradle.kts +135 -0
  3. package/android/consumer-rules.pro +10 -0
  4. package/android/proguard-rules.pro +1 -0
  5. package/android/src/main/AndroidManifest.xml +15 -0
  6. package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +860 -0
  7. package/android/src/main/java/com/rejourney/engine/DeviceRegistrar.kt +290 -0
  8. package/android/src/main/java/com/rejourney/engine/DiagnosticLog.kt +385 -0
  9. package/android/src/main/java/com/rejourney/engine/RejourneyImpl.kt +512 -0
  10. package/android/src/main/java/com/rejourney/platform/OEMDetector.kt +173 -0
  11. package/android/src/main/java/com/rejourney/platform/PerfTiming.kt +384 -0
  12. package/android/src/main/java/com/rejourney/platform/SessionLifecycleService.kt +160 -0
  13. package/android/src/main/java/com/rejourney/platform/Telemetry.kt +301 -0
  14. package/android/src/main/java/com/rejourney/platform/WindowUtils.kt +100 -0
  15. package/android/src/main/java/com/rejourney/recording/AnrSentinel.kt +129 -0
  16. package/android/src/main/java/com/rejourney/recording/EventBuffer.kt +330 -0
  17. package/android/src/main/java/com/rejourney/recording/InteractionRecorder.kt +519 -0
  18. package/android/src/main/java/com/rejourney/recording/ReplayOrchestrator.kt +740 -0
  19. package/android/src/main/java/com/rejourney/recording/SegmentDispatcher.kt +559 -0
  20. package/android/src/main/java/com/rejourney/recording/StabilityMonitor.kt +238 -0
  21. package/android/src/main/java/com/rejourney/recording/TelemetryPipeline.kt +633 -0
  22. package/android/src/main/java/com/rejourney/recording/ViewHierarchyScanner.kt +232 -0
  23. package/android/src/main/java/com/rejourney/recording/VisualCapture.kt +474 -0
  24. package/android/src/main/java/com/rejourney/utility/DataCompression.kt +63 -0
  25. package/android/src/main/java/com/rejourney/utility/ImageBlur.kt +412 -0
  26. package/android/src/main/java/com/rejourney/utility/ViewIdentifier.kt +169 -0
  27. package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +232 -0
  28. package/android/src/newarch/java/com/rejourney/RejourneyPackage.kt +40 -0
  29. package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +268 -0
  30. package/android/src/oldarch/java/com/rejourney/RejourneyPackage.kt +23 -0
  31. package/ios/Engine/DeviceRegistrar.swift +288 -0
  32. package/ios/Engine/DiagnosticLog.swift +387 -0
  33. package/ios/Engine/RejourneyImpl.swift +719 -0
  34. package/ios/Recording/AnrSentinel.swift +142 -0
  35. package/ios/Recording/EventBuffer.swift +326 -0
  36. package/ios/Recording/InteractionRecorder.swift +428 -0
  37. package/ios/Recording/ReplayOrchestrator.swift +624 -0
  38. package/ios/Recording/SegmentDispatcher.swift +492 -0
  39. package/ios/Recording/StabilityMonitor.swift +223 -0
  40. package/ios/Recording/TelemetryPipeline.swift +547 -0
  41. package/ios/Recording/ViewHierarchyScanner.swift +156 -0
  42. package/ios/Recording/VisualCapture.swift +675 -0
  43. package/ios/Rejourney.h +38 -0
  44. package/ios/Rejourney.mm +375 -0
  45. package/ios/Utility/DataCompression.swift +55 -0
  46. package/ios/Utility/ImageBlur.swift +89 -0
  47. package/ios/Utility/RuntimeMethodSwap.swift +41 -0
  48. package/ios/Utility/ViewIdentifier.swift +37 -0
  49. package/lib/commonjs/NativeRejourney.js +40 -0
  50. package/lib/commonjs/components/Mask.js +88 -0
  51. package/lib/commonjs/index.js +1443 -0
  52. package/lib/commonjs/sdk/autoTracking.js +1087 -0
  53. package/lib/commonjs/sdk/constants.js +166 -0
  54. package/lib/commonjs/sdk/errorTracking.js +187 -0
  55. package/lib/commonjs/sdk/index.js +50 -0
  56. package/lib/commonjs/sdk/metricsTracking.js +205 -0
  57. package/lib/commonjs/sdk/navigation.js +128 -0
  58. package/lib/commonjs/sdk/networkInterceptor.js +375 -0
  59. package/lib/commonjs/sdk/utils.js +433 -0
  60. package/lib/commonjs/sdk/version.js +13 -0
  61. package/lib/commonjs/types/expo-router.d.js +2 -0
  62. package/lib/commonjs/types/index.js +2 -0
  63. package/lib/module/NativeRejourney.js +38 -0
  64. package/lib/module/components/Mask.js +83 -0
  65. package/lib/module/index.js +1341 -0
  66. package/lib/module/sdk/autoTracking.js +1059 -0
  67. package/lib/module/sdk/constants.js +154 -0
  68. package/lib/module/sdk/errorTracking.js +177 -0
  69. package/lib/module/sdk/index.js +26 -0
  70. package/lib/module/sdk/metricsTracking.js +187 -0
  71. package/lib/module/sdk/navigation.js +120 -0
  72. package/lib/module/sdk/networkInterceptor.js +364 -0
  73. package/lib/module/sdk/utils.js +412 -0
  74. package/lib/module/sdk/version.js +7 -0
  75. package/lib/module/types/expo-router.d.js +2 -0
  76. package/lib/module/types/index.js +2 -0
  77. package/lib/typescript/NativeRejourney.d.ts +160 -0
  78. package/lib/typescript/components/Mask.d.ts +54 -0
  79. package/lib/typescript/index.d.ts +117 -0
  80. package/lib/typescript/sdk/autoTracking.d.ts +226 -0
  81. package/lib/typescript/sdk/constants.d.ts +138 -0
  82. package/lib/typescript/sdk/errorTracking.d.ts +47 -0
  83. package/lib/typescript/sdk/index.d.ts +24 -0
  84. package/lib/typescript/sdk/metricsTracking.d.ts +75 -0
  85. package/lib/typescript/sdk/navigation.d.ts +48 -0
  86. package/lib/typescript/sdk/networkInterceptor.d.ts +62 -0
  87. package/lib/typescript/sdk/utils.d.ts +193 -0
  88. package/lib/typescript/sdk/version.d.ts +6 -0
  89. package/lib/typescript/types/index.d.ts +618 -0
  90. package/package.json +122 -0
  91. package/rejourney.podspec +23 -0
  92. package/src/NativeRejourney.ts +185 -0
  93. package/src/components/Mask.tsx +93 -0
  94. package/src/index.ts +1555 -0
  95. package/src/sdk/autoTracking.ts +1245 -0
  96. package/src/sdk/constants.ts +155 -0
  97. package/src/sdk/errorTracking.ts +231 -0
  98. package/src/sdk/index.ts +25 -0
  99. package/src/sdk/metricsTracking.ts +227 -0
  100. package/src/sdk/navigation.ts +152 -0
  101. package/src/sdk/networkInterceptor.ts +423 -0
  102. package/src/sdk/utils.ts +442 -0
  103. package/src/sdk/version.ts +6 -0
  104. package/src/types/expo-router.d.ts +7 -0
  105. package/src/types/index.ts +709 -0
@@ -0,0 +1,128 @@
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
+ * Copyright 2026 Rejourney
11
+ *
12
+ * Licensed under the Apache License, Version 2.0 (the "License");
13
+ * you may not use this file except in compliance with the License.
14
+ * You may obtain a copy of the License at
15
+ *
16
+ * http://www.apache.org/licenses/LICENSE-2.0
17
+ *
18
+ * Unless required by applicable law or agreed to in writing, software
19
+ * distributed under the License is distributed on an "AS IS" BASIS,
20
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ * See the License for the specific language governing permissions and
22
+ * limitations under the License.
23
+ */
24
+
25
+ /**
26
+ * Rejourney Navigation Utilities
27
+ *
28
+ * Helper functions for extracting human-readable screen names from
29
+ * React Navigation / Expo Router state.
30
+ *
31
+ * These functions are used internally by the SDK's automatic navigation
32
+ * detection. You don't need to import or use these directly.
33
+ */
34
+
35
+ /**
36
+ * Normalize a screen name to be human-readable
37
+ * Handles common patterns from React Native / Expo Router
38
+ *
39
+ * @param raw - Raw screen name to normalize
40
+ * @returns Cleaned, human-readable screen name
41
+ */
42
+ function normalizeScreenName(raw) {
43
+ if (!raw) return 'Unknown';
44
+ let name = raw;
45
+ name = name.replace(/[^\x20-\x7E\s]/g, '');
46
+ name = name.split(/[-_]/).map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
47
+ const suffixes = ['Screen', 'Page', 'View', 'Controller', 'ViewController', 'VC'];
48
+ for (const suffix of suffixes) {
49
+ if (name.endsWith(suffix) && name.length > suffix.length) {
50
+ name = name.slice(0, -suffix.length).trim();
51
+ }
52
+ }
53
+ const prefixes = ['RNS', 'RCT', 'RN', 'UI'];
54
+ for (const prefix of prefixes) {
55
+ if (name.startsWith(prefix) && name.length > prefix.length + 2) {
56
+ name = name.slice(prefix.length).trim();
57
+ }
58
+ }
59
+ name = name.replace(/\[([a-zA-Z]+)(?:Id)?\]/g, (_, param) => {
60
+ const clean = param.replace(/Id$/i, '');
61
+ if (clean.length < 2) return '';
62
+ return clean.charAt(0).toUpperCase() + clean.slice(1);
63
+ });
64
+ name = name.replace(/\[\]/g, '');
65
+ name = name.replace(/([a-z])([A-Z])/g, '$1 $2');
66
+ name = name.replace(/\s+/g, ' ').trim();
67
+ if (name.length > 0) {
68
+ name = name.charAt(0).toUpperCase() + name.slice(1);
69
+ }
70
+ return name || 'Unknown';
71
+ }
72
+
73
+ /**
74
+ * Get a human-readable screen name from Expo Router path and segments
75
+ *
76
+ * @param pathname - The current route pathname
77
+ * @param segments - Route segments from useSegments()
78
+ * @returns Human-readable screen name
79
+ */
80
+ function getScreenNameFromPath(pathname, segments) {
81
+ if (segments.length > 0) {
82
+ const cleanSegments = segments.filter(s => !s.startsWith('(') && !s.endsWith(')'));
83
+ if (cleanSegments.length > 0) {
84
+ const processedSegments = cleanSegments.map(s => {
85
+ if (s.startsWith('[') && s.endsWith(']')) {
86
+ const param = s.slice(1, -1);
87
+ if (param === 'id' || param === 'slug') return null;
88
+ if (param === 'id' || param === 'slug') return null;
89
+ const clean = param.replace(/Id$/i, '');
90
+ return clean.charAt(0).toUpperCase() + clean.slice(1);
91
+ }
92
+ return s.charAt(0).toUpperCase() + s.slice(1);
93
+ }).filter(Boolean);
94
+ if (processedSegments.length > 0) {
95
+ return processedSegments.join(' > ');
96
+ }
97
+ }
98
+ }
99
+ if (!pathname || pathname === '/') {
100
+ return 'Home';
101
+ }
102
+ const cleanPath = pathname.replace(/^\/(tabs)?/, '').replace(/\([^)]+\)/g, '').replace(/\[([^\]]+)\]/g, (_, param) => {
103
+ if (param === 'id' || param === 'slug') return '';
104
+ const clean = param.replace(/Id$/i, '');
105
+ return clean.charAt(0).toUpperCase() + clean.slice(1);
106
+ }).replace(/\/+/g, '/').replace(/^\//, '').replace(/\/$/, '').replace(/\//g, ' > ').trim();
107
+ if (!cleanPath) {
108
+ return 'Home';
109
+ }
110
+ return cleanPath.split(' > ').map(s => s.charAt(0).toUpperCase() + s.slice(1)).filter(s => s.length > 0).join(' > ') || 'Home';
111
+ }
112
+
113
+ /**
114
+ * Get the current route name from a navigation state object
115
+ *
116
+ * @param state - React Navigation state object
117
+ * @returns Current route name or null
118
+ */
119
+ function getCurrentRouteFromState(state) {
120
+ if (!state || !state.routes) return null;
121
+ const route = state.routes[state.index ?? state.routes.length - 1];
122
+ if (!route) return null;
123
+ if (route.state) {
124
+ return getCurrentRouteFromState(route.state);
125
+ }
126
+ return route.name || null;
127
+ }
128
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1,375 @@
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
+ * Copyright 2026 Rejourney
14
+ *
15
+ * Licensed under the Apache License, Version 2.0 (the "License");
16
+ * you may not use this file except in compliance with the License.
17
+ * You may obtain a copy of the License at
18
+ *
19
+ * http://www.apache.org/licenses/LICENSE-2.0
20
+ *
21
+ * Unless required by applicable law or agreed to in writing, software
22
+ * distributed under the License is distributed on an "AS IS" BASIS,
23
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
+ * See the License for the specific language governing permissions and
25
+ * limitations under the License.
26
+ */
27
+
28
+ /**
29
+ * Network Interceptor for Rejourney - Optimized Version
30
+ *
31
+ * Automatically intercepts fetch() and XMLHttpRequest to log API calls.
32
+ *
33
+ * PERFORMANCE OPTIMIZATIONS:
34
+ * - Minimal synchronous overhead (just captures timing, no processing)
35
+ * - Batched async logging (doesn't block requests)
36
+ * - Circular buffer with max size limit
37
+ * - Sampling for high-frequency endpoints
38
+ * - No string allocations in hot path
39
+ * - Lazy URL parsing
40
+ * - PII Scrubbing for query parameters
41
+ */
42
+
43
+ let originalFetch = null;
44
+ let originalXHROpen = null;
45
+ let originalXHRSend = null;
46
+ let logCallback = null;
47
+ const MAX_PENDING_REQUESTS = 100;
48
+ const pendingRequests = new Array(MAX_PENDING_REQUESTS).fill(null);
49
+ let pendingHead = 0;
50
+ let pendingTail = 0;
51
+ let pendingCount = 0;
52
+ let flushTimer = null;
53
+ const FLUSH_INTERVAL = 500;
54
+ const endpointCounts = new Map();
55
+ const SAMPLE_WINDOW = 10000;
56
+ const MAX_PER_ENDPOINT = 20;
57
+ const config = {
58
+ enabled: true,
59
+ ignorePatterns: [],
60
+ maxUrlLength: 300,
61
+ captureSizes: false
62
+ };
63
+ const SENSITIVE_KEYS = ['token', 'key', 'secret', 'password', 'auth', 'access_token', 'api_key'];
64
+
65
+ /**
66
+ * Scrub sensitive data from URL
67
+ */
68
+ function scrubUrl(url) {
69
+ try {
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
+ return modified ? urlObj.toString() : url;
80
+ } catch {
81
+ // Ignore error, fallback to primitive scrubbing
82
+
83
+ let scrubbed = url;
84
+ SENSITIVE_KEYS.forEach(key => {
85
+ const regex = new RegExp(`([?&])${key}=[^&]*`, 'gi');
86
+ scrubbed = scrubbed.replace(regex, `$1${key}=[REDACTED]`);
87
+ });
88
+ return scrubbed;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Fast check if URL should be ignored (no regex for speed)
94
+ */
95
+ function shouldIgnoreUrl(url) {
96
+ const patterns = config.ignorePatterns;
97
+ for (let i = 0; i < patterns.length; i++) {
98
+ const pattern = patterns[i];
99
+ if (pattern && url.indexOf(pattern) !== -1) return true;
100
+ }
101
+ return false;
102
+ }
103
+
104
+ /**
105
+ * Check if we should sample this request (rate limiting per endpoint)
106
+ */
107
+ function shouldSampleRequest(urlPath) {
108
+ const now = Date.now();
109
+ let entry = endpointCounts.get(urlPath);
110
+ if (!entry || now - entry.lastReset > SAMPLE_WINDOW) {
111
+ entry = {
112
+ count: 0,
113
+ lastReset: now
114
+ };
115
+ endpointCounts.set(urlPath, entry);
116
+ }
117
+ entry.count++;
118
+ return entry.count <= MAX_PER_ENDPOINT;
119
+ }
120
+
121
+ /**
122
+ * Add request to pending buffer (non-blocking)
123
+ */
124
+ function queueRequest(request) {
125
+ if (pendingCount >= MAX_PENDING_REQUESTS) {
126
+ // Buffer full, drop oldest
127
+ pendingHead = (pendingHead + 1) % MAX_PENDING_REQUESTS;
128
+ pendingCount--;
129
+ }
130
+ request.url = scrubUrl(request.url);
131
+ pendingRequests[pendingTail] = request;
132
+ pendingTail = (pendingTail + 1) % MAX_PENDING_REQUESTS;
133
+ pendingCount++;
134
+ if (!flushTimer) {
135
+ flushTimer = setTimeout(flushPendingRequests, FLUSH_INTERVAL);
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Flush pending requests to callback
141
+ */
142
+ function flushPendingRequests() {
143
+ flushTimer = null;
144
+ if (!logCallback || pendingCount === 0) return;
145
+ while (pendingCount > 0) {
146
+ const request = pendingRequests[pendingHead];
147
+ pendingRequests[pendingHead] = null; // Allow GC
148
+ pendingHead = (pendingHead + 1) % MAX_PENDING_REQUESTS;
149
+ pendingCount--;
150
+ if (request) {
151
+ try {
152
+ logCallback(request);
153
+ } catch {
154
+ // Ignore
155
+ }
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Parse URL efficiently (only extract what we need)
162
+ */
163
+ function parseUrlFast(url) {
164
+ // Fast path for common patterns
165
+ let hostEnd = -1;
166
+ let pathStart = -1;
167
+ const protoEnd = url.indexOf('://');
168
+ if (protoEnd !== -1) {
169
+ const afterProto = protoEnd + 3;
170
+ const slashPos = url.indexOf('/', afterProto);
171
+ if (slashPos !== -1) {
172
+ hostEnd = slashPos;
173
+ pathStart = slashPos;
174
+ } else {
175
+ hostEnd = url.length;
176
+ pathStart = url.length;
177
+ }
178
+ return {
179
+ host: url.substring(afterProto, hostEnd),
180
+ path: pathStart < url.length ? url.substring(pathStart) : '/'
181
+ };
182
+ }
183
+ return {
184
+ host: '',
185
+ path: url
186
+ };
187
+ }
188
+
189
+ /**
190
+ * Intercept fetch - minimal overhead version
191
+ */
192
+ function interceptFetch() {
193
+ if (typeof globalThis.fetch === 'undefined') return;
194
+ if (originalFetch) return;
195
+ originalFetch = globalThis.fetch;
196
+ globalThis.fetch = function optimizedFetch(input, init) {
197
+ if (!config.enabled || !logCallback) {
198
+ return originalFetch(input, init);
199
+ }
200
+ const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
201
+ if (shouldIgnoreUrl(url)) {
202
+ return originalFetch(input, init);
203
+ }
204
+
205
+ // Parse URL and check sampling
206
+ const {
207
+ path
208
+ } = parseUrlFast(url);
209
+ if (!shouldSampleRequest(path)) {
210
+ return originalFetch(input, init);
211
+ }
212
+ const startTime = Date.now();
213
+ const method = (init?.method || 'GET').toUpperCase();
214
+ return originalFetch(input, init).then(response => {
215
+ queueRequest({
216
+ requestId: `f${startTime}`,
217
+ method,
218
+ url: url.length > config.maxUrlLength ? url.substring(0, config.maxUrlLength) : url,
219
+ statusCode: response.status,
220
+ duration: Date.now() - startTime,
221
+ startTimestamp: startTime,
222
+ endTimestamp: Date.now(),
223
+ success: response.ok
224
+ });
225
+ return response;
226
+ }, error => {
227
+ queueRequest({
228
+ requestId: `f${startTime}`,
229
+ method,
230
+ url: url.length > config.maxUrlLength ? url.substring(0, config.maxUrlLength) : url,
231
+ statusCode: 0,
232
+ duration: Date.now() - startTime,
233
+ startTimestamp: startTime,
234
+ endTimestamp: Date.now(),
235
+ success: false,
236
+ errorMessage: error?.message || 'Network error'
237
+ });
238
+ throw error;
239
+ });
240
+ };
241
+ }
242
+
243
+ /**
244
+ * Intercept XMLHttpRequest - minimal overhead version
245
+ */
246
+ function interceptXHR() {
247
+ if (typeof XMLHttpRequest === 'undefined') return;
248
+ if (originalXHROpen) return;
249
+ originalXHROpen = XMLHttpRequest.prototype.open;
250
+ originalXHRSend = XMLHttpRequest.prototype.send;
251
+ XMLHttpRequest.prototype.open = function (method, url, async = true, username, password) {
252
+ const urlString = typeof url === 'string' ? url : url.toString();
253
+ this.__rj = {
254
+ m: method.toUpperCase(),
255
+ u: urlString,
256
+ t: 0
257
+ };
258
+ return originalXHROpen.call(this, method, urlString, async, username, password);
259
+ };
260
+ XMLHttpRequest.prototype.send = function (body) {
261
+ const data = this.__rj;
262
+ if (!config.enabled || !logCallback || !data || shouldIgnoreUrl(data.u)) {
263
+ return originalXHRSend.call(this, body);
264
+ }
265
+ const {
266
+ path
267
+ } = parseUrlFast(data.u);
268
+ if (!shouldSampleRequest(path)) {
269
+ return originalXHRSend.call(this, body);
270
+ }
271
+ data.t = Date.now();
272
+ const onComplete = () => {
273
+ const endTime = Date.now();
274
+ queueRequest({
275
+ requestId: `x${data.t}`,
276
+ method: data.m,
277
+ url: data.u.length > config.maxUrlLength ? data.u.substring(0, config.maxUrlLength) : data.u,
278
+ statusCode: this.status,
279
+ duration: endTime - data.t,
280
+ startTimestamp: data.t,
281
+ endTimestamp: endTime,
282
+ success: this.status >= 200 && this.status < 400,
283
+ errorMessage: this.status === 0 ? 'Network error' : undefined
284
+ });
285
+ };
286
+ this.addEventListener('load', onComplete);
287
+ this.addEventListener('error', onComplete);
288
+ this.addEventListener('abort', onComplete);
289
+ return originalXHRSend.call(this, body);
290
+ };
291
+ }
292
+
293
+ /**
294
+ * Initialize network interception
295
+ */
296
+ function initNetworkInterceptor(callback, options) {
297
+ logCallback = callback;
298
+ if (options?.ignoreUrls) {
299
+ config.ignorePatterns = options.ignoreUrls.filter(p => typeof p === 'string');
300
+ }
301
+ if (options?.captureSizes !== undefined) {
302
+ config.captureSizes = options.captureSizes;
303
+ }
304
+ interceptFetch();
305
+ interceptXHR();
306
+ }
307
+
308
+ /**
309
+ * Disable network interception
310
+ */
311
+ function disableNetworkInterceptor() {
312
+ config.enabled = false;
313
+ if (flushTimer) {
314
+ clearTimeout(flushTimer);
315
+ flushTimer = null;
316
+ }
317
+ flushPendingRequests();
318
+ }
319
+
320
+ /**
321
+ * Re-enable network interception
322
+ */
323
+ function enableNetworkInterceptor() {
324
+ config.enabled = true;
325
+ }
326
+
327
+ /**
328
+ * Force flush pending requests (call before app termination)
329
+ */
330
+ function flushNetworkRequests() {
331
+ if (flushTimer) {
332
+ clearTimeout(flushTimer);
333
+ flushTimer = null;
334
+ }
335
+ flushPendingRequests();
336
+ }
337
+
338
+ /**
339
+ * Restore original fetch and XHR
340
+ */
341
+ function restoreNetworkInterceptor() {
342
+ if (originalFetch) {
343
+ globalThis.fetch = originalFetch;
344
+ originalFetch = null;
345
+ }
346
+ if (originalXHROpen && originalXHRSend) {
347
+ XMLHttpRequest.prototype.open = originalXHROpen;
348
+ XMLHttpRequest.prototype.send = originalXHRSend;
349
+ originalXHROpen = null;
350
+ originalXHRSend = null;
351
+ }
352
+ logCallback = null;
353
+
354
+ // Clear state
355
+ pendingHead = 0;
356
+ pendingTail = 0;
357
+ pendingCount = 0;
358
+ endpointCounts.clear();
359
+ if (flushTimer) {
360
+ clearTimeout(flushTimer);
361
+ flushTimer = null;
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Get stats for debugging
367
+ */
368
+ function getNetworkInterceptorStats() {
369
+ return {
370
+ pendingCount,
371
+ endpointCount: endpointCounts.size,
372
+ enabled: config.enabled
373
+ };
374
+ }
375
+ //# sourceMappingURL=networkInterceptor.js.map