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

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