@multiplayer-app/session-recorder-react-native 1.0.1-beta.4 → 1.0.1-beta.5

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 (165) hide show
  1. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModule.kt +2 -2
  2. package/lib/module/components/SessionRecorderWidget/ErrorBanner.js.map +1 -1
  3. package/lib/module/components/SessionRecorderWidget/ModalHeader.js.map +1 -1
  4. package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -1
  5. package/lib/module/components/SessionRecorderWidget/icons.js.map +1 -1
  6. package/lib/module/components/SessionRecorderWidget/styles.js.map +1 -1
  7. package/lib/module/config/constants.js.map +1 -1
  8. package/lib/module/config/defaults.js.map +1 -1
  9. package/lib/module/config/masking.js.map +1 -1
  10. package/lib/module/config/session-recorder.js.map +1 -1
  11. package/lib/module/config/validators.js.map +1 -1
  12. package/lib/module/config/widget.js.map +1 -1
  13. package/lib/module/context/SessionRecorderStore.js.map +1 -1
  14. package/lib/module/context/useSessionRecorderStore.js.map +1 -1
  15. package/lib/module/context/useStoreSelector.js.map +1 -1
  16. package/lib/module/native/SessionRecorderNative.js.map +1 -1
  17. package/lib/module/native/index.js.map +1 -1
  18. package/lib/module/otel/helpers.js +1 -1
  19. package/lib/module/otel/helpers.js.map +1 -1
  20. package/lib/module/otel/index.js.map +1 -1
  21. package/lib/module/otel/instrumentations/index.js.map +1 -1
  22. package/lib/module/patch/xhr.js.map +1 -1
  23. package/lib/module/recorder/eventExporter.js.map +1 -1
  24. package/lib/module/recorder/gestureRecorder.js.map +1 -1
  25. package/lib/module/recorder/index.js.map +1 -1
  26. package/lib/module/recorder/navigationTracker.js.map +1 -1
  27. package/lib/module/recorder/screenRecorder.js.map +1 -1
  28. package/lib/module/services/api.service.js.map +1 -1
  29. package/lib/module/services/network.service.js.map +1 -1
  30. package/lib/module/services/screenMaskingService.js.map +1 -1
  31. package/lib/module/services/storage.service.js.map +1 -1
  32. package/lib/module/session-recorder.js.map +1 -1
  33. package/lib/module/types/index.js.map +1 -1
  34. package/lib/module/types/session-recorder.js.map +1 -1
  35. package/lib/module/utils/app-metadata.js +2 -2
  36. package/lib/module/utils/constants.optional.js.map +1 -1
  37. package/lib/module/utils/createStore.js.map +1 -1
  38. package/lib/module/utils/logger.js +0 -8
  39. package/lib/module/utils/logger.js.map +1 -1
  40. package/lib/module/utils/platform.js +1 -1
  41. package/lib/module/utils/platform.js.map +1 -1
  42. package/lib/module/utils/rrweb-events.js.map +1 -1
  43. package/lib/module/utils/session.js.map +1 -1
  44. package/lib/module/utils/shallowEqual.js.map +1 -1
  45. package/lib/module/utils/time.js.map +1 -1
  46. package/lib/module/version.js +1 -1
  47. package/lib/typescript/src/components/ScreenRecorderView/index.d.ts +1 -1
  48. package/lib/typescript/src/components/SessionRecorderWidget/ErrorBanner.d.ts.map +1 -1
  49. package/lib/typescript/src/components/SessionRecorderWidget/ModalHeader.d.ts.map +1 -1
  50. package/lib/typescript/src/components/SessionRecorderWidget/SessionRecorderWidget.d.ts.map +1 -1
  51. package/lib/typescript/src/components/SessionRecorderWidget/icons.d.ts.map +1 -1
  52. package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts +1 -1
  53. package/lib/typescript/src/components/SessionRecorderWidget/styles.d.ts.map +1 -1
  54. package/lib/typescript/src/components/index.d.ts.map +1 -1
  55. package/lib/typescript/src/config/constants.d.ts.map +1 -1
  56. package/lib/typescript/src/config/defaults.d.ts.map +1 -1
  57. package/lib/typescript/src/config/index.d.ts.map +1 -1
  58. package/lib/typescript/src/config/masking.d.ts.map +1 -1
  59. package/lib/typescript/src/config/session-recorder.d.ts.map +1 -1
  60. package/lib/typescript/src/config/validators.d.ts.map +1 -1
  61. package/lib/typescript/src/config/widget.d.ts +1 -1
  62. package/lib/typescript/src/config/widget.d.ts.map +1 -1
  63. package/lib/typescript/src/context/SessionRecorderStore.d.ts.map +1 -1
  64. package/lib/typescript/src/context/useSessionRecorderStore.d.ts +3 -3
  65. package/lib/typescript/src/context/useSessionRecorderStore.d.ts.map +1 -1
  66. package/lib/typescript/src/context/useStoreSelector.d.ts.map +1 -1
  67. package/lib/typescript/src/index.d.ts.map +1 -1
  68. package/lib/typescript/src/native/SessionRecorderNative.d.ts.map +1 -1
  69. package/lib/typescript/src/native/index.d.ts +1 -1
  70. package/lib/typescript/src/native/index.d.ts.map +1 -1
  71. package/lib/typescript/src/otel/helpers.d.ts.map +1 -1
  72. package/lib/typescript/src/otel/index.d.ts.map +1 -1
  73. package/lib/typescript/src/otel/instrumentations/index.d.ts.map +1 -1
  74. package/lib/typescript/src/patch/index.d.ts.map +1 -1
  75. package/lib/typescript/src/patch/xhr.d.ts.map +1 -1
  76. package/lib/typescript/src/recorder/eventExporter.d.ts.map +1 -1
  77. package/lib/typescript/src/recorder/gestureRecorder.d.ts.map +1 -1
  78. package/lib/typescript/src/recorder/index.d.ts.map +1 -1
  79. package/lib/typescript/src/recorder/navigationTracker.d.ts.map +1 -1
  80. package/lib/typescript/src/recorder/screenRecorder.d.ts.map +1 -1
  81. package/lib/typescript/src/services/api.service.d.ts.map +1 -1
  82. package/lib/typescript/src/services/network.service.d.ts.map +1 -1
  83. package/lib/typescript/src/services/screenMaskingService.d.ts.map +1 -1
  84. package/lib/typescript/src/services/storage.service.d.ts.map +1 -1
  85. package/lib/typescript/src/session-recorder.d.ts.map +1 -1
  86. package/lib/typescript/src/types/configs.d.ts.map +1 -1
  87. package/lib/typescript/src/types/index.d.ts.map +1 -1
  88. package/lib/typescript/src/types/session-recorder.d.ts +4 -4
  89. package/lib/typescript/src/types/session-recorder.d.ts.map +1 -1
  90. package/lib/typescript/src/types/session.d.ts.map +1 -1
  91. package/lib/typescript/src/utils/app-metadata.d.ts.map +1 -1
  92. package/lib/typescript/src/utils/constants.optional.d.ts.map +1 -1
  93. package/lib/typescript/src/utils/constants.optional.expo.d.ts.map +1 -1
  94. package/lib/typescript/src/utils/createStore.d.ts.map +1 -1
  95. package/lib/typescript/src/utils/index.d.ts.map +1 -1
  96. package/lib/typescript/src/utils/logger.d.ts +1 -1
  97. package/lib/typescript/src/utils/logger.d.ts.map +1 -1
  98. package/lib/typescript/src/utils/platform.d.ts.map +1 -1
  99. package/lib/typescript/src/utils/request-utils.d.ts.map +1 -1
  100. package/lib/typescript/src/utils/rrweb-events.d.ts.map +1 -1
  101. package/lib/typescript/src/utils/session.d.ts.map +1 -1
  102. package/lib/typescript/src/utils/shallowEqual.d.ts.map +1 -1
  103. package/lib/typescript/src/utils/time.d.ts.map +1 -1
  104. package/lib/typescript/src/utils/type-utils.d.ts.map +1 -1
  105. package/lib/typescript/src/version.d.ts.map +1 -1
  106. package/package.json +1 -1
  107. package/src/components/ScreenRecorderView/index.ts +1 -1
  108. package/src/components/SessionRecorderWidget/ErrorBanner.tsx +14 -14
  109. package/src/components/SessionRecorderWidget/ModalHeader.tsx +11 -9
  110. package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +70 -56
  111. package/src/components/SessionRecorderWidget/icons.tsx +58 -30
  112. package/src/components/SessionRecorderWidget/index.ts +1 -1
  113. package/src/components/SessionRecorderWidget/styles.ts +17 -18
  114. package/src/components/index.ts +2 -2
  115. package/src/config/constants.ts +19 -20
  116. package/src/config/defaults.ts +35 -31
  117. package/src/config/index.ts +5 -5
  118. package/src/config/masking.ts +44 -18
  119. package/src/config/session-recorder.ts +54 -26
  120. package/src/config/validators.ts +43 -20
  121. package/src/config/widget.ts +24 -15
  122. package/src/context/SessionRecorderStore.ts +19 -18
  123. package/src/context/useSessionRecorderStore.ts +17 -10
  124. package/src/context/useStoreSelector.ts +20 -18
  125. package/src/index.ts +7 -7
  126. package/src/native/SessionRecorderNative.ts +83 -67
  127. package/src/native/index.ts +5 -1
  128. package/src/otel/helpers.ts +109 -93
  129. package/src/otel/index.ts +46 -49
  130. package/src/otel/instrumentations/index.ts +44 -41
  131. package/src/patch/index.ts +1 -1
  132. package/src/patch/xhr.ts +77 -78
  133. package/src/recorder/eventExporter.ts +63 -68
  134. package/src/recorder/gestureRecorder.ts +359 -212
  135. package/src/recorder/index.ts +75 -62
  136. package/src/recorder/navigationTracker.ts +120 -97
  137. package/src/recorder/screenRecorder.ts +214 -163
  138. package/src/services/api.service.ts +49 -48
  139. package/src/services/network.service.ts +67 -58
  140. package/src/services/screenMaskingService.ts +81 -50
  141. package/src/services/storage.service.ts +99 -70
  142. package/src/session-recorder.ts +270 -214
  143. package/src/types/configs.ts +53 -31
  144. package/src/types/expo-constants.d.ts +2 -2
  145. package/src/types/index.ts +16 -18
  146. package/src/types/session-recorder.ts +106 -111
  147. package/src/types/session.ts +45 -45
  148. package/src/utils/app-metadata.ts +9 -9
  149. package/src/utils/constants.optional.expo.ts +3 -3
  150. package/src/utils/constants.optional.ts +14 -12
  151. package/src/utils/createStore.ts +23 -20
  152. package/src/utils/index.ts +7 -7
  153. package/src/utils/logger.ts +87 -58
  154. package/src/utils/platform.ts +149 -118
  155. package/src/utils/request-utils.ts +15 -15
  156. package/src/utils/rrweb-events.ts +47 -34
  157. package/src/utils/session.ts +15 -12
  158. package/src/utils/shallowEqual.ts +16 -10
  159. package/src/utils/time.ts +7 -4
  160. package/src/utils/type-utils.ts +36 -36
  161. package/src/version.ts +1 -1
  162. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModuleSpec.kt +0 -51
  163. package/android/src/main/java/com/xxx/XxxModule.kt +0 -23
  164. package/ios/Xxx.h +0 -5
  165. package/ios/Xxx.mm +0 -21
