@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.
- package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +72 -391
- package/android/src/main/java/com/rejourney/capture/CaptureEngine.kt +11 -113
- package/android/src/main/java/com/rejourney/capture/SegmentUploader.kt +1 -15
- package/android/src/main/java/com/rejourney/capture/VideoEncoder.kt +1 -61
- package/android/src/main/java/com/rejourney/capture/ViewHierarchyScanner.kt +3 -1
- package/android/src/main/java/com/rejourney/lifecycle/SessionLifecycleService.kt +1 -22
- package/android/src/main/java/com/rejourney/network/DeviceAuthManager.kt +3 -26
- package/android/src/main/java/com/rejourney/network/NetworkMonitor.kt +0 -2
- package/android/src/main/java/com/rejourney/network/UploadManager.kt +7 -93
- package/android/src/main/java/com/rejourney/network/UploadWorker.kt +5 -41
- package/android/src/main/java/com/rejourney/privacy/PrivacyMask.kt +2 -58
- package/android/src/main/java/com/rejourney/touch/TouchInterceptor.kt +4 -4
- package/android/src/main/java/com/rejourney/utils/EventBuffer.kt +36 -7
- package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +7 -0
- package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +9 -0
- package/ios/Capture/RJCaptureEngine.m +3 -34
- package/ios/Capture/RJVideoEncoder.m +0 -26
- package/ios/Capture/RJViewHierarchyScanner.m +68 -51
- package/ios/Core/RJLifecycleManager.m +0 -14
- package/ios/Core/Rejourney.mm +53 -129
- package/ios/Network/RJDeviceAuthManager.m +0 -2
- package/ios/Network/RJUploadManager.h +8 -0
- package/ios/Network/RJUploadManager.m +45 -0
- package/ios/Privacy/RJPrivacyMask.m +5 -31
- package/ios/Rejourney.h +0 -14
- package/ios/Touch/RJTouchInterceptor.m +21 -15
- package/ios/Utils/RJEventBuffer.m +57 -69
- package/ios/Utils/RJPerfTiming.m +0 -5
- package/ios/Utils/RJWindowUtils.m +87 -87
- package/lib/commonjs/components/Mask.js +1 -6
- package/lib/commonjs/index.js +46 -117
- package/lib/commonjs/sdk/autoTracking.js +39 -313
- package/lib/commonjs/sdk/constants.js +2 -13
- package/lib/commonjs/sdk/errorTracking.js +1 -29
- package/lib/commonjs/sdk/metricsTracking.js +3 -24
- package/lib/commonjs/sdk/navigation.js +3 -42
- package/lib/commonjs/sdk/networkInterceptor.js +7 -60
- package/lib/commonjs/sdk/utils.js +73 -19
- package/lib/module/components/Mask.js +1 -6
- package/lib/module/index.js +45 -121
- package/lib/module/sdk/autoTracking.js +39 -314
- package/lib/module/sdk/constants.js +2 -13
- package/lib/module/sdk/errorTracking.js +1 -29
- package/lib/module/sdk/index.js +0 -2
- package/lib/module/sdk/metricsTracking.js +3 -24
- package/lib/module/sdk/navigation.js +3 -42
- package/lib/module/sdk/networkInterceptor.js +7 -60
- package/lib/module/sdk/utils.js +73 -19
- package/lib/typescript/NativeRejourney.d.ts +1 -0
- package/lib/typescript/sdk/autoTracking.d.ts +4 -4
- package/lib/typescript/sdk/utils.d.ts +31 -1
- package/lib/typescript/types/index.d.ts +0 -1
- package/package.json +17 -11
- package/src/NativeRejourney.ts +2 -0
- package/src/components/Mask.tsx +0 -3
- package/src/index.ts +43 -92
- package/src/sdk/autoTracking.ts +51 -284
- package/src/sdk/constants.ts +13 -13
- package/src/sdk/errorTracking.ts +1 -17
- package/src/sdk/index.ts +0 -2
- package/src/sdk/metricsTracking.ts +5 -33
- package/src/sdk/navigation.ts +8 -29
- package/src/sdk/networkInterceptor.ts +9 -42
- package/src/sdk/utils.ts +76 -19
- package/src/types/index.ts +0 -29
|
@@ -243,7 +243,6 @@ let LogLevel = exports.LogLevel = /*#__PURE__*/function (LogLevel) {
|
|
|
243
243
|
*/
|
|
244
244
|
class Logger {
|
|
245
245
|
prefix = '[Rejourney]';
|
|
246
|
-
debugMode = false;
|
|
247
246
|
|
|
248
247
|
/**
|
|
249
248
|
* Minimum log level to display.
|
|
@@ -264,7 +263,6 @@ class Logger {
|
|
|
264
263
|
this.minimumLogLevel = level;
|
|
265
264
|
}
|
|
266
265
|
setDebugMode(enabled) {
|
|
267
|
-
this.debugMode = enabled;
|
|
268
266
|
this.minimumLogLevel = enabled ? LogLevel.DEBUG : typeof __DEV__ !== 'undefined' && __DEV__ ? LogLevel.ERROR : LogLevel.SILENT;
|
|
269
267
|
}
|
|
270
268
|
|
|
@@ -285,14 +283,26 @@ class Logger {
|
|
|
285
283
|
/** Log a warning message */
|
|
286
284
|
warn(...args) {
|
|
287
285
|
if (this.minimumLogLevel <= LogLevel.WARNING) {
|
|
288
|
-
|
|
286
|
+
if (this.minimumLogLevel <= LogLevel.DEBUG) {
|
|
287
|
+
// Explicit Debug Mode: Show YellowBox
|
|
288
|
+
console.warn(this.prefix, ...args);
|
|
289
|
+
} else {
|
|
290
|
+
// Default Dev Mode: Log to console only, avoid YellowBox
|
|
291
|
+
console.log(this.prefix, '[WARN]', ...args);
|
|
292
|
+
}
|
|
289
293
|
}
|
|
290
294
|
}
|
|
291
295
|
|
|
292
296
|
/** Log an error message */
|
|
293
297
|
error(...args) {
|
|
294
298
|
if (this.minimumLogLevel <= LogLevel.ERROR) {
|
|
295
|
-
|
|
299
|
+
if (this.minimumLogLevel <= LogLevel.DEBUG) {
|
|
300
|
+
// Explicit Debug Mode: Show RedBox
|
|
301
|
+
console.error(this.prefix, ...args);
|
|
302
|
+
} else {
|
|
303
|
+
// Default Dev Mode: Log to console only, avoid RedBox
|
|
304
|
+
console.log(this.prefix, '[ERROR]', ...args);
|
|
305
|
+
}
|
|
296
306
|
}
|
|
297
307
|
}
|
|
298
308
|
notice(...args) {
|
|
@@ -301,19 +311,12 @@ class Logger {
|
|
|
301
311
|
}
|
|
302
312
|
}
|
|
303
313
|
|
|
304
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
305
|
-
// Lifecycle Logs - Industry standard minimal logging
|
|
306
|
-
// These are the only logs integrators will see in debug builds
|
|
307
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
308
|
-
|
|
309
314
|
/**
|
|
310
315
|
* Log SDK initialization success.
|
|
311
316
|
* Only shown in development builds - this is the minimal "SDK started" log.
|
|
312
317
|
*/
|
|
313
318
|
logInitSuccess(version) {
|
|
314
|
-
|
|
315
|
-
this.info(`✓ SDK initialized (v${version})`);
|
|
316
|
-
}
|
|
319
|
+
this.notice(`✓ SDK initialized (v${version})`);
|
|
317
320
|
}
|
|
318
321
|
|
|
319
322
|
/**
|
|
@@ -329,9 +332,7 @@ class Logger {
|
|
|
329
332
|
* Only shown in development builds.
|
|
330
333
|
*/
|
|
331
334
|
logSessionStart(sessionId) {
|
|
332
|
-
|
|
333
|
-
this.info(`Session started: ${sessionId}`);
|
|
334
|
-
}
|
|
335
|
+
this.notice(`Session started: ${sessionId}`);
|
|
335
336
|
}
|
|
336
337
|
|
|
337
338
|
/**
|
|
@@ -339,12 +340,10 @@ class Logger {
|
|
|
339
340
|
* Only shown in development builds.
|
|
340
341
|
*/
|
|
341
342
|
logSessionEnd(sessionId) {
|
|
342
|
-
|
|
343
|
-
this.info(`Session ended: ${sessionId}`);
|
|
344
|
-
}
|
|
343
|
+
this.notice(`Session ended: ${sessionId}`);
|
|
345
344
|
}
|
|
346
345
|
logObservabilityStart() {
|
|
347
|
-
this.notice('Starting Rejourney observability');
|
|
346
|
+
this.notice('💧 Starting Rejourney observability');
|
|
348
347
|
}
|
|
349
348
|
logRecordingStart() {
|
|
350
349
|
this.notice('Starting recording');
|
|
@@ -358,6 +357,61 @@ class Logger {
|
|
|
358
357
|
logPackageMismatch() {
|
|
359
358
|
this.notice('Bundle ID / package name mismatch');
|
|
360
359
|
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Log network request details
|
|
363
|
+
*/
|
|
364
|
+
logNetworkRequest(request) {
|
|
365
|
+
const statusIcon = request.error || request.statusCode && request.statusCode >= 400 ? '🔴' : '🟢';
|
|
366
|
+
const method = request.method || 'GET';
|
|
367
|
+
// Shorten URL to just path if possible
|
|
368
|
+
let url = request.url || '';
|
|
369
|
+
try {
|
|
370
|
+
if (url.startsWith('http')) {
|
|
371
|
+
const urlObj = new URL(url);
|
|
372
|
+
url = urlObj.pathname;
|
|
373
|
+
}
|
|
374
|
+
} catch {
|
|
375
|
+
// Keep full URL if parsing fails
|
|
376
|
+
}
|
|
377
|
+
const duration = request.duration ? `(${Math.round(request.duration)}ms)` : '';
|
|
378
|
+
const status = request.statusCode ? `${request.statusCode}` : 'ERR';
|
|
379
|
+
this.notice(`${statusIcon} [NET] ${status} ${method} ${url} ${duration} ${request.error ? `Error: ${request.error}` : ''}`);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Log frustration event (rage taps, etc)
|
|
384
|
+
*/
|
|
385
|
+
logFrustration(kind) {
|
|
386
|
+
this.notice(`🤬 Frustration detected: ${kind}`);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Log error captured by SDK
|
|
391
|
+
*/
|
|
392
|
+
logError(message) {
|
|
393
|
+
this.notice(`X Error captured: ${message}`);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Log lifecycle event (Background/Foreground)
|
|
398
|
+
* Visible in development builds.
|
|
399
|
+
*/
|
|
400
|
+
logLifecycleEvent(event) {
|
|
401
|
+
this.notice(`🔄 Lifecycle: ${event}`);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Log upload statistics
|
|
406
|
+
*/
|
|
407
|
+
logUploadStats(metrics) {
|
|
408
|
+
const success = metrics.uploadSuccessCount;
|
|
409
|
+
const failed = metrics.uploadFailureCount;
|
|
410
|
+
const bytes = formatBytes(metrics.totalBytesUploaded);
|
|
411
|
+
|
|
412
|
+
// Always show in dev mode for reassurance, even if 0
|
|
413
|
+
this.notice(`📡 Upload Stats: ${success} success, ${failed} failed (${bytes} uploaded)`);
|
|
414
|
+
}
|
|
361
415
|
}
|
|
362
416
|
const logger = exports.logger = new Logger();
|
|
363
417
|
//# sourceMappingURL=utils.js.map
|
|
@@ -24,7 +24,6 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
|
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
import React from 'react';
|
|
27
|
-
// Lazy-loaded React Native modules
|
|
28
27
|
let _RN = null;
|
|
29
28
|
function getRN() {
|
|
30
29
|
if (_RN) return _RN;
|
|
@@ -48,8 +47,6 @@ export const Mask = ({
|
|
|
48
47
|
...props
|
|
49
48
|
}) => {
|
|
50
49
|
const RN = getRN();
|
|
51
|
-
|
|
52
|
-
// If RN isn't loaded yet (shouldn't happen in practice), render children directly
|
|
53
50
|
if (!RN) {
|
|
54
51
|
return /*#__PURE__*/React.createElement(React.Fragment, null, children);
|
|
55
52
|
}
|
|
@@ -58,9 +55,7 @@ export const Mask = ({
|
|
|
58
55
|
StyleSheet
|
|
59
56
|
} = RN;
|
|
60
57
|
const styles = StyleSheet.create({
|
|
61
|
-
container: {
|
|
62
|
-
// Minimal container style - doesn't affect layout
|
|
63
|
-
}
|
|
58
|
+
container: {}
|
|
64
59
|
});
|
|
65
60
|
return /*#__PURE__*/React.createElement(View, _extends({}, props, {
|
|
66
61
|
style: [styles.container, style],
|
package/lib/module/index.js
CHANGED
|
@@ -67,13 +67,10 @@ function getReactNative() {
|
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
|
|
71
|
-
// Lazy-loaded logger
|
|
72
70
|
let _logger = null;
|
|
73
71
|
function getLogger() {
|
|
74
72
|
if (_logger) return _logger;
|
|
75
73
|
if (_sdkDisabled) {
|
|
76
|
-
// Return a no-op logger if SDK is disabled
|
|
77
74
|
return {
|
|
78
75
|
debug: () => {},
|
|
79
76
|
info: console.log.bind(console, '[Rejourney]'),
|
|
@@ -89,7 +86,12 @@ function getLogger() {
|
|
|
89
86
|
logRecordingStart: () => {},
|
|
90
87
|
logRecordingRemoteDisabled: () => {},
|
|
91
88
|
logInvalidProjectKey: () => {},
|
|
92
|
-
logPackageMismatch: () => {}
|
|
89
|
+
logPackageMismatch: () => {},
|
|
90
|
+
logNetworkRequest: () => {},
|
|
91
|
+
logFrustration: () => {},
|
|
92
|
+
logError: () => {},
|
|
93
|
+
logUploadStats: () => {},
|
|
94
|
+
logLifecycleEvent: () => {}
|
|
93
95
|
};
|
|
94
96
|
}
|
|
95
97
|
try {
|
|
@@ -114,7 +116,12 @@ function getLogger() {
|
|
|
114
116
|
logRecordingStart: () => {},
|
|
115
117
|
logRecordingRemoteDisabled: () => {},
|
|
116
118
|
logInvalidProjectKey: () => {},
|
|
117
|
-
logPackageMismatch: () => {}
|
|
119
|
+
logPackageMismatch: () => {},
|
|
120
|
+
logNetworkRequest: () => {},
|
|
121
|
+
logFrustration: () => {},
|
|
122
|
+
logError: () => {},
|
|
123
|
+
logUploadStats: () => {},
|
|
124
|
+
logLifecycleEvent: () => {}
|
|
118
125
|
};
|
|
119
126
|
}
|
|
120
127
|
}
|
|
@@ -152,7 +159,7 @@ const noopAutoTracking = {
|
|
|
152
159
|
notifyStateChange: () => {},
|
|
153
160
|
getSessionMetrics: () => ({}),
|
|
154
161
|
resetMetrics: () => {},
|
|
155
|
-
collectDeviceInfo: () => ({}),
|
|
162
|
+
collectDeviceInfo: async () => ({}),
|
|
156
163
|
ensurePersistentAnonymousId: async () => 'anonymous'
|
|
157
164
|
};
|
|
158
165
|
function getAutoTracking() {
|
|
@@ -171,6 +178,7 @@ function getAutoTracking() {
|
|
|
171
178
|
let _isInitialized = false;
|
|
172
179
|
let _isRecording = false;
|
|
173
180
|
let _initializationFailed = false;
|
|
181
|
+
let _metricsInterval = null;
|
|
174
182
|
let _appStateSubscription = null;
|
|
175
183
|
let _authErrorSubscription = null;
|
|
176
184
|
let _currentAppState = 'active'; // Default to active, will be updated on init
|
|
@@ -193,7 +201,7 @@ async function loadPersistedUserIdentity() {
|
|
|
193
201
|
|
|
194
202
|
// NATIVE STORAGE: Read directly from SharedPreferences/NSUserDefaults
|
|
195
203
|
return await nativeModule.getUserIdentity();
|
|
196
|
-
} catch
|
|
204
|
+
} catch {
|
|
197
205
|
return null;
|
|
198
206
|
}
|
|
199
207
|
}
|
|
@@ -213,9 +221,7 @@ let _runtimeReady = false;
|
|
|
213
221
|
function isRuntimeReady() {
|
|
214
222
|
if (_runtimeReady) return true;
|
|
215
223
|
try {
|
|
216
|
-
// Try to access a core module to verify runtime is ready
|
|
217
224
|
const RN = require('react-native');
|
|
218
|
-
// If we can access NativeModules without error, runtime is ready
|
|
219
225
|
if (RN.NativeModules) {
|
|
220
226
|
_runtimeReady = true;
|
|
221
227
|
return true;
|
|
@@ -298,12 +304,9 @@ function getRejourneyNative() {
|
|
|
298
304
|
}
|
|
299
305
|
}
|
|
300
306
|
} catch (error) {
|
|
301
|
-
// If any access fails, log and return null
|
|
302
307
|
getLogger().warn('Rejourney: Failed to access native modules:', error);
|
|
303
308
|
_rejourneyNative = null;
|
|
304
309
|
}
|
|
305
|
-
|
|
306
|
-
// Ensure we never return undefined - convert to null
|
|
307
310
|
if (_rejourneyNative === undefined) {
|
|
308
311
|
_rejourneyNative = null;
|
|
309
312
|
}
|
|
@@ -378,18 +381,12 @@ const Rejourney = {
|
|
|
378
381
|
const apiUrl = _storedConfig.apiUrl || 'https://api.rejourney.co';
|
|
379
382
|
const publicKey = _storedConfig.publicRouteKey || '';
|
|
380
383
|
getLogger().debug(`Calling native startSession (apiUrl=${apiUrl})`);
|
|
381
|
-
|
|
382
|
-
// Use user identity if set, otherwise use anonymous device ID
|
|
383
384
|
const deviceId = await getAutoTracking().ensurePersistentAnonymousId();
|
|
384
|
-
|
|
385
|
-
// Try to load persisted user identity if not already set in memory
|
|
386
385
|
if (!_userIdentity) {
|
|
387
386
|
_userIdentity = await loadPersistedUserIdentity();
|
|
388
387
|
}
|
|
389
388
|
const userId = _userIdentity || deviceId;
|
|
390
389
|
getLogger().debug(`userId=${userId.substring(0, 8)}...`);
|
|
391
|
-
|
|
392
|
-
// Start native session
|
|
393
390
|
const result = await nativeModule.startSession(userId, apiUrl, publicKey);
|
|
394
391
|
getLogger().debug('Native startSession returned:', JSON.stringify(result));
|
|
395
392
|
if (!result?.success) {
|
|
@@ -402,10 +399,27 @@ const Rejourney = {
|
|
|
402
399
|
}
|
|
403
400
|
_isRecording = true;
|
|
404
401
|
getLogger().debug(`✅ Session started: ${result.sessionId}`);
|
|
405
|
-
// Use lifecycle log for session start - only shown in dev builds
|
|
406
402
|
getLogger().logSessionStart(result.sessionId);
|
|
407
|
-
|
|
408
|
-
|
|
403
|
+
// Start polling for upload stats in dev mode
|
|
404
|
+
if (__DEV__) {
|
|
405
|
+
_metricsInterval = setInterval(async () => {
|
|
406
|
+
if (!_isRecording) {
|
|
407
|
+
if (_metricsInterval) clearInterval(_metricsInterval);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
try {
|
|
411
|
+
const native = getRejourneyNative();
|
|
412
|
+
if (native) {
|
|
413
|
+
const metrics = await native.getSDKMetrics();
|
|
414
|
+
if (metrics) {
|
|
415
|
+
getLogger().logUploadStats(metrics);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
} catch (e) {
|
|
419
|
+
getLogger().debug('Failed to fetch metrics:', e);
|
|
420
|
+
}
|
|
421
|
+
}, 10000); // Poll more frequently in dev (10s) for better feedback
|
|
422
|
+
}
|
|
409
423
|
getAutoTracking().initAutoTracking({
|
|
410
424
|
rageTapThreshold: _storedConfig?.rageTapThreshold ?? 3,
|
|
411
425
|
rageTapTimeWindow: _storedConfig?.rageTapTimeWindow ?? 500,
|
|
@@ -423,7 +437,7 @@ const Rejourney = {
|
|
|
423
437
|
x,
|
|
424
438
|
y
|
|
425
439
|
});
|
|
426
|
-
|
|
440
|
+
getLogger().logFrustration(`Rage tap (${count} taps)`);
|
|
427
441
|
},
|
|
428
442
|
// Error callback - log as error event
|
|
429
443
|
onError: error => {
|
|
@@ -432,46 +446,31 @@ const Rejourney = {
|
|
|
432
446
|
stack: error.stack,
|
|
433
447
|
name: error.name
|
|
434
448
|
});
|
|
435
|
-
|
|
449
|
+
getLogger().logError(error.message);
|
|
436
450
|
},
|
|
437
|
-
|
|
438
|
-
onScreen: (_screenName, _previousScreen) => {
|
|
439
|
-
// Native module already handles screen changes
|
|
440
|
-
// This is just for metrics tracking
|
|
441
|
-
// logger.debug(`Screen changed: ${previousScreen} -> ${screenName}`);
|
|
442
|
-
}
|
|
451
|
+
onScreen: (_screenName, _previousScreen) => {}
|
|
443
452
|
});
|
|
444
|
-
|
|
445
|
-
// Collect and log device info
|
|
446
453
|
if (_storedConfig?.collectDeviceInfo !== false) {
|
|
447
454
|
try {
|
|
448
|
-
const deviceInfo = getAutoTracking().collectDeviceInfo();
|
|
455
|
+
const deviceInfo = await getAutoTracking().collectDeviceInfo();
|
|
449
456
|
this.logEvent('device_info', deviceInfo);
|
|
450
457
|
} catch (deviceError) {
|
|
451
458
|
getLogger().warn('Failed to collect device info:', deviceError);
|
|
452
459
|
}
|
|
453
460
|
}
|
|
454
|
-
|
|
455
|
-
// Setup automatic network interception
|
|
456
461
|
if (_storedConfig?.autoTrackNetwork !== false) {
|
|
457
462
|
try {
|
|
458
463
|
const ignoreUrls = [apiUrl, '/api/ingest/presign', '/api/ingest/batch/complete', '/api/ingest/session/end', ...(_storedConfig?.networkIgnoreUrls || [])];
|
|
459
464
|
getNetworkInterceptor().initNetworkInterceptor(request => {
|
|
460
|
-
this.logNetworkRequest(request);
|
|
461
465
|
getAutoTracking().trackAPIRequest(request.success || false, request.statusCode, request.duration || 0, request.responseBodySize || 0);
|
|
462
466
|
}, {
|
|
463
467
|
ignoreUrls,
|
|
464
468
|
captureSizes: _storedConfig?.networkCaptureSizes !== false
|
|
465
469
|
});
|
|
466
|
-
|
|
467
|
-
// logger.debug('Network interception enabled');
|
|
468
470
|
} catch (networkError) {
|
|
469
471
|
getLogger().warn('Failed to setup network interception:', networkError);
|
|
470
472
|
}
|
|
471
473
|
}
|
|
472
|
-
|
|
473
|
-
// logger.debug('Auto tracking enabled');
|
|
474
|
-
|
|
475
474
|
return true;
|
|
476
475
|
} catch (error) {
|
|
477
476
|
getLogger().error('Failed to start recording:', error);
|
|
@@ -488,17 +487,17 @@ const Rejourney = {
|
|
|
488
487
|
return;
|
|
489
488
|
}
|
|
490
489
|
try {
|
|
491
|
-
// Get session metrics before stopping
|
|
492
490
|
const metrics = getAutoTracking().getSessionMetrics();
|
|
493
491
|
this.logEvent('session_metrics', metrics);
|
|
494
|
-
|
|
495
|
-
// Cleanup
|
|
496
492
|
getNetworkInterceptor().disableNetworkInterceptor();
|
|
497
493
|
getAutoTracking().cleanupAutoTracking();
|
|
498
494
|
getAutoTracking().resetMetrics();
|
|
499
495
|
await safeNativeCall('stopSession', () => getRejourneyNative().stopSession(), undefined);
|
|
496
|
+
if (_metricsInterval) {
|
|
497
|
+
clearInterval(_metricsInterval);
|
|
498
|
+
_metricsInterval = null;
|
|
499
|
+
}
|
|
500
500
|
_isRecording = false;
|
|
501
|
-
// Use lifecycle log for session end - only shown in dev builds
|
|
502
501
|
getLogger().logSessionEnd('current');
|
|
503
502
|
} catch (error) {
|
|
504
503
|
getLogger().error('Failed to stop recording:', error);
|
|
@@ -514,7 +513,6 @@ const Rejourney = {
|
|
|
514
513
|
*/
|
|
515
514
|
logEvent(name, properties) {
|
|
516
515
|
safeNativeCallSync('logEvent', () => {
|
|
517
|
-
// Fire and forget - don't await
|
|
518
516
|
getRejourneyNative().logEvent(name, properties || {}).catch(() => {});
|
|
519
517
|
}, undefined);
|
|
520
518
|
},
|
|
@@ -530,9 +528,6 @@ const Rejourney = {
|
|
|
530
528
|
setUserIdentity(userId) {
|
|
531
529
|
_userIdentity = userId;
|
|
532
530
|
persistUserIdentity(userId).catch(() => {});
|
|
533
|
-
// logger.debug(`User identity set: ${userId}`);
|
|
534
|
-
|
|
535
|
-
// If recording is active, update the native module immediately
|
|
536
531
|
if (_isRecording && getRejourneyNative()) {
|
|
537
532
|
safeNativeCallSync('setUserIdentity', () => {
|
|
538
533
|
getRejourneyNative().setUserIdentity(userId).catch(() => {});
|
|
@@ -546,9 +541,6 @@ const Rejourney = {
|
|
|
546
541
|
clearUserIdentity() {
|
|
547
542
|
_userIdentity = null;
|
|
548
543
|
persistUserIdentity(null).catch(() => {});
|
|
549
|
-
// logger.debug('User identity cleared');
|
|
550
|
-
|
|
551
|
-
// If recording is active, update the native module immediately
|
|
552
544
|
if (_isRecording && getRejourneyNative()) {
|
|
553
545
|
safeNativeCallSync('setUserIdentity', () => {
|
|
554
546
|
getRejourneyNative().setUserIdentity('anonymous').catch(() => {});
|
|
@@ -562,10 +554,7 @@ const Rejourney = {
|
|
|
562
554
|
* @param params - Optional screen parameters
|
|
563
555
|
*/
|
|
564
556
|
tagScreen(screenName, _params) {
|
|
565
|
-
// Track screen for metrics and funnel tracking
|
|
566
557
|
getAutoTracking().trackScreen(screenName);
|
|
567
|
-
|
|
568
|
-
// Notify state change (kept for API compatibility)
|
|
569
558
|
getAutoTracking().notifyStateChange();
|
|
570
559
|
safeNativeCallSync('tagScreen', () => {
|
|
571
560
|
getRejourneyNative().screenChanged(screenName).catch(() => {});
|
|
@@ -651,7 +640,6 @@ const Rejourney = {
|
|
|
651
640
|
* @returns Path to export file (not implemented)
|
|
652
641
|
*/
|
|
653
642
|
async exportSession(_sessionId) {
|
|
654
|
-
// Return empty string - actual export should be done from dashboard server
|
|
655
643
|
getLogger().warn('exportSession not implemented - export from dashboard server');
|
|
656
644
|
return '';
|
|
657
645
|
},
|
|
@@ -743,10 +731,6 @@ const Rejourney = {
|
|
|
743
731
|
getAutoTracking().trackScroll();
|
|
744
732
|
await safeNativeCall('onScroll', () => getRejourneyNative().onScroll(scrollOffset), undefined);
|
|
745
733
|
},
|
|
746
|
-
// ========================================================================
|
|
747
|
-
// OAuth / External URL Tracking
|
|
748
|
-
// ========================================================================
|
|
749
|
-
|
|
750
734
|
/**
|
|
751
735
|
* Notify the SDK that an OAuth flow is starting
|
|
752
736
|
*
|
|
@@ -877,15 +861,9 @@ const Rejourney = {
|
|
|
877
861
|
errorMessage: request.errorMessage,
|
|
878
862
|
cached: request.cached
|
|
879
863
|
};
|
|
880
|
-
|
|
881
|
-
// Fire and forget - don't await, this is low priority
|
|
882
864
|
getRejourneyNative().logEvent('network_request', networkEvent).catch(() => {});
|
|
883
865
|
}, undefined);
|
|
884
866
|
},
|
|
885
|
-
// ========================================================================
|
|
886
|
-
// SDK Telemetry / Observability
|
|
887
|
-
// ========================================================================
|
|
888
|
-
|
|
889
867
|
/**
|
|
890
868
|
* Get SDK telemetry metrics for observability
|
|
891
869
|
*
|
|
@@ -933,10 +911,6 @@ const Rejourney = {
|
|
|
933
911
|
getLogger().warn('debugTriggerANR is only available in development mode');
|
|
934
912
|
}
|
|
935
913
|
},
|
|
936
|
-
// ========================================================================
|
|
937
|
-
// Privacy / View Masking
|
|
938
|
-
// ========================================================================
|
|
939
|
-
|
|
940
914
|
/**
|
|
941
915
|
* Mask a view by its nativeID prop (will be occluded in recordings)
|
|
942
916
|
*
|
|
@@ -972,10 +946,6 @@ const Rejourney = {
|
|
|
972
946
|
}
|
|
973
947
|
};
|
|
974
948
|
|
|
975
|
-
// =============================================================================
|
|
976
|
-
// Automatic Lifecycle Management
|
|
977
|
-
// =============================================================================
|
|
978
|
-
|
|
979
949
|
/**
|
|
980
950
|
* Handle app state changes for automatic session management
|
|
981
951
|
* - Pauses recording when app goes to background
|
|
@@ -987,10 +957,10 @@ function handleAppStateChange(nextAppState) {
|
|
|
987
957
|
try {
|
|
988
958
|
if (_currentAppState.match(/active/) && nextAppState === 'background') {
|
|
989
959
|
// App going to background - native module handles this automatically
|
|
990
|
-
getLogger().
|
|
960
|
+
getLogger().logLifecycleEvent('App moving to background');
|
|
991
961
|
} else if (_currentAppState.match(/inactive|background/) && nextAppState === 'active') {
|
|
992
962
|
// App coming back to foreground
|
|
993
|
-
getLogger().
|
|
963
|
+
getLogger().logLifecycleEvent('App returning to foreground');
|
|
994
964
|
}
|
|
995
965
|
_currentAppState = nextAppState;
|
|
996
966
|
} catch (error) {
|
|
@@ -1006,20 +976,13 @@ function setupLifecycleManagement() {
|
|
|
1006
976
|
if (_sdkDisabled) return;
|
|
1007
977
|
const RN = getReactNative();
|
|
1008
978
|
if (!RN) return;
|
|
1009
|
-
|
|
1010
|
-
// Remove any existing subscription
|
|
1011
979
|
if (_appStateSubscription) {
|
|
1012
980
|
_appStateSubscription.remove();
|
|
1013
981
|
_appStateSubscription = null;
|
|
1014
982
|
}
|
|
1015
983
|
try {
|
|
1016
|
-
// Get current app state
|
|
1017
984
|
_currentAppState = RN.AppState.currentState || 'active';
|
|
1018
|
-
|
|
1019
|
-
// Subscribe to app state changes
|
|
1020
985
|
_appStateSubscription = RN.AppState.addEventListener('change', handleAppStateChange);
|
|
1021
|
-
|
|
1022
|
-
// Setup auth error listener from native module
|
|
1023
986
|
setupAuthErrorListener();
|
|
1024
987
|
getLogger().debug('Lifecycle management enabled');
|
|
1025
988
|
} catch (error) {
|
|
@@ -1042,9 +1005,6 @@ function setupAuthErrorListener() {
|
|
|
1042
1005
|
try {
|
|
1043
1006
|
const nativeModule = getRejourneyNative();
|
|
1044
1007
|
if (nativeModule) {
|
|
1045
|
-
// RN warns if a non-null module is passed without addListener/removeListeners.
|
|
1046
|
-
// Our native module may not implement these no-op methods yet, so only pass
|
|
1047
|
-
// the module when those hooks exist; otherwise use the global emitter.
|
|
1048
1008
|
const maybeAny = nativeModule;
|
|
1049
1009
|
const hasEventEmitterHooks = typeof maybeAny?.addListener === 'function' && typeof maybeAny?.removeListeners === 'function';
|
|
1050
1010
|
const eventEmitter = hasEventEmitterHooks ? new RN.NativeEventEmitter(maybeAny) : new RN.NativeEventEmitter();
|
|
@@ -1055,11 +1015,7 @@ function setupAuthErrorListener() {
|
|
|
1055
1015
|
} else if (error?.code === 404) {
|
|
1056
1016
|
getLogger().logInvalidProjectKey();
|
|
1057
1017
|
}
|
|
1058
|
-
|
|
1059
|
-
// Update SDK state - recording has been stopped by native
|
|
1060
1018
|
_isRecording = false;
|
|
1061
|
-
|
|
1062
|
-
// Call user's error handler if provided
|
|
1063
1019
|
if (_storedConfig?.onAuthError) {
|
|
1064
1020
|
try {
|
|
1065
1021
|
_storedConfig.onAuthError(error);
|
|
@@ -1070,7 +1026,6 @@ function setupAuthErrorListener() {
|
|
|
1070
1026
|
});
|
|
1071
1027
|
}
|
|
1072
1028
|
} catch (error) {
|
|
1073
|
-
// Event emitter not available on this platform - that's OK
|
|
1074
1029
|
getLogger().debug('Auth error listener not available:', error);
|
|
1075
1030
|
}
|
|
1076
1031
|
}
|
|
@@ -1089,10 +1044,6 @@ function cleanupLifecycleManagement() {
|
|
|
1089
1044
|
}
|
|
1090
1045
|
}
|
|
1091
1046
|
|
|
1092
|
-
// =============================================================================
|
|
1093
|
-
// Simple Initialization API
|
|
1094
|
-
// =============================================================================
|
|
1095
|
-
|
|
1096
1047
|
/**
|
|
1097
1048
|
* Initialize Rejourney SDK - STEP 1 of 3
|
|
1098
1049
|
*
|
|
@@ -1122,14 +1073,11 @@ function cleanupLifecycleManagement() {
|
|
|
1122
1073
|
* ```
|
|
1123
1074
|
*/
|
|
1124
1075
|
export function initRejourney(publicRouteKey, options) {
|
|
1125
|
-
// Validate public route key
|
|
1126
1076
|
if (!publicRouteKey || typeof publicRouteKey !== 'string') {
|
|
1127
1077
|
getLogger().warn('Rejourney: Invalid public route key provided. SDK will be disabled.');
|
|
1128
1078
|
_initializationFailed = true;
|
|
1129
1079
|
return;
|
|
1130
1080
|
}
|
|
1131
|
-
|
|
1132
|
-
// Store config for later use
|
|
1133
1081
|
_storedConfig = {
|
|
1134
1082
|
...options,
|
|
1135
1083
|
publicRouteKey
|
|
@@ -1183,8 +1131,6 @@ export function startRejourney() {
|
|
|
1183
1131
|
}
|
|
1184
1132
|
getLogger().logRecordingStart();
|
|
1185
1133
|
getLogger().debug('Starting session...');
|
|
1186
|
-
|
|
1187
|
-
// Fire and forget - don't block the caller
|
|
1188
1134
|
(async () => {
|
|
1189
1135
|
try {
|
|
1190
1136
|
const started = await Rejourney._startSession();
|
|
@@ -1216,19 +1162,9 @@ export function stopRejourney() {
|
|
|
1216
1162
|
}
|
|
1217
1163
|
}
|
|
1218
1164
|
export default Rejourney;
|
|
1219
|
-
|
|
1220
|
-
// Export types
|
|
1221
1165
|
export * from './types';
|
|
1222
|
-
|
|
1223
|
-
// Export auto tracking utilities for advanced usage
|
|
1224
|
-
// These are used internally but can be called manually if needed
|
|
1225
1166
|
export { trackTap, trackScroll, trackGesture, trackInput, trackScreen, captureError, getSessionMetrics } from './sdk/autoTracking';
|
|
1226
|
-
|
|
1227
|
-
// Navigation
|
|
1228
1167
|
export { trackNavigationState, useNavigationTracking } from './sdk/autoTracking';
|
|
1229
|
-
|
|
1230
|
-
// Re-export LogLevel enum from utils
|
|
1231
|
-
// Note: This is safe because the enum itself doesn't trigger react-native imports
|
|
1232
1168
|
export { LogLevel } from './sdk/utils';
|
|
1233
1169
|
|
|
1234
1170
|
/**
|
|
@@ -1262,17 +1198,5 @@ export { LogLevel } from './sdk/utils';
|
|
|
1262
1198
|
export function setLogLevel(level) {
|
|
1263
1199
|
getLogger().setLogLevel(level);
|
|
1264
1200
|
}
|
|
1265
|
-
|
|
1266
|
-
// Note: Components and hooks removed in new engine
|
|
1267
|
-
// Session replay now handled by dashboard web UI
|
|
1268
|
-
// export { RejourneyReplay } from './components/replay/RejourneyReplay';
|
|
1269
|
-
// export { GestureTracker } from './components/GestureTracker';
|
|
1270
|
-
// export { SessionList } from './components/SessionList';
|
|
1271
|
-
// export { useRejourney } from './hooks/useRejourney';
|
|
1272
|
-
// export { useReplay } from './hooks/useReplay';
|
|
1273
|
-
|
|
1274
|
-
// Note: SDK managers removed in new engine - all functionality handled by native module
|
|
1275
|
-
|
|
1276
|
-
// Export Mask component
|
|
1277
1201
|
export { Mask } from './components/Mask';
|
|
1278
1202
|
//# sourceMappingURL=index.js.map
|