@multiplayer-app/session-recorder-react-native 0.0.1-beta.7 → 0.0.1-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/app.plugin.js +42 -0
  2. package/docs/NATIVE_MODULE_SETUP.md +177 -0
  3. package/ios/SessionRecorderNative.podspec +5 -0
  4. package/package.json +10 -1
  5. package/plugin/package.json +20 -0
  6. package/plugin/src/index.js +42 -0
  7. package/android/src/main/AndroidManifest.xml +0 -2
  8. package/android/src/main/java/com/multiplayer/sessionrecorder/ScreenMaskingModule.kt +0 -202
  9. package/android/src/main/java/com/multiplayer/sessionrecorder/ScreenMaskingPackage.kt +0 -16
  10. package/android/src/main/java/com/multiplayer/sessionrecorder/SessionRecorderModule.kt +0 -202
  11. package/android/src/main/java/com/multiplayer/sessionrecorder/SessionRecorderPackage.kt +0 -16
  12. package/babel.config.js +0 -13
  13. package/docs/AUTO_METADATA_DETECTION.md +0 -108
  14. package/docs/TROUBLESHOOTING.md +0 -168
  15. package/ios/ScreenMasking.m +0 -12
  16. package/ios/ScreenMasking.podspec +0 -21
  17. package/ios/ScreenMasking.swift +0 -205
  18. package/ios/SessionRecorder.podspec +0 -21
  19. package/scripts/generate-app-metadata.js +0 -173
  20. package/src/components/GestureCaptureWrapper/GestureCaptureWrapper.tsx +0 -86
  21. package/src/components/GestureCaptureWrapper/index.ts +0 -1
  22. package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +0 -72
  23. package/src/components/ScreenRecorderView/index.ts +0 -1
  24. package/src/components/SessionRecorderWidget/FinalPopover.tsx +0 -62
  25. package/src/components/SessionRecorderWidget/FloatingButton.tsx +0 -136
  26. package/src/components/SessionRecorderWidget/InitialPopover.tsx +0 -89
  27. package/src/components/SessionRecorderWidget/ModalContainer.tsx +0 -128
  28. package/src/components/SessionRecorderWidget/ModalHeader.tsx +0 -24
  29. package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +0 -109
  30. package/src/components/SessionRecorderWidget/icons.tsx +0 -52
  31. package/src/components/SessionRecorderWidget/index.ts +0 -3
  32. package/src/components/SessionRecorderWidget/styles.ts +0 -150
  33. package/src/components/index.ts +0 -3
  34. package/src/config/constants.ts +0 -60
  35. package/src/config/defaults.ts +0 -83
  36. package/src/config/index.ts +0 -6
  37. package/src/config/masking.ts +0 -28
  38. package/src/config/session-recorder.ts +0 -55
  39. package/src/config/validators.ts +0 -31
  40. package/src/context/SessionRecorderContext.tsx +0 -53
  41. package/src/index.ts +0 -9
  42. package/src/native/ScreenMasking.ts +0 -34
  43. package/src/native/SessionRecorderNative.ts +0 -34
  44. package/src/otel/helpers.ts +0 -275
  45. package/src/otel/index.ts +0 -138
  46. package/src/otel/instrumentations/index.ts +0 -115
  47. package/src/patch/index.ts +0 -1
  48. package/src/patch/xhr.ts +0 -141
  49. package/src/recorder/eventExporter.ts +0 -141
  50. package/src/recorder/gestureRecorder.ts +0 -498
  51. package/src/recorder/index.ts +0 -179
  52. package/src/recorder/navigationTracker.ts +0 -449
  53. package/src/recorder/screenRecorder.ts +0 -527
  54. package/src/services/api.service.ts +0 -203
  55. package/src/services/screenMaskingService.ts +0 -118
  56. package/src/services/storage.service.ts +0 -199
  57. package/src/session-recorder.ts +0 -606
  58. package/src/types/expo.d.ts +0 -23
  59. package/src/types/index.ts +0 -28
  60. package/src/types/session-recorder.ts +0 -429
  61. package/src/types/session.ts +0 -65
  62. package/src/utils/app-metadata.ts +0 -31
  63. package/src/utils/index.ts +0 -8
  64. package/src/utils/logger.ts +0 -225
  65. package/src/utils/nativeModuleTest.ts +0 -60
  66. package/src/utils/platform.ts +0 -384
  67. package/src/utils/request-utils.ts +0 -61
  68. package/src/utils/rrweb-events.ts +0 -309
  69. package/src/utils/session.ts +0 -18
  70. package/src/utils/time.ts +0 -17
  71. package/src/utils/type-utils.ts +0 -75
  72. package/src/version.ts +0 -1
  73. package/tsconfig.json +0 -24
  74. /package/ios/{SessionRecorder.m → SessionRecorderNative.m} +0 -0
  75. /package/ios/{SessionRecorder.swift → SessionRecorderNative.swift} +0 -0
