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

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 (180) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/AndroidManifest.xml +2 -2
  3. package/android/src/main/java/com/{multiplayer/sessionrecordernative → sessionrecordernative}/SessionRecorderNativeConfig.kt +1 -1
  4. package/android/src/main/java/com/{multiplayer/sessionrecordernative → sessionrecordernative}/SessionRecorderNativeModule.kt +9 -9
  5. package/android/src/main/java/com/{multiplayer/sessionrecordernative → sessionrecordernative}/SessionRecorderNativePackage.kt +2 -2
  6. package/android/src/main/java/com/{multiplayer/sessionrecordernative → sessionrecordernative}/model/TargetInfo.kt +1 -1
  7. package/android/src/main/java/com/{multiplayer/sessionrecordernative → sessionrecordernative}/util/ViewUtils.kt +2 -2
  8. package/lib/module/SessionRecorderNativeSpec.js +5 -0
  9. package/lib/module/SessionRecorderNativeSpec.js.map +1 -0
  10. package/lib/module/components/SessionRecorderWidget/ErrorBanner.js.map +1 -1
  11. package/lib/module/components/SessionRecorderWidget/ModalHeader.js.map +1 -1
  12. package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -1
  13. package/lib/module/components/SessionRecorderWidget/icons.js.map +1 -1
  14. package/lib/module/components/SessionRecorderWidget/styles.js.map +1 -1
  15. package/lib/module/config/constants.js.map +1 -1
  16. package/lib/module/config/defaults.js.map +1 -1
  17. package/lib/module/config/masking.js.map +1 -1
  18. package/lib/module/config/session-recorder.js.map +1 -1
  19. package/lib/module/config/validators.js.map +1 -1
  20. package/lib/module/config/widget.js.map +1 -1
  21. package/lib/module/context/SessionRecorderStore.js.map +1 -1
  22. package/lib/module/context/useSessionRecorderStore.js.map +1 -1
  23. package/lib/module/context/useStoreSelector.js.map +1 -1
  24. package/lib/module/native/SessionRecorderNative.js +16 -11
  25. package/lib/module/native/SessionRecorderNative.js.map +1 -1
  26. package/lib/module/native/index.js.map +1 -1
  27. package/lib/module/otel/helpers.js +1 -1
  28. package/lib/module/otel/helpers.js.map +1 -1
  29. package/lib/module/otel/index.js.map +1 -1
  30. package/lib/module/otel/instrumentations/index.js.map +1 -1
  31. package/lib/module/patch/xhr.js.map +1 -1
  32. package/lib/module/recorder/eventExporter.js.map +1 -1
  33. package/lib/module/recorder/gestureRecorder.js.map +1 -1
  34. package/lib/module/recorder/index.js.map +1 -1
  35. package/lib/module/recorder/navigationTracker.js.map +1 -1
  36. package/lib/module/recorder/screenRecorder.js.map +1 -1
  37. package/lib/module/services/api.service.js.map +1 -1
  38. package/lib/module/services/network.service.js.map +1 -1
  39. package/lib/module/services/screenMaskingService.js +1 -1
  40. package/lib/module/services/screenMaskingService.js.map +1 -1
  41. package/lib/module/services/storage.service.js.map +1 -1
  42. package/lib/module/session-recorder.js.map +1 -1
  43. package/lib/module/types/index.js.map +1 -1
  44. package/lib/module/types/session-recorder.js.map +1 -1
  45. package/lib/module/utils/app-metadata.js +2 -2
  46. package/lib/module/utils/constants.optional.js.map +1 -1
  47. package/lib/module/utils/createStore.js.map +1 -1
  48. package/lib/module/utils/logger.js +0 -8
  49. package/lib/module/utils/logger.js.map +1 -1
  50. package/lib/module/utils/platform.js +1 -1
  51. package/lib/module/utils/platform.js.map +1 -1
  52. package/lib/module/utils/rrweb-events.js.map +1 -1
  53. package/lib/module/utils/session.js.map +1 -1
  54. package/lib/module/utils/shallowEqual.js.map +1 -1
  55. package/lib/module/utils/time.js.map +1 -1
  56. package/lib/module/version.js +1 -1
  57. package/lib/typescript/src/SessionRecorderNativeSpec.d.ts +42 -0
  58. package/lib/typescript/src/SessionRecorderNativeSpec.d.ts.map +1 -0
  59. package/lib/typescript/src/components/ScreenRecorderView/index.d.ts +1 -1
  60. package/lib/typescript/src/components/SessionRecorderWidget/ErrorBanner.d.ts.map +1 -1
  61. package/lib/typescript/src/components/SessionRecorderWidget/ModalHeader.d.ts.map +1 -1
  62. package/lib/typescript/src/components/SessionRecorderWidget/SessionRecorderWidget.d.ts.map +1 -1
  63. package/lib/typescript/src/components/SessionRecorderWidget/icons.d.ts.map +1 -1
  64. package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts +1 -1
  65. package/lib/typescript/src/components/SessionRecorderWidget/styles.d.ts.map +1 -1
  66. package/lib/typescript/src/components/index.d.ts.map +1 -1
  67. package/lib/typescript/src/config/constants.d.ts.map +1 -1
  68. package/lib/typescript/src/config/defaults.d.ts.map +1 -1
  69. package/lib/typescript/src/config/index.d.ts.map +1 -1
  70. package/lib/typescript/src/config/masking.d.ts.map +1 -1
  71. package/lib/typescript/src/config/session-recorder.d.ts.map +1 -1
  72. package/lib/typescript/src/config/validators.d.ts.map +1 -1
  73. package/lib/typescript/src/config/widget.d.ts +1 -1
  74. package/lib/typescript/src/config/widget.d.ts.map +1 -1
  75. package/lib/typescript/src/context/SessionRecorderStore.d.ts.map +1 -1
  76. package/lib/typescript/src/context/useSessionRecorderStore.d.ts +3 -3
  77. package/lib/typescript/src/context/useSessionRecorderStore.d.ts.map +1 -1
  78. package/lib/typescript/src/context/useStoreSelector.d.ts.map +1 -1
  79. package/lib/typescript/src/index.d.ts.map +1 -1
  80. package/lib/typescript/src/native/SessionRecorderNative.d.ts +3 -54
  81. package/lib/typescript/src/native/SessionRecorderNative.d.ts.map +1 -1
  82. package/lib/typescript/src/native/index.d.ts +1 -1
  83. package/lib/typescript/src/native/index.d.ts.map +1 -1
  84. package/lib/typescript/src/otel/helpers.d.ts.map +1 -1
  85. package/lib/typescript/src/otel/index.d.ts.map +1 -1
  86. package/lib/typescript/src/otel/instrumentations/index.d.ts.map +1 -1
  87. package/lib/typescript/src/patch/index.d.ts.map +1 -1
  88. package/lib/typescript/src/patch/xhr.d.ts.map +1 -1
  89. package/lib/typescript/src/recorder/eventExporter.d.ts.map +1 -1
  90. package/lib/typescript/src/recorder/gestureRecorder.d.ts.map +1 -1
  91. package/lib/typescript/src/recorder/index.d.ts.map +1 -1
  92. package/lib/typescript/src/recorder/navigationTracker.d.ts.map +1 -1
  93. package/lib/typescript/src/recorder/screenRecorder.d.ts.map +1 -1
  94. package/lib/typescript/src/services/api.service.d.ts.map +1 -1
  95. package/lib/typescript/src/services/network.service.d.ts.map +1 -1
  96. package/lib/typescript/src/services/screenMaskingService.d.ts +1 -1
  97. package/lib/typescript/src/services/screenMaskingService.d.ts.map +1 -1
  98. package/lib/typescript/src/services/storage.service.d.ts.map +1 -1
  99. package/lib/typescript/src/session-recorder.d.ts.map +1 -1
  100. package/lib/typescript/src/types/configs.d.ts.map +1 -1
  101. package/lib/typescript/src/types/index.d.ts.map +1 -1
  102. package/lib/typescript/src/types/session-recorder.d.ts +4 -4
  103. package/lib/typescript/src/types/session-recorder.d.ts.map +1 -1
  104. package/lib/typescript/src/types/session.d.ts.map +1 -1
  105. package/lib/typescript/src/utils/app-metadata.d.ts.map +1 -1
  106. package/lib/typescript/src/utils/constants.optional.d.ts.map +1 -1
  107. package/lib/typescript/src/utils/constants.optional.expo.d.ts.map +1 -1
  108. package/lib/typescript/src/utils/createStore.d.ts.map +1 -1
  109. package/lib/typescript/src/utils/index.d.ts.map +1 -1
  110. package/lib/typescript/src/utils/logger.d.ts +1 -1
  111. package/lib/typescript/src/utils/logger.d.ts.map +1 -1
  112. package/lib/typescript/src/utils/platform.d.ts.map +1 -1
  113. package/lib/typescript/src/utils/request-utils.d.ts.map +1 -1
  114. package/lib/typescript/src/utils/rrweb-events.d.ts.map +1 -1
  115. package/lib/typescript/src/utils/session.d.ts.map +1 -1
  116. package/lib/typescript/src/utils/shallowEqual.d.ts.map +1 -1
  117. package/lib/typescript/src/utils/time.d.ts.map +1 -1
  118. package/lib/typescript/src/utils/type-utils.d.ts.map +1 -1
  119. package/lib/typescript/src/version.d.ts.map +1 -1
  120. package/package.json +2 -2
  121. package/src/SessionRecorderNativeSpec.ts +53 -0
  122. package/src/components/ScreenRecorderView/index.ts +1 -1
  123. package/src/components/SessionRecorderWidget/ErrorBanner.tsx +14 -14
  124. package/src/components/SessionRecorderWidget/ModalHeader.tsx +11 -9
  125. package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +70 -56
  126. package/src/components/SessionRecorderWidget/icons.tsx +58 -30
  127. package/src/components/SessionRecorderWidget/index.ts +1 -1
  128. package/src/components/SessionRecorderWidget/styles.ts +17 -18
  129. package/src/components/index.ts +2 -2
  130. package/src/config/constants.ts +19 -20
  131. package/src/config/defaults.ts +35 -31
  132. package/src/config/index.ts +5 -5
  133. package/src/config/masking.ts +44 -18
  134. package/src/config/session-recorder.ts +54 -26
  135. package/src/config/validators.ts +43 -20
  136. package/src/config/widget.ts +24 -15
  137. package/src/context/SessionRecorderStore.ts +19 -18
  138. package/src/context/useSessionRecorderStore.ts +17 -10
  139. package/src/context/useStoreSelector.ts +20 -18
  140. package/src/index.ts +7 -7
  141. package/src/native/SessionRecorderNative.ts +68 -112
  142. package/src/native/index.ts +5 -1
  143. package/src/otel/helpers.ts +109 -93
  144. package/src/otel/index.ts +46 -49
  145. package/src/otel/instrumentations/index.ts +44 -41
  146. package/src/patch/index.ts +1 -1
  147. package/src/patch/xhr.ts +77 -78
  148. package/src/recorder/eventExporter.ts +63 -68
  149. package/src/recorder/gestureRecorder.ts +359 -212
  150. package/src/recorder/index.ts +75 -62
  151. package/src/recorder/navigationTracker.ts +120 -97
  152. package/src/recorder/screenRecorder.ts +214 -163
  153. package/src/services/api.service.ts +49 -48
  154. package/src/services/network.service.ts +67 -58
  155. package/src/services/screenMaskingService.ts +81 -50
  156. package/src/services/storage.service.ts +99 -70
  157. package/src/session-recorder.ts +270 -214
  158. package/src/types/configs.ts +53 -31
  159. package/src/types/expo-constants.d.ts +2 -2
  160. package/src/types/index.ts +16 -18
  161. package/src/types/session-recorder.ts +106 -111
  162. package/src/types/session.ts +45 -45
  163. package/src/utils/app-metadata.ts +9 -9
  164. package/src/utils/constants.optional.expo.ts +3 -3
  165. package/src/utils/constants.optional.ts +14 -12
  166. package/src/utils/createStore.ts +23 -20
  167. package/src/utils/index.ts +7 -7
  168. package/src/utils/logger.ts +87 -58
  169. package/src/utils/platform.ts +149 -118
  170. package/src/utils/request-utils.ts +15 -15
  171. package/src/utils/rrweb-events.ts +47 -34
  172. package/src/utils/session.ts +15 -12
  173. package/src/utils/shallowEqual.ts +16 -10
  174. package/src/utils/time.ts +7 -4
  175. package/src/utils/type-utils.ts +36 -36
  176. package/src/version.ts +1 -1
  177. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModuleSpec.kt +0 -51
  178. package/android/src/main/java/com/xxx/XxxModule.kt +0 -23
  179. package/ios/Xxx.h +0 -5
  180. package/ios/Xxx.mm +0 -21