@@ -1,148 +1,159 @@
1
- import { type ScreenEvent, type RecorderConfig, type EventRecorder } from '../types'
2
- import { type eventWithTime } from '@rrweb/types'
3
- import { trace, SpanStatusCode } from '@opentelemetry/api'
4
- import { Dimensions, Platform } from 'react-native'
1
+ import {
2
+ type ScreenEvent,
3
+ type RecorderConfig,
4
+ type EventRecorder,
5
+ } from '../types';
6
+ import { type eventWithTime } from '@rrweb/types';
7
+ import { trace, SpanStatusCode } from '@opentelemetry/api';
8
+ import { Dimensions, Platform } from 'react-native';
5
9
  import {
6
10
  createRecordingMetaEvent,
7
11
  createFullSnapshotEvent,
8
12
  createIncrementalSnapshotWithImageUpdate as createIncrementalSnapshotUtil,
9
13
  generateScreenHash,
10
14
  logger,
11
- } from '../utils'
12
- import { screenMaskingService, type ScreenMaskingConfig } from '../services/screenMaskingService'
13
- import { captureRef } from 'react-native-view-shot'
14
- const isWeb = Platform.OS === 'web'
15
-
15
+ } from '../utils';
16
+ import {
17
+ screenMaskingService,
18
+ type ScreenMaskingConfig,
19
+ } from '../services/screenMaskingService';
20
+ import { captureRef } from 'react-native-view-shot';
21
+ const isWeb = Platform.OS === 'web';
16
22
 