@@ -1,498 +0,0 @@
1
- import { GestureEvent, RecorderConfig, EventRecorder } from '../types'
2
- import { trace, SpanStatusCode } from '@opentelemetry/api'
3
- import { Dimensions } from 'react-native'
4
- import { logger } from '../utils'
5
- import { MouseInteractions, eventWithTime, EventType, IncrementalSource } from '@rrweb/types'
6
-
7
- export class GestureRecorder implements EventRecorder {
8
- private config?: RecorderConfig
9
- private isRecording = false
10
- private events: GestureEvent[] = []
11
- private gestureHandlers: Map<string, any> = new Map()
12
- private screenDimensions: { width: number; height: number } | null = null
13
- private lastGestureTime: number = 0
14
- private gestureThrottleMs: number = 50 // Throttle gestures to avoid spam
15
- private lastTouchTime: number = 0
16
- private touchThrottleMs: number = 100 // Throttle touch events to max 10 per second
17
-
18
- // Cyclic call detection
19
- private isRecordingGesture = false
20
- private gestureCallStack: string[] = []
21
- private maxGestureCallDepth = 5
22
- private eventRecorder?: EventRecorder
23
- private imageNodeId: number = 1 // ID of the image node for touch interactions
24
- private screenRecorder?: any // Reference to screen recorder for force capture
25
-
26
- init(config: RecorderConfig, eventRecorder?: EventRecorder, screenRecorder?: any): void {
27
- this.config = config
28
- this.eventRecorder = eventRecorder
29
- this.screenRecorder = screenRecorder
30
- this._getScreenDimensions()
31
- }
32
-
33
- start(): void {
34
- logger.info('GestureRecorder', 'Gesture recording started')
35
- this.isRecording = true
36
- this.events = []
37
- // Gesture recording started
38
- }
39
-
40
- stop(): void {
41
- this.isRecording = false
42
- this._removeGestureHandlers()
43
- // Gesture recording stopped
44
- }
45
-
46
-
47
- private _getScreenDimensions(): void {
48
- try {
49
- this.screenDimensions = Dimensions.get('window')
50
- } catch (error) {
51
- // Failed to get screen dimensions - silently continue
52
- this.screenDimensions = { width: 375, height: 667 } // Default fallback
53
- }
54
- }
55
-
56
-
57
- private _removeGestureHandlers(): void {
58
- this.gestureHandlers.clear()
59
- // Gesture handlers removed
60
- }
61
-
62
- private _recordEvent(event: GestureEvent): void {
63
- if (!this.isRecording) return
64
-
65
- // Throttle gestures to avoid spam
66
- const now = Date.now()
67
- if (now - this.lastGestureTime < this.gestureThrottleMs) {
68
- return
69
- }
70
- this.lastGestureTime = now
71
-
72
- this.events.push(event)
73
- this._sendEvent(event)
74
- this._recordOpenTelemetrySpan(event)
75
- }
76
-
77
-
78
-
79
- private _sendEvent(event: GestureEvent): void {
80
- // Send event to backend or store locally
81
- // Gesture event recorded
82
- }
83
-
84
- private _recordOpenTelemetrySpan(event: GestureEvent): void {
85
- try {
86
- const span = trace.getTracer('@opentelemetry/instrumentation-user-interaction').startSpan(`Gesture.${event.type}`, {
87
- attributes: {
88
- 'gesture.type': event.type,
89
- 'gesture.timestamp': event.timestamp,
90
- 'gesture.platform': 'react-native',
91
- },
92
- })
93
-
94
- if (event.coordinates) {
95
- span.setAttribute('gesture.coordinates.x', event.coordinates.x)
96
- span.setAttribute('gesture.coordinates.y', event.coordinates.y)
97
-
98
- // Calculate relative position
99
- if (this.screenDimensions) {
100
- const relativeX = event.coordinates.x / this.screenDimensions.width
101
- const relativeY = event.coordinates.y / this.screenDimensions.height
102
- span.setAttribute('gesture.coordinates.relative_x', relativeX)
103
- span.setAttribute('gesture.coordinates.relative_y', relativeY)
104
- }
105
- }
106
-
107
- if (event.target) {
108
- span.setAttribute('gesture.target', event.target)
109
- }
110
-
111
- if (event.metadata) {
112
- Object.entries(event.metadata).forEach(([key, value]) => {
113
- span.setAttribute(`gesture.metadata.${key}`, String(value))
114
- })
115
- }
116
-
117
- span.setStatus({ code: SpanStatusCode.OK })
118
- span.end()
119
- } catch (error) {
120
- // Failed to record OpenTelemetry span for gesture - silently continue
121
- }
122
- }
123
-
124
- // Public methods for manual event recording
125
- recordTap(x: number, y: number, target?: string, pressure?: number): void {
126
- const event: GestureEvent = {
127
- type: 'tap',
128
- timestamp: Date.now(),
129
- coordinates: { x, y },
130
- target,
131
- metadata: {
132
- pressure: pressure || 1.0,
133
- screenWidth: this.screenDimensions?.width,
134
- screenHeight: this.screenDimensions?.height,
135
- },
136
- }
137
-
138
- this._recordEvent(event)
139
- }
140
-
141
- recordSwipe(direction: string, target?: string, velocity?: number, distance?: number): void {
142
- const event: GestureEvent = {
143
- type: 'swipe',
144
- timestamp: Date.now(),
145
- target,
146
- metadata: {
147
- direction,
148
- velocity: velocity || 0,
149
- distance: distance || 0,
150
- screenWidth: this.screenDimensions?.width,
151
- screenHeight: this.screenDimensions?.height,
152
- },
153
- }
154
-
155
- this._recordEvent(event)
156
- }
157
-
158
- recordPinch(scale: number, target?: string, velocity?: number): void {
159
- const event: GestureEvent = {
160
- type: 'pinch',
161
- timestamp: Date.now(),
162
- target,
163
- metadata: {
164
- scale,
165
- velocity: velocity || 0,
166
- screenWidth: this.screenDimensions?.width,
167
- screenHeight: this.screenDimensions?.height,
168
- },
169
- }
170
-
171
- this._recordEvent(event)
172
- }
173
-
174
- recordPan(deltaX: number, deltaY: number, target?: string, velocity?: number): void {
175
- const event: GestureEvent = {
176
- type: 'pan',
177
- timestamp: Date.now(),
178
- target,
179
- metadata: {
180
- deltaX,
181
- deltaY,
182
- velocity: velocity || 0,
183
- screenWidth: this.screenDimensions?.width,
184
- screenHeight: this.screenDimensions?.height,
185
- },
186
- }
187
-
188
- this._recordEvent(event)
189
- }
190
-
191
- recordLongPress(duration: number, target?: string, pressure?: number): void {
192
- const event: GestureEvent = {
193
- type: 'longPress',
194
- timestamp: Date.now(),
195
- target,
196
- metadata: {
197
- duration,
198
- pressure: pressure || 1.0,
199
- screenWidth: this.screenDimensions?.width,
200
- screenHeight: this.screenDimensions?.height,
201
- },
202
- }
203
-
204
- this._recordEvent(event)
205
- }
206
-
207
- recordDoubleTap(x: number, y: number, target?: string): void {
208
- const event: GestureEvent = {
209
- type: 'doubleTap',
210
- timestamp: Date.now(),
211
- coordinates: { x, y },
212
- target,
213
- metadata: {
214
- screenWidth: this.screenDimensions?.width,
215
- screenHeight: this.screenDimensions?.height,
216
- },
217
- }
218
-
219
- this._recordEvent(event)
220
- }
221
-
222
- recordRotate(rotation: number, target?: string, velocity?: number): void {
223
- const event: GestureEvent = {
224
- type: 'rotate',
225
- timestamp: Date.now(),
226
- target,
227
- metadata: {
228
- rotation,
229
- velocity: velocity || 0,
230
- screenWidth: this.screenDimensions?.width,
231
- screenHeight: this.screenDimensions?.height,
232
- },
233
- }
234
-
235
- this._recordEvent(event)
236
- }
237
-
238
- recordFling(direction: string, velocity: number, target?: string): void {
239
- const event: GestureEvent = {
240
- type: 'fling',
241
- timestamp: Date.now(),
242
- target,
243
- metadata: {
244
- direction,
245
- velocity,
246
- screenWidth: this.screenDimensions?.width,
247
- screenHeight: this.screenDimensions?.height,
248
- },
249
- }
250
-
251
- this._recordEvent(event)
252
- }
253
-
254
- // Advanced gesture tracking methods
255
- recordMultiTouch(touchCount: number, target?: string): void {
256
- const event: GestureEvent = {
257
- type: 'multiTouch',
258
- timestamp: Date.now(),
259
- target,
260
- metadata: {
261
- touchCount,
262
- screenWidth: this.screenDimensions?.width,
263
- screenHeight: this.screenDimensions?.height,
264
- },
265
- }
266
-
267
- this._recordEvent(event)
268
- }
269
-
270
- recordScroll(direction: string, distance: number, velocity: number, target?: string): void {
271
- const event: GestureEvent = {
272
- type: 'scroll',
273
- timestamp: Date.now(),
274
- target,
275
- metadata: {
276
- direction,
277
- distance,
278
- velocity,
279
- screenWidth: this.screenDimensions?.width,
280
- screenHeight: this.screenDimensions?.height,
281
- },
282
- }
283
-
284
- this._recordEvent(event)
285
- }
286
-
287
- recordZoom(scale: number, target?: string, velocity?: number): void {
288
- const event: GestureEvent = {
289
- type: 'zoom',
290
- timestamp: Date.now(),
291
- target,
292
- metadata: {
293
- scale,
294
- velocity: velocity || 0,
295
- screenWidth: this.screenDimensions?.width,
296
- screenHeight: this.screenDimensions?.height,
297
- },
298
- }
299
-
300
- this._recordEvent(event)
301
- }
302
-
303
- // Get recorded events
304
- getEvents(): GestureEvent[] {
305
- return [...this.events]
306
- }
307
-
308
- // Clear events
309
- clearEvents(): void {
310
- this.events = []
311
- }
312
-
313
- // Get event statistics
314
- getEventStats(): Record<string, number> {
315
- const stats: Record<string, number> = {}
316
- this.events.forEach(event => {
317
- stats[event.type] = (stats[event.type] || 0) + 1
318
- })
319
- return stats
320
- }
321
-
322
- // Set gesture throttle
323
- setGestureThrottle(throttleMs: number): void {
324
- this.gestureThrottleMs = throttleMs
325
- }
326
-
327
- // Get recording status
328
- isRecordingEnabled(): boolean {
329
- return this.isRecording
330
- }
331
-
332
- /**
333
- * Record an rrweb event
334
- * @param event - The rrweb event to record
335
- */
336
- recordEvent(event: any): void {
337
- if (this.eventRecorder) {
338
- this.eventRecorder.recordEvent(event)
339
- }
340
- }
341
-
342
- /**
343
- * Create and emit a rrweb MouseInteraction event for touch interactions
344
- * @param x - X coordinate
345
- * @param y - Y coordinate
346
- * @param interactionType - Type of interaction (TouchStart, TouchMove, TouchEnd, etc.)
347
- * @param target - Target element identifier
348
- */
349
- private _createMouseInteractionEvent(
350
- x: number,
351
- y: number,
352
- interactionType: MouseInteractions,
353
- target?: string,
354
- ): void {
355
- const incrementalSnapshotEvent: eventWithTime = {
356
- type: EventType.IncrementalSnapshot,
357
- data: {
358
- source: IncrementalSource.MouseInteraction,
359
- type: interactionType,
360
- id: this.imageNodeId, // Reference to the image node
361
- x: x, // Preserve decimal precision like web rrweb
362
- y: y, // Preserve decimal precision like web rrweb
363
- pointerType: 2, // 2 = Touch for React Native (0=Mouse, 1=Pen, 2=Touch)
364
- },
365
- timestamp: Date.now(),
366
- }
367
-
368
- this.recordEvent(incrementalSnapshotEvent)
369
- }
370
-
371
- /**
372
- * Create mouse move event with positions array (like web rrweb)
373
- * @param x - X coordinate
374
- * @param y - Y coordinate
375
- * @param target - Target element identifier
376
- */
377
- private _createMouseMoveEvent(x: number, y: number, target?: string): void {
378
- const incrementalSnapshotEvent: eventWithTime = {
379
- type: EventType.IncrementalSnapshot,
380
- data: {
381
- source: IncrementalSource.TouchMove, // Use MouseMove instead of MouseInteraction
382
- positions: [
383
- {
384
- x: x, // Preserve decimal precision like web rrweb
385
- y: y, // Preserve decimal precision like web rrweb
386
- id: this.imageNodeId, // Reference to the image node
387
- timeOffset: 0, // No time offset for single position
388
- },
389
- ],
390
- },
391
- timestamp: Date.now(),
392
- }
393
-
394
- this.recordEvent(incrementalSnapshotEvent)
395
- }
396
-
397
- /**
398
- * Record touch start event as rrweb MouseInteraction
399
- * @param x - X coordinate
400
- * @param y - Y coordinate
401
- * @param target - Target element identifier
402
- * @param pressure - Touch pressure (optional)
403
- */
404
- recordTouchStart(x: number, y: number, target?: string, pressure?: number): void {
405
- // Throttle touch events to prevent spam
406
- const now = Date.now()
407
- if (now - this.lastTouchTime < this.touchThrottleMs) {
408
- logger.debug('GestureRecorder', `Touch start throttled (${now - this.lastTouchTime}ms < ${this.touchThrottleMs}ms)`)
409
- return
410
- }
411
- this.lastTouchTime = now
412
-
413
- logger.debug('GestureRecorder', 'Touch start recorded', { x, y, target, pressure })
414
- // Record as MouseDown (type: 1) like web rrweb
415
- this._createMouseInteractionEvent(x, y, MouseInteractions.TouchStart, target)
416
- }
417
-
418
- /**
419
- * Record touch move event as rrweb MouseMove with positions array
420
- * @param x - X coordinate
421
- * @param y - Y coordinate
422
- * @param target - Target element identifier
423
- * @param pressure - Touch pressure (optional)
424
- */
425
- recordTouchMove(x: number, y: number, target?: string, pressure?: number): void {
426
- // Throttle touch move events more aggressively
427
- const now = Date.now()
428
- if (now - this.lastTouchTime < this.touchThrottleMs * 2) { // 200ms throttle for move events
429
- logger.debug('GestureRecorder', `Touch move throttled (${now - this.lastTouchTime}ms < ${this.touchThrottleMs * 2}ms)`)
430
- return
431
- }
432
- this.lastTouchTime = now
433
-
434
- logger.debug('GestureRecorder', 'Touch move recorded', { x, y, target, pressure })
435
- // Record as MouseMove with positions array (like web rrweb)
436
- this._createMouseMoveEvent(x, y, target)
437
- }
438
-
439
- /**
440
- * Record touch end event as rrweb MouseInteraction
441
- * @param x - X coordinate
442
- * @param y - Y coordinate
443
- * @param target - Target element identifier
444
- * @param pressure - Touch pressure (optional)
445
- */
446
- recordTouchEnd(x: number, y: number, target?: string, pressure?: number): void {
447
- // Cyclic call detection
448
- if (this.isRecordingGesture) {
449
- logger.error('GestureRecorder', 'CYCLIC CALL DETECTED! Already recording gesture', this.gestureCallStack)
450
- return
451
- }
452
-
453
- if (this.gestureCallStack.length >= this.maxGestureCallDepth) {
454
- logger.error('GestureRecorder', 'MAX GESTURE CALL DEPTH REACHED!', this.gestureCallStack)
455
- return
456
- }
457
-
458
- this.isRecordingGesture = true
459
- this.gestureCallStack.push('recordTouchEnd')
460
-
461
- try {
462
- logger.debug('GestureRecorder', 'Touch end recorded', { x, y, target, pressure })
463
- // Always record touch end (no throttling for completion)
464
- this.recordTap(x, y, target, pressure)
465
- // Record as MouseUp (type: 0) like web rrweb
466
- this._createMouseInteractionEvent(x, y, MouseInteractions.TouchEnd, target)
467
- // Also record Click (type: 2) like web rrweb
468
- // this._createMouseInteractionEvent(x, y, MouseInteractions.Click, target)
469
-
470
- // Only force screen capture on touch end (not on every touch event)
471
- logger.debug('GestureRecorder', 'Forcing screen capture after touch end')
472
- this.screenRecorder?.forceCapture()
473
- } finally {
474
- this.isRecordingGesture = false
475
- this.gestureCallStack.pop()
476
- }
477
- }
478
-
479
- /**
480
- * Record touch cancel event as rrweb MouseInteraction
481
- * @param x - X coordinate
482
- * @param y - Y coordinate
483
- * @param target - Target element identifier
484
- */
485
- recordTouchCancel(x: number, y: number, target?: string): void {
486
- // Record as MouseUp (type: 0) like web rrweb for touch cancel
487
- this._createMouseInteractionEvent(x, y, MouseInteractions.TouchCancel, target)
488
- }
489
-
490
- /**
491
- * Set the image node ID for touch interactions
492
- * This should be called when a new screen snapshot is created
493
- * @param nodeId - The ID of the image node in the current snapshot
494
- */
495
- setImageNodeId(nodeId: number): void {
496
- this.imageNodeId = nodeId
497
- }
498
- }
@@ -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
- }