@multiplayer-app/session-recorder-react-native 0.0.1 → 1.0.0-beta.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 (229) hide show
  1. package/README.md +708 -83
  2. package/SessionRecorderNative.podspec +26 -0
  3. package/android/build.gradle +34 -0
  4. package/copy-react-native-dist.sh +34 -16
  5. package/dist/components/ScreenRecorderView/ScreenRecorderView.js +1 -1
  6. package/dist/components/ScreenRecorderView/ScreenRecorderView.js.map +1 -1
  7. package/dist/components/SessionRecorderWidget/ErrorBanner.d.ts +7 -0
  8. package/dist/components/SessionRecorderWidget/ErrorBanner.js +1 -0
  9. package/dist/components/SessionRecorderWidget/ErrorBanner.js.map +1 -0
  10. package/dist/components/SessionRecorderWidget/FinalPopover.d.ts +12 -0
  11. package/dist/components/SessionRecorderWidget/FinalPopover.js +1 -0
  12. package/dist/components/SessionRecorderWidget/FinalPopover.js.map +1 -0
  13. package/dist/components/SessionRecorderWidget/FloatingButton.d.ts +8 -0
  14. package/dist/components/SessionRecorderWidget/FloatingButton.js +1 -0
  15. package/dist/components/SessionRecorderWidget/FloatingButton.js.map +1 -0
  16. package/dist/components/SessionRecorderWidget/InitialPopover.d.ts +16 -0
  17. package/dist/components/SessionRecorderWidget/InitialPopover.js +1 -0
  18. package/dist/components/SessionRecorderWidget/InitialPopover.js.map +1 -0
  19. package/dist/components/SessionRecorderWidget/ModalContainer.d.ts +8 -0
  20. package/dist/components/SessionRecorderWidget/ModalContainer.js +1 -0
  21. package/dist/components/SessionRecorderWidget/ModalContainer.js.map +1 -0
  22. package/dist/components/SessionRecorderWidget/ModalHeader.d.ts +6 -0
  23. package/dist/components/SessionRecorderWidget/ModalHeader.js +1 -0
  24. package/dist/components/SessionRecorderWidget/ModalHeader.js.map +1 -0
  25. package/dist/components/SessionRecorderWidget/SessionRecorderWidget.d.ts +5 -0
  26. package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js +1 -0
  27. package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -0
  28. package/dist/components/SessionRecorderWidget/icons.d.ts +11 -0
  29. package/dist/components/SessionRecorderWidget/icons.js +1 -0
  30. package/dist/components/SessionRecorderWidget/icons.js.map +1 -0
  31. package/dist/components/SessionRecorderWidget/index.d.ts +2 -0
  32. package/dist/components/SessionRecorderWidget/index.js +1 -0
  33. package/dist/components/SessionRecorderWidget/index.js.map +1 -0
  34. package/dist/components/SessionRecorderWidget/styles.d.ts +165 -0
  35. package/dist/components/SessionRecorderWidget/styles.js +1 -0
  36. package/dist/components/SessionRecorderWidget/styles.js.map +1 -0
  37. package/dist/components/index.d.ts +2 -1
  38. package/dist/components/index.js +1 -1
  39. package/dist/components/index.js.map +1 -1
  40. package/dist/config/constants.js +1 -1
  41. package/dist/config/constants.js.map +1 -1
  42. package/dist/config/defaults.d.ts +4 -4
  43. package/dist/config/defaults.js +1 -1
  44. package/dist/config/defaults.js.map +1 -1
  45. package/dist/config/masking.d.ts +2 -2
  46. package/dist/config/masking.js +1 -1
  47. package/dist/config/masking.js.map +1 -1
  48. package/dist/config/session-recorder.js +1 -1
  49. package/dist/config/session-recorder.js.map +1 -1
  50. package/dist/config/validators.d.ts +1 -1
  51. package/dist/config/validators.js +1 -1
  52. package/dist/config/validators.js.map +1 -1
  53. package/dist/config/widget.d.ts +9 -0
  54. package/dist/config/widget.js +1 -0
  55. package/dist/config/widget.js.map +1 -0
  56. package/dist/context/SessionRecorderContext.d.ts +12 -3
  57. package/dist/context/SessionRecorderContext.js +1 -1
  58. package/dist/context/SessionRecorderContext.js.map +1 -1
  59. package/dist/context/SessionRecorderStore.d.ts +12 -0
  60. package/dist/context/SessionRecorderStore.js +1 -0
  61. package/dist/context/SessionRecorderStore.js.map +1 -0
  62. package/dist/context/useSessionRecorderStore.d.ts +8 -0
  63. package/dist/context/useSessionRecorderStore.js +1 -0
  64. package/dist/context/useSessionRecorderStore.js.map +1 -0
  65. package/dist/context/useStoreSelector.d.ts +4 -0
  66. package/dist/context/useStoreSelector.js +1 -0
  67. package/dist/context/useStoreSelector.js.map +1 -0
  68. package/dist/index.d.ts +1 -1
  69. package/dist/index.js +1 -1
  70. package/dist/index.js.map +1 -1
  71. package/dist/native/GestureRecorderNative.d.ts +57 -0
  72. package/dist/native/GestureRecorderNative.js +1 -0
  73. package/dist/native/GestureRecorderNative.js.map +1 -0
  74. package/dist/native/SessionRecorderNative.d.ts +33 -0
  75. package/dist/native/SessionRecorderNative.js +1 -0
  76. package/dist/native/SessionRecorderNative.js.map +1 -0
  77. package/dist/native/index.d.ts +2 -0
  78. package/dist/native/index.js +1 -0
  79. package/dist/native/index.js.map +1 -0
  80. package/dist/otel/index.js +1 -1
  81. package/dist/otel/index.js.map +1 -1
  82. package/dist/patch/xhr.js +1 -1
  83. package/dist/patch/xhr.js.map +1 -1
  84. package/dist/recorder/eventExporter.d.ts +4 -1
  85. package/dist/recorder/eventExporter.js +1 -1
  86. package/dist/recorder/eventExporter.js.map +1 -1
  87. package/dist/recorder/gestureRecorder.d.ts +28 -62
  88. package/dist/recorder/gestureRecorder.js +1 -1
  89. package/dist/recorder/gestureRecorder.js.map +1 -1
  90. package/dist/recorder/index.d.ts +2 -0
  91. package/dist/recorder/index.js +1 -1
  92. package/dist/recorder/index.js.map +1 -1
  93. package/dist/recorder/navigationTracker.d.ts +4 -19
  94. package/dist/recorder/navigationTracker.js +1 -1
  95. package/dist/recorder/navigationTracker.js.map +1 -1
  96. package/dist/recorder/screenRecorder.d.ts +11 -5
  97. package/dist/recorder/screenRecorder.js +1 -1
  98. package/dist/recorder/screenRecorder.js.map +1 -1
  99. package/dist/services/api.service.d.ts +12 -3
  100. package/dist/services/api.service.js +1 -1
  101. package/dist/services/api.service.js.map +1 -1
  102. package/dist/services/network.service.d.ts +46 -0
  103. package/dist/services/network.service.js +1 -0
  104. package/dist/services/network.service.js.map +1 -0
  105. package/dist/services/screenMaskingService.d.ts +47 -0
  106. package/dist/services/screenMaskingService.js +1 -0
  107. package/dist/services/screenMaskingService.js.map +1 -0
  108. package/dist/services/storage.service.d.ts +18 -2
  109. package/dist/services/storage.service.js +1 -1
  110. package/dist/services/storage.service.js.map +1 -1
  111. package/dist/session-recorder.d.ts +18 -33
  112. package/dist/session-recorder.js +1 -1
  113. package/dist/session-recorder.js.map +1 -1
  114. package/dist/types/configs.d.ts +85 -0
  115. package/dist/types/configs.js +1 -0
  116. package/dist/types/configs.js.map +1 -0
  117. package/dist/types/index.d.ts +1 -0
  118. package/dist/types/index.js +1 -1
  119. package/dist/types/index.js.map +1 -1
  120. package/dist/types/session-recorder.d.ts +105 -132
  121. package/dist/types/session-recorder.js +1 -1
  122. package/dist/types/session-recorder.js.map +1 -1
  123. package/dist/utils/constants.optional.d.ts +21 -0
  124. package/dist/utils/constants.optional.expo.d.ts +3 -0
  125. package/dist/utils/constants.optional.expo.js +1 -0
  126. package/dist/utils/constants.optional.expo.js.map +1 -0
  127. package/dist/utils/constants.optional.js +1 -0
  128. package/dist/utils/constants.optional.js.map +1 -0
  129. package/dist/utils/createStore.d.ts +8 -0
  130. package/dist/utils/createStore.js +1 -0
  131. package/dist/utils/createStore.js.map +1 -0
  132. package/dist/utils/logger.d.ts +2 -7
  133. package/dist/utils/logger.js +1 -1
  134. package/dist/utils/logger.js.map +1 -1
  135. package/dist/utils/platform.d.ts +11 -0
  136. package/dist/utils/platform.js +1 -1
  137. package/dist/utils/platform.js.map +1 -1
  138. package/dist/utils/rrweb-events.d.ts +4 -3
  139. package/dist/utils/rrweb-events.js +1 -1
  140. package/dist/utils/rrweb-events.js.map +1 -1
  141. package/dist/utils/session.d.ts +2 -1
  142. package/dist/utils/session.js +1 -1
  143. package/dist/utils/session.js.map +1 -1
  144. package/dist/utils/shallowEqual.d.ts +1 -0
  145. package/dist/utils/shallowEqual.js +1 -0
  146. package/dist/utils/shallowEqual.js.map +1 -0
  147. package/dist/version.d.ts +1 -1
  148. package/dist/version.js +1 -1
  149. package/dist/version.js.map +1 -1
  150. package/ios/GestureRecorderNative.m +21 -0
  151. package/ios/GestureRecorderNative.swift +316 -0
  152. package/ios/SessionRecorderNative.m +17 -0
  153. package/ios/SessionRecorderNative.podspec +26 -0
  154. package/ios/SessionRecorderNative.swift +599 -0
  155. package/package.json +15 -16
  156. package/react-native.config.js +12 -0
  157. package/RRWEB_INTEGRATION.md +0 -336
  158. package/VIEWSHOT_INTEGRATION_TEST.md +0 -123
  159. package/babel.config.js +0 -13
  160. package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.d.ts +0 -6
  161. package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.js +0 -1
  162. package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.js.map +0 -1
  163. package/dist/components/GestureCaptureWrapper/index.d.ts +0 -1
  164. package/dist/components/GestureCaptureWrapper/index.js +0 -1
  165. package/dist/components/GestureCaptureWrapper/index.js.map +0 -1
  166. package/dist/components/GestureCaptureWrapper.d.ts +0 -6
  167. package/dist/components/GestureCaptureWrapper.js +0 -1
  168. package/dist/components/GestureCaptureWrapper.js.map +0 -1
  169. package/dist/expo.d.ts +0 -7
  170. package/dist/expo.js +0 -1
  171. package/dist/expo.js.map +0 -1
  172. package/dist/otel/instrumentations/gestureInstrumentation.d.ts +0 -15
  173. package/dist/otel/instrumentations/gestureInstrumentation.js +0 -1
  174. package/dist/otel/instrumentations/gestureInstrumentation.js.map +0 -1
  175. package/dist/otel/instrumentations/reactNativeInstrumentation.d.ts +0 -8
  176. package/dist/otel/instrumentations/reactNativeInstrumentation.js +0 -1
  177. package/dist/otel/instrumentations/reactNativeInstrumentation.js.map +0 -1
  178. package/dist/otel/instrumentations/reactNavigationInstrumentation.d.ts +0 -13
  179. package/dist/otel/instrumentations/reactNavigationInstrumentation.js +0 -1
  180. package/dist/otel/instrumentations/reactNavigationInstrumentation.js.map +0 -1
  181. package/dist/recorder/gestureHandlerRecorder.d.ts +0 -19
  182. package/dist/recorder/gestureHandlerRecorder.js +0 -1
  183. package/dist/recorder/gestureHandlerRecorder.js.map +0 -1
  184. package/dist/types/rrweb.d.ts +0 -118
  185. package/dist/types/rrweb.js +0 -1
  186. package/dist/types/rrweb.js.map +0 -1
  187. package/scripts/generate-app-metadata.js +0 -173
  188. package/src/components/GestureCaptureWrapper/GestureCaptureWrapper.tsx +0 -86
  189. package/src/components/GestureCaptureWrapper/index.ts +0 -1
  190. package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +0 -72
  191. package/src/components/ScreenRecorderView/index.ts +0 -1
  192. package/src/components/index.ts +0 -1
  193. package/src/config/constants.ts +0 -60
  194. package/src/config/defaults.ts +0 -82
  195. package/src/config/index.ts +0 -6
  196. package/src/config/masking.ts +0 -27
  197. package/src/config/session-recorder.ts +0 -55
  198. package/src/config/validators.ts +0 -31
  199. package/src/context/SessionRecorderContext.tsx +0 -75
  200. package/src/expo.ts +0 -11
  201. package/src/index.ts +0 -17
  202. package/src/otel/helpers.ts +0 -275
  203. package/src/otel/index.ts +0 -138
  204. package/src/otel/instrumentations/index.ts +0 -115
  205. package/src/patch/index.ts +0 -1
  206. package/src/patch/xhr.ts +0 -142
  207. package/src/recorder/eventExporter.ts +0 -141
  208. package/src/recorder/gestureRecorder.ts +0 -498
  209. package/src/recorder/index.ts +0 -179
  210. package/src/recorder/navigationTracker.ts +0 -449
  211. package/src/recorder/screenRecorder.ts +0 -498
  212. package/src/services/api.service.ts +0 -203
  213. package/src/services/storage.service.ts +0 -158
  214. package/src/session-recorder.ts +0 -600
  215. package/src/types/expo.d.ts +0 -23
  216. package/src/types/index.ts +0 -28
  217. package/src/types/session-recorder.ts +0 -423
  218. package/src/types/session.ts +0 -65
  219. package/src/utils/app-metadata.ts +0 -31
  220. package/src/utils/index.ts +0 -8
  221. package/src/utils/logger.ts +0 -225
  222. package/src/utils/platform.ts +0 -384
  223. package/src/utils/request-utils.ts +0 -61
  224. package/src/utils/rrweb-events.ts +0 -309
  225. package/src/utils/session.ts +0 -18
  226. package/src/utils/time.ts +0 -17
  227. package/src/utils/type-utils.ts +0 -75
  228. package/src/version.ts +0 -1
  229. package/tsconfig.json +0 -24