@@ -1,4 +1,4 @@
1
- import { type Span } from '@opentelemetry/api'
1
+ import { type Span } from '@opentelemetry/api';
2
2
  import {
3
3
  MULTIPLAYER_TRACE_DEBUG_PREFIX,
4
4
  MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
@@ -6,24 +6,22 @@ import {
6
6
  ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS,
7
7
  ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY,
8
8
  ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS,
9
- } from '@multiplayer-app/session-recorder-common'
10
- import { logger } from '../utils'
11
- import { type TracerReactNativeConfig } from '../types'
12
-
13
-
9
+ } from '@multiplayer-app/session-recorder-common';
10
+ import { logger } from '../utils';
11
+ import { type TracerReactNativeConfig } from '../types';
14
12
 
15
13
  export interface HttpPayloadData {
16
- requestBody?: any
17
- responseBody?: any
18
- requestHeaders?: Record<string, string>
19
- responseHeaders?: Record<string, string>
14
+ requestBody?: any;
15
+ responseBody?: any;
16
+ requestHeaders?: Record<string, string>;
17
+ responseHeaders?: Record<string, string>;
20
18
  }
21
19
 
22
20
  export interface ProcessedHttpPayload {
23
- requestBody?: string
24
- responseBody?: string
25
- requestHeaders?: string
26
- responseHeaders?: string
21
+ requestBody?: string;
22
+ responseBody?: string;
23
+ requestHeaders?: string;
24
+ responseHeaders?: string;
27
25
  }