17
23
  export class ScreenRecorder implements EventRecorder {
18
- private config?: RecorderConfig
19
- private isRecording = false
20
- private events: ScreenEvent[] = []
21
- private captureInterval?: NodeJS.Timeout
22
- private captureCount: number = 0
23
- private maxCaptures: number = 100 // Limit captures to prevent memory issues
24
- private captureQuality: number = 0.2
25
- private captureScale: number = 0.66
26
- private captureFormat: 'png' | 'jpg' = 'jpg'
27
- private screenDimensions: { width: number; height: number } | null = null
28
- private eventRecorder?: EventRecorder
29
- private nodeIdCounter: number = 1
30
- private viewShotRef: any = null
31
- private lastScreenCapture: string | null = null
32
- private lastScreenHash: string | null = null
33
- private enableChangeDetection: boolean = true
34
- private hashSampleSize: number = 100
35
- private currentImageNodeId: number | null = null
36
- private maskingConfig?: ScreenMaskingConfig
24
+ private config?: RecorderConfig;
25
+ private isRecording = false;
26
+ private events: ScreenEvent[] = [];
27
+ private captureInterval?: any;
28
+ private captureCount: number = 0;
29
+ private maxCaptures: number = 100; // Limit captures to prevent memory issues
30
+ private captureQuality: number = 0.2;
31
+ private captureScale: number = 0.66;
32
+ private captureFormat: 'png' | 'jpg' = 'jpg';
33
+ private screenDimensions: { width: number; height: number } | null = null;
34
+ private eventRecorder?: EventRecorder;
35
+ private nodeIdCounter: number = 1;
36
+ private viewShotRef: any = null;
37
+ private lastScreenCapture: string | null = null;
38
+ private lastScreenHash: string | null = null;
39
+ private enableChangeDetection: boolean = true;
40
+ private hashSampleSize: number = 100;
41
+ private currentImageNodeId: number | null = null;
42
+ private maskingConfig?: ScreenMaskingConfig;
37
43
 
38
44
  init(config: RecorderConfig, eventRecorder?: EventRecorder): void {
39
- this.config = config
40
- this.eventRecorder = eventRecorder
41
- this._getScreenDimensions()
45
+ this.config = config;
46
+ this.eventRecorder = eventRecorder;
47
+ this._getScreenDimensions();
42
48
 
43
49
  // Initialize masking configuration
44
50
  this.maskingConfig = {
45
51
  enabled: true,
46
52
  ...this.config.masking,
47
- }
53
+ };
48
54
 
49
55
  // Update the masking service configuration
50
- screenMaskingService.updateConfig(this.maskingConfig)
56
+ screenMaskingService.updateConfig(this.maskingConfig);
51
57
  }
