11import { getCurrentHub } from '@sentry/core' ;
22import type { BrowserClientReplayOptions , Integration } from '@sentry/types' ;
3+ import { dropUndefinedKeys } from '@sentry/utils' ;
34
45import { DEFAULT_FLUSH_MAX_DELAY , DEFAULT_FLUSH_MIN_DELAY , MASK_ALL_TEXT_SELECTOR } from './constants' ;
56import { ReplayContainer } from './replay' ;
@@ -10,6 +11,9 @@ const MEDIA_SELECTORS = 'img,image,svg,path,rect,area,video,object,picture,embed
1011
1112let _initialized = false ;
1213
14+ type InitialReplayPluginOptions = Omit < ReplayPluginOptions , 'sessionSampleRate' | 'errorSampleRate' > &
15+ Partial < Pick < ReplayPluginOptions , 'sessionSampleRate' | 'errorSampleRate' > > ;
16+
1317/**
1418 * The main replay integration class, to be passed to `init({ integrations: [] })`.
1519 */
@@ -29,7 +33,14 @@ export class Replay implements Integration {
2933 */
3034 private readonly _recordingOptions : RecordingOptions ;
3135
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 ;
3344
3445 private _replay ?: ReplayContainer ;
3546
@@ -61,12 +72,12 @@ export class Replay implements Integration {
6172 ..._recordingOptions ,
6273 } ;
6374
64- this . _options = {
75+ this . _initialOptions = {
6576 flushMinDelay,
6677 flushMaxDelay,
6778 stickySession,
68- sessionSampleRate : 0 ,
69- errorSampleRate : 0 ,
79+ sessionSampleRate,
80+ errorSampleRate,
7081 useCompression,
7182 maskAllText : typeof maskAllText === 'boolean' ? maskAllText : ! maskTextSelector ,
7283 blockAllMedia,
@@ -82,7 +93,7 @@ Instead, configure \`replaysSessionSampleRate\` directly in the SDK init options
8293Sentry.init({ replaysSessionSampleRate: ${ sessionSampleRate } })` ,
8394 ) ;
8495
85- this . _options . sessionSampleRate = sessionSampleRate ;
96+ this . _initialOptions . sessionSampleRate = sessionSampleRate ;
8697 }
8798
8899 if ( typeof errorSampleRate === 'number' ) {
@@ -94,17 +105,17 @@ Instead, configure \`replaysOnErrorSampleRate\` directly in the SDK init options
94105Sentry.init({ replaysOnErrorSampleRate: ${ errorSampleRate } })` ,
95106 ) ;
96107
97- this . _options . errorSampleRate = errorSampleRate ;
108+ this . _initialOptions . errorSampleRate = errorSampleRate ;
98109 }
99110
100- if ( this . _options . maskAllText ) {
111+ if ( this . _initialOptions . maskAllText ) {
101112 // `maskAllText` is a more user friendly option to configure
102113 // `maskTextSelector`. This means that all nodes will have their text
103114 // content masked.
104115 this . _recordingOptions . maskTextSelector = MASK_ALL_TEXT_SELECTOR ;
105116 }
106117
107- if ( this . _options . blockAllMedia ) {
118+ if ( this . _initialOptions . blockAllMedia ) {
108119 // `blockAllMedia` is a more user friendly option to configure blocking
109120 // embedded media elements
110121 this . _recordingOptions . blockSelector = ! this . _recordingOptions . blockSelector
@@ -190,30 +201,45 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
190201 /** Setup the integration. */
191202 private _setup ( ) : void {
192203 // 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 ) ;
199205
200206 this . _replay = new ReplayContainer ( {
201- options : this . _options ,
207+ options : finalOptions ,
202208 recordingOptions : this . _recordingOptions ,
203209 } ) ;
204210 }
205211
206212 /** Parse Replay-related options from SDK options */
207- private _loadReplayOptionsFromClient ( ) : void {
213+ private _loadReplayOptionsFromClient ( initialOptions : InitialReplayPluginOptions ) : ReplayPluginOptions {
208214 const client = getCurrentHub ( ) . getClient ( ) ;
209215 const opt = client && ( client . getOptions ( ) as BrowserClientReplayOptions | undefined ) ;
210216
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 ;
213221 }
214222
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 ;
217241 }
242+
243+ return finalOptions ;
218244 }
219245}
0 commit comments