28
26
 
29
27
  /**
@@ -33,7 +31,7 @@ export function shouldProcessTrace(traceId: string): boolean {
33
31
  return (
34
32
  traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) ||
35
33
  traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
36
- )
34
+ );
37
35
  }
38
36
 
39
37
  /**
@@ -42,22 +40,22 @@ export function shouldProcessTrace(traceId: string): boolean {
42
40
  export function processBody(
43
41
  payload: HttpPayloadData,
44
42
  config: TracerReactNativeConfig,
45
- span: Span,
43
+ span: Span
46
44
  ): { requestBody?: string; responseBody?: string } {
47
- const { captureBody, masking } = config
48
- const traceId = span.spanContext().traceId
45
+ const { captureBody, masking } = config;
46
+ const traceId = span.spanContext().traceId;
49
47
 
50
48
  if (!captureBody) {
51
- return {}
49
+ return {};
52
50
  }
53
51
 
54
- let { requestBody, responseBody } = payload
52
+ let { requestBody, responseBody } = payload;
55
53
 
56
54
  if (requestBody !== undefined && requestBody !== null) {
57
- requestBody = JSON.parse(JSON.stringify(requestBody))
55
+ requestBody = JSON.parse(JSON.stringify(requestBody));
58
56
  }
59
57
  if (responseBody !== undefined && responseBody !== null) {
60
- responseBody = JSON.parse(JSON.stringify(responseBody))
58
+ responseBody = JSON.parse(JSON.stringify(responseBody));
61
59
  }
62
60
 
63
61
  // Apply masking for debug traces
@@ -66,24 +64,24 @@ export function processBody(
66
64
  traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
67
65
  ) {
68
66
  if (masking.isContentMaskingEnabled) {
69
- requestBody = requestBody && masking.maskBody?.(requestBody, span)
70
- responseBody = responseBody && masking.maskBody?.(responseBody, span)
67
+ requestBody = requestBody && masking.maskBody?.(requestBody, span);
68
+ responseBody = responseBody && masking.maskBody?.(responseBody, span);
71
69
  }
72
70
  }
73
71
 
74
72
  // Convert to string if needed
75
73
  if (typeof requestBody !== 'string') {
76
- requestBody = JSON.stringify(requestBody)
74
+ requestBody = JSON.stringify(requestBody);
77
75
  }
78
76
 
79
77
  if (typeof responseBody !== 'string') {
80
- responseBody = JSON.stringify(responseBody)
78
+ responseBody = JSON.stringify(responseBody);
81
79
  }
82
80
 
83
81
  return {
84
82
  requestBody: requestBody?.length ? requestBody : undefined,
85
83
  responseBody: responseBody?.length ? responseBody : undefined,
86
- }
84
+ };
87
85
  }
88
86
 
89
87
  /**
@@ -92,71 +90,74 @@ export function processBody(
92
90
  export function processHeaders(
93
91
  payload: HttpPayloadData,
94
92
  config: TracerReactNativeConfig,
95
- span: Span,
93
+ span: Span
96
94
  ): { requestHeaders?: string; responseHeaders?: string } {
97
- const { captureHeaders, masking } = config
95
+ const { captureHeaders, masking } = config;
98
96
 
99
97
  if (!captureHeaders) {
100
- return {}
98
+ return {};
101
99
  }
102
100
 
103
- let { requestHeaders = {}, responseHeaders = {} } = payload
101
+ let { requestHeaders = {}, responseHeaders = {} } = payload;
104
102
 
105
103
  // Handle header filtering
106
- if (
107
- !masking.headersToInclude?.length &&
108
- !masking.headersToExclude?.length
109
- ) {
104
+ if (!masking.headersToInclude?.length && !masking.headersToExclude?.length) {
110
105
  // Add null checks to prevent JSON.parse error when headers is undefined
111
106
  if (requestHeaders !== undefined && requestHeaders !== null) {
112
- requestHeaders = JSON.parse(JSON.stringify(requestHeaders))
107
+ requestHeaders = JSON.parse(JSON.stringify(requestHeaders));
113
108
  }
114
109
  if (responseHeaders !== undefined && responseHeaders !== null) {
115
- responseHeaders = JSON.parse(JSON.stringify(responseHeaders))
110
+ responseHeaders = JSON.parse(JSON.stringify(responseHeaders));
116
111
  }
117
112
  } else {
118
113
  if (masking.headersToInclude) {
119
- const _requestHeaders: Record<string, string> = {}
120
- const _responseHeaders: Record<string, string> = {}
114
+ const _requestHeaders: Record<string, string> = {};
115
+ const _responseHeaders: Record<string, string> = {};
121
116
 
122
117
  for (const headerName of masking.headersToInclude) {
123
118
  if (requestHeaders[headerName]) {
124
- _requestHeaders[headerName] = requestHeaders[headerName]
119
+ _requestHeaders[headerName] = requestHeaders[headerName];
125
120
  }
126
121
  if (responseHeaders[headerName]) {
127
- _responseHeaders[headerName] = responseHeaders[headerName]
122
+ _responseHeaders[headerName] = responseHeaders[headerName];
128
123
  }
129
124
  }
130
125
 
131
- requestHeaders = _requestHeaders
132
- responseHeaders = _responseHeaders
126
+ requestHeaders = _requestHeaders;
127
+ responseHeaders = _responseHeaders;
133
128
  }
134
129
 
135
130
  if (masking.headersToExclude?.length) {
136
131
  for (const headerName of masking.headersToExclude) {
137
- delete requestHeaders[headerName]
138
- delete responseHeaders[headerName]
132
+ delete requestHeaders[headerName];
133
+ delete responseHeaders[headerName];
139
134
  }
140
135
  }
141
136
  }
142
137
 
143
138
  // Apply masking
144
- const maskedRequestHeaders = masking.maskHeaders?.(requestHeaders, span) || requestHeaders
145
- const maskedResponseHeaders = masking.maskHeaders?.(responseHeaders, span) || responseHeaders
139
+ const maskedRequestHeaders =
140
+ masking.maskHeaders?.(requestHeaders, span) || requestHeaders;
141
+ const maskedResponseHeaders =
142
+ masking.maskHeaders?.(responseHeaders, span) || responseHeaders;
146
143
 
147
144
  // Convert to string
148
- const requestHeadersStr = typeof maskedRequestHeaders === 'string'
149
- ? maskedRequestHeaders
150
- : JSON.stringify(maskedRequestHeaders)
145
+ const requestHeadersStr =
146
+ typeof maskedRequestHeaders === 'string'
147
+ ? maskedRequestHeaders
148
+ : JSON.stringify(maskedRequestHeaders);
151
149
 
152
- const responseHeadersStr = typeof maskedResponseHeaders === 'string'
153
- ? maskedResponseHeaders
154
- : JSON.stringify(maskedResponseHeaders)
150
+ const responseHeadersStr =
151
+ typeof maskedResponseHeaders === 'string'
152
+ ? maskedResponseHeaders
153
+ : JSON.stringify(maskedResponseHeaders);
155
154
 
156
155
  return {
157
156
  requestHeaders: requestHeadersStr?.length ? requestHeadersStr : undefined,
158
- responseHeaders: responseHeadersStr?.length ? responseHeadersStr : undefined,
159
- }
157
+ responseHeaders: responseHeadersStr?.length
158
+ ? responseHeadersStr
159
+ : undefined,
160
+ };
160
161
  }
161
162
 
162
163
  /**
@@ -165,110 +166,125 @@ export function processHeaders(
165
166
  export function processHttpPayload(
166
167
  payload: HttpPayloadData,
167
168
  config: TracerReactNativeConfig,
168
- span: Span,
169
+ span: Span
169
170
  ): void {
170
- const traceId = span.spanContext().traceId
171
+ const traceId = span.spanContext().traceId;
171
172
 
172
173
  if (!shouldProcessTrace(traceId)) {
173
- return
174
+ return;
174
175
  }
175
176
 
176
- const { requestBody, responseBody } = processBody(payload, config, span)
177
- const { requestHeaders, responseHeaders } = processHeaders(payload, config, span)
177
+ const { requestBody, responseBody } = processBody(payload, config, span);
178
+ const { requestHeaders, responseHeaders } = processHeaders(
179
+ payload,
180
+ config,
181
+ span
182
+ );
178
183
 
179
184
  // Set span attributes
180
185
  if (requestBody) {
181
- span.setAttribute(ATTR_MULTIPLAYER_HTTP_REQUEST_BODY, requestBody)
186
+ span.setAttribute(ATTR_MULTIPLAYER_HTTP_REQUEST_BODY, requestBody);
182
187
  }
183
188
 
184
189
  if (responseBody) {
185
- span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY, responseBody)
190
+ span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY, responseBody);
186
191
  }
187
192
 
188
193
  if (requestHeaders) {
189
- span.setAttribute(ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS, requestHeaders)
194
+ span.setAttribute(ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS, requestHeaders);
190
195
  }
191
196
 
192
197
  if (responseHeaders) {
193
- span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS, responseHeaders)
198
+ span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS, responseHeaders);
194
199
  }
195
200
  }
196
201
 
197
202
  /**
198
203
  * Converts Headers object to plain object
199
204
  */