52
58
 
53
59
  start(): void {
54
- this.isRecording = true
55
- this.events = []
56
- this.captureCount = 0
57
- this.lastScreenCapture = null
58
- this.lastScreenHash = null
59
- this.currentImageNodeId = null // Reset image node ID for new session
60
- logger.info('ScreenRecorder', 'Screen recording started')
60
+ this.isRecording = true;
61
+ this.events = [];
62
+ this.captureCount = 0;
63
+ this.lastScreenCapture = null;
64
+ this.lastScreenHash = null;
65
+ this.currentImageNodeId = null; // Reset image node ID for new session
66
+ logger.info('ScreenRecorder', 'Screen recording started');
61
67
  // Emit screen recording started meta event
62
68
 
63
- this.recordEvent(createRecordingMetaEvent())
69
+ this.recordEvent(createRecordingMetaEvent());
64
70
 
65
- this._startPeriodicCapture()
71
+ this._startPeriodicCapture();
66
72
 
67
73
  // Capture initial screen immediately
68
- this._captureScreen()
74
+ this._captureScreen();
69
75
 
70
76
  // Screen recording started
71
77
  }
72
78
 
73
79
  stop(): void {
74
- this.isRecording = false
75
- this._stopPeriodicCapture()
80
+ this.isRecording = false;
81
+ this._stopPeriodicCapture();
76
82
  // Screen recording stopped
77
83
  }
78
84
 
79
85
  pause(): void {
80
- this.isRecording = false
81
- this._stopPeriodicCapture()
86
+ this.isRecording = false;
87
+ this._stopPeriodicCapture();
82
88
  }
83
89
 
84
90
  resume(): void {
85
- this.isRecording = true
91
+ this.isRecording = true;
86
92
  // this._startPeriodicCapture()
87
93
  }
88
94
 
89
95
  private _getScreenDimensions(): void {
90
96
  try {
91
- this.screenDimensions = Dimensions.get('window')
97
+ this.screenDimensions = Dimensions.get('window');
92
98
  } catch (error) {
93
99
  // Failed to get screen dimensions - silently continue
94
- this.screenDimensions = { width: 375, height: 667 } // Default fallback
100
+ this.screenDimensions = { width: 375, height: 667 }; // Default fallback
95
101
  }
96
102
  }
97
103
 
98
104
  private _startPeriodicCapture(): void {
99
105
  if (this.captureInterval) {
100
- clearInterval(this.captureInterval)
106
+ clearInterval(this.captureInterval);
101
107
  }
102
108
 
103
109
  // Capture screen every 5 seconds (reduced frequency)
104
110
  this.captureInterval = setInterval(() => {
105
- this._captureScreen()
106
- }, 5000)
111
+ this._captureScreen();
112
+ }, 5000);
107
113
  }
108
114
 
109
115
  private _stopPeriodicCapture(): void {
110
116
  if (this.captureInterval) {
111
- clearInterval(this.captureInterval)
112
- this.captureInterval = undefined
117
+ clearInterval(this.captureInterval);
118
+ this.captureInterval = undefined;
113
119
  }
114
120
  }
115
121
 
