@rejourneyco/react-native 1.0.2 → 1.0.4
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 +38 -363
- 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 +14 -27
- 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/ios/Capture/RJCaptureEngine.m +9 -61
- package/ios/Capture/RJViewHierarchyScanner.m +68 -51
- package/ios/Core/RJLifecycleManager.m +0 -14
- package/ios/Core/Rejourney.mm +24 -37
- 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/RJWindowUtils.m +87 -86
- package/lib/commonjs/index.js +44 -31
- package/lib/commonjs/sdk/autoTracking.js +0 -3
- package/lib/commonjs/sdk/constants.js +1 -1
- package/lib/commonjs/sdk/networkInterceptor.js +0 -11
- package/lib/commonjs/sdk/utils.js +73 -14
- package/lib/module/index.js +44 -31
- package/lib/module/sdk/autoTracking.js +0 -3
- package/lib/module/sdk/constants.js +1 -1
- package/lib/module/sdk/networkInterceptor.js +0 -11
- package/lib/module/sdk/utils.js +73 -14
- package/lib/typescript/sdk/constants.d.ts +1 -1
- package/lib/typescript/sdk/utils.d.ts +31 -1
- package/package.json +16 -4
- package/src/index.ts +42 -20
- package/src/sdk/autoTracking.ts +0 -2
- package/src/sdk/constants.ts +14 -14
- package/src/sdk/networkInterceptor.ts +0 -9
- package/src/sdk/utils.ts +76 -14
|
@@ -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) {
|
|
@@ -306,9 +316,7 @@ class Logger {
|
|
|
306
316
|
* Only shown in development builds - this is the minimal "SDK started" log.
|
|
307
317
|
*/
|
|
308
318
|
logInitSuccess(version) {
|
|
309
|
-
|
|
310
|
-
this.info(`✓ SDK initialized (v${version})`);
|
|
311
|
-
}
|
|
319
|
+
this.notice(`✓ SDK initialized (v${version})`);
|
|
312
320
|
}
|
|
313
321
|
|
|
314
322
|
/**
|
|
@@ -324,9 +332,7 @@ class Logger {
|
|
|
324
332
|
* Only shown in development builds.
|
|
325
333
|
*/
|
|
326
334
|
logSessionStart(sessionId) {
|
|
327
|
-
|
|
328
|
-
this.info(`Session started: ${sessionId}`);
|
|
329
|
-
}
|
|
335
|
+
this.notice(`Session started: ${sessionId}`);
|
|
330
336
|
}
|
|
331
337
|
|
|
332
338
|
/**
|
|
@@ -334,12 +340,10 @@ class Logger {
|
|
|
334
340
|
* Only shown in development builds.
|
|
335
341
|
*/
|
|
336
342
|
logSessionEnd(sessionId) {
|
|
337
|
-
|
|
338
|
-
this.info(`Session ended: ${sessionId}`);
|
|
339
|
-
}
|
|
343
|
+
this.notice(`Session ended: ${sessionId}`);
|
|
340
344
|
}
|
|
341
345
|
logObservabilityStart() {
|
|
342
|
-
this.notice('Starting Rejourney observability');
|
|
346
|
+
this.notice('💧 Starting Rejourney observability');
|
|
343
347
|
}
|
|
344
348
|
logRecordingStart() {
|
|
345
349
|
this.notice('Starting recording');
|
|
@@ -353,6 +357,61 @@ class Logger {
|
|
|
353
357
|
logPackageMismatch() {
|
|
354
358
|
this.notice('Bundle ID / package name mismatch');
|
|
355
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
|
+
}
|
|
356
415
|
}
|
|
357
416
|
const logger = exports.logger = new Logger();
|
|
358
417
|
//# sourceMappingURL=utils.js.map
|
package/lib/module/index.js
CHANGED
|
@@ -86,7 +86,12 @@ function getLogger() {
|
|
|
86
86
|
logRecordingStart: () => {},
|
|
87
87
|
logRecordingRemoteDisabled: () => {},
|
|
88
88
|
logInvalidProjectKey: () => {},
|
|
89
|
-
logPackageMismatch: () => {}
|
|
89
|
+
logPackageMismatch: () => {},
|
|
90
|
+
logNetworkRequest: () => {},
|
|
91
|
+
logFrustration: () => {},
|
|
92
|
+
logError: () => {},
|
|
93
|
+
logUploadStats: () => {},
|
|
94
|
+
logLifecycleEvent: () => {}
|
|
90
95
|
};
|
|
91
96
|
}
|
|
92
97
|
try {
|
|
@@ -111,7 +116,12 @@ function getLogger() {
|
|
|
111
116
|
logRecordingStart: () => {},
|
|
112
117
|
logRecordingRemoteDisabled: () => {},
|
|
113
118
|
logInvalidProjectKey: () => {},
|
|
114
|
-
logPackageMismatch: () => {}
|
|
119
|
+
logPackageMismatch: () => {},
|
|
120
|
+
logNetworkRequest: () => {},
|
|
121
|
+
logFrustration: () => {},
|
|
122
|
+
logError: () => {},
|
|
123
|
+
logUploadStats: () => {},
|
|
124
|
+
logLifecycleEvent: () => {}
|
|
115
125
|
};
|
|
116
126
|
}
|
|
117
127
|
}
|
|
@@ -168,6 +178,7 @@ function getAutoTracking() {
|
|
|
168
178
|
let _isInitialized = false;
|
|
169
179
|
let _isRecording = false;
|
|
170
180
|
let _initializationFailed = false;
|
|
181
|
+
let _metricsInterval = null;
|
|
171
182
|
let _appStateSubscription = null;
|
|
172
183
|
let _authErrorSubscription = null;
|
|
173
184
|
let _currentAppState = 'active'; // Default to active, will be updated on init
|
|
@@ -370,18 +381,12 @@ const Rejourney = {
|
|
|
370
381
|
const apiUrl = _storedConfig.apiUrl || 'https://api.rejourney.co';
|
|
371
382
|
const publicKey = _storedConfig.publicRouteKey || '';
|
|
372
383
|
getLogger().debug(`Calling native startSession (apiUrl=${apiUrl})`);
|
|
373
|
-
|
|
374
|
-
// Use user identity if set, otherwise use anonymous device ID
|
|
375
384
|
const deviceId = await getAutoTracking().ensurePersistentAnonymousId();
|
|
376
|
-
|
|
377
|
-
// Try to load persisted user identity if not already set in memory
|
|
378
385
|
if (!_userIdentity) {
|
|
379
386
|
_userIdentity = await loadPersistedUserIdentity();
|
|
380
387
|
}
|
|
381
388
|
const userId = _userIdentity || deviceId;
|
|
382
389
|
getLogger().debug(`userId=${userId.substring(0, 8)}...`);
|
|
383
|
-
|
|
384
|
-
// Start native session
|
|
385
390
|
const result = await nativeModule.startSession(userId, apiUrl, publicKey);
|
|
386
391
|
getLogger().debug('Native startSession returned:', JSON.stringify(result));
|
|
387
392
|
if (!result?.success) {
|
|
@@ -394,10 +399,27 @@ const Rejourney = {
|
|
|
394
399
|
}
|
|
395
400
|
_isRecording = true;
|
|
396
401
|
getLogger().debug(`✅ Session started: ${result.sessionId}`);
|
|
397
|
-
// Use lifecycle log for session start - only shown in dev builds
|
|
398
402
|
getLogger().logSessionStart(result.sessionId);
|
|
399
|
-
|
|
400
|
-
|
|
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
|
+
}
|
|
401
423
|
getAutoTracking().initAutoTracking({
|
|
402
424
|
rageTapThreshold: _storedConfig?.rageTapThreshold ?? 3,
|
|
403
425
|
rageTapTimeWindow: _storedConfig?.rageTapTimeWindow ?? 500,
|
|
@@ -415,7 +437,7 @@ const Rejourney = {
|
|
|
415
437
|
x,
|
|
416
438
|
y
|
|
417
439
|
});
|
|
418
|
-
|
|
440
|
+
getLogger().logFrustration(`Rage tap (${count} taps)`);
|
|
419
441
|
},
|
|
420
442
|
// Error callback - log as error event
|
|
421
443
|
onError: error => {
|
|
@@ -424,17 +446,10 @@ const Rejourney = {
|
|
|
424
446
|
stack: error.stack,
|
|
425
447
|
name: error.name
|
|
426
448
|
});
|
|
427
|
-
|
|
449
|
+
getLogger().logError(error.message);
|
|
428
450
|
},
|
|
429
|
-
|
|
430
|
-
onScreen: (_screenName, _previousScreen) => {
|
|
431
|
-
// Native module already handles screen changes
|
|
432
|
-
// This is just for metrics tracking
|
|
433
|
-
// logger.debug(`Screen changed: ${previousScreen} -> ${screenName}`);
|
|
434
|
-
}
|
|
451
|
+
onScreen: (_screenName, _previousScreen) => {}
|
|
435
452
|
});
|
|
436
|
-
|
|
437
|
-
// Collect and log device info
|
|
438
453
|
if (_storedConfig?.collectDeviceInfo !== false) {
|
|
439
454
|
try {
|
|
440
455
|
const deviceInfo = await getAutoTracking().collectDeviceInfo();
|
|
@@ -443,14 +458,12 @@ const Rejourney = {
|
|
|
443
458
|
getLogger().warn('Failed to collect device info:', deviceError);
|
|
444
459
|
}
|
|
445
460
|
}
|
|
446
|
-
|
|
447
|
-
// Setup automatic network interception
|
|
448
461
|
if (_storedConfig?.autoTrackNetwork !== false) {
|
|
449
462
|
try {
|
|
450
463
|
const ignoreUrls = [apiUrl, '/api/ingest/presign', '/api/ingest/batch/complete', '/api/ingest/session/end', ...(_storedConfig?.networkIgnoreUrls || [])];
|
|
451
464
|
getNetworkInterceptor().initNetworkInterceptor(request => {
|
|
452
|
-
this.logNetworkRequest(request);
|
|
453
465
|
getAutoTracking().trackAPIRequest(request.success || false, request.statusCode, request.duration || 0, request.responseBodySize || 0);
|
|
466
|
+
Rejourney.logNetworkRequest(request);
|
|
454
467
|
}, {
|
|
455
468
|
ignoreUrls,
|
|
456
469
|
captureSizes: _storedConfig?.networkCaptureSizes !== false
|
|
@@ -481,6 +494,10 @@ const Rejourney = {
|
|
|
481
494
|
getAutoTracking().cleanupAutoTracking();
|
|
482
495
|
getAutoTracking().resetMetrics();
|
|
483
496
|
await safeNativeCall('stopSession', () => getRejourneyNative().stopSession(), undefined);
|
|
497
|
+
if (_metricsInterval) {
|
|
498
|
+
clearInterval(_metricsInterval);
|
|
499
|
+
_metricsInterval = null;
|
|
500
|
+
}
|
|
484
501
|
_isRecording = false;
|
|
485
502
|
getLogger().logSessionEnd('current');
|
|
486
503
|
} catch (error) {
|
|
@@ -497,7 +514,6 @@ const Rejourney = {
|
|
|
497
514
|
*/
|
|
498
515
|
logEvent(name, properties) {
|
|
499
516
|
safeNativeCallSync('logEvent', () => {
|
|
500
|
-
// Fire and forget - don't await
|
|
501
517
|
getRejourneyNative().logEvent(name, properties || {}).catch(() => {});
|
|
502
518
|
}, undefined);
|
|
503
519
|
},
|
|
@@ -598,7 +614,7 @@ const Rejourney = {
|
|
|
598
614
|
eventCount: 0,
|
|
599
615
|
videoSegmentCount: 0,
|
|
600
616
|
storageSize: 0,
|
|
601
|
-
sdkVersion:
|
|
617
|
+
sdkVersion: SDK_VERSION,
|
|
602
618
|
isComplete: false
|
|
603
619
|
},
|
|
604
620
|
events: []
|
|
@@ -625,7 +641,6 @@ const Rejourney = {
|
|
|
625
641
|
* @returns Path to export file (not implemented)
|
|
626
642
|
*/
|
|
627
643
|
async exportSession(_sessionId) {
|
|
628
|
-
// Return empty string - actual export should be done from dashboard server
|
|
629
644
|
getLogger().warn('exportSession not implemented - export from dashboard server');
|
|
630
645
|
return '';
|
|
631
646
|
},
|
|
@@ -847,8 +862,6 @@ const Rejourney = {
|
|
|
847
862
|
errorMessage: request.errorMessage,
|
|
848
863
|
cached: request.cached
|
|
849
864
|
};
|
|
850
|
-
|
|
851
|
-
// Fire and forget - don't await, this is low priority
|
|
852
865
|
getRejourneyNative().logEvent('network_request', networkEvent).catch(() => {});
|
|
853
866
|
}, undefined);
|
|
854
867
|
},
|
|
@@ -945,10 +958,10 @@ function handleAppStateChange(nextAppState) {
|
|
|
945
958
|
try {
|
|
946
959
|
if (_currentAppState.match(/active/) && nextAppState === 'background') {
|
|
947
960
|
// App going to background - native module handles this automatically
|
|
948
|
-
getLogger().
|
|
961
|
+
getLogger().logLifecycleEvent('App moving to background');
|
|
949
962
|
} else if (_currentAppState.match(/inactive|background/) && nextAppState === 'active') {
|
|
950
963
|
// App coming back to foreground
|
|
951
|
-
getLogger().
|
|
964
|
+
getLogger().logLifecycleEvent('App returning to foreground');
|
|
952
965
|
}
|
|
953
966
|
_currentAppState = nextAppState;
|
|
954
967
|
} catch (error) {
|
|
@@ -452,9 +452,6 @@ function setupNavigationTracking() {
|
|
|
452
452
|
if (__DEV__) {
|
|
453
453
|
logger.debug('Setting up navigation tracking...');
|
|
454
454
|
}
|
|
455
|
-
|
|
456
|
-
// Delay to ensure navigation is initialized - Expo Router needs more time
|
|
457
|
-
// We retry a few times with increasing delays
|
|
458
455
|
let attempts = 0;
|
|
459
456
|
const maxAttempts = 5;
|
|
460
457
|
const trySetup = () => {
|
|
@@ -115,8 +115,6 @@ function queueRequest(request) {
|
|
|
115
115
|
function flushPendingRequests() {
|
|
116
116
|
flushTimer = null;
|
|
117
117
|
if (!logCallback || pendingCount === 0) return;
|
|
118
|
-
|
|
119
|
-
// Process all pending requests
|
|
120
118
|
while (pendingCount > 0) {
|
|
121
119
|
const request = pendingRequests[pendingHead];
|
|
122
120
|
pendingRequests[pendingHead] = null; // Allow GC
|
|
@@ -184,14 +182,9 @@ function interceptFetch() {
|
|
|
184
182
|
if (!shouldSampleRequest(path)) {
|
|
185
183
|
return originalFetch(input, init);
|
|
186
184
|
}
|
|
187
|
-
|
|
188
|
-
// Capture start time (only synchronous work)
|
|
189
185
|
const startTime = Date.now();
|
|
190
186
|
const method = (init?.method || 'GET').toUpperCase();
|
|
191
|
-
|
|
192
|
-
// Call original fetch
|
|
193
187
|
return originalFetch(input, init).then(response => {
|
|
194
|
-
// Success - queue the log asynchronously
|
|
195
188
|
queueRequest({
|
|
196
189
|
requestId: `f${startTime}`,
|
|
197
190
|
method,
|
|
@@ -242,8 +235,6 @@ function interceptXHR() {
|
|
|
242
235
|
if (!config.enabled || !logCallback || !data || shouldIgnoreUrl(data.u)) {
|
|
243
236
|
return originalXHRSend.call(this, body);
|
|
244
237
|
}
|
|
245
|
-
|
|
246
|
-
// Check sampling
|
|
247
238
|
const {
|
|
248
239
|
path
|
|
249
240
|
} = parseUrlFast(data.u);
|
|
@@ -292,8 +283,6 @@ export function initNetworkInterceptor(callback, options) {
|
|
|
292
283
|
*/
|
|
293
284
|
export function disableNetworkInterceptor() {
|
|
294
285
|
config.enabled = false;
|
|
295
|
-
|
|
296
|
-
// Flush any pending requests
|
|
297
286
|
if (flushTimer) {
|
|
298
287
|
clearTimeout(flushTimer);
|
|
299
288
|
flushTimer = null;
|
package/lib/module/sdk/utils.js
CHANGED
|
@@ -222,7 +222,6 @@ export let LogLevel = /*#__PURE__*/function (LogLevel) {
|
|
|
222
222
|
*/
|
|
223
223
|
class Logger {
|
|
224
224
|
prefix = '[Rejourney]';
|
|
225
|
-
debugMode = false;
|
|
226
225
|
|
|
227
226
|
/**
|
|
228
227
|
* Minimum log level to display.
|
|
@@ -243,7 +242,6 @@ class Logger {
|
|
|
243
242
|
this.minimumLogLevel = level;
|
|
244
243
|
}
|
|
245
244
|
setDebugMode(enabled) {
|
|
246
|
-
this.debugMode = enabled;
|
|
247
245
|
this.minimumLogLevel = enabled ? LogLevel.DEBUG : typeof __DEV__ !== 'undefined' && __DEV__ ? LogLevel.ERROR : LogLevel.SILENT;
|
|
248
246
|
}
|
|
249
247
|
|
|
@@ -264,14 +262,26 @@ class Logger {
|
|
|
264
262
|
/** Log a warning message */
|
|
265
263
|
warn(...args) {
|
|
266
264
|
if (this.minimumLogLevel <= LogLevel.WARNING) {
|
|
267
|
-
|
|
265
|
+
if (this.minimumLogLevel <= LogLevel.DEBUG) {
|
|
266
|
+
// Explicit Debug Mode: Show YellowBox
|
|
267
|
+
console.warn(this.prefix, ...args);
|
|
268
|
+
} else {
|
|
269
|
+
// Default Dev Mode: Log to console only, avoid YellowBox
|
|
270
|
+
console.log(this.prefix, '[WARN]', ...args);
|
|
271
|
+
}
|
|
268
272
|
}
|
|
269
273
|
}
|
|
270
274
|
|
|
271
275
|
/** Log an error message */
|
|
272
276
|
error(...args) {
|
|
273
277
|
if (this.minimumLogLevel <= LogLevel.ERROR) {
|
|
274
|
-
|
|
278
|
+
if (this.minimumLogLevel <= LogLevel.DEBUG) {
|
|
279
|
+
// Explicit Debug Mode: Show RedBox
|
|
280
|
+
console.error(this.prefix, ...args);
|
|
281
|
+
} else {
|
|
282
|
+
// Default Dev Mode: Log to console only, avoid RedBox
|
|
283
|
+
console.log(this.prefix, '[ERROR]', ...args);
|
|
284
|
+
}
|
|
275
285
|
}
|
|
276
286
|
}
|
|
277
287
|
notice(...args) {
|
|
@@ -285,9 +295,7 @@ class Logger {
|
|
|
285
295
|
* Only shown in development builds - this is the minimal "SDK started" log.
|
|
286
296
|
*/
|
|
287
297
|
logInitSuccess(version) {
|
|
288
|
-
|
|
289
|
-
this.info(`✓ SDK initialized (v${version})`);
|
|
290
|
-
}
|
|
298
|
+
this.notice(`✓ SDK initialized (v${version})`);
|
|
291
299
|
}
|
|
292
300
|
|
|
293
301
|
/**
|
|
@@ -303,9 +311,7 @@ class Logger {
|
|
|
303
311
|
* Only shown in development builds.
|
|
304
312
|
*/
|
|
305
313
|
logSessionStart(sessionId) {
|
|
306
|
-
|
|
307
|
-
this.info(`Session started: ${sessionId}`);
|
|
308
|
-
}
|
|
314
|
+
this.notice(`Session started: ${sessionId}`);
|
|
309
315
|
}
|
|
310
316
|
|
|
311
317
|
/**
|
|
@@ -313,12 +319,10 @@ class Logger {
|
|
|
313
319
|
* Only shown in development builds.
|
|
314
320
|
*/
|
|
315
321
|
logSessionEnd(sessionId) {
|
|
316
|
-
|
|
317
|
-
this.info(`Session ended: ${sessionId}`);
|
|
318
|
-
}
|
|
322
|
+
this.notice(`Session ended: ${sessionId}`);
|
|
319
323
|
}
|
|
320
324
|
logObservabilityStart() {
|
|
321
|
-
this.notice('Starting Rejourney observability');
|
|
325
|
+
this.notice('💧 Starting Rejourney observability');
|
|
322
326
|
}
|
|
323
327
|
logRecordingStart() {
|
|
324
328
|
this.notice('Starting recording');
|
|
@@ -332,6 +336,61 @@ class Logger {
|
|
|
332
336
|
logPackageMismatch() {
|
|
333
337
|
this.notice('Bundle ID / package name mismatch');
|
|
334
338
|
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Log network request details
|
|
342
|
+
*/
|
|
343
|
+
logNetworkRequest(request) {
|
|
344
|
+
const statusIcon = request.error || request.statusCode && request.statusCode >= 400 ? '🔴' : '🟢';
|
|
345
|
+
const method = request.method || 'GET';
|
|
346
|
+
// Shorten URL to just path if possible
|
|
347
|
+
let url = request.url || '';
|
|
348
|
+
try {
|
|
349
|
+
if (url.startsWith('http')) {
|
|
350
|
+
const urlObj = new URL(url);
|
|
351
|
+
url = urlObj.pathname;
|
|
352
|
+
}
|
|
353
|
+
} catch {
|
|
354
|
+
// Keep full URL if parsing fails
|
|
355
|
+
}
|
|
356
|
+
const duration = request.duration ? `(${Math.round(request.duration)}ms)` : '';
|
|
357
|
+
const status = request.statusCode ? `${request.statusCode}` : 'ERR';
|
|
358
|
+
this.notice(`${statusIcon} [NET] ${status} ${method} ${url} ${duration} ${request.error ? `Error: ${request.error}` : ''}`);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Log frustration event (rage taps, etc)
|
|
363
|
+
*/
|
|
364
|
+
logFrustration(kind) {
|
|
365
|
+
this.notice(`🤬 Frustration detected: ${kind}`);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Log error captured by SDK
|
|
370
|
+
*/
|
|
371
|
+
logError(message) {
|
|
372
|
+
this.notice(`X Error captured: ${message}`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Log lifecycle event (Background/Foreground)
|
|
377
|
+
* Visible in development builds.
|
|
378
|
+
*/
|
|
379
|
+
logLifecycleEvent(event) {
|
|
380
|
+
this.notice(`🔄 Lifecycle: ${event}`);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Log upload statistics
|
|
385
|
+
*/
|
|
386
|
+
logUploadStats(metrics) {
|
|
387
|
+
const success = metrics.uploadSuccessCount;
|
|
388
|
+
const failed = metrics.uploadFailureCount;
|
|
389
|
+
const bytes = formatBytes(metrics.totalBytesUploaded);
|
|
390
|
+
|
|
391
|
+
// Always show in dev mode for reassurance, even if 0
|
|
392
|
+
this.notice(`📡 Upload Stats: ${success} success, ${failed} failed (${bytes} uploaded)`);
|
|
393
|
+
}
|
|
335
394
|
}
|
|
336
395
|
export const logger = new Logger();
|
|
337
396
|
//# sourceMappingURL=utils.js.map
|
|
@@ -91,7 +91,6 @@ export declare enum LogLevel {
|
|
|
91
91
|
*/
|
|
92
92
|
declare class Logger {
|
|
93
93
|
private prefix;
|
|
94
|
-
private debugMode;
|
|
95
94
|
/**
|
|
96
95
|
* Minimum log level to display.
|
|
97
96
|
*
|
|
@@ -142,6 +141,37 @@ declare class Logger {
|
|
|
142
141
|
logRecordingRemoteDisabled(): void;
|
|
143
142
|
logInvalidProjectKey(): void;
|
|
144
143
|
logPackageMismatch(): void;
|
|
144
|
+
/**
|
|
145
|
+
* Log network request details
|
|
146
|
+
*/
|
|
147
|
+
logNetworkRequest(request: {
|
|
148
|
+
method?: string;
|
|
149
|
+
url?: string;
|
|
150
|
+
statusCode?: number;
|
|
151
|
+
duration?: number;
|
|
152
|
+
error?: string;
|
|
153
|
+
}): void;
|
|
154
|
+
/**
|
|
155
|
+
* Log frustration event (rage taps, etc)
|
|
156
|
+
*/
|
|
157
|
+
logFrustration(kind: string): void;
|
|
158
|
+
/**
|
|
159
|
+
* Log error captured by SDK
|
|
160
|
+
*/
|
|
161
|
+
logError(message: string): void;
|
|
162
|
+
/**
|
|
163
|
+
* Log lifecycle event (Background/Foreground)
|
|
164
|
+
* Visible in development builds.
|
|
165
|
+
*/
|
|
166
|
+
logLifecycleEvent(event: string): void;
|
|
167
|
+
/**
|
|
168
|
+
* Log upload statistics
|
|
169
|
+
*/
|
|
170
|
+
logUploadStats(metrics: {
|
|
171
|
+
uploadSuccessCount: number;
|
|
172
|
+
uploadFailureCount: number;
|
|
173
|
+
totalBytesUploaded: number;
|
|
174
|
+
}): void;
|
|
145
175
|
}
|
|
146
176
|
export declare const logger: Logger;
|
|
147
177
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rejourneyco/react-native",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Rejourney Session Recording SDK for React Native",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -47,9 +47,21 @@
|
|
|
47
47
|
},
|
|
48
48
|
"keywords": [
|
|
49
49
|
"react-native",
|
|
50
|
-
"session-
|
|
51
|
-
"
|
|
52
|
-
"
|
|
50
|
+
"session-replay",
|
|
51
|
+
"observability",
|
|
52
|
+
"error-tracking",
|
|
53
|
+
"crash-reporting",
|
|
54
|
+
"anr-reporting",
|
|
55
|
+
"api-monitoring",
|
|
56
|
+
"alerting",
|
|
57
|
+
"mobile-analytics",
|
|
58
|
+
"mobile-observability",
|
|
59
|
+
"mobile-error-tracking",
|
|
60
|
+
"mobile-crash-reporting",
|
|
61
|
+
"mobile-anr-reporting",
|
|
62
|
+
"mobile-api-monitoring",
|
|
63
|
+
"mobile-performance-monitoring",
|
|
64
|
+
"mobile-user-behavior-analytics"
|
|
53
65
|
],
|
|
54
66
|
"repository": {
|
|
55
67
|
"type": "git",
|