200
- export function headersToObject(headers: Headers | Record<string, string> | Record<string, string | string[]> | string[][] | undefined): Record<string, string> {
201
- const result: Record<string, string> = {}
205
+ export function headersToObject(
206
+ headers:
207
+ | Headers
208
+ | Record<string, string>
209
+ | Record<string, string | string[]>
210
+ | string[][]
211
+ | undefined
212
+ ): Record<string, string> {
213
+ const result: Record<string, string> = {};
202
214
 
203
215
  if (!headers) {
204
- return result
216
+ return result;
205
217
  }
206
218
 
207
219
  if (headers instanceof Headers) {
208
220
  headers.forEach((value: string, key: string) => {
209
- result[key] = value
210
- })
221
+ result[key] = value;
222
+ });
211
223
  } else if (Array.isArray(headers)) {
212
224
  // Handle array of [key, value] pairs
213
225
  for (const [key, value] of headers) {
214
226
  if (typeof key === 'string' && typeof value === 'string') {
215
- result[key] = value
227
+ result[key] = value;
216
228
  }
217
229
  }
218
230
  } else if (typeof headers === 'object' && !Array.isArray(headers)) {
219
231
  for (const [key, value] of Object.entries(headers)) {
220
232
  if (typeof key === 'string' && typeof value === 'string') {
221
- result[key] = value
233
+ result[key] = value;
222
234
  }
223
235
  }
224
236
  }