116
122
  private async _captureScreen(timestamp?: number): Promise<void> {
117
- if (!this.isRecording || this.captureCount >= this.maxCaptures) return
123
+ if (!this.isRecording || this.captureCount >= this.maxCaptures) return;
118
124
 
119
125
  try {
120
- const base64Image = await this._captureScreenBase64()
126
+ const base64Image = await this._captureScreenBase64();
121
127
 
122
128
  if (base64Image) {
123
129
  // Check if screen has changed by comparing with previous capture
124
- const hasChanged = this.enableChangeDetection ? this._hasScreenChanged(base64Image) : true
130
+ const hasChanged = this.enableChangeDetection
131
+ ? this._hasScreenChanged(base64Image)
132
+ : true;
125
133
 
126
134
  if (hasChanged) {
127
135
  // Use incremental snapshot if we have an existing image node, otherwise create full snapshot
128
136
  if (this.currentImageNodeId !== null && this.lastScreenCapture) {
129
- const success = this.updateScreenWithIncrementalSnapshot(base64Image, timestamp)
137
+ const success = this.updateScreenWithIncrementalSnapshot(
138
+ base64Image,
139
+ timestamp
140
+ );
130
141
  if (!success) {
131
142
  // Fallback to full snapshot if incremental update fails
132
- this._createAndEmitFullSnapshotEvent(base64Image, timestamp)
143
+ this._createAndEmitFullSnapshotEvent(base64Image, timestamp);
133
144
  }
134
145
  } else {
135
146
  // First capture or no existing image node - create full snapshot
136
- this._createAndEmitFullSnapshotEvent(base64Image, timestamp)
147
+ this._createAndEmitFullSnapshotEvent(base64Image, timestamp);
137
148
  }
138
149
 
139
- this.lastScreenCapture = base64Image
140
- this.lastScreenHash = this._generateScreenHash(base64Image)
141
- this.captureCount++
150
+ this.lastScreenCapture = base64Image;
151
+ this.lastScreenHash = this._generateScreenHash(base64Image);
152
+ this.captureCount++;
142
153
  }
143
154
  }
144
155
  } catch (error) {
145
- this._recordScreenCaptureError(error as Error)
156
+ this._recordScreenCaptureError(error as Error);
146
157
  }
147
158
  }
148
159
 
@@ -150,35 +161,47 @@ export class ScreenRecorder implements EventRecorder {
150
161
  try {
151
162
  // Check if we're on web platform
152
163
  if (isWeb) {
153
- logger.warn('ScreenRecorder', 'Screen capture not available on web platform')
154
- return null
164
+ logger.warn(
165
+ 'ScreenRecorder',
166
+ 'Screen capture not available on web platform'
167
+ );
168
+ return null;
155
169
  }
156
170
 
157
171
  // Try native masking first if available
158
172
  if (screenMaskingService.isScreenMaskingAvailable()) {
159
- logger.info('ScreenRecorder', 'Using native masking for screen capture')
173
+ logger.info(
174
+ 'ScreenRecorder',
175
+ 'Using native masking for screen capture'
176
+ );
160
177
  const maskedImage = await screenMaskingService.captureMaskedScreen({
161
178
  quality: this.captureQuality,
162
179
  scale: this.captureScale,
163
- })
180
+ });
164
181
 
165
182
  if (maskedImage) {
166
- return maskedImage
183
+ return maskedImage;
167
184
  }
168
185
 
169
- logger.warn('ScreenRecorder', 'Native masking failed, falling back to view-shot')
186
+ logger.warn(
187
+ 'ScreenRecorder',
188
+ 'Native masking failed, falling back to view-shot'
189
+ );
170
190
  }
171
191
 
172
192
  // Fallback to react-native-view-shot
173
193
  if (!this.viewShotRef) {
174
- logger.warn('ScreenRecorder', 'ViewShot ref not available for screen capture')
175
- return null
194
+ logger.warn(
195
+ 'ScreenRecorder',
196
+ 'ViewShot ref not available for screen capture'
197
+ );
198
+ return null;
176
199
  }
177
200
 
178
201
  // Check if captureRef is available
179
202
  if (!captureRef) {
180
- logger.warn('ScreenRecorder', 'react-native-view-shot not available')
181
- return null
203
+ logger.warn('ScreenRecorder', 'react-native-view-shot not available');
204
+ return null;
182
205
  }
183
206
 
184
207
  // Capture the screen using react-native-view-shot
@@ -186,21 +209,28 @@ export class ScreenRecorder implements EventRecorder {
186
209
  format: this.captureFormat,
187
210
  quality: this.captureQuality,
188
211
  result: 'base64',
189
- })
212
+ });
190
213
 
191
- return result
214
+ return result;
192
215
  } catch (error) {
193
- logger.error('ScreenRecorder', 'Failed to capture screen. Make sure react-native-view-shot is properly installed and linked:', error)
194
- return null
216
+ logger.error(
217
+ 'ScreenRecorder',
218
+ 'Failed to capture screen. Make sure react-native-view-shot is properly installed and linked:',
219
+ error
220
+ );
221
+ return null;
195
222
  }
196
223
  }
197
224
 
