@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,364 @@
1
+ /**
2
+ * Copyright 2026 Rejourney
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * Network Interceptor for Rejourney - Optimized Version
19
+ *
20
+ * Automatically intercepts fetch() and XMLHttpRequest to log API calls.
21
+ *
22
+ * PERFORMANCE OPTIMIZATIONS:
23
+ * - Minimal synchronous overhead (just captures timing, no processing)
24
+ * - Batched async logging (doesn't block requests)
25
+ * - Circular buffer with max size limit
26
+ * - Sampling for high-frequency endpoints
27
+ * - No string allocations in hot path
28
+ * - Lazy URL parsing
29
+ * - PII Scrubbing for query parameters
30
+ */
31
+
32
+ let originalFetch = null;
33
+ let originalXHROpen = null;
34
+ let originalXHRSend = null;
35
+ let logCallback = null;
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
+ let flushTimer = null;
42
+ const FLUSH_INTERVAL = 500;
43
+ const endpointCounts = new Map();
44
+ const SAMPLE_WINDOW = 10000;
45
+ const MAX_PER_ENDPOINT = 20;
46
+ const config = {
47
+ enabled: true,
48
+ ignorePatterns: [],
49
+ maxUrlLength: 300,
50
+ captureSizes: false
51
+ };
52
+ const SENSITIVE_KEYS = ['token', 'key', 'secret', 'password', 'auth', 'access_token', 'api_key'];
53
+
54
+ /**
55
+ * Scrub sensitive data from URL
56
+ */
57
+ function scrubUrl(url) {
58
+ try {
59
+ if (url.indexOf('?') === -1) return url;
60
+ const urlObj = new URL(url);
61
+ let modified = false;
62
+ SENSITIVE_KEYS.forEach(key => {
63
+ if (urlObj.searchParams.has(key)) {
64
+ urlObj.searchParams.set(key, '[REDACTED]');
65
+ modified = true;
66
+ }
67
+ });
68
+ return modified ? urlObj.toString() : url;
69
+ } catch {
70
+ // Ignore error, fallback to primitive scrubbing
71
+
72
+ let scrubbed = url;
73
+ SENSITIVE_KEYS.forEach(key => {
74
+ const regex = new RegExp(`([?&])${key}=[^&]*`, 'gi');
75
+ scrubbed = scrubbed.replace(regex, `$1${key}=[REDACTED]`);
76
+ });
77
+ return scrubbed;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Fast check if URL should be ignored (no regex for speed)
83
+ */
84
+ function shouldIgnoreUrl(url) {
85
+ const patterns = config.ignorePatterns;
86
+ for (let i = 0; i < patterns.length; i++) {
87
+ const pattern = patterns[i];
88
+ if (pattern && url.indexOf(pattern) !== -1) return true;
89
+ }
90
+ return false;
91
+ }
92
+
93
+ /**
94
+ * Check if we should sample this request (rate limiting per endpoint)
95
+ */
96
+ function shouldSampleRequest(urlPath) {
97
+ const now = Date.now();
98
+ let entry = endpointCounts.get(urlPath);
99
+ if (!entry || now - entry.lastReset > SAMPLE_WINDOW) {
100
+ entry = {
101
+ count: 0,
102
+ lastReset: now
103
+ };
104
+ endpointCounts.set(urlPath, entry);
105
+ }
106
+ entry.count++;
107
+ return entry.count <= MAX_PER_ENDPOINT;
108
+ }
109
+
110
+ /**
111
+ * Add request to pending buffer (non-blocking)
112
+ */
113
+ function queueRequest(request) {
114
+ if (pendingCount >= MAX_PENDING_REQUESTS) {
115
+ // Buffer full, drop oldest
116
+ pendingHead = (pendingHead + 1) % MAX_PENDING_REQUESTS;
117
+ pendingCount--;
118
+ }
119
+ request.url = scrubUrl(request.url);
120
+ pendingRequests[pendingTail] = request;
121
+ pendingTail = (pendingTail + 1) % MAX_PENDING_REQUESTS;
122
+ pendingCount++;
123
+ if (!flushTimer) {
124
+ flushTimer = setTimeout(flushPendingRequests, FLUSH_INTERVAL);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Flush pending requests to callback
130
+ */
131
+ function flushPendingRequests() {
132
+ flushTimer = null;
133
+ if (!logCallback || pendingCount === 0) return;
134
+ while (pendingCount > 0) {
135
+ const request = pendingRequests[pendingHead];
136
+ pendingRequests[pendingHead] = null; // Allow GC
137
+ pendingHead = (pendingHead + 1) % MAX_PENDING_REQUESTS;
138
+ pendingCount--;
139
+ if (request) {
140
+ try {
141
+ logCallback(request);
142
+ } catch {
143
+ // Ignore
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Parse URL efficiently (only extract what we need)
151
+ */
152
+ function parseUrlFast(url) {
153
+ // Fast path for common patterns
154
+ let hostEnd = -1;
155
+ let pathStart = -1;
156
+ const protoEnd = url.indexOf('://');
157
+ if (protoEnd !== -1) {
158
+ const afterProto = protoEnd + 3;
159
+ const slashPos = url.indexOf('/', afterProto);
160
+ if (slashPos !== -1) {
161
+ hostEnd = slashPos;
162
+ pathStart = slashPos;
163
+ } else {
164
+ hostEnd = url.length;
165
+ pathStart = url.length;
166
+ }
167
+ return {
168
+ host: url.substring(afterProto, hostEnd),
169
+ path: pathStart < url.length ? url.substring(pathStart) : '/'
170
+ };
171
+ }
172
+ return {
173
+ host: '',
174
+ path: url
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Intercept fetch - minimal overhead version
180
+ */
181
+ function interceptFetch() {
182
+ if (typeof globalThis.fetch === 'undefined') return;
183
+ if (originalFetch) return;
184
+ originalFetch = globalThis.fetch;
185
+ globalThis.fetch = function optimizedFetch(input, init) {
186
+ if (!config.enabled || !logCallback) {
187
+ return originalFetch(input, init);
188
+ }
189
+ const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
190
+ if (shouldIgnoreUrl(url)) {
191
+ return originalFetch(input, init);
192
+ }
193
+
194
+ // Parse URL and check sampling
195
+ const {
196
+ path
197
+ } = parseUrlFast(url);
198
+ if (!shouldSampleRequest(path)) {
199
+ return originalFetch(input, init);
200
+ }
201
+ const startTime = Date.now();
202
+ const method = (init?.method || 'GET').toUpperCase();
203
+ return originalFetch(input, init).then(response => {
204
+ queueRequest({
205
+ requestId: `f${startTime}`,
206
+ method,
207
+ url: url.length > config.maxUrlLength ? url.substring(0, config.maxUrlLength) : url,
208
+ statusCode: response.status,
209
+ duration: Date.now() - startTime,
210
+ startTimestamp: startTime,
211
+ endTimestamp: Date.now(),
212
+ success: response.ok
213
+ });
214
+ return response;
215
+ }, error => {
216
+ queueRequest({
217
+ requestId: `f${startTime}`,
218
+ method,
219
+ url: url.length > config.maxUrlLength ? url.substring(0, config.maxUrlLength) : url,
220
+ statusCode: 0,
221
+ duration: Date.now() - startTime,
222
+ startTimestamp: startTime,
223
+ endTimestamp: Date.now(),
224
+ success: false,
225
+ errorMessage: error?.message || 'Network error'
226
+ });
227
+ throw error;
228
+ });
229
+ };
230
+ }
231
+
232
+ /**
233
+ * Intercept XMLHttpRequest - minimal overhead version
234
+ */
235
+ function interceptXHR() {
236
+ if (typeof XMLHttpRequest === 'undefined') return;
237
+ if (originalXHROpen) return;
238
+ originalXHROpen = XMLHttpRequest.prototype.open;
239
+ originalXHRSend = XMLHttpRequest.prototype.send;
240
+ XMLHttpRequest.prototype.open = function (method, url, async = true, username, password) {
241
+ const urlString = typeof url === 'string' ? url : url.toString();
242
+ this.__rj = {
243
+ m: method.toUpperCase(),
244
+ u: urlString,
245
+ t: 0
246
+ };
247
+ return originalXHROpen.call(this, method, urlString, async, username, password);
248
+ };
249
+ XMLHttpRequest.prototype.send = function (body) {
250
+ const data = this.__rj;
251
+ if (!config.enabled || !logCallback || !data || shouldIgnoreUrl(data.u)) {
252
+ return originalXHRSend.call(this, body);
253
+ }
254
+ const {
255
+ path
256
+ } = parseUrlFast(data.u);
257
+ if (!shouldSampleRequest(path)) {
258
+ return originalXHRSend.call(this, body);
259
+ }
260
+ data.t = Date.now();
261
+ const onComplete = () => {
262
+ const endTime = Date.now();
263
+ queueRequest({
264
+ requestId: `x${data.t}`,
265
+ method: data.m,
266
+ url: data.u.length > config.maxUrlLength ? data.u.substring(0, config.maxUrlLength) : data.u,
267
+ statusCode: this.status,
268
+ duration: endTime - data.t,
269
+ startTimestamp: data.t,
270
+ endTimestamp: endTime,
271
+ success: this.status >= 200 && this.status < 400,
272
+ errorMessage: this.status === 0 ? 'Network error' : undefined
273
+ });
274
+ };
275
+ this.addEventListener('load', onComplete);
276
+ this.addEventListener('error', onComplete);
277
+ this.addEventListener('abort', onComplete);
278
+ return originalXHRSend.call(this, body);
279
+ };
280
+ }
281
+
282
+ /**
283
+ * Initialize network interception
284
+ */
285
+ export function initNetworkInterceptor(callback, options) {
286
+ logCallback = callback;
287
+ if (options?.ignoreUrls) {
288
+ config.ignorePatterns = options.ignoreUrls.filter(p => typeof p === 'string');
289
+ }
290
+ if (options?.captureSizes !== undefined) {
291
+ config.captureSizes = options.captureSizes;
292
+ }
293
+ interceptFetch();
294
+ interceptXHR();
295
+ }
296
+
297
+ /**
298
+ * Disable network interception
299
+ */
300
+ export function disableNetworkInterceptor() {
301
+ config.enabled = false;
302
+ if (flushTimer) {
303
+ clearTimeout(flushTimer);
304
+ flushTimer = null;
305
+ }
306
+ flushPendingRequests();
307
+ }
308
+
309
+ /**
310
+ * Re-enable network interception
311
+ */
312
+ export function enableNetworkInterceptor() {
313
+ config.enabled = true;
314
+ }
315
+
316
+ /**
317
+ * Force flush pending requests (call before app termination)
318
+ */
319
+ export function flushNetworkRequests() {
320
+ if (flushTimer) {
321
+ clearTimeout(flushTimer);
322
+ flushTimer = null;
323
+ }
324
+ flushPendingRequests();
325
+ }
326
+
327
+ /**
328
+ * Restore original fetch and XHR
329
+ */
330
+ export function restoreNetworkInterceptor() {
331
+ if (originalFetch) {
332
+ globalThis.fetch = originalFetch;
333
+ originalFetch = null;
334
+ }
335
+ if (originalXHROpen && originalXHRSend) {
336
+ XMLHttpRequest.prototype.open = originalXHROpen;
337
+ XMLHttpRequest.prototype.send = originalXHRSend;
338
+ originalXHROpen = null;
339
+ originalXHRSend = null;
340
+ }
341
+ logCallback = null;
342
+
343
+ // Clear state
344
+ pendingHead = 0;
345
+ pendingTail = 0;
346
+ pendingCount = 0;
347
+ endpointCounts.clear();
348
+ if (flushTimer) {
349
+ clearTimeout(flushTimer);
350
+ flushTimer = null;
351
+ }
352
+ }
353
+
354
+ /**
355
+ * Get stats for debugging
356
+ */
357
+ export function getNetworkInterceptorStats() {
358
+ return {
359
+ pendingCount,
360
+ endpointCount: endpointCounts.size,
361
+ enabled: config.enabled
362
+ };
363
+ }
364
+ //# sourceMappingURL=networkInterceptor.js.map