225
237
 
226
- return result
238
+ return result;
227
239
  }
228
240
 
229
241
  /**
230
242
  * Extracts response body as string from Response object
231
243
  */
232
- export async function extractResponseBody(response: Response): Promise<string | null> {
244
+ export async function extractResponseBody(
245
+ response: Response
246
+ ): Promise<string | null> {
233
247
  if (!response.body) {
234
- return null
248
+ return null;
235
249
  }
236
250
 
237
251
  try {
238
252
  if (response.body instanceof ReadableStream) {
239
253
  // Check if response body is already consumed
240
254
  if (response.bodyUsed) {
241
- return null
255
+ return null;
242
256
  }
243
257
 
244
- const responseClone = response.clone()
245
- return responseClone.text()
258
+ const responseClone = response.clone();
259
+ return responseClone.text();
246
260
  } else {
247
- return JSON.stringify(response.body)
261
+ return JSON.stringify(response.body);
248
262
  }
249
263
  } catch (error) {
250
264
  // If cloning fails (body already consumed), return null
251
- // eslint-disable-next-line no-console
252
- logger.warn('DEBUGGER_LIB', 'Failed to extract response body', error)
253
- return null
265
+
266
+ logger.warn('DEBUGGER_LIB', 'Failed to extract response body', error);
267
+ return null;
254
268
  }
255
269
  }
256
270
 
257
271
  export const getExporterEndpoint = (exporterEndpoint: string): string => {
258
- const hasPath = exporterEndpoint && (() => {
259
- try {
260
- const url = new URL(exporterEndpoint)
261
- return url.pathname !== '/' && url.pathname !== ''
262
- } catch {
263
- return false
264
- }
265
- })()
272
+ const hasPath =
273
+ exporterEndpoint &&
274
+ (() => {
275
+ try {
276
+ const url = new URL(exporterEndpoint);
277
+ return url.pathname !== '/' && url.pathname !== '';
278
+ } catch {
279
+ return false;
280
+ }
281
+ })();
266
282
 
267
283
  if (hasPath) {
268
- return exporterEndpoint
284
+ return exporterEndpoint;
269
285
  }
270
286
 
271
- const trimmedExporterEndpoint = new URL(exporterEndpoint).origin
287
+ const trimmedExporterEndpoint = new URL(exporterEndpoint).origin;
272
288
 
273
- return `${trimmedExporterEndpoint}/v1/traces`
274
- }
289
+ return `${trimmedExporterEndpoint}/v1/traces`;
290
+ };
package/src/otel/index.ts CHANGED
@@ -1,55 +1,51 @@
1
- import { resourceFromAttributes } from '@opentelemetry/resources'
2
- import { W3CTraceContextPropagator } from '@opentelemetry/core'
3
- import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
4
- import * as SemanticAttributes from '@opentelemetry/semantic-conventions'
5
- import { registerInstrumentations } from '@opentelemetry/instrumentation'
1
+ import { resourceFromAttributes } from '@opentelemetry/resources';
2
+ import { W3CTraceContextPropagator } from '@opentelemetry/core';
3
+ import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
4
+ import * as SemanticAttributes from '@opentelemetry/semantic-conventions';
5
+ import { registerInstrumentations } from '@opentelemetry/instrumentation';
6
6
  import {
7
7
  SessionType,
8
8
  ATTR_MULTIPLAYER_SESSION_ID,
9
9
  SessionRecorderIdGenerator,
10
10
  SessionRecorderTraceIdRatioBasedSampler,
11
11
  SessionRecorderBrowserTraceExporter,
12
- } from '@multiplayer-app/session-recorder-common'
13
- import { type TracerReactNativeConfig } from '../types'
14
- import { getInstrumentations } from './instrumentations'
15
- import { getExporterEndpoint } from './helpers'
16
-
17
- import { getPlatformAttributes } from '../utils/platform'
18
- import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'
19
-
20
-
12
+ } from '@multiplayer-app/session-recorder-common';
13
+ import { type TracerReactNativeConfig } from '../types';
14
+ import { getInstrumentations } from './instrumentations';
15
+ import { getExporterEndpoint } from './helpers';
21
16
 