198
- private _createAndEmitFullSnapshotEvent(base64Image: string, timestamp?: number): void {
199
- if (!this.screenDimensions) return
225
+ private _createAndEmitFullSnapshotEvent(
226
+ base64Image: string,
227
+ timestamp?: number
228
+ ): void {
229
+ if (!this.screenDimensions) return;
200
230
 
201
231
  // Use the new createFullSnapshot method
202
- const fullSnapshotEvent = this.createFullSnapshot(base64Image, timestamp)
203
- this.recordEvent(fullSnapshotEvent)
232
+ const fullSnapshotEvent = this.createFullSnapshot(base64Image, timestamp);
233
+ this.recordEvent(fullSnapshotEvent);
204
234
  }
205
235
 
206
236
  /**
@@ -211,11 +241,11 @@ export class ScreenRecorder implements EventRecorder {
211
241
  */
212
242
  createFullSnapshot(base64Image: string, timestamp?: number): eventWithTime {
213
243
  if (!this.screenDimensions) {
214
- throw new Error('Screen dimensions not available')
244
+ throw new Error('Screen dimensions not available');
215
245
  }
216
246
 
217
- const { width, height } = this.screenDimensions
218
- this.nodeIdCounter = 1
247
+ const { width, height } = this.screenDimensions;
248
+ this.nodeIdCounter = 1;
219
249
 
220
250
  // Use utility function to create full snapshot event
221
251
  const fullSnapshotEvent = createFullSnapshotEvent(
@@ -224,14 +254,14 @@ export class ScreenRecorder implements EventRecorder {
224
254
  height,
225
255
  this.captureFormat,
226
256
  { current: this.nodeIdCounter },
227
- timestamp,
228
- )
257
+ timestamp
258
+ );
229
259
 
230
260
  // Store the image node ID for future incremental updates
231
261
  // The image node ID is the first node created (after the document)
232
- this.currentImageNodeId = 0 // First element node is the image
262
+ this.currentImageNodeId = 0; // First element node is the image
233
263
 
234
- return fullSnapshotEvent
264
+ return fullSnapshotEvent;
235
265
  }
236
266
 
237
267
  /**
@@ -241,30 +271,43 @@ export class ScreenRecorder implements EventRecorder {
241
271
  * @param timestamp - Optional timestamp to use for the event
242
272
  * @returns Incremental snapshot event with mutation data
243
273
  */
244
- createIncrementalSnapshotWithImageUpdate(base64Image: string, captureFormat?: string, timestamp?: number): eventWithTime {
274
+ createIncrementalSnapshotWithImageUpdate(
275
+ base64Image: string,
276
+ captureFormat?: string,
277
+ timestamp?: number
278
+ ): eventWithTime {
245
279
  return createIncrementalSnapshotUtil(
246
280
  base64Image,
247
281
  captureFormat || this.captureFormat,
248
- timestamp,
249
- )
282
+ timestamp
283
+ );
250
284
  }
251
285
 
252
-
253
286
  /**
254
287
  * Update the screen with a new image using incremental snapshot
255
288
  * @param base64Image - New base64 encoded image data
256
289
  * @param timestamp - Optional timestamp to use for the event
257
290
  * @returns true if update was successful, false otherwise
258
291
  */
259
- updateScreenWithIncrementalSnapshot(base64Image: string, timestamp?: number): boolean {
292
+ updateScreenWithIncrementalSnapshot(
293
+ base64Image: string,
294
+ timestamp?: number
295
+ ): boolean {
260
296
  if (this.currentImageNodeId === null) {
261
- logger.warn('ScreenRecorder', 'No image node ID available for incremental update')
262
- return false
297
+ logger.warn(
298
+ 'ScreenRecorder',
299
+ 'No image node ID available for incremental update'
300
+ );
301
+ return false;
263
302
  }
264
303
 
265
- const incrementalEvent = this.createIncrementalSnapshotWithImageUpdate(base64Image, 'jpg', timestamp)
266
- this.recordEvent(incrementalEvent)
267
- return true
304
+ const incrementalEvent = this.createIncrementalSnapshotWithImageUpdate(
305
+ base64Image,
306
+ 'jpg',
307
+ timestamp
308
+ );
309
+ this.recordEvent(incrementalEvent);
310
+ return true;
268
311
  }
269
312
 
270
313
  /**
@@ -272,10 +315,10 @@ export class ScreenRecorder implements EventRecorder {
272
315
  * @param base64Image - Base64 encoded image data
273
316
  */
274
317
  forceFullSnapshot(base64Image: string): void {
275
- this._createAndEmitFullSnapshotEvent(base64Image)
276
- this.lastScreenCapture = base64Image
277
- this.lastScreenHash = this._generateScreenHash(base64Image)
278
- this.captureCount++
318
+ this._createAndEmitFullSnapshotEvent(base64Image);
319
+ this.lastScreenCapture = base64Image;
320
+ this.lastScreenHash = this._generateScreenHash(base64Image);
321
+ this.captureCount++;
279
322
  }
280
323
 
281
324
  /**
@@ -286,14 +329,14 @@ export class ScreenRecorder implements EventRecorder {
286
329
  private _hasScreenChanged(currentBase64: string): boolean {
287
330
  // If this is the first capture, consider it changed
288
331
  if (!this.lastScreenCapture) {
289
- return true
332
+ return true;
290
333
  }
291
334
 
292
335
  // Generate hash for current capture
293
- const currentHash = this._generateScreenHash(currentBase64)
336
+ const currentHash = this._generateScreenHash(currentBase64);
294
337
 
295
338
  // Compare with previous hash
296
- return currentHash !== this.lastScreenHash
339
+ return currentHash !== this.lastScreenHash;
297
340
  }
298
341
 
299
342
  /**
@@ -304,7 +347,7 @@ export class ScreenRecorder implements EventRecorder {
304
347
  * @returns Hash string for comparison
305
348
  */
306
349
  private _generateScreenHash(base64Image: string): string {
307
- return generateScreenHash(base64Image, this.hashSampleSize)
350
+ return generateScreenHash(base64Image, this.hashSampleSize);
308
351
  }
309
352
 
310
353
  private _sendEvent(_event: ScreenEvent): void {
@@ -320,16 +363,16 @@ export class ScreenRecorder implements EventRecorder {
320
363
  'screen.timestamp': event.timestamp,
321
364
  'screen.platform': 'react-native',
322
365
  },
323
- })
366
+ });
324
367
 
