@rejourneyco/react-native 1.0.0 → 1.0.2
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/README.md +29 -0
- package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +47 -30
- package/android/src/main/java/com/rejourney/capture/CaptureEngine.kt +25 -1
- package/android/src/main/java/com/rejourney/capture/CaptureHeuristics.kt +70 -32
- package/android/src/main/java/com/rejourney/core/Constants.kt +4 -4
- package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +14 -0
- package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +9 -0
- package/ios/Capture/RJCaptureEngine.m +72 -34
- package/ios/Capture/RJCaptureHeuristics.h +7 -5
- package/ios/Capture/RJCaptureHeuristics.m +138 -112
- package/ios/Capture/RJVideoEncoder.m +0 -26
- package/ios/Core/Rejourney.mm +64 -102
- package/ios/Utils/RJPerfTiming.m +0 -5
- package/ios/Utils/RJWindowUtils.m +0 -1
- package/lib/commonjs/components/Mask.js +1 -6
- package/lib/commonjs/index.js +12 -101
- package/lib/commonjs/sdk/autoTracking.js +55 -353
- 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 -49
- package/lib/commonjs/sdk/utils.js +0 -5
- package/lib/module/components/Mask.js +1 -6
- package/lib/module/index.js +11 -105
- package/lib/module/sdk/autoTracking.js +55 -354
- 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 -49
- package/lib/module/sdk/utils.js +0 -5
- package/lib/typescript/NativeRejourney.d.ts +2 -0
- package/lib/typescript/sdk/autoTracking.d.ts +5 -6
- package/lib/typescript/types/index.d.ts +0 -1
- package/package.json +11 -3
- package/src/NativeRejourney.ts +4 -0
- package/src/components/Mask.tsx +0 -3
- package/src/index.ts +11 -88
- package/src/sdk/autoTracking.ts +72 -331
- 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 -33
- package/src/sdk/utils.ts +0 -5
- package/src/types/index.ts +0 -29
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]'),
|
|
@@ -152,7 +149,7 @@ const noopAutoTracking = {
|
|
|
152
149
|
notifyStateChange: () => {},
|
|
153
150
|
getSessionMetrics: () => ({}),
|
|
154
151
|
resetMetrics: () => {},
|
|
155
|
-
collectDeviceInfo: () => ({}),
|
|
152
|
+
collectDeviceInfo: async () => ({}),
|
|
156
153
|
ensurePersistentAnonymousId: async () => 'anonymous'
|
|
157
154
|
};
|
|
158
155
|
function getAutoTracking() {
|
|
@@ -168,7 +165,6 @@ function getAutoTracking() {
|
|
|
168
165
|
}
|
|
169
166
|
|
|
170
167
|
// State
|
|
171
|
-
const USER_IDENTITY_KEY = '@rejourney_user_identity';
|
|
172
168
|
let _isInitialized = false;
|
|
173
169
|
let _isRecording = false;
|
|
174
170
|
let _initializationFailed = false;
|
|
@@ -183,23 +179,18 @@ let _lastScrollOffset = 0;
|
|
|
183
179
|
const SCROLL_THROTTLE_MS = 100;
|
|
184
180
|
|
|
185
181
|
// Helper to save/load user identity
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (identity) {
|
|
190
|
-
await AsyncStorage.setItem(USER_IDENTITY_KEY, identity);
|
|
191
|
-
} else {
|
|
192
|
-
await AsyncStorage.removeItem(USER_IDENTITY_KEY);
|
|
193
|
-
}
|
|
194
|
-
} catch (e) {
|
|
195
|
-
// Ignore storage errors
|
|
196
|
-
}
|
|
182
|
+
// NOW HANDLED NATIVELY - No-op on JS side to avoid unnecessary bridge calls
|
|
183
|
+
async function persistUserIdentity(_identity) {
|
|
184
|
+
// Native module handles persistence automatically in setUserIdentity
|
|
197
185
|
}
|
|
198
186
|
async function loadPersistedUserIdentity() {
|
|
199
187
|
try {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
188
|
+
const nativeModule = getRejourneyNative();
|
|
189
|
+
if (!nativeModule) return null;
|
|
190
|
+
|
|
191
|
+
// NATIVE STORAGE: Read directly from SharedPreferences/NSUserDefaults
|
|
192
|
+
return await nativeModule.getUserIdentity();
|
|
193
|
+
} catch {
|
|
203
194
|
return null;
|
|
204
195
|
}
|
|
205
196
|
}
|
|
@@ -219,9 +210,7 @@ let _runtimeReady = false;
|
|
|
219
210
|
function isRuntimeReady() {
|
|
220
211
|
if (_runtimeReady) return true;
|
|
221
212
|
try {
|
|
222
|
-
// Try to access a core module to verify runtime is ready
|
|
223
213
|
const RN = require('react-native');
|
|
224
|
-
// If we can access NativeModules without error, runtime is ready
|
|
225
214
|
if (RN.NativeModules) {
|
|
226
215
|
_runtimeReady = true;
|
|
227
216
|
return true;
|
|
@@ -304,12 +293,9 @@ function getRejourneyNative() {
|
|
|
304
293
|
}
|
|
305
294
|
}
|
|
306
295
|
} catch (error) {
|
|
307
|
-
// If any access fails, log and return null
|
|
308
296
|
getLogger().warn('Rejourney: Failed to access native modules:', error);
|
|
309
297
|
_rejourneyNative = null;
|
|
310
298
|
}
|
|
311
|
-
|
|
312
|
-
// Ensure we never return undefined - convert to null
|
|
313
299
|
if (_rejourneyNative === undefined) {
|
|
314
300
|
_rejourneyNative = null;
|
|
315
301
|
}
|
|
@@ -451,7 +437,7 @@ const Rejourney = {
|
|
|
451
437
|
// Collect and log device info
|
|
452
438
|
if (_storedConfig?.collectDeviceInfo !== false) {
|
|
453
439
|
try {
|
|
454
|
-
const deviceInfo = getAutoTracking().collectDeviceInfo();
|
|
440
|
+
const deviceInfo = await getAutoTracking().collectDeviceInfo();
|
|
455
441
|
this.logEvent('device_info', deviceInfo);
|
|
456
442
|
} catch (deviceError) {
|
|
457
443
|
getLogger().warn('Failed to collect device info:', deviceError);
|
|
@@ -469,15 +455,10 @@ const Rejourney = {
|
|
|
469
455
|
ignoreUrls,
|
|
470
456
|
captureSizes: _storedConfig?.networkCaptureSizes !== false
|
|
471
457
|
});
|
|
472
|
-
|
|
473
|
-
// logger.debug('Network interception enabled');
|
|
474
458
|
} catch (networkError) {
|
|
475
459
|
getLogger().warn('Failed to setup network interception:', networkError);
|
|
476
460
|
}
|
|
477
461
|
}
|
|
478
|
-
|
|
479
|
-
// logger.debug('Auto tracking enabled');
|
|
480
|
-
|
|
481
462
|
return true;
|
|
482
463
|
} catch (error) {
|
|
483
464
|
getLogger().error('Failed to start recording:', error);
|
|
@@ -494,17 +475,13 @@ const Rejourney = {
|
|
|
494
475
|
return;
|
|
495
476
|
}
|
|
496
477
|
try {
|
|
497
|
-
// Get session metrics before stopping
|
|
498
478
|
const metrics = getAutoTracking().getSessionMetrics();
|
|
499
479
|
this.logEvent('session_metrics', metrics);
|
|
500
|
-
|
|
501
|
-
// Cleanup
|
|
502
480
|
getNetworkInterceptor().disableNetworkInterceptor();
|
|
503
481
|
getAutoTracking().cleanupAutoTracking();
|
|
504
482
|
getAutoTracking().resetMetrics();
|
|
505
483
|
await safeNativeCall('stopSession', () => getRejourneyNative().stopSession(), undefined);
|
|
506
484
|
_isRecording = false;
|
|
507
|
-
// Use lifecycle log for session end - only shown in dev builds
|
|
508
485
|
getLogger().logSessionEnd('current');
|
|
509
486
|
} catch (error) {
|
|
510
487
|
getLogger().error('Failed to stop recording:', error);
|
|
@@ -536,9 +513,6 @@ const Rejourney = {
|
|
|
536
513
|
setUserIdentity(userId) {
|
|
537
514
|
_userIdentity = userId;
|
|
538
515
|
persistUserIdentity(userId).catch(() => {});
|
|
539
|
-
// logger.debug(`User identity set: ${userId}`);
|
|
540
|
-
|
|
541
|
-
// If recording is active, update the native module immediately
|
|
542
516
|
if (_isRecording && getRejourneyNative()) {
|
|
543
517
|
safeNativeCallSync('setUserIdentity', () => {
|
|
544
518
|
getRejourneyNative().setUserIdentity(userId).catch(() => {});
|
|
@@ -552,9 +526,6 @@ const Rejourney = {
|
|
|
552
526
|
clearUserIdentity() {
|
|
553
527
|
_userIdentity = null;
|
|
554
528
|
persistUserIdentity(null).catch(() => {});
|
|
555
|
-
// logger.debug('User identity cleared');
|
|
556
|
-
|
|
557
|
-
// If recording is active, update the native module immediately
|
|
558
529
|
if (_isRecording && getRejourneyNative()) {
|
|
559
530
|
safeNativeCallSync('setUserIdentity', () => {
|
|
560
531
|
getRejourneyNative().setUserIdentity('anonymous').catch(() => {});
|
|
@@ -568,10 +539,7 @@ const Rejourney = {
|
|
|
568
539
|
* @param params - Optional screen parameters
|
|
569
540
|
*/
|
|
570
541
|
tagScreen(screenName, _params) {
|
|
571
|
-
// Track screen for metrics and funnel tracking
|
|
572
542
|
getAutoTracking().trackScreen(screenName);
|
|
573
|
-
|
|
574
|
-
// Notify state change (kept for API compatibility)
|
|
575
543
|
getAutoTracking().notifyStateChange();
|
|
576
544
|
safeNativeCallSync('tagScreen', () => {
|
|
577
545
|
getRejourneyNative().screenChanged(screenName).catch(() => {});
|
|
@@ -749,10 +717,6 @@ const Rejourney = {
|
|
|
749
717
|
getAutoTracking().trackScroll();
|
|
750
718
|
await safeNativeCall('onScroll', () => getRejourneyNative().onScroll(scrollOffset), undefined);
|
|
751
719
|
},
|
|
752
|
-
// ========================================================================
|
|
753
|
-
// OAuth / External URL Tracking
|
|
754
|
-
// ========================================================================
|
|
755
|
-
|
|
756
720
|
/**
|
|
757
721
|
* Notify the SDK that an OAuth flow is starting
|
|
758
722
|
*
|
|
@@ -888,10 +852,6 @@ const Rejourney = {
|
|
|
888
852
|
getRejourneyNative().logEvent('network_request', networkEvent).catch(() => {});
|
|
889
853
|
}, undefined);
|
|
890
854
|
},
|
|
891
|
-
// ========================================================================
|
|
892
|
-
// SDK Telemetry / Observability
|
|
893
|
-
// ========================================================================
|
|
894
|
-
|
|
895
855
|
/**
|
|
896
856
|
* Get SDK telemetry metrics for observability
|
|
897
857
|
*
|
|
@@ -939,10 +899,6 @@ const Rejourney = {
|
|
|
939
899
|
getLogger().warn('debugTriggerANR is only available in development mode');
|
|
940
900
|
}
|
|
941
901
|
},
|
|
942
|
-
// ========================================================================
|
|
943
|
-
// Privacy / View Masking
|
|
944
|
-
// ========================================================================
|
|
945
|
-
|
|
946
902
|
/**
|
|
947
903
|
* Mask a view by its nativeID prop (will be occluded in recordings)
|
|
948
904
|
*
|
|
@@ -978,10 +934,6 @@ const Rejourney = {
|
|
|
978
934
|
}
|
|
979
935
|
};
|
|
980
936
|
|
|
981
|
-
// =============================================================================
|
|
982
|
-
// Automatic Lifecycle Management
|
|
983
|
-
// =============================================================================
|
|
984
|
-
|
|
985
937
|
/**
|
|
986
938
|
* Handle app state changes for automatic session management
|
|
987
939
|
* - Pauses recording when app goes to background
|
|
@@ -1012,20 +964,13 @@ function setupLifecycleManagement() {
|
|
|
1012
964
|
if (_sdkDisabled) return;
|
|
1013
965
|
const RN = getReactNative();
|
|
1014
966
|
if (!RN) return;
|
|
1015
|
-
|
|
1016
|
-
// Remove any existing subscription
|
|
1017
967
|
if (_appStateSubscription) {
|
|
1018
968
|
_appStateSubscription.remove();
|
|
1019
969
|
_appStateSubscription = null;
|
|
1020
970
|
}
|
|
1021
971
|
try {
|
|
1022
|
-
// Get current app state
|
|
1023
972
|
_currentAppState = RN.AppState.currentState || 'active';
|
|
1024
|
-
|
|
1025
|
-
// Subscribe to app state changes
|
|
1026
973
|
_appStateSubscription = RN.AppState.addEventListener('change', handleAppStateChange);
|
|
1027
|
-
|
|
1028
|
-
// Setup auth error listener from native module
|
|
1029
974
|
setupAuthErrorListener();
|
|
1030
975
|
getLogger().debug('Lifecycle management enabled');
|
|
1031
976
|
} catch (error) {
|
|
@@ -1048,9 +993,6 @@ function setupAuthErrorListener() {
|
|
|
1048
993
|
try {
|
|
1049
994
|
const nativeModule = getRejourneyNative();
|
|
1050
995
|
if (nativeModule) {
|
|
1051
|
-
// RN warns if a non-null module is passed without addListener/removeListeners.
|
|
1052
|
-
// Our native module may not implement these no-op methods yet, so only pass
|
|
1053
|
-
// the module when those hooks exist; otherwise use the global emitter.
|
|
1054
996
|
const maybeAny = nativeModule;
|
|
1055
997
|
const hasEventEmitterHooks = typeof maybeAny?.addListener === 'function' && typeof maybeAny?.removeListeners === 'function';
|
|
1056
998
|
const eventEmitter = hasEventEmitterHooks ? new RN.NativeEventEmitter(maybeAny) : new RN.NativeEventEmitter();
|
|
@@ -1061,11 +1003,7 @@ function setupAuthErrorListener() {
|
|
|
1061
1003
|
} else if (error?.code === 404) {
|
|
1062
1004
|
getLogger().logInvalidProjectKey();
|
|
1063
1005
|
}
|
|
1064
|
-
|
|
1065
|
-
// Update SDK state - recording has been stopped by native
|
|
1066
1006
|
_isRecording = false;
|
|
1067
|
-
|
|
1068
|
-
// Call user's error handler if provided
|
|
1069
1007
|
if (_storedConfig?.onAuthError) {
|
|
1070
1008
|
try {
|
|
1071
1009
|
_storedConfig.onAuthError(error);
|
|
@@ -1076,7 +1014,6 @@ function setupAuthErrorListener() {
|
|
|
1076
1014
|
});
|
|
1077
1015
|
}
|
|
1078
1016
|
} catch (error) {
|
|
1079
|
-
// Event emitter not available on this platform - that's OK
|
|
1080
1017
|
getLogger().debug('Auth error listener not available:', error);
|
|
1081
1018
|
}
|
|
1082
1019
|
}
|
|
@@ -1095,10 +1032,6 @@ function cleanupLifecycleManagement() {
|
|
|
1095
1032
|
}
|
|
1096
1033
|
}
|
|
1097
1034
|
|
|
1098
|
-
// =============================================================================
|
|
1099
|
-
// Simple Initialization API
|
|
1100
|
-
// =============================================================================
|
|
1101
|
-
|
|
1102
1035
|
/**
|
|
1103
1036
|
* Initialize Rejourney SDK - STEP 1 of 3
|
|
1104
1037
|
*
|
|
@@ -1128,14 +1061,11 @@ function cleanupLifecycleManagement() {
|
|
|
1128
1061
|
* ```
|
|
1129
1062
|
*/
|
|
1130
1063
|
export function initRejourney(publicRouteKey, options) {
|
|
1131
|
-
// Validate public route key
|
|
1132
1064
|
if (!publicRouteKey || typeof publicRouteKey !== 'string') {
|
|
1133
1065
|
getLogger().warn('Rejourney: Invalid public route key provided. SDK will be disabled.');
|
|
1134
1066
|
_initializationFailed = true;
|
|
1135
1067
|
return;
|
|
1136
1068
|
}
|
|
1137
|
-
|
|
1138
|
-
// Store config for later use
|
|
1139
1069
|
_storedConfig = {
|
|
1140
1070
|
...options,
|
|
1141
1071
|
publicRouteKey
|
|
@@ -1189,8 +1119,6 @@ export function startRejourney() {
|
|
|
1189
1119
|
}
|
|
1190
1120
|
getLogger().logRecordingStart();
|
|
1191
1121
|
getLogger().debug('Starting session...');
|
|
1192
|
-
|
|
1193
|
-
// Fire and forget - don't block the caller
|
|
1194
1122
|
(async () => {
|
|
1195
1123
|
try {
|
|
1196
1124
|
const started = await Rejourney._startSession();
|
|
@@ -1222,19 +1150,9 @@ export function stopRejourney() {
|
|
|
1222
1150
|
}
|
|
1223
1151
|
}
|
|
1224
1152
|
export default Rejourney;
|
|
1225
|
-
|
|
1226
|
-
// Export types
|
|
1227
1153
|
export * from './types';
|
|
1228
|
-
|
|
1229
|
-
// Export auto tracking utilities for advanced usage
|
|
1230
|
-
// These are used internally but can be called manually if needed
|
|
1231
1154
|
export { trackTap, trackScroll, trackGesture, trackInput, trackScreen, captureError, getSessionMetrics } from './sdk/autoTracking';
|
|
1232
|
-
|
|
1233
|
-
// Navigation
|
|
1234
1155
|
export { trackNavigationState, useNavigationTracking } from './sdk/autoTracking';
|
|
1235
|
-
|
|
1236
|
-
// Re-export LogLevel enum from utils
|
|
1237
|
-
// Note: This is safe because the enum itself doesn't trigger react-native imports
|
|
1238
1156
|
export { LogLevel } from './sdk/utils';
|
|
1239
1157
|
|
|
1240
1158
|
/**
|
|
@@ -1268,17 +1186,5 @@ export { LogLevel } from './sdk/utils';
|
|
|
1268
1186
|
export function setLogLevel(level) {
|
|
1269
1187
|
getLogger().setLogLevel(level);
|
|
1270
1188
|
}
|
|
1271
|
-
|
|
1272
|
-
// Note: Components and hooks removed in new engine
|
|
1273
|
-
// Session replay now handled by dashboard web UI
|
|
1274
|
-
// export { RejourneyReplay } from './components/replay/RejourneyReplay';
|
|
1275
|
-
// export { GestureTracker } from './components/GestureTracker';
|
|
1276
|
-
// export { SessionList } from './components/SessionList';
|
|
1277
|
-
// export { useRejourney } from './hooks/useRejourney';
|
|
1278
|
-
// export { useReplay } from './hooks/useReplay';
|
|
1279
|
-
|
|
1280
|
-
// Note: SDK managers removed in new engine - all functionality handled by native module
|
|
1281
|
-
|
|
1282
|
-
// Export Mask component
|
|
1283
1189
|
export { Mask } from './components/Mask';
|
|
1284
1190
|
//# sourceMappingURL=index.js.map
|