17
+ import { getPlatformAttributes } from '../utils/platform';
18
+ import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
22
19
 
23
20
  export class TracerReactNativeSDK {
24
- private tracerProvider?: WebTracerProvider
25
- private config?: TracerReactNativeConfig
21
+ private tracerProvider?: WebTracerProvider;
22
+ private config?: TracerReactNativeConfig;
26
23
 
27
- private sessionId = ''
28
- private idGenerator?: SessionRecorderIdGenerator
29
- private exporter?: any
24
+ private sessionId = '';
25
+ private idGenerator?: SessionRecorderIdGenerator;
26
+ private exporter?: any;
30
27
 
31
-
32
- constructor() { }
28
+ constructor() {}
33
29
 
34
30
  private _setSessionId(
35
31
  sessionId: string,
36
- sessionType: SessionType = SessionType.PLAIN,
32
+ sessionType: SessionType = SessionType.PLAIN
37
33
  ) {
38
- this.sessionId = sessionId
39
- this.idGenerator?.setSessionId(sessionId, sessionType)
34
+ this.sessionId = sessionId;
35
+ this.idGenerator?.setSessionId(sessionId, sessionType);
40
36
  }
41
37
 
42
38
  init(options: TracerReactNativeConfig): void {
43
- this.config = options
39
+ this.config = options;
44
40
 
45
- const { application, version, environment } = this.config
41
+ const { application, version, environment } = this.config;
46
42
 
47
- this.idGenerator = new SessionRecorderIdGenerator()
43
+ this.idGenerator = new SessionRecorderIdGenerator();
48
44
 
49
45
  this.exporter = new SessionRecorderBrowserTraceExporter({
50
46
  apiKey: options.apiKey,
51
47
  url: getExporterEndpoint(options.exporterEndpoint),
52
- })
48
+ });
53
49
 