325
368
  if (event.metadata) {
326
369
  Object.entries(event.metadata).forEach(([key, value]) => {
327
- span.setAttribute(`screen.metadata.${key}`, String(value))
328
- })
370
+ span.setAttribute(`screen.metadata.${key}`, String(value));
371
+ });
329
372
  }
330
373
 
331
- span.setStatus({ code: SpanStatusCode.OK })
332
- span.end()
374
+ span.setStatus({ code: SpanStatusCode.OK });
375
+ span.end();
333
376
  } catch (error) {
334
377
  // Failed to record OpenTelemetry span for screen - silently continue
335
378
  }
@@ -344,11 +387,11 @@ export class ScreenRecorder implements EventRecorder {
344
387
  'screen.error.message': error.message,
345
388
  'screen.timestamp': Date.now(),
346
389
  },
347
- })
390
+ });
348
391
 
349
- span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
350
- span.recordException(error)
351
- span.end()
392
+ span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
393
+ span.recordException(error);
394
+ span.end();
352
395
  } catch (spanError) {
353
396
  // Failed to record error span - silently continue
354
397
  }
@@ -357,45 +400,48 @@ export class ScreenRecorder implements EventRecorder {
357
400
  async captureSpecificElement(
358
401
  elementRef: any,
359
402
  _options?: {
360
- format?: 'png' | 'jpg' | 'webp'
361
- quality?: number
362
- },
403
+ format?: 'png' | 'jpg' | 'webp';
404
+ quality?: number;
405
+ }
363
406
  ): Promise<string | null> {
364
407
  try {
365
408
  if (isWeb || !captureRef) {
366
- logger.warn('ScreenRecorder', 'Element capture not available on web platform')
367
- return null
409
+ logger.warn(
410
+ 'ScreenRecorder',
411
+ 'Element capture not available on web platform'
412
+ );
413
+ return null;
368
414
  }
369
- return await captureRef(elementRef)
415
+ return await captureRef(elementRef);
370
416
  } catch (error) {
371
417
  // Failed to capture specific element - silently continue
372
- return null
418
+ return null;
373
419
  }
374
420
  }
375
421
 
376
422
  // Configuration methods
377
423
  setCaptureInterval(intervalMs: number): void {
378
424
  if (this.captureInterval) {
379
- clearInterval(this.captureInterval)
425
+ clearInterval(this.captureInterval);
380
426
  }
381
427
 
382
428
  if (this.isRecording) {
383
429
  this.captureInterval = setInterval(() => {
384
- this._captureScreen()
385
- }, intervalMs)
430
+ this._captureScreen();
431
+ }, intervalMs);
386
432
  }
387
433
  }
388
434
 
389
435
  setCaptureQuality(quality: number): void {
390
- this.captureQuality = Math.max(0.1, Math.min(1.0, quality))
436
+ this.captureQuality = Math.max(0.1, Math.min(1.0, quality));
391
437
  }
392
438
 
393
439
  setCaptureFormat(format: 'png' | 'jpg'): void {
394
- this.captureFormat = format
440
+ this.captureFormat = format;
395
441
  }
396
442
 
397
443
  setMaxCaptures(max: number): void {
398
- this.maxCaptures = Math.max(1, max)
444
+ this.maxCaptures = Math.max(1, max);
399
445
  }
400
446
 
401
447
  /**
@@ -403,7 +449,7 @@ export class ScreenRecorder implements EventRecorder {
403
449
  * @param enabled - Whether to enable change detection
404
450
  */
405
451
  setChangeDetection(enabled: boolean): void {
406
- this.enableChangeDetection = enabled
452
+ this.enableChangeDetection = enabled;
407
453
  }
408
454
 
409
455
  /**
@@ -411,7 +457,7 @@ export class ScreenRecorder implements EventRecorder {
411
457
  * @param size - Number of characters to sample from each part of the image
412
458
  */
413
459
  setHashSampleSize(size: number): void {
414
- this.hashSampleSize = Math.max(10, Math.min(1000, size))
460
+ this.hashSampleSize = Math.max(10, Math.min(1000, size));
415
461
  }
416
462
 
417
463
  // Performance monitoring
@@ -426,14 +472,14 @@ export class ScreenRecorder implements EventRecorder {
426
472
  performance: 'monitoring',
427
473
  captureCount: this.captureCount,
428
474
  },
429
- }
475
+ };
430
476
 
