1
1
import { getCurrentHub } from '@sentry/core' ;
2
2
import type { BrowserClientReplayOptions , Integration } from '@sentry/types' ;
3
+ import { dropUndefinedKeys } from '@sentry/utils' ;
3
4
4
5
import { DEFAULT_FLUSH_MAX_DELAY , DEFAULT_FLUSH_MIN_DELAY , MASK_ALL_TEXT_SELECTOR } from './constants' ;
5
6
import { ReplayContainer } from './replay' ;
@@ -10,6 +11,9 @@ const MEDIA_SELECTORS = 'img,image,svg,path,rect,area,video,object,picture,embed
10
11
11
12
let _initialized = false ;
12
13
14
+ type InitialReplayPluginOptions = Omit < ReplayPluginOptions , 'sessionSampleRate' | 'errorSampleRate' > &
15
+ Partial < Pick < ReplayPluginOptions , 'sessionSampleRate' | 'errorSampleRate' > > ;
16
+
13
17
/**
14
18
* The main replay integration class, to be passed to `init({ integrations: [] })`.
15
19
*/
@@ -29,7 +33,14 @@ export class Replay implements Integration {
29
33
*/
30
34
private readonly _recordingOptions : RecordingOptions ;
31
35
32
- private readonly _options : ReplayPluginOptions ;
36
+ /**
37
+ * Initial options passed to the replay integration, merged with default values.
38
+ * Note: `sessionSampleRate` and `errorSampleRate` are not required here, as they
39
+ * can only be finally set when setupOnce() is called.
40
+ *
41
+ * @private
42
+ */
43
+ private readonly _initialOptions : InitialReplayPluginOptions ;
33
44
34
45
private _replay ?: ReplayContainer ;
35
46
@@ -61,12 +72,12 @@ export class Replay implements Integration {
61
72
..._recordingOptions ,
62
73
} ;
63
74
64
- this . _options = {
75
+ this . _initialOptions = {
65
76
flushMinDelay,
66
77
flushMaxDelay,
67
78
stickySession,
68
- sessionSampleRate : 0 ,
69
- errorSampleRate : 0 ,
79
+ sessionSampleRate,
80
+ errorSampleRate,
70
81
useCompression,
71
82
maskAllText : typeof maskAllText === 'boolean' ? maskAllText : ! maskTextSelector ,
72
83
blockAllMedia,
@@ -82,7 +93,7 @@ Instead, configure \`replaysSessionSampleRate\` directly in the SDK init options
82
93
Sentry.init({ replaysSessionSampleRate: ${ sessionSampleRate } })` ,
83
94
) ;
84
95
85
- this . _options . sessionSampleRate = sessionSampleRate ;
96
+ this . _initialOptions . sessionSampleRate = sessionSampleRate ;
86
97
}
87
98
88
99
if ( typeof errorSampleRate === 'number' ) {
@@ -94,17 +105,17 @@ Instead, configure \`replaysOnErrorSampleRate\` directly in the SDK init options
94
105
Sentry.init({ replaysOnErrorSampleRate: ${ errorSampleRate } })` ,
95
106
) ;
96
107
97
- this . _options . errorSampleRate = errorSampleRate ;
108
+ this . _initialOptions . errorSampleRate = errorSampleRate ;
98
109
}
99
110
100
- if ( this . _options . maskAllText ) {
111
+ if ( this . _initialOptions . maskAllText ) {
101
112
// `maskAllText` is a more user friendly option to configure
102
113
// `maskTextSelector`. This means that all nodes will have their text
103
114
// content masked.
104
115
this . _recordingOptions . maskTextSelector = MASK_ALL_TEXT_SELECTOR ;
105
116
}
106
117
107
- if ( this . _options . blockAllMedia ) {
118
+ if ( this . _initialOptions . blockAllMedia ) {
108
119
// `blockAllMedia` is a more user friendly option to configure blocking
109
120
// embedded media elements
110
121
this . _recordingOptions . blockSelector = ! this . _recordingOptions . blockSelector
@@ -190,30 +201,45 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
190
201
/** Setup the integration. */
191
202
private _setup ( ) : void {
192
203
// Client is not available in constructor, so we need to wait until setupOnce
193
- this . _loadReplayOptionsFromClient ( ) ;
194
-
195
- if ( ! this . _options . sessionSampleRate && ! this . _options . errorSampleRate ) {
196
- // eslint-disable-next-line no-console
197
- console . warn ( 'Replay is disabled because both `replaysSessionSampleRate` and `replaysOnErrorSampleRate` are 0' ) ;
198
- }
204
+ const finalOptions = this . _loadReplayOptionsFromClient ( this . _initialOptions ) ;
199
205
200
206
this . _replay = new ReplayContainer ( {
201
- options : this . _options ,
207
+ options : finalOptions ,
202
208
recordingOptions : this . _recordingOptions ,
203
209
} ) ;
204
210
}
205
211
206
212
/** Parse Replay-related options from SDK options */
207
- private _loadReplayOptionsFromClient ( ) : void {
213
+ private _loadReplayOptionsFromClient ( initialOptions : InitialReplayPluginOptions ) : ReplayPluginOptions {
208
214
const client = getCurrentHub ( ) . getClient ( ) ;
209
215
const opt = client && ( client . getOptions ( ) as BrowserClientReplayOptions | undefined ) ;
210
216
211
- if ( opt && typeof opt . replaysSessionSampleRate === 'number' ) {
212
- this . _options . sessionSampleRate = opt . replaysSessionSampleRate ;
217
+ const finalOptions = { sessionSampleRate : 0 , errorSampleRate : 0 , ...dropUndefinedKeys ( initialOptions ) } ;
218
+
219
+ if ( ! opt ) {
220
+ return finalOptions ;
213
221
}
214
222
215
- if ( opt && typeof opt . replaysOnErrorSampleRate === 'number' ) {
216
- this . _options . errorSampleRate = opt . replaysOnErrorSampleRate ;
223
+ if (
224
+ initialOptions . sessionSampleRate == null && // TODO remove once deprecated rates are removed
225
+ initialOptions . errorSampleRate == null && // TODO remove once deprecated rates are removed
226
+ opt . replaysSessionSampleRate == null &&
227
+ opt . replaysOnErrorSampleRate == null
228
+ ) {
229
+ // eslint-disable-next-line no-console
230
+ console . warn (
231
+ 'Replay is disabled because neither `replaysSessionSampleRate` nor `replaysOnErrorSampleRate` are set' ,
232
+ ) ;
233
+ }
234
+
235
+ if ( typeof opt . replaysSessionSampleRate === 'number' ) {
236
+ finalOptions . sessionSampleRate = opt . replaysSessionSampleRate ;
237
+ }
238
+
239
+ if ( typeof opt . replaysOnErrorSampleRate === 'number' ) {
240
+ finalOptions . errorSampleRate = opt . replaysOnErrorSampleRate ;
217
241
}
242
+
243
+ return finalOptions ;
218
244
}
219
245
}
0 commit comments