54
50
  this.tracerProvider = new WebTracerProvider({
55
51
  resource: resourceFromAttributes({
@@ -59,77 +55,78 @@ export class TracerReactNativeSDK {
59
55
  ...getPlatformAttributes(),
60
56
  }),
61
57
  idGenerator: this.idGenerator,
62
- sampler: new SessionRecorderTraceIdRatioBasedSampler(this.config.sampleTraceRatio || 0.15),
58
+ sampler: new SessionRecorderTraceIdRatioBasedSampler(
59
+ this.config.sampleTraceRatio || 0.15
60
+ ),
63
61
  spanProcessors: [
64
62
  this._getSpanSessionIdProcessor(),
65
63
  new BatchSpanProcessor(this.exporter),
66
64
  ],
67
- })
65
+ });
68
66
 
69
67
  this.tracerProvider.register({
70
68
  propagator: new W3CTraceContextPropagator(),
71
- })
69
+ });
72
70
 
73
71
  // Register instrumentations
74
72
  registerInstrumentations({
75
73
  tracerProvider: this.tracerProvider,
76
74
  instrumentations: getInstrumentations(this.config),
77
- })
78
-
75
+ });
79
76
  }
80
77
 
81
78
  private _getSpanSessionIdProcessor() {
82
79
  return {
83
80
  onStart: (span: any) => {
84
81
  if (this.sessionId) {
85
- span.setAttribute(ATTR_MULTIPLAYER_SESSION_ID, this.sessionId)
82
+ span.setAttribute(ATTR_MULTIPLAYER_SESSION_ID, this.sessionId);
86
83
  }
87
84
  // Add React Native specific attributes
88
- span.setAttribute('platform', 'react-native')
89
- span.setAttribute('timestamp', Date.now())
85
+ span.setAttribute('platform', 'react-native');
86
+ span.setAttribute('timestamp', Date.now());
90
87
  },
91
- onEnd: () => { },
88
+ onEnd: () => {},
92
89
  shutdown: () => Promise.resolve(),
93
90
  forceFlush: () => Promise.resolve(),
94
- }
91
+ };
95
92
  }