@@ -1,600 +0,0 @@
1
-
2
- import { SessionType } from '@multiplayer-app/session-recorder-common'
3
- import { Observable } from 'lib0/observable'
4
-
5
- import { TracerReactNativeSDK } from './otel'
6
- import { RecorderReactNativeSDK } from './recorder'
7
- import { logger } from './utils'
8
-
9
- import {
10
- ISession,
11
- SessionState,
12
- ISessionRecorder,
13
- SessionRecorderConfigs,
14
- SessionRecorderOptions,
15
- EventRecorder
16
- } from './types'
17
- import { getFormattedDate, isSessionActive, getNavigatorInfo } from './utils'
18
- import { setMaxCapturingHttpPayloadSize, setShouldRecordHttpData } from './patch/xhr'
19
- import { DEFAULT_MAX_HTTP_CAPTURING_PAYLOAD_SIZE, getSessionRecorderConfig } from './config'
20
-
21
- import { StorageService } from './services/storage.service'
22
- import { ApiService, StartSessionRequest, StopSessionRequest } from './services/api.service'
23
- import { eventWithTime } from '@rrweb/types'
24
-
25
- // Utility functions for React Native
26
-
27
- type SessionRecorderEvents =
28
- | 'state-change'
29
-
30
-
31
- class SessionRecorder extends Observable<SessionRecorderEvents> implements ISessionRecorder, EventRecorder {
32
- private _isInitialized = false
33
- private _configs: SessionRecorderConfigs | null = null
34
- private _apiService = new ApiService()
35
- private _tracer = new TracerReactNativeSDK()
36
- private _recorder = new RecorderReactNativeSDK()
37
- private _storageService = new StorageService()
38
- private _startRequestController: AbortController | null = null
39
-
40
- // Session ID and state are stored in AsyncStorage
41
- private _sessionId: string | null = null
42
- get sessionId(): string | null {
43
- return this._sessionId
44
- }
45
- set sessionId(sessionId: string | null) {
46
- this._sessionId = sessionId
47
- if (sessionId) {
48
- this._storageService.saveSessionId(sessionId)
49
- }
50
- }
51
-
52
- private _sessionType: SessionType = SessionType.PLAIN
53
- get sessionType(): SessionType {
54
- return this._sessionType
55
- }
56
- set sessionType(sessionType: SessionType) {
57
- this._sessionType = sessionType
58
- this._storageService.saveSessionType(sessionType)
59
- }
60
-
61
- get continuousRecording(): boolean {
62
- return this.sessionType === SessionType.CONTINUOUS
63
- }
64
-
65
- private _sessionState: SessionState | null = null
66
- get sessionState(): SessionState | null {
67
- return this._sessionState || SessionState.stopped
68
- }
69
- set sessionState(state: SessionState | null) {
70
- this._sessionState = state
71
- this.emit('state-change', [state || SessionState.stopped])
72
- if (state) {
73
- this._storageService.saveSessionState(state)
74
- }
75
- }
76
-
77
- private _session: ISession | null = null
78
- get session(): ISession | null {
79
- return this._session
80
- }
81
- set session(session: ISession | null) {
82
- this._session = session
83
- if (session) {
84
- this._storageService.saveSessionObject(session)
85
- }
86
- }
87
-
88
- private _sessionAttributes: Record<string, any> | null = null
89
- get sessionAttributes(): Record<string, any> {
90
- return this._sessionAttributes || {}
91
- }
92
- set sessionAttributes(attributes: Record<string, any> | null) {
93
- this._sessionAttributes = attributes
94
- }
95
-
96
- /**
97
- * Error message getter and setter
98
- */
99
- public get error(): string {
100
- return this._error || ''
101
- }
102
-
103
- public set error(v: string) {
104
- this._error = v
105
- }
106
- private _error: string = ''
107
-
108
- /**
109
- * React Native doesn't have HTML elements, so we return null
110
- */
111
- public get sessionWidgetButtonElement(): any {
112
- return null
113
- }
114
-
115
- /**
116
- * Initialize debugger with default or custom configurations
117
- */
118
- constructor() {
119
- super()
120
- // Initialize with stored session data if available
121
- StorageService.initialize()
122
- }
123
-
124
- private async _loadStoredSessionData(): Promise<void> {
125
- try {
126
- await StorageService.initialize()
127
- const storedData = await this._storageService.getAllSessionData()
128
- if (isSessionActive(storedData.sessionObject, storedData.sessionType === SessionType.CONTINUOUS)) {
129
- this.session = storedData.sessionObject
130
- this.sessionId = storedData.sessionId
131
- this.sessionType = storedData.sessionType || SessionType.PLAIN
132
- this.sessionState = storedData.sessionState
133
- } else {
134
- this.session = null
135
- this.sessionId = null
136
- this.sessionState = null
137
- this.sessionType = SessionType.PLAIN
138
- }
139
- } catch (error) {
140
- logger.error('SessionRecorder', 'Failed to load stored session data', error)
141
- this.session = null
142
- this.sessionId = null
143
- this.sessionState = null
144
- this.sessionType = SessionType.PLAIN
145
- }
146
- }
147
-
148
- /**
149
- * Initialize the session debugger
150
- * @param configs - custom configurations for session debugger
151
- */
152
- public async init(configs: SessionRecorderOptions): Promise<void> {
153
- this._configs = getSessionRecorderConfig({ ...this._configs, ...configs })
154
- this._isInitialized = true
155
- this._checkOperation('init')
156
- await this._loadStoredSessionData()
157
- setMaxCapturingHttpPayloadSize(this._configs.maxCapturingHttpPayloadSize || DEFAULT_MAX_HTTP_CAPTURING_PAYLOAD_SIZE)
158
- setShouldRecordHttpData(!this._configs.captureBody, this._configs.captureHeaders)
159
-
160
-
161
- try {
162
- this._apiService.init(this._configs)
163
- this._tracer.init(this._configs)
164
- } catch (error) {
165
- logger.error('SessionRecorder', 'Failed to initialize API service', error)
166
- }
167
- if (this._configs.apiKey) {
168
- this._recorder.init(this._configs)
169
- }
170
-
171
- if (this.sessionId && (this.sessionState === SessionState.started || this.sessionState === SessionState.paused)) {
172
- this._start()
173
- }
174
-
175
- }
176
-
177
- /**
178
- * Start a new session
179
- * @param type - the type of session to start
180
- * @param session - the session to start
181
- */
182
- public async start(type: SessionType = SessionType.PLAIN, session?: ISession): Promise<void> {
183
- this._checkOperation('start')
184
- // If continuous recording is disabled, force plain mode
185
- if (type === SessionType.CONTINUOUS && !this._configs?.showContinuousRecording) {
186
- type = SessionType.PLAIN
187
- }
188
- this.sessionType = type
189
- this._startRequestController = new AbortController()
190
- if (session) {
191
- this._setupSessionAndStart(session, true)
192
- } else {
193
- await this._createSessionAndStart()
194
- }
195
- }
196
-
197
- /**
198
- * Stop the current session with an optional comment
199
- * @param comment - user-provided comment to include in session session attributes
200
- */
201
- public async stop(comment?: string): Promise<void> {
202
- try {
203
- this._checkOperation('stop')
204
- this._stop()
205
- if (this.continuousRecording) {
206
- await this._apiService.stopContinuousDebugSession(this.sessionId!)
207
- this.sessionType = SessionType.PLAIN
208
- } else {
209
- const request: StopSessionRequest = {
210
- sessionAttributes: { comment },
211
- stoppedAt: Date.now(),
212
- }
213
- const response = await this._apiService.stopSession(this.sessionId!, request)
214
- }
215
- this._clearSession()
216
- } catch (error: any) {
217
- this.error = error.message
218
- }
219
- }
220
-
221
- /**
222
- * Pause the current session
223
- */
224
- public async pause(): Promise<void> {
225
- try {
226
- this._checkOperation('pause')
227
- this._pause()
228
- } catch (error: any) {
229
- this.error = error.message
230
- }
231
- }
232
-
233
- /**
234
- * Resume the current session
235
- */
236
- public async resume(): Promise<void> {
237
- try {
238
- this._checkOperation('resume')
239
- this._resume()
240
- } catch (error: any) {
241
- this.error = error.message
242
- }
243
- }
244
-
245
- /**
246
- * Cancel the current session
247
- */
248
- public async cancel(): Promise<void> {
249
- try {
250
- this._checkOperation('cancel')
251
- this._stop()
252
- if (this.continuousRecording) {
253
- await this._apiService.stopContinuousDebugSession(this.sessionId!)
254
- this.sessionType = SessionType.PLAIN
255
- } else {
256
- await this._apiService.cancelSession(this.sessionId!)
257
- }
258
- this._clearSession()
259
- } catch (error: any) {
260
- this.error = error.message
261
- }
262
- }
263
-
264
- /**
265
- * Save the continuous recording session
266
- */
267
- public async save(): Promise<any> {
268
- try {
269
- this._checkOperation('save')
270
- if (!this.continuousRecording || !this._configs?.showContinuousRecording) {
271
- return
272
- }
273
-
274
- const res = await this._apiService.saveContinuousDebugSession(
275
- this.sessionId!,
276
- {
277
- sessionAttributes: this.sessionAttributes,
278
- resourceAttributes: getNavigatorInfo(),
279
- stoppedAt: Date.now(),
280
- name: this.sessionAttributes.userName
281
- ? `${this.sessionAttributes.userName}'s session on ${getFormattedDate(
282
- Date.now(),
283
- { month: 'short', day: 'numeric' },
284
- )}`
285
- : `Session on ${getFormattedDate(Date.now())}`,
286
- },
287
- )
288
-
289
- return res
290
- } catch (error: any) {
291
- this.error = error.message
292
- }
293
- }
294
-
295
- /**
296
- * Set the session attributes
297
- * @param attributes - the attributes to set
298
- */
299
- public setSessionAttributes(attributes: Record<string, any>): void {
300
- this._sessionAttributes = attributes
301
- }
302
-
303
- /**
304
- * Set a custom click handler for the recording button
305
- * @param handler - function that will be invoked when the button is clicked
306
- */
307
- public set recordingButtonClickHandler(handler: () => boolean | void) {
308
- // React Native doesn't have HTML elements, so this is a no-op
309
- }
310
-
311
- /**
312
- * @description Check if session should be started/stopped automatically
313
- * @param {ISession} [sessionPayload]
314
- * @returns {Promise<void>}
315
- */
316
- public async checkRemoteContinuousSession(
317
- sessionPayload?: Omit<ISession, '_id' | 'shortId'>,
318
- ): Promise<void> {
319
- this._checkOperation('autoStartRemoteContinuousSession')
320
- if (!this._configs?.showContinuousRecording) {
321
- return
322
- }
323
- const payload = {
324
- sessionAttributes: {
325
- ...this.sessionAttributes,
326
- ...(sessionPayload?.sessionAttributes || {}),
327
- },
328
- resourceAttributes: {
329
- ...getNavigatorInfo(),
330
- ...(sessionPayload?.resourceAttributes || {}),
331
- },
332
- }
333
-
334
- const { state } = await this._apiService.checkRemoteSession(payload)
335
-
336
- if (state == 'START') {
337
- if (this.sessionState !== SessionState.started) {
338
- await this.start(SessionType.CONTINUOUS)
339
- }
340
- } else if (state == 'STOP') {
341
- if (this.sessionState !== SessionState.stopped) {
342
- await this.stop()
343
- }
344
- }
345
- }
346
-
347
- /**
348
- * Create a new session and start it
349
- */
350
- private async _createSessionAndStart(): Promise<void> {
351
- const signal = this._startRequestController?.signal
352
- try {
353
- const payload = {
354
- sessionAttributes: this.sessionAttributes,
355
- resourceAttributes: getNavigatorInfo(),
356
- name: this.sessionAttributes.userName
357
- ? `${this.sessionAttributes.userName}'s session on ${getFormattedDate(Date.now(), { month: 'short', day: 'numeric' })}`
358
- : `Session on ${getFormattedDate(Date.now())}`,
359
- }
360
- const request: StartSessionRequest = !this.continuousRecording ?
361
- payload : { debugSessionData: payload }
362
-
363
- const session = this.continuousRecording
364
- ? await this._apiService.startContinuousDebugSession(request, signal)
365
- : await this._apiService.startSession(request, signal)
366
-
367
- if (session) {
368
- session.sessionType = this.continuousRecording
369
- ? SessionType.CONTINUOUS
370
- : SessionType.PLAIN
371
- this._setupSessionAndStart(session, false)
372
- }
373
- } catch (error: any) {
374
- this.error = error.message
375
- if (this.continuousRecording) {
376
- this.sessionType = SessionType.PLAIN
377
- }
378
- }
379
- }
380
-
381
- /**
382
- * Start tracing and recording for the session
383
- */
384
- private _start(): void {
385
- this.sessionState = SessionState.started
386
- if (this.sessionId) {
387
- this._tracer.start(this.sessionId, this.sessionType)
388
- this._recorder.start(this.sessionId, this.sessionType)
389
- }
390
- }
391
-
392
- /**
393
- * Stop tracing and recording for the session
394
- */
395
- private _stop(): void {
396
- this.sessionState = SessionState.stopped
397
- this._tracer.shutdown()
398
- this._recorder.stop()
399
- }
400
-
401
- /**
402
- * Pause the session tracing and recording
403
- */
404
- private _pause(): void {
405
- this._tracer.shutdown()
406
- this._recorder.stop()
407
- this.sessionState = SessionState.paused
408
- }
409
-
410
- /**
411
- * Resume the session tracing and recording
412
- */
413
- private _resume(): void {
414
- if (this.sessionId) {
415
- this._tracer.setSessionId(this.sessionId, this.sessionType)
416
- this._recorder.start(this.sessionId, this.sessionType)
417
- }
418
- this.sessionState = SessionState.started
419
- }
420
-
421
- private _setupSessionAndStart(session: ISession, configureExporters: boolean = true): void {
422
- if (configureExporters && session.tempApiKey) {
423
- this._configs!.apiKey = session.tempApiKey
424
- this._recorder.init(this._configs!)
425
- this._tracer.init(this._configs!)
426
- this._apiService.updateConfigs({ apiKey: this._configs!.apiKey })
427
- }
428
-
429
- this._setSession(session)
430
- this._start()
431
- }
432
-
433
- /**
434
- * Set the session ID in storage
435
- * @param sessionId - the session ID to set or clear
436
- */
437
- private _setSession(
438
- session: ISession,
439
- ): void {
440
- this.session = { ...session, createdAt: session.createdAt || new Date().toISOString() }
441
- this.sessionId = session?.shortId || session?._id
442
- }
443
-
444
- private _clearSession(): void {
445
- this.session = null
446
- this.sessionId = null
447
- this.sessionState = SessionState.stopped
448
- this._storageService.clearSessionData()
449
- }
450
-
451
- /**
452
- * Check the operation validity based on the session state and action
453
- * @param action - action being checked ('init', 'start', 'stop', 'cancel', 'pause', 'resume')
454
- */
455
- private _checkOperation(
456
- action:
457
- | 'init'
458
- | 'start'
459
- | 'stop'
460
- | 'cancel'
461
- | 'pause'
462
- | 'resume'
463
- | 'save'
464
- | 'autoStartRemoteContinuousSession',
465
- payload?: any,
466
- ): void {
467
- if (!this._isInitialized) {
468
- throw new Error(
469
- 'Configuration not initialized. Call init() before performing any actions.',
470
- )
471
- }
472
- switch (action) {
473
- case 'start':
474
- if (this.sessionState === SessionState.started) {
475
- throw new Error('Session is already started.')
476
- }
477
- break
478
- case 'stop':
479
- if (this.sessionState !== SessionState.paused && this.sessionState !== SessionState.started) {
480
- throw new Error('Cannot stop. Session is not currently started.')
481
- }
482
- break
483
- case 'cancel':
484
- if (this.sessionState === SessionState.stopped) {
485
- throw new Error('Cannot cancel. Session has already been stopped.')
486
- }
487
- break
488
- case 'pause':
489
- if (this.sessionState !== SessionState.started) {
490
- throw new Error('Cannot pause. Session is not running.')
491
- }
492
- break
493
- case 'resume':
494
- if (this.sessionState !== SessionState.paused) {
495
- throw new Error('Cannot resume. Session is not paused.')
496
- }
497
- break
498
- case 'save':
499
- if (!this.continuousRecording) {
500
- throw new Error('Cannot save continuous recording session. Continuous recording is not enabled.')
501
- }
502
- if (this.sessionState !== SessionState.started) {
503
- throw new Error('Cannot save continuous recording session. Session is not started.')
504
- }
505
- break
506
- case 'autoStartRemoteContinuousSession':
507
- if (this.sessionState !== SessionState.stopped) {
508
- throw new Error('Cannot start remote continuous session. Session is not stopped.')
509
- }
510
- break
511
- }
512
- }
513
- // Session attributes
514
- setSessionAttribute(key: string, value: any): void {
515
- if (this._session) {
516
- if (!this._session.sessionAttributes) {
517
- this._session.sessionAttributes = {}
518
- }
519
- this._session.sessionAttributes[key] = value
520
- this._session.updatedAt = new Date().toISOString()
521
- }
522
- }
523
-
524
- /**
525
- * Record a custom rrweb event
526
- * Note: Screen capture and touch events are recorded automatically when session is started
527
- * @param event - The rrweb event to record
528
- */
529
- recordEvent(event: eventWithTime): void {
530
- if (!this._isInitialized || this.sessionState !== SessionState.started) {
531
- return
532
- }
533
-
534
- // Forward the event to the recorder SDK
535
- this._recorder.recordEvent(event)
536
- }
537
-
538
- /**
539
- * Record touch start event (internal use - touch recording is automatic)
540
- * @param x - X coordinate
541
- * @param y - Y coordinate
542
- * @param target - Target element identifier
543
- * @param pressure - Touch pressure
544
- * @internal
545
- */
546
- recordTouchStart(x: number, y: number, target?: string, pressure?: number): void {
547
- if (!this._isInitialized || this.sessionState !== SessionState.started) {
548
- return
549
- }
550
-
551
- // Forward to gesture recorder
552
- this._recorder.recordTouchStart(x, y, target, pressure)
553
- }
554
-
555
- /**
556
- * Record touch move event (internal use - touch recording is automatic)
557
- * @param x - X coordinate
558
- * @param y - Y coordinate
559
- * @param target - Target element identifier
560
- * @param pressure - Touch pressure
561
- * @internal
562
- */
563
- recordTouchMove(x: number, y: number, target?: string, pressure?: number): void {
564
- if (!this._isInitialized || this.sessionState !== SessionState.started) {
565
- return
566
- }
567
-
568
- // Forward to gesture recorder
569
- this._recorder.recordTouchMove(x, y, target, pressure)
570
- }
571
-
572
- /**
573
- * Record touch end event (internal use - touch recording is automatic)
574
- * @param x - X coordinate
575
- * @param y - Y coordinate
576
- * @param target - Target element identifier
577
- * @param pressure - Touch pressure
578
- * @internal
579
- */
580
- recordTouchEnd(x: number, y: number, target?: string, pressure?: number): void {
581
- if (!this._isInitialized || this.sessionState !== SessionState.started) {
582
- return
583
- }
584
-
585
- // Forward to gesture recorder
586
- this._recorder.recordTouchEnd(x, y, target, pressure)
587
- }
588
-
589
- /**
590
- * Set the viewshot ref for screen capture
591
- * @param ref - React Native View ref for screen capture
592
- */
593
- setViewShotRef(ref: any): void {
594
- if (this._recorder) {
595
- this._recorder.setViewShotRef(ref)
596
- }
597
- }
598
- }
599
-
600
- export default new SessionRecorder()
@@ -1,23 +0,0 @@
1
- import { SessionRecorderOptions, PlatformInfo } from './index'
2
-
3
- declare module '@multiplayer-app/session-recorder-react-native' {
4
- export interface ExpoSessionRecorderOptions extends SessionRecorderOptions {
5
- platform: 'expo'
6
- expoVersion?: string
7
- }
8
-
9
- export interface ExpoPlatformInfo {
10
- isExpo: true
11
- isReactNative: true
12
- platform: 'ios' | 'android' | 'web'
13
- expoVersion: string
14
- deviceType: 'expo'
15
- }
16
-
17
- export function isExpoEnvironment(): boolean
18
- export function getPlatformAttributes(): Record<string, any>
19
- export function detectPlatform(): PlatformInfo | ExpoPlatformInfo
20
- }
21
-
22
- // Expo-specific exports
23
- export * from './index'
@@ -1,28 +0,0 @@
1
- export * from './session-recorder'
2
- export * from './session'
3
-
4
- // Import types for use in this file
5
- import type { eventWithTime } from '@rrweb/types'
6
-
7
-
8
- export interface ReactNativeScreenData {
9
- width: number
10
- height: number
11
- base64Image: string
12
- timestamp: number
13
- screenName?: string
14
- }
15
-
16
- export interface ReactNativeTouchData {
17
- pageX: number
18
- pageY: number
19
- target?: string
20
- pressure?: number
21
- timestamp: number
22
- }
23
-
24
-
25
- // Event recording interface
26
- export interface EventRecorder {
27
- recordEvent(event: eventWithTime): void
28
- }