431
- this.events.push(event)
432
- this._sendEvent(event)
433
- this._recordOpenTelemetrySpan(event)
434
- this.events.push(event)
435
- this._sendEvent(event)
436
- this._recordOpenTelemetrySpan(event)
477
+ this.events.push(event);
478
+ this._sendEvent(event);
479
+ this._recordOpenTelemetrySpan(event);
480
+ this.events.push(event);
481
+ this._sendEvent(event);
482
+ this._recordOpenTelemetrySpan(event);
437
483
  }
438
484
 
439
485
  // Error tracking
@@ -449,25 +495,25 @@ export class ScreenRecorder implements EventRecorder {
449
495
  screenName,
450
496
  captureCount: this.captureCount,
451
497
  },
452
- }
498
+ };
453
499
 
454
- this.events.push(event)
455
- this._sendEvent(event)
456
- this._recordOpenTelemetrySpan(event)
457
- this.events.push(event)
458
- this._sendEvent(event)
459
- this._recordScreenCaptureError(error)
500
+ this.events.push(event);
501
+ this._sendEvent(event);
502
+ this._recordOpenTelemetrySpan(event);
503
+ this.events.push(event);
504
+ this._sendEvent(event);
505
+ this._recordScreenCaptureError(error);
460
506
  }
461
507
 
462
508
  // Get recorded events
463
509
  getEvents(): ScreenEvent[] {
464
- return [...this.events]
510
+ return [...this.events];
465
511
  }
466
512
 
467
513
  // Clear events
468
514
  clearEvents(): void {
469
- this.events = []
470
- this.captureCount = 0
515
+ this.events = [];
516
+ this.captureCount = 0;
471
517
  }
472
518
 
473
519
  // Get screen capture statistics
@@ -477,25 +523,30 @@ export class ScreenRecorder implements EventRecorder {
477
523
  totalEvents: this.events.length,
478
524
  averageCaptureTime: 0,
479
525
  successRate: 0,
480
- }
526
+ };
481
527
 
482
528
  if (this.events.length > 0) {
483
- const captureTimes = this.events.map((event) => event.metadata?.captureTime || 0).filter((time) => time > 0)
529
+ const captureTimes = this.events
530
+ .map((event) => event.metadata?.captureTime || 0)
531
+ .filter((time) => time > 0);
484
532
 
485
533
  if (captureTimes.length > 0) {
486
- stats.averageCaptureTime = captureTimes.reduce((a, b) => a + b, 0) / captureTimes.length
534
+ stats.averageCaptureTime =
535
+ captureTimes.reduce((a, b) => a + b, 0) / captureTimes.length;
487
536
  }
488
537
 
489
- const successfulCaptures = this.events.filter((event) => event.dataUrl).length
490
- stats.successRate = (successfulCaptures / this.events.length) * 100
538
+ const successfulCaptures = this.events.filter(
539
+ (event) => event.dataUrl
540
+ ).length;
541
+ stats.successRate = (successfulCaptures / this.events.length) * 100;
491
542
  }
492
543
 
493
- return stats
544
+ return stats;
494
545
  }
495
546
 
496
547
  // Get recording status
497
548
  isRecordingEnabled(): boolean {
498
- return this.isRecording
549
+ return this.isRecording;
499
550
  }
500
551
 
501
552
  // Get current configuration
@@ -506,13 +557,13 @@ export class ScreenRecorder implements EventRecorder {
506
557
  captureFormat: this.captureFormat,
507
558
  maxCaptures: this.maxCaptures,
508
559
  screenDimensions: this.screenDimensions,
509
- }
560
+ };
510
561
  }
511
562
 
512
563
  // Shutdown
513
564
  shutdown(): void {
514
- this.stop()
515
- this.clearEvents()
565
+ this.stop();
566
+ this.clearEvents();
516
567
  // Screen recorder shutdown
517
568
  }
518
569
 
@@ -521,7 +572,7 @@ export class ScreenRecorder implements EventRecorder {
521
572
  * @param ref - React Native View ref for screen capture
522
573
  */
523
574
  setViewShotRef(ref: any): void {
524
- this.viewShotRef = ref
575
+ this.viewShotRef = ref;
525
576
  }
526
577
 
527
578
  /**
@@ -531,10 +582,10 @@ export class ScreenRecorder implements EventRecorder {
531
582
  */
532
583
  forceCapture(timestamp?: number): void {
533
584
  if (!this.isRecording) {
534
- return
585
+ return;
535
586
  }
536
587
 
537
- this._captureScreen(timestamp)
588
+ this._captureScreen(timestamp);
538
589
  }
539
590
 
540
591
  /**
@@ -543,7 +594,7 @@ export class ScreenRecorder implements EventRecorder {
543
594
  */
544
595
  recordEvent(event: any): void {
545
596
  if (this.eventRecorder) {
546
- this.eventRecorder.recordEvent(event)
597
+ this.eventRecorder.recordEvent(event);
547
598
  }
548
599
  }
549
600
  }