96
93
 
97
94
  start(sessionId: string, sessionType: SessionType): void {
98
95
  if (!this.tracerProvider) {
99
96
  throw new Error(
100
- 'Configuration not initialized. Call init() before start().',
101
- )
97
+ 'Configuration not initialized. Call init() before start().'
98
+ );
102
99
  }
103
100
 
104
- this._setSessionId(sessionId, sessionType)
101
+ this._setSessionId(sessionId, sessionType);
105
102
  }
106
103
 
107
104
  stop(): void {
108
105
  if (!this.tracerProvider) {
109
106
  throw new Error(
110
- 'Configuration not initialized. Call init() before start().',
111
- )
107
+ 'Configuration not initialized. Call init() before start().'
108
+ );
112
109
  }
113
110
 
114
- this._setSessionId('')
111
+ this._setSessionId('');
115
112
  }
116
113
 
117
114
  setApiKey(apiKey: string): void {
118
115
  if (!this.exporter) {
119
116
  throw new Error(
120
- 'Configuration not initialized. Call init() before setApiKey().',
121
- )
117
+ 'Configuration not initialized. Call init() before setApiKey().'
118
+ );
122
119
  }
123
120
 
124
- this.exporter.setApiKey?.(apiKey)
121
+ this.exporter.setApiKey?.(apiKey);
125
122
  }
126
123
 
127
124
  setSessionId(sessionId: string, sessionType: SessionType): void {
128
- this._setSessionId(sessionId, sessionType)
125
+ this._setSessionId(sessionId, sessionType);
129
126
  }
130
127
 
131
128
  // Shutdown (React Native specific)
132
129
  shutdown(): Promise<void> {
133
- return Promise.resolve()
130
+ return Promise.resolve();
134
131
  }
135
132
  }