@multiplayer-app/session-recorder-react-native 0.0.1-beta.1 → 0.0.1-beta.11
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/SessionRecorderNative.podspec +29 -0
- package/android/build.gradle +32 -0
- package/copy-react-native-dist.sh +4 -10
- package/dist/components/MaskableComponent.d.ts +22 -0
- package/dist/components/MaskableComponent.js +1 -0
- package/dist/components/MaskableComponent.js.map +1 -0
- package/dist/components/MaskableTextInput.d.ts +14 -0
- package/dist/components/MaskableTextInput.js +1 -0
- package/dist/components/MaskableTextInput.js.map +1 -0
- package/dist/components/SessionRecorderWidget/FinalPopover.d.ts +11 -0
- package/dist/components/SessionRecorderWidget/FinalPopover.js +1 -0
- package/dist/components/SessionRecorderWidget/FinalPopover.js.map +1 -0
- package/dist/components/SessionRecorderWidget/FloatingButton.d.ts +8 -0
- package/dist/components/SessionRecorderWidget/FloatingButton.js +1 -0
- package/dist/components/SessionRecorderWidget/FloatingButton.js.map +1 -0
- package/dist/components/SessionRecorderWidget/InitialPopover.d.ts +13 -0
- package/dist/components/SessionRecorderWidget/InitialPopover.js +1 -0
- package/dist/components/SessionRecorderWidget/InitialPopover.js.map +1 -0
- package/dist/components/SessionRecorderWidget/ModalContainer.d.ts +8 -0
- package/dist/components/SessionRecorderWidget/ModalContainer.js +1 -0
- package/dist/components/SessionRecorderWidget/ModalContainer.js.map +1 -0
- package/dist/components/SessionRecorderWidget/ModalHeader.d.ts +6 -0
- package/dist/components/SessionRecorderWidget/ModalHeader.js +1 -0
- package/dist/components/SessionRecorderWidget/ModalHeader.js.map +1 -0
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.d.ts +5 -0
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js +1 -0
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -0
- package/dist/components/SessionRecorderWidget/icons.d.ts +11 -0
- package/dist/components/SessionRecorderWidget/icons.js +1 -0
- package/dist/components/SessionRecorderWidget/icons.js.map +1 -0
- package/dist/components/SessionRecorderWidget/index.d.ts +2 -0
- package/dist/components/SessionRecorderWidget/index.js +1 -0
- package/dist/components/SessionRecorderWidget/index.js.map +1 -0
- package/dist/components/SessionRecorderWidget/styles.d.ts +145 -0
- package/dist/components/SessionRecorderWidget/styles.js +1 -0
- package/dist/components/SessionRecorderWidget/styles.js.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -1
- package/dist/components/index.js.map +1 -1
- package/dist/config/defaults.js +1 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/masking.js +1 -1
- package/dist/config/masking.js.map +1 -1
- package/dist/context/SessionRecorderContext.d.ts +5 -3
- package/dist/context/SessionRecorderContext.js +1 -1
- package/dist/context/SessionRecorderContext.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/native/ScreenMasking.d.ts +21 -0
- package/dist/native/ScreenMasking.js +1 -0
- package/dist/native/ScreenMasking.js.map +1 -0
- package/dist/native/SessionRecorderNative.d.ts +21 -0
- package/dist/native/SessionRecorderNative.js +1 -0
- package/dist/native/SessionRecorderNative.js.map +1 -0
- package/dist/patch/xhr.js +1 -1
- package/dist/patch/xhr.js.map +1 -1
- package/dist/recorder/screenRecorder.d.ts +1 -0
- package/dist/recorder/screenRecorder.js +1 -1
- package/dist/recorder/screenRecorder.js.map +1 -1
- package/dist/recorder/screenshotManager.d.ts +10 -0
- package/dist/recorder/screenshotManager.js +1 -0
- package/dist/recorder/screenshotManager.js.map +1 -0
- package/dist/services/screenMaskingService.d.ts +39 -0
- package/dist/services/screenMaskingService.js +1 -0
- package/dist/services/screenMaskingService.js.map +1 -0
- package/dist/services/storage.service.d.ts +18 -2
- package/dist/services/storage.service.js +1 -1
- package/dist/services/storage.service.js.map +1 -1
- package/dist/session-recorder.d.ts +2 -1
- package/dist/session-recorder.js +1 -1
- package/dist/session-recorder.js.map +1 -1
- package/dist/types/session-recorder.d.ts +6 -0
- package/dist/types/session-recorder.js.map +1 -1
- package/dist/utils/componentRegistry.d.ts +64 -0
- package/dist/utils/componentRegistry.js +1 -0
- package/dist/utils/componentRegistry.js.map +1 -0
- package/dist/utils/nativeModuleTest.d.ts +8 -0
- package/dist/utils/nativeModuleTest.js +1 -0
- package/dist/utils/nativeModuleTest.js.map +1 -0
- package/dist/utils/platform.d.ts +3 -0
- package/dist/utils/reactNativeHierarchyExtractor.d.ts +38 -0
- package/dist/utils/reactNativeHierarchyExtractor.js +1 -0
- package/dist/utils/reactNativeHierarchyExtractor.js.map +1 -0
- package/dist/utils/screenshotMasker.d.ts +96 -0
- package/dist/utils/screenshotMasker.js +1 -0
- package/dist/utils/screenshotMasker.js.map +1 -0
- package/dist/utils/viewHierarchyTracker.d.ts +89 -0
- package/dist/utils/viewHierarchyTracker.js +1 -0
- package/dist/utils/viewHierarchyTracker.js.map +1 -0
- package/ios/SessionRecorderNative.m +17 -0
- package/ios/SessionRecorderNative.podspec +26 -0
- package/ios/SessionRecorderNative.swift +205 -0
- package/package.json +22 -7
- package/react-native.config.js +15 -0
- package/RRWEB_INTEGRATION.md +0 -336
- package/VIEWSHOT_INTEGRATION_TEST.md +0 -123
- package/babel.config.js +0 -13
- package/dist/components/GestureCaptureWrapper.d.ts +0 -6
- package/dist/components/GestureCaptureWrapper.js +0 -1
- package/dist/components/GestureCaptureWrapper.js.map +0 -1
- package/dist/expo.d.ts +0 -7
- package/dist/expo.js +0 -1
- package/dist/expo.js.map +0 -1
- package/dist/otel/instrumentations/gestureInstrumentation.d.ts +0 -15
- package/dist/otel/instrumentations/gestureInstrumentation.js +0 -1
- package/dist/otel/instrumentations/gestureInstrumentation.js.map +0 -1
- package/dist/otel/instrumentations/reactNativeInstrumentation.d.ts +0 -8
- package/dist/otel/instrumentations/reactNativeInstrumentation.js +0 -1
- package/dist/otel/instrumentations/reactNativeInstrumentation.js.map +0 -1
- package/dist/otel/instrumentations/reactNavigationInstrumentation.d.ts +0 -13
- package/dist/otel/instrumentations/reactNavigationInstrumentation.js +0 -1
- package/dist/otel/instrumentations/reactNavigationInstrumentation.js.map +0 -1
- package/dist/recorder/gestureHandlerRecorder.d.ts +0 -19
- package/dist/recorder/gestureHandlerRecorder.js +0 -1
- package/dist/recorder/gestureHandlerRecorder.js.map +0 -1
- package/dist/types/rrweb.d.ts +0 -118
- package/dist/types/rrweb.js +0 -1
- package/dist/types/rrweb.js.map +0 -1
- package/scripts/generate-app-metadata.js +0 -173
- package/src/components/GestureCaptureWrapper/GestureCaptureWrapper.tsx +0 -86
- package/src/components/GestureCaptureWrapper/index.ts +0 -1
- package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +0 -72
- package/src/components/ScreenRecorderView/index.ts +0 -1
- package/src/components/index.ts +0 -1
- package/src/config/constants.ts +0 -60
- package/src/config/defaults.ts +0 -82
- package/src/config/index.ts +0 -6
- package/src/config/masking.ts +0 -27
- package/src/config/session-recorder.ts +0 -55
- package/src/config/validators.ts +0 -31
- package/src/context/SessionRecorderContext.tsx +0 -75
- package/src/expo.ts +0 -11
- package/src/index.ts +0 -17
- package/src/otel/helpers.ts +0 -275
- package/src/otel/index.ts +0 -138
- package/src/otel/instrumentations/index.ts +0 -115
- package/src/patch/index.ts +0 -1
- package/src/patch/xhr.ts +0 -142
- package/src/recorder/eventExporter.ts +0 -141
- package/src/recorder/gestureRecorder.ts +0 -498
- package/src/recorder/index.ts +0 -179
- package/src/recorder/navigationTracker.ts +0 -449
- package/src/recorder/screenRecorder.ts +0 -498
- package/src/services/api.service.ts +0 -203
- package/src/services/storage.service.ts +0 -158
- package/src/session-recorder.ts +0 -600
- package/src/types/expo.d.ts +0 -23
- package/src/types/index.ts +0 -28
- package/src/types/session-recorder.ts +0 -423
- package/src/types/session.ts +0 -65
- package/src/utils/app-metadata.ts +0 -31
- package/src/utils/index.ts +0 -8
- package/src/utils/logger.ts +0 -225
- package/src/utils/platform.ts +0 -384
- package/src/utils/request-utils.ts +0 -61
- package/src/utils/rrweb-events.ts +0 -309
- package/src/utils/session.ts +0 -18
- package/src/utils/time.ts +0 -17
- package/src/utils/type-utils.ts +0 -75
- package/src/version.ts +0 -1
- package/tsconfig.json +0 -24
package/src/recorder/index.ts
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { SessionType } from '@multiplayer-app/session-recorder-common'
|
|
2
|
-
// import { pack } from '@rrweb/packer' // Removed to avoid blob creation issues in Hermes
|
|
3
|
-
import { EventExporter } from './eventExporter'
|
|
4
|
-
import { logger } from '../utils'
|
|
5
|
-
import { ScreenRecorder } from './screenRecorder'
|
|
6
|
-
import { GestureRecorder } from './gestureRecorder'
|
|
7
|
-
import { NavigationTracker } from './navigationTracker'
|
|
8
|
-
import { RecorderConfig, EventRecorder } from '../types'
|
|
9
|
-
import { eventWithTime } from '@rrweb/types'
|
|
10
|
-
export class RecorderReactNativeSDK implements EventRecorder {
|
|
11
|
-
private isRecording = false
|
|
12
|
-
private config?: RecorderConfig
|
|
13
|
-
private screenRecorder: ScreenRecorder
|
|
14
|
-
private gestureRecorder: GestureRecorder
|
|
15
|
-
private navigationTracker: NavigationTracker
|
|
16
|
-
private recordedEvents: eventWithTime[] = []
|
|
17
|
-
private exporter: EventExporter | undefined
|
|
18
|
-
private sessionId: string | null = null
|
|
19
|
-
private sessionType: SessionType = SessionType.PLAIN
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
constructor() {
|
|
23
|
-
this.screenRecorder = new ScreenRecorder()
|
|
24
|
-
this.gestureRecorder = new GestureRecorder()
|
|
25
|
-
this.navigationTracker = new NavigationTracker()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
init(config: RecorderConfig): void {
|
|
29
|
-
this.config = config
|
|
30
|
-
this.gestureRecorder.init(config, this, this.screenRecorder)
|
|
31
|
-
this.navigationTracker.init(config)
|
|
32
|
-
this.screenRecorder.init(config, this)
|
|
33
|
-
this.exporter = new EventExporter({
|
|
34
|
-
socketUrl: config.apiBaseUrl || '',
|
|
35
|
-
apiKey: config.apiKey,
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
start(sessionId: string | null, sessionType: SessionType): void {
|
|
40
|
-
if (!this.config) {
|
|
41
|
-
throw new Error('Configuration not initialized. Call init() before start().')
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this.sessionId = sessionId
|
|
45
|
-
this.sessionType = sessionType
|
|
46
|
-
this.isRecording = true
|
|
47
|
-
|
|
48
|
-
// Emit recording started meta event
|
|
49
|
-
|
|
50
|
-
if (this.config.recordScreen) {
|
|
51
|
-
this.screenRecorder.start()
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (this.config.recordGestures) {
|
|
55
|
-
this.gestureRecorder.start()
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (this.config.recordNavigation) {
|
|
59
|
-
this.navigationTracker.start()
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
stop(): void {
|
|
66
|
-
this.isRecording = false
|
|
67
|
-
this.gestureRecorder.stop()
|
|
68
|
-
this.navigationTracker.stop()
|
|
69
|
-
this.screenRecorder.stop()
|
|
70
|
-
this.exporter?.close()
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
setNavigationRef(ref: any): void {
|
|
75
|
-
this.navigationTracker.setNavigationRef(ref)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Set the viewshot ref for screen capture
|
|
80
|
-
* @param ref - React Native View ref for screen capture
|
|
81
|
-
*/
|
|
82
|
-
setViewShotRef(ref: any): void {
|
|
83
|
-
this.screenRecorder.setViewShotRef(ref)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Record an rrweb event
|
|
88
|
-
* @param event - The rrweb event to record
|
|
89
|
-
*/
|
|
90
|
-
recordEvent(event: eventWithTime): void {
|
|
91
|
-
if (!this.isRecording) {
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (this.exporter) {
|
|
96
|
-
logger.debug('RecorderReactNativeSDK', 'Sending to exporter', event)
|
|
97
|
-
// Skip packing to avoid blob creation issues in Hermes
|
|
98
|
-
// const packedEvent = pack(event)
|
|
99
|
-
this.exporter.send({
|
|
100
|
-
event: event, // Send raw event instead of packed
|
|
101
|
-
eventType: event.type,
|
|
102
|
-
timestamp: event.timestamp,
|
|
103
|
-
debugSessionId: this.sessionId,
|
|
104
|
-
debugSessionType: this.sessionType,
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Record touch start event
|
|
111
|
-
* @param x - X coordinate
|
|
112
|
-
* @param y - Y coordinate
|
|
113
|
-
* @param target - Target element identifier
|
|
114
|
-
* @param pressure - Touch pressure
|
|
115
|
-
*/
|
|
116
|
-
recordTouchStart(x: number, y: number, target?: string, pressure?: number): void {
|
|
117
|
-
if (!this.isRecording) {
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
this.gestureRecorder.recordTouchStart(x, y, target, pressure)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Record touch move event
|
|
126
|
-
* @param x - X coordinate
|
|
127
|
-
* @param y - Y coordinate
|
|
128
|
-
* @param target - Target element identifier
|
|
129
|
-
* @param pressure - Touch pressure
|
|
130
|
-
*/
|
|
131
|
-
recordTouchMove(x: number, y: number, target?: string, pressure?: number): void {
|
|
132
|
-
if (!this.isRecording) {
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
this.gestureRecorder.recordTouchMove(x, y, target, pressure)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Record touch end event
|
|
141
|
-
* @param x - X coordinate
|
|
142
|
-
* @param y - Y coordinate
|
|
143
|
-
* @param target - Target element identifier
|
|
144
|
-
* @param pressure - Touch pressure
|
|
145
|
-
*/
|
|
146
|
-
recordTouchEnd(x: number, y: number, target?: string, pressure?: number): void {
|
|
147
|
-
if (!this.isRecording) {
|
|
148
|
-
return
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
this.gestureRecorder.recordTouchEnd(x, y, target, pressure)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Get all recorded events
|
|
156
|
-
* @returns Array of recorded rrweb events
|
|
157
|
-
*/
|
|
158
|
-
getRecordedEvents(): eventWithTime[] {
|
|
159
|
-
return [...this.recordedEvents]
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Clear all recorded events
|
|
164
|
-
*/
|
|
165
|
-
clearRecordedEvents(): void {
|
|
166
|
-
this.recordedEvents = []
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Get recording statistics
|
|
171
|
-
* @returns Recording statistics
|
|
172
|
-
*/
|
|
173
|
-
getRecordingStats(): { totalEvents: number; isRecording: boolean } {
|
|
174
|
-
return {
|
|
175
|
-
totalEvents: this.recordedEvents.length,
|
|
176
|
-
isRecording: this.isRecording,
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
import { NavigationEvent, RecorderConfig } from '../types'
|
|
2
|
-
import { trace, SpanStatusCode } from '@opentelemetry/api'
|
|
3
|
-
import { logger } from '../utils'
|
|
4
|
-
|
|
5
|
-
export class NavigationTracker {
|
|
6
|
-
private config?: RecorderConfig
|
|
7
|
-
private isRecording = false
|
|
8
|
-
private navigationRef: any = null
|
|
9
|
-
private events: NavigationEvent[] = []
|
|
10
|
-
private navigationListeners: Map<string, any> = new Map()
|
|
11
|
-
private currentRoute: string | null = null
|
|
12
|
-
private navigationStack: string[] = []
|
|
13
|
-
private navigationStartTime: number = 0
|
|
14
|
-
|
|
15
|
-
init(config: RecorderConfig): void {
|
|
16
|
-
this.config = config
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
setNavigationRef(ref: any): void {
|
|
20
|
-
this.navigationRef = ref
|
|
21
|
-
if (this.isRecording) {
|
|
22
|
-
this._setupNavigationListener()
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
start(): void {
|
|
27
|
-
logger.info('NavigationTracker', 'Navigation tracking started')
|
|
28
|
-
this.isRecording = true
|
|
29
|
-
this.events = []
|
|
30
|
-
this.navigationStack = []
|
|
31
|
-
this.navigationStartTime = Date.now()
|
|
32
|
-
this._setupNavigationListener()
|
|
33
|
-
// Navigation tracking started
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
stop(): void {
|
|
37
|
-
this.isRecording = false
|
|
38
|
-
this._removeNavigationListener()
|
|
39
|
-
// Navigation tracking stopped
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
pause(): void {
|
|
43
|
-
this.isRecording = false
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
resume(): void {
|
|
47
|
-
this.isRecording = true
|
|
48
|
-
this._setupNavigationListener()
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private _setupNavigationListener(): void {
|
|
52
|
-
if (!this.navigationRef) {
|
|
53
|
-
// Navigation ref not set - silently continue
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
// Listen to navigation state changes
|
|
59
|
-
const stateListener = this.navigationRef.addListener('state', (e: any) => {
|
|
60
|
-
this._recordNavigationEvent('state_change', e.data)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
// Listen to focus events
|
|
64
|
-
const focusListener = this.navigationRef.addListener('focus', (e: any) => {
|
|
65
|
-
this._recordNavigationEvent('focus', e.data)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
// Listen to blur events
|
|
69
|
-
const blurListener = this.navigationRef.addListener('blur', (e: any) => {
|
|
70
|
-
this._recordNavigationEvent('blur', e.data)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
// Listen to beforeRemove events
|
|
74
|
-
const beforeRemoveListener = this.navigationRef.addListener('beforeRemove', (e: any) => {
|
|
75
|
-
this._recordNavigationEvent('beforeRemove', e.data)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
// Store listeners for cleanup
|
|
79
|
-
this.navigationListeners.set('state', stateListener)
|
|
80
|
-
this.navigationListeners.set('focus', focusListener)
|
|
81
|
-
this.navigationListeners.set('blur', blurListener)
|
|
82
|
-
this.navigationListeners.set('beforeRemove', beforeRemoveListener)
|
|
83
|
-
|
|
84
|
-
// Navigation listeners setup complete
|
|
85
|
-
} catch (error) {
|
|
86
|
-
// Failed to setup navigation listeners - silently continue
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private _removeNavigationListener(): void {
|
|
91
|
-
try {
|
|
92
|
-
// Remove all listeners
|
|
93
|
-
this.navigationListeners.forEach((listener, key) => {
|
|
94
|
-
if (listener && typeof listener.remove === 'function') {
|
|
95
|
-
listener.remove()
|
|
96
|
-
}
|
|
97
|
-
})
|
|
98
|
-
this.navigationListeners.clear()
|
|
99
|
-
// Navigation listeners removed
|
|
100
|
-
} catch (error) {
|
|
101
|
-
// Failed to remove navigation listeners - silently continue
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
private _recordNavigationEvent(eventType: string, data: any): void {
|
|
106
|
-
if (!this.isRecording) return
|
|
107
|
-
|
|
108
|
-
const event: NavigationEvent = {
|
|
109
|
-
type: 'navigate', // Default type
|
|
110
|
-
timestamp: Date.now(),
|
|
111
|
-
metadata: {
|
|
112
|
-
eventType,
|
|
113
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
114
|
-
stackDepth: this.navigationStack.length,
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (data) {
|
|
119
|
-
if (data.routeName) {
|
|
120
|
-
event.routeName = data.routeName
|
|
121
|
-
this._updateNavigationStack(data.routeName, eventType)
|
|
122
|
-
}
|
|
123
|
-
if (data.params) {
|
|
124
|
-
event.params = data.params
|
|
125
|
-
}
|
|
126
|
-
if (data.key) {
|
|
127
|
-
event.metadata!.routeKey = data.key
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
this.events.push(event)
|
|
132
|
-
this._sendEvent(event)
|
|
133
|
-
this._recordOpenTelemetrySpan(event)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
private _updateNavigationStack(routeName: string, eventType: string): void {
|
|
139
|
-
if (eventType === 'focus' || eventType === 'state_change') {
|
|
140
|
-
if (this.currentRoute !== routeName) {
|
|
141
|
-
this.currentRoute = routeName
|
|
142
|
-
this.navigationStack.push(routeName)
|
|
143
|
-
}
|
|
144
|
-
} else if (eventType === 'blur' || eventType === 'beforeRemove') {
|
|
145
|
-
const index = this.navigationStack.indexOf(routeName)
|
|
146
|
-
if (index > -1) {
|
|
147
|
-
this.navigationStack.splice(index, 1)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
private _sendEvent(event: NavigationEvent): void {
|
|
153
|
-
// Navigation event recorded
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
private _recordOpenTelemetrySpan(event: NavigationEvent): void {
|
|
157
|
-
try {
|
|
158
|
-
const span = trace.getTracer('navigation').startSpan(`Navigation.${event.type}`, {
|
|
159
|
-
attributes: {
|
|
160
|
-
'navigation.system': 'ReactNavigation',
|
|
161
|
-
'navigation.operation': event.type,
|
|
162
|
-
'navigation.type': event.type,
|
|
163
|
-
'navigation.timestamp': event.timestamp,
|
|
164
|
-
'navigation.platform': 'react-native',
|
|
165
|
-
},
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
if (event.routeName) {
|
|
169
|
-
span.setAttribute('navigation.route_name', event.routeName)
|
|
170
|
-
}
|
|
171
|
-
if (event.params) {
|
|
172
|
-
span.setAttribute('navigation.params', JSON.stringify(event.params))
|
|
173
|
-
}
|
|
174
|
-
if (event.metadata) {
|
|
175
|
-
Object.entries(event.metadata).forEach(([key, value]) => {
|
|
176
|
-
span.setAttribute(`navigation.metadata.${key}`, String(value))
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
span.setStatus({ code: SpanStatusCode.OK })
|
|
181
|
-
span.end()
|
|
182
|
-
} catch (error) {
|
|
183
|
-
// Failed to record OpenTelemetry span for navigation - silently continue
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Public methods for manual event recording
|
|
188
|
-
recordNavigate(routeName: string, params?: Record<string, any>): void {
|
|
189
|
-
const event: NavigationEvent = {
|
|
190
|
-
type: 'navigate',
|
|
191
|
-
timestamp: Date.now(),
|
|
192
|
-
routeName,
|
|
193
|
-
params,
|
|
194
|
-
metadata: {
|
|
195
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
196
|
-
stackDepth: this.navigationStack.length,
|
|
197
|
-
manual: true,
|
|
198
|
-
},
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
this._updateNavigationStack(routeName, 'focus')
|
|
202
|
-
this._recordEvent(event)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
recordGoBack(): void {
|
|
206
|
-
const event: NavigationEvent = {
|
|
207
|
-
type: 'goBack',
|
|
208
|
-
timestamp: Date.now(),
|
|
209
|
-
metadata: {
|
|
210
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
211
|
-
stackDepth: this.navigationStack.length,
|
|
212
|
-
manual: true,
|
|
213
|
-
},
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
this._recordEvent(event)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
recordReset(routes: any[]): void {
|
|
220
|
-
const event: NavigationEvent = {
|
|
221
|
-
type: 'reset',
|
|
222
|
-
timestamp: Date.now(),
|
|
223
|
-
metadata: {
|
|
224
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
225
|
-
routesCount: routes.length,
|
|
226
|
-
manual: true,
|
|
227
|
-
},
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Update navigation stack
|
|
231
|
-
this.navigationStack = routes.map(route => route.name || route.routeName)
|
|
232
|
-
if (routes.length > 0) {
|
|
233
|
-
this.currentRoute = routes[0].name || routes[0].routeName
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
this._recordEvent(event)
|
|
237
|
-
this._recordEvent(event)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
private _recordEvent(event: NavigationEvent): void {
|
|
241
|
-
if (!this.isRecording) return
|
|
242
|
-
|
|
243
|
-
this.events.push(event)
|
|
244
|
-
this._sendEvent(event)
|
|
245
|
-
this._recordOpenTelemetrySpan(event)
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Advanced navigation tracking methods
|
|
249
|
-
recordDeepLink(url: string, params?: Record<string, any>): void {
|
|
250
|
-
const event: NavigationEvent = {
|
|
251
|
-
type: 'navigate',
|
|
252
|
-
timestamp: Date.now(),
|
|
253
|
-
routeName: 'deepLink',
|
|
254
|
-
params: { url, ...params },
|
|
255
|
-
metadata: {
|
|
256
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
257
|
-
stackDepth: this.navigationStack.length,
|
|
258
|
-
deepLink: true,
|
|
259
|
-
},
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
this._recordEvent(event)
|
|
263
|
-
this._recordEvent(event)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
recordTabChange(tabName: string, tabIndex: number): void {
|
|
267
|
-
const event: NavigationEvent = {
|
|
268
|
-
type: 'navigate',
|
|
269
|
-
timestamp: Date.now(),
|
|
270
|
-
routeName: tabName,
|
|
271
|
-
params: { tabIndex },
|
|
272
|
-
metadata: {
|
|
273
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
274
|
-
stackDepth: this.navigationStack.length,
|
|
275
|
-
tabChange: true,
|
|
276
|
-
tabIndex,
|
|
277
|
-
},
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
this._recordEvent(event)
|
|
281
|
-
this._recordEvent(event)
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
recordModalOpen(modalName: string, params?: Record<string, any>): void {
|
|
285
|
-
const event: NavigationEvent = {
|
|
286
|
-
type: 'navigate',
|
|
287
|
-
timestamp: Date.now(),
|
|
288
|
-
routeName: modalName,
|
|
289
|
-
params,
|
|
290
|
-
metadata: {
|
|
291
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
292
|
-
stackDepth: this.navigationStack.length,
|
|
293
|
-
modal: true,
|
|
294
|
-
},
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
this._recordEvent(event)
|
|
298
|
-
this._recordEvent(event)
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
recordModalClose(modalName: string): void {
|
|
302
|
-
const event: NavigationEvent = {
|
|
303
|
-
type: 'goBack',
|
|
304
|
-
timestamp: Date.now(),
|
|
305
|
-
routeName: modalName,
|
|
306
|
-
metadata: {
|
|
307
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
308
|
-
stackDepth: this.navigationStack.length,
|
|
309
|
-
modal: true,
|
|
310
|
-
modalClose: true,
|
|
311
|
-
},
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
this._recordEvent(event)
|
|
315
|
-
this._recordEvent(event)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
recordStackPush(routeName: string, params?: Record<string, any>): void {
|
|
319
|
-
const event: NavigationEvent = {
|
|
320
|
-
type: 'navigate',
|
|
321
|
-
timestamp: Date.now(),
|
|
322
|
-
routeName,
|
|
323
|
-
params,
|
|
324
|
-
metadata: {
|
|
325
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
326
|
-
stackDepth: this.navigationStack.length,
|
|
327
|
-
stackOperation: 'push',
|
|
328
|
-
},
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
this._recordEvent(event)
|
|
332
|
-
this._recordEvent(event)
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
recordStackPop(routeName?: string): void {
|
|
336
|
-
const event: NavigationEvent = {
|
|
337
|
-
type: 'goBack',
|
|
338
|
-
timestamp: Date.now(),
|
|
339
|
-
routeName,
|
|
340
|
-
metadata: {
|
|
341
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
342
|
-
stackDepth: this.navigationStack.length,
|
|
343
|
-
stackOperation: 'pop',
|
|
344
|
-
},
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
this._recordEvent(event)
|
|
348
|
-
this._recordEvent(event)
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Performance monitoring
|
|
352
|
-
recordNavigationPerformance(routeName: string, loadTime: number): void {
|
|
353
|
-
const event: NavigationEvent = {
|
|
354
|
-
type: 'navigate',
|
|
355
|
-
timestamp: Date.now(),
|
|
356
|
-
routeName,
|
|
357
|
-
metadata: {
|
|
358
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
359
|
-
stackDepth: this.navigationStack.length,
|
|
360
|
-
performance: 'monitoring',
|
|
361
|
-
loadTime,
|
|
362
|
-
},
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
this._recordEvent(event)
|
|
366
|
-
this._recordEvent(event)
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// Error tracking
|
|
370
|
-
recordNavigationError(error: Error, routeName?: string): void {
|
|
371
|
-
const event: NavigationEvent = {
|
|
372
|
-
type: 'navigate',
|
|
373
|
-
timestamp: Date.now(),
|
|
374
|
-
routeName,
|
|
375
|
-
metadata: {
|
|
376
|
-
navigationDuration: Date.now() - this.navigationStartTime,
|
|
377
|
-
stackDepth: this.navigationStack.length,
|
|
378
|
-
error: true,
|
|
379
|
-
errorType: error.name,
|
|
380
|
-
errorMessage: error.message,
|
|
381
|
-
},
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
this._recordEvent(event)
|
|
385
|
-
this._recordEvent(event)
|
|
386
|
-
|
|
387
|
-
// Also record as OpenTelemetry error span
|
|
388
|
-
try {
|
|
389
|
-
const span = trace.getTracer('navigation').startSpan('Navigation.error', {
|
|
390
|
-
attributes: {
|
|
391
|
-
'navigation.system': 'ReactNavigation',
|
|
392
|
-
'navigation.error': true,
|
|
393
|
-
'navigation.error.type': error.name,
|
|
394
|
-
'navigation.error.message': error.message,
|
|
395
|
-
'navigation.route_name': routeName || 'unknown',
|
|
396
|
-
'navigation.timestamp': Date.now(),
|
|
397
|
-
},
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
|
|
401
|
-
span.recordException(error)
|
|
402
|
-
span.end()
|
|
403
|
-
} catch (spanError) {
|
|
404
|
-
// Failed to record error span - silently continue
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Get current navigation state
|
|
409
|
-
getCurrentRoute(): string | null {
|
|
410
|
-
return this.currentRoute
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
getNavigationStack(): string[] {
|
|
414
|
-
return [...this.navigationStack]
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
getNavigationDepth(): number {
|
|
418
|
-
return this.navigationStack.length
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// Get recorded events
|
|
422
|
-
getEvents(): NavigationEvent[] {
|
|
423
|
-
return [...this.events]
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// Clear events
|
|
427
|
-
clearEvents(): void {
|
|
428
|
-
this.events = []
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Get navigation statistics
|
|
432
|
-
getNavigationStats(): Record<string, number> {
|
|
433
|
-
const stats: Record<string, number> = {}
|
|
434
|
-
this.events.forEach(event => {
|
|
435
|
-
stats[event.type] = (stats[event.type] || 0) + 1
|
|
436
|
-
})
|
|
437
|
-
return stats
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Get recording status
|
|
441
|
-
isRecordingEnabled(): boolean {
|
|
442
|
-
return this.isRecording
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// Get navigation duration
|
|
446
|
-
getNavigationDuration(): number {
|
|
447
|
-
return Date.now() - this.navigationStartTime
|
|
448
|
-
}
|
|
449
|
-
}
|