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

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 (79) hide show
  1. package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.d.ts +6 -0
  2. package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.js +1 -0
  3. package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.js.map +1 -0
  4. package/dist/components/GestureCaptureWrapper/index.d.ts +1 -0
  5. package/dist/components/GestureCaptureWrapper/index.js +1 -0
  6. package/dist/components/GestureCaptureWrapper/index.js.map +1 -0
  7. package/dist/components/GestureCaptureWrapper.js +1 -1
  8. package/dist/components/GestureCaptureWrapper.js.map +1 -1
  9. package/dist/components/ScreenRecorderView/ScreenRecorderView.d.ts +5 -0
  10. package/dist/components/ScreenRecorderView/ScreenRecorderView.js +1 -0
  11. package/dist/components/ScreenRecorderView/ScreenRecorderView.js.map +1 -0
  12. package/dist/components/ScreenRecorderView/index.d.ts +1 -0
  13. package/dist/components/ScreenRecorderView/index.js +1 -0
  14. package/dist/components/ScreenRecorderView/index.js.map +1 -0
  15. package/dist/components/index.d.ts +1 -0
  16. package/dist/components/index.js +1 -0
  17. package/dist/components/index.js.map +1 -0
  18. package/dist/context/SessionRecorderContext.js +1 -1
  19. package/dist/context/SessionRecorderContext.js.map +1 -1
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.js +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/otel/index.d.ts +0 -2
  24. package/dist/otel/index.js.map +1 -1
  25. package/dist/otel/instrumentations/gestureInstrumentation.js +1 -1
  26. package/dist/otel/instrumentations/gestureInstrumentation.js.map +1 -1
  27. package/dist/otel/instrumentations/index.d.ts +0 -3
  28. package/dist/otel/instrumentations/index.js +1 -1
  29. package/dist/otel/instrumentations/index.js.map +1 -1
  30. package/dist/recorder/gestureRecorder.d.ts +0 -9
  31. package/dist/recorder/gestureRecorder.js +1 -1
  32. package/dist/recorder/gestureRecorder.js.map +1 -1
  33. package/dist/recorder/index.d.ts +4 -3
  34. package/dist/recorder/index.js.map +1 -1
  35. package/dist/recorder/screenRecorder.d.ts +1 -6
  36. package/dist/recorder/screenRecorder.js +1 -1
  37. package/dist/recorder/screenRecorder.js.map +1 -1
  38. package/dist/session-recorder.d.ts +3 -2
  39. package/dist/session-recorder.js.map +1 -1
  40. package/dist/types/index.d.ts +2 -16
  41. package/dist/types/index.js +1 -1
  42. package/dist/types/index.js.map +1 -1
  43. package/dist/utils/app-metadata.d.ts +16 -0
  44. package/dist/utils/app-metadata.js +1 -0
  45. package/dist/utils/app-metadata.js.map +1 -0
  46. package/dist/utils/platform.d.ts +35 -3
  47. package/dist/utils/platform.js +1 -1
  48. package/dist/utils/platform.js.map +1 -1
  49. package/dist/utils/rrweb-events.d.ts +1 -1
  50. package/dist/utils/rrweb-events.js +1 -1
  51. package/dist/utils/rrweb-events.js.map +1 -1
  52. package/dist/version.d.ts +1 -1
  53. package/dist/version.js +1 -1
  54. package/dist/version.js.map +1 -1
  55. package/docs/AUTO_METADATA_DETECTION.md +108 -0
  56. package/package.json +6 -9
  57. package/scripts/generate-app-metadata.js +173 -0
  58. package/src/components/{GestureCaptureWrapper.tsx → GestureCaptureWrapper/GestureCaptureWrapper.tsx} +1 -25
  59. package/src/components/GestureCaptureWrapper/index.ts +1 -0
  60. package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +72 -0
  61. package/src/components/ScreenRecorderView/index.ts +1 -0
  62. package/src/components/index.ts +1 -0
  63. package/src/context/SessionRecorderContext.tsx +21 -89
  64. package/src/index.ts +8 -0
  65. package/src/otel/index.ts +1 -12
  66. package/src/otel/instrumentations/index.ts +1 -6
  67. package/src/recorder/gestureRecorder.ts +10 -134
  68. package/src/recorder/index.ts +5 -4
  69. package/src/recorder/screenRecorder.ts +6 -14
  70. package/src/session-recorder.ts +2 -3
  71. package/src/types/index.ts +2 -20
  72. package/src/utils/app-metadata.ts +31 -0
  73. package/src/utils/platform.ts +303 -6
  74. package/src/utils/rrweb-events.ts +2 -4
  75. package/src/version.ts +1 -1
  76. package/src/otel/instrumentations/gestureInstrumentation.ts +0 -141
  77. package/src/otel/instrumentations/reactNativeInstrumentation.ts +0 -77
  78. package/src/otel/instrumentations/reactNavigationInstrumentation.ts +0 -119
  79. package/src/recorder/gestureHandlerRecorder.ts +0 -157
@@ -1,7 +1,8 @@
1
- import { GestureEvent, RecorderConfig, EventType, IncrementalSource, MouseInteractionType, EventRecorder, eventWithTime } from '../types'
1
+ import { GestureEvent, RecorderConfig, EventRecorder } from '../types'
2
2
  import { trace, SpanStatusCode } from '@opentelemetry/api'
3
3
  import { Dimensions } from 'react-native'
4
4
  import { logger } from '../utils'
5
+ import { MouseInteractions, eventWithTime, EventType, IncrementalSource } from '@rrweb/types'
5
6
 
6
7
  export class GestureRecorder implements EventRecorder {
7
8
  private config?: RecorderConfig
@@ -21,6 +22,7 @@ export class GestureRecorder implements EventRecorder {
21
22
  private eventRecorder?: EventRecorder
22
23
  private imageNodeId: number = 1 // ID of the image node for touch interactions
23
24
  private screenRecorder?: any // Reference to screen recorder for force capture
25
+
24
26
  init(config: RecorderConfig, eventRecorder?: EventRecorder, screenRecorder?: any): void {
25
27
  this.config = config
26
28
  this.eventRecorder = eventRecorder
@@ -32,8 +34,6 @@ export class GestureRecorder implements EventRecorder {
32
34
  logger.info('GestureRecorder', 'Gesture recording started')
33
35
  this.isRecording = true
34
36
  this.events = []
35
- this._setupGestureHandlers()
36
- this._setupAutomaticTouchCapture()
37
37
  // Gesture recording started
38
38
  }
39
39
 
@@ -43,15 +43,6 @@ export class GestureRecorder implements EventRecorder {
43
43
  // Gesture recording stopped
44
44
  }
45
45
 
46
- pause(): void {
47
- this.isRecording = false
48
- }
49
-
50
- resume(): void {
51
- this.isRecording = true
52
- }
53
-
54
- // Input component registration temporarily disabled
55
46
 
56
47
  private _getScreenDimensions(): void {
57
48
  try {
@@ -62,48 +53,6 @@ export class GestureRecorder implements EventRecorder {
62
53
  }
63
54
  }
64
55
 
65
- private _setupInputTracking(): void {
66
- // Set up React Native input component tracking
67
- try {
68
- // This would integrate with React Native's component tracking
69
- // For now, we'll provide methods for manual registration
70
- // Input tracking setup complete
71
- } catch (error) {
72
- // Failed to setup input tracking - silently continue
73
- }
74
- }
75
-
76
- private _setupGestureHandlers(): void {
77
- // This would integrate with react-native-gesture-handler
78
- // For now, we'll create a comprehensive implementation that can be easily integrated
79
- // Setting up gesture handlers
80
-
81
- // Set up global gesture listener
82
- this._setupGlobalGestureListener()
83
- }
84
-
85
- private _setupGlobalGestureListener(): void {
86
- try {
87
- // Listen for touch events at the app level
88
- // This is a simplified implementation - in production you'd use react-native-gesture-handler
89
- // Global gesture listener setup complete
90
- } catch (error) {
91
- // Failed to setup global gesture listener - silently continue
92
- }
93
- }
94
-
95
- private _setupAutomaticTouchCapture(): void {
96
- try {
97
- // This method sets up automatic touch capture
98
- // The actual touch capture is handled by the TouchEventCapture component
99
- // in the SessionRecorderContext, which automatically calls our recording methods
100
-
101
- // We can add any additional setup here if needed
102
- // For now, the TouchEventCapture component handles everything automatically
103
- } catch (error) {
104
- // Failed to setup automatic touch capture - silently continue
105
- }
106
- }
107
56
 
108
57
  private _removeGestureHandlers(): void {
109
58
  this.gestureHandlers.clear()
@@ -134,7 +83,7 @@ export class GestureRecorder implements EventRecorder {
134
83
 
135
84
  private _recordOpenTelemetrySpan(event: GestureEvent): void {
136
85
  try {
137
- const span = trace.getTracer('gesture').startSpan(`Gesture.${event.type}`, {
86
+ const span = trace.getTracer('@opentelemetry/instrumentation-user-interaction').startSpan(`Gesture.${event.type}`, {
138
87
  attributes: {
139
88
  'gesture.type': event.type,
140
89
  'gesture.timestamp': event.timestamp,
@@ -351,79 +300,6 @@ export class GestureRecorder implements EventRecorder {
351
300
  this._recordEvent(event)
352
301
  }
353
302
 
354
- // Gesture sequence tracking
355
- recordGestureSequence(gestures: string[], duration: number, target?: string): void {
356
- const event: GestureEvent = {
357
- type: 'gestureSequence',
358
- timestamp: Date.now(),
359
- target,
360
- metadata: {
361
- gestures: gestures.join(','),
362
- duration,
363
- gestureCount: gestures.length,
364
- screenWidth: this.screenDimensions?.width,
365
- screenHeight: this.screenDimensions?.height,
366
- },
367
- }
368
-
369
- this._recordEvent(event)
370
- }
371
-
372
- // Error tracking for gesture failures
373
- recordGestureError(error: Error, gestureType: string, target?: string): void {
374
- const event: GestureEvent = {
375
- type: 'gestureError',
376
- timestamp: Date.now(),
377
- target,
378
- metadata: {
379
- errorType: error.name,
380
- errorMessage: error.message,
381
- gestureType,
382
- screenWidth: this.screenDimensions?.width,
383
- screenHeight: this.screenDimensions?.height,
384
- },
385
- }
386
-
387
- this._recordEvent(event)
388
-
389
- // Also record as OpenTelemetry error span
390
- try {
391
- const span = trace.getTracer('gesture').startSpan(`Gesture.${gestureType}.error`, {
392
- attributes: {
393
- 'gesture.type': gestureType,
394
- 'gesture.error': true,
395
- 'gesture.error.type': error.name,
396
- 'gesture.error.message': error.message,
397
- 'gesture.timestamp': Date.now(),
398
- },
399
- })
400
-
401
- span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
402
- span.recordException(error)
403
- span.end()
404
- } catch (spanError) {
405
- // Failed to record error span - silently continue
406
- }
407
- }
408
-
409
- // Performance monitoring
410
- recordGesturePerformance(gestureType: string, duration: number, target?: string): void {
411
- const event: GestureEvent = {
412
- type: 'gesturePerformance',
413
- timestamp: Date.now(),
414
- target,
415
- metadata: {
416
- gestureType,
417
- duration,
418
- performance: 'monitoring',
419
- screenWidth: this.screenDimensions?.width,
420
- screenHeight: this.screenDimensions?.height,
421
- },
422
- }
423
-
424
- this._recordEvent(event)
425
- }
426
-
427
303
  // Get recorded events
428
304
  getEvents(): GestureEvent[] {
429
305
  return [...this.events]
@@ -473,7 +349,7 @@ export class GestureRecorder implements EventRecorder {
473
349
  private _createMouseInteractionEvent(
474
350
  x: number,
475
351
  y: number,
476
- interactionType: MouseInteractionType,
352
+ interactionType: MouseInteractions,
477
353
  target?: string,
478
354
  ): void {
479
355
  const incrementalSnapshotEvent: eventWithTime = {
@@ -502,7 +378,7 @@ export class GestureRecorder implements EventRecorder {
502
378
  const incrementalSnapshotEvent: eventWithTime = {
503
379
  type: EventType.IncrementalSnapshot,
504
380
  data: {
505
- source: IncrementalSource.MouseMove, // Use MouseMove instead of MouseInteraction
381
+ source: IncrementalSource.TouchMove, // Use MouseMove instead of MouseInteraction
506
382
  positions: [
507
383
  {
508
384
  x: x, // Preserve decimal precision like web rrweb
@@ -536,7 +412,7 @@ export class GestureRecorder implements EventRecorder {
536
412
 
537
413
  logger.debug('GestureRecorder', 'Touch start recorded', { x, y, target, pressure })
538
414
  // Record as MouseDown (type: 1) like web rrweb
539
- this._createMouseInteractionEvent(x, y, MouseInteractionType.MouseDown, target)
415
+ this._createMouseInteractionEvent(x, y, MouseInteractions.TouchStart, target)
540
416
  }
541
417
 
542
418
  /**
@@ -587,9 +463,9 @@ export class GestureRecorder implements EventRecorder {
587
463
  // Always record touch end (no throttling for completion)
588
464
  this.recordTap(x, y, target, pressure)
589
465
  // Record as MouseUp (type: 0) like web rrweb
590
- this._createMouseInteractionEvent(x, y, MouseInteractionType.MouseUp, target)
466
+ this._createMouseInteractionEvent(x, y, MouseInteractions.TouchEnd, target)
591
467
  // Also record Click (type: 2) like web rrweb
592
- this._createMouseInteractionEvent(x, y, MouseInteractionType.Click, target)
468
+ // this._createMouseInteractionEvent(x, y, MouseInteractions.Click, target)
593
469
 
594
470
  // Only force screen capture on touch end (not on every touch event)
595
471
  logger.debug('GestureRecorder', 'Forcing screen capture after touch end')
@@ -608,7 +484,7 @@ export class GestureRecorder implements EventRecorder {
608
484
  */
609
485
  recordTouchCancel(x: number, y: number, target?: string): void {
610
486
  // Record as MouseUp (type: 0) like web rrweb for touch cancel
611
- this._createMouseInteractionEvent(x, y, MouseInteractionType.MouseUp, target)
487
+ this._createMouseInteractionEvent(x, y, MouseInteractions.TouchCancel, target)
612
488
  }
613
489
 
614
490
  /**
@@ -5,14 +5,15 @@ import { logger } from '../utils'
5
5
  import { ScreenRecorder } from './screenRecorder'
6
6
  import { GestureRecorder } from './gestureRecorder'
7
7
  import { NavigationTracker } from './navigationTracker'
8
- import { RecorderConfig, EventRecorder, RRWebEvent } from '../types'
8
+ import { RecorderConfig, EventRecorder } from '../types'
9
+ import { eventWithTime } from '@rrweb/types'
9
10
  export class RecorderReactNativeSDK implements EventRecorder {
10
11
  private isRecording = false
11
12
  private config?: RecorderConfig
12
13
  private screenRecorder: ScreenRecorder
13
14
  private gestureRecorder: GestureRecorder
14
15
  private navigationTracker: NavigationTracker
15
- private recordedEvents: RRWebEvent[] = []
16
+ private recordedEvents: eventWithTime[] = []
16
17
  private exporter: EventExporter | undefined
17
18
  private sessionId: string | null = null
18
19
  private sessionType: SessionType = SessionType.PLAIN
@@ -86,7 +87,7 @@ export class RecorderReactNativeSDK implements EventRecorder {
86
87
  * Record an rrweb event
87
88
  * @param event - The rrweb event to record
88
89
  */
89
- recordEvent(event: RRWebEvent): void {
90
+ recordEvent(event: eventWithTime): void {
90
91
  if (!this.isRecording) {
91
92
  return
92
93
  }
@@ -154,7 +155,7 @@ export class RecorderReactNativeSDK implements EventRecorder {
154
155
  * Get all recorded events
155
156
  * @returns Array of recorded rrweb events
156
157
  */
157
- getRecordedEvents(): RRWebEvent[] {
158
+ getRecordedEvents(): eventWithTime[] {
158
159
  return [...this.recordedEvents]
159
160
  }
160
161
 
@@ -112,7 +112,7 @@ export class ScreenRecorder implements EventRecorder {
112
112
 
113
113
  if (hasChanged) {
114
114
  // Use incremental snapshot if we have an existing image node, otherwise create full snapshot
115
- if (this.currentImageNodeId && this.lastScreenCapture) {
115
+ if (this.currentImageNodeId !== null && this.lastScreenCapture) {
116
116
  const success = this.updateScreenWithIncrementalSnapshot(base64Image)
117
117
  if (!success) {
118
118
  // Fallback to full snapshot if incremental update fails
@@ -149,7 +149,7 @@ export class ScreenRecorder implements EventRecorder {
149
149
 
150
150
  return result
151
151
  } catch (error) {
152
- logger.error('ScreenRecorder', 'Failed to capture screen', error)
152
+ logger.error('ScreenRecorder', 'Failed to capture screen. Make sure react-native-view-shot is properly installed and linked:', error)
153
153
  return null
154
154
  }
155
155
  }
@@ -186,7 +186,7 @@ export class ScreenRecorder implements EventRecorder {
186
186
 
187
187
  // Store the image node ID for future incremental updates
188
188
  // The image node ID is the first node created (after the document)
189
- this.currentImageNodeId = 2 // First element node is the image
189
+ this.currentImageNodeId = 0 // First element node is the image
190
190
 
191
191
  return fullSnapshotEvent
192
192
  }
@@ -197,21 +197,13 @@ export class ScreenRecorder implements EventRecorder {
197
197
  * @param imageNodeId - ID of the image node to update
198
198
  * @returns Incremental snapshot event with mutation data
199
199
  */
200
- createIncrementalSnapshotWithImageUpdate(base64Image: string, imageNodeId: number): eventWithTime {
200
+ createIncrementalSnapshotWithImageUpdate(base64Image: string): eventWithTime {
201
201
  return createIncrementalSnapshotUtil(
202
202
  base64Image,
203
- imageNodeId,
204
203
  this.captureFormat,
205
204
  )
206
205
  }
207
206
 
208
- /**
209
- * Get the current image node ID
210
- * @returns The current image node ID or null if not set
211
- */
212
- getCurrentImageNodeId(): number | null {
213
- return this.currentImageNodeId
214
- }
215
207
 
216
208
  /**
217
209
  * Update the screen with a new image using incremental snapshot
@@ -219,12 +211,12 @@ export class ScreenRecorder implements EventRecorder {
219
211
  * @returns true if update was successful, false otherwise
220
212
  */
221
213
  updateScreenWithIncrementalSnapshot(base64Image: string): boolean {
222
- if (!this.currentImageNodeId) {
214
+ if (this.currentImageNodeId === null) {
223
215
  logger.warn('ScreenRecorder', 'No image node ID available for incremental update')
224
216
  return false
225
217
  }
226
218
 
227
- const incrementalEvent = this.createIncrementalSnapshotWithImageUpdate(base64Image, this.currentImageNodeId)
219
+ const incrementalEvent = this.createIncrementalSnapshotWithImageUpdate(base64Image)
228
220
  this.recordEvent(incrementalEvent)
229
221
  return true
230
222
  }
@@ -12,7 +12,6 @@ import {
12
12
  ISessionRecorder,
13
13
  SessionRecorderConfigs,
14
14
  SessionRecorderOptions,
15
- RRWebEvent,
16
15
  EventRecorder
17
16
  } from './types'
18
17
  import { getFormattedDate, isSessionActive, getNavigatorInfo } from './utils'
@@ -21,6 +20,7 @@ import { DEFAULT_MAX_HTTP_CAPTURING_PAYLOAD_SIZE, getSessionRecorderConfig } fro
21
20
 
22
21
  import { StorageService } from './services/storage.service'
23
22
  import { ApiService, StartSessionRequest, StopSessionRequest } from './services/api.service'
23
+ import { eventWithTime } from '@rrweb/types'
24
24
 
25
25
  // Utility functions for React Native
26
26
 
@@ -161,7 +161,6 @@ class SessionRecorder extends Observable<SessionRecorderEvents> implements ISess
161
161
  try {
162
162
  this._apiService.init(this._configs)
163
163
  this._tracer.init(this._configs)
164
-
165
164
  } catch (error) {
166
165
  logger.error('SessionRecorder', 'Failed to initialize API service', error)
167
166
  }
@@ -527,7 +526,7 @@ class SessionRecorder extends Observable<SessionRecorderEvents> implements ISess
527
526
  * Note: Screen capture and touch events are recorded automatically when session is started
528
527
  * @param event - The rrweb event to record
529
528
  */
530
- recordEvent(event: RRWebEvent): void {
529
+ recordEvent(event: eventWithTime): void {
531
530
  if (!this._isInitialized || this.sessionState !== SessionState.started) {
532
531
  return
533
532
  }
@@ -1,23 +1,9 @@
1
1
  export * from './session-recorder'
2
2
  export * from './session'
3
3
 
4
- // Re-export rrweb types for convenience
5
- export { EventType, IncrementalSource, MouseInteractions as MouseInteractionType } from 'rrweb'
6
- export type { eventWithTime, serializedNodeWithId, mouseInteractionData, metaEvent } from '@rrweb/types'
7
-
8
4
  // Import types for use in this file
9
- import type { MouseInteractions } from 'rrweb'
10
- import type { eventWithTime, mouseInteractionData, metaEvent } from '@rrweb/types'
5
+ import type { eventWithTime } from '@rrweb/types'
11
6
 
12
- // React Native specific types
13
- export interface TouchInteractionData {
14
- type: MouseInteractions
15
- id: number
16
- x: number
17
- y: number
18
- pressure?: number
19
- target?: string
20
- }
21
7
 
22
8
  export interface ReactNativeScreenData {
23
9
  width: number
@@ -35,12 +21,8 @@ export interface ReactNativeTouchData {
35
21
  timestamp: number
36
22
  }
37
23
 
38
- // Type aliases for convenience
39
- export type RRWebEvent = eventWithTime
40
- export type MouseInteractionData = mouseInteractionData
41
- export type MetaEvent = metaEvent
42
24
 
43
25
  // Event recording interface
44
26
  export interface EventRecorder {
45
- recordEvent(event: RRWebEvent): void
27
+ recordEvent(event: eventWithTime): void
46
28
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Auto-generated app metadata
3
+ * This file is generated at build time to provide app metadata without developer intervention
4
+ */
5
+
6
+ // This file is automatically generated by the build process
7
+ // It extracts metadata from app.json, app.config.js, or package.json
8
+
9
+ export interface AppMetadata {
10
+ name?: string
11
+ version?: string
12
+ bundleId?: string
13
+ buildNumber?: string
14
+ displayName?: string
15
+ }
16
+
17
+ // Auto-detected values from project configuration files
18
+ export const APP_METADATA: AppMetadata = {
19
+ name: "@multiplayer-app/session-recorder-react-native",
20
+ version: "0.0.1",
21
+ bundleId: undefined,
22
+ buildNumber: undefined,
23
+ displayName: undefined,
24
+ }
25
+
26
+ /**
27
+ * Get auto-detected app metadata
28
+ */
29
+ export function getAutoDetectedAppMetadata(): AppMetadata {
30
+ return { ...APP_METADATA }
31
+ }