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' ;
@@ -11,6 +12,9 @@ const MEDIA_SELECTORS = 'img,image,svg,path,rect,area,video,object,picture,embed
1112
1213let _initialized = false ;
1314
15+ type InitialReplayPluginOptions = Omit < ReplayPluginOptions , 'sessionSampleRate' | 'errorSampleRate' > &
16+ Partial < Pick < ReplayPluginOptions , 'sessionSampleRate' | 'errorSampleRate' > > ;
17+
1418/**
1519 * The main replay integration class, to be passed to `init({ integrations: [] })`.
1620 */
@@ -30,7 +34,14 @@ export class Replay implements Integration {
3034 */
3135 private readonly _recordingOptions : RecordingOptions ;
3236
33- private readonly _options : ReplayPluginOptions ;
37+ /**
38+ * Initial options passed to the replay integration, merged with default values.
39+ * Note: `sessionSampleRate` and `errorSampleRate` are not required here, as they
40+ * can only be finally set when setupOnce() is called.
41+ *
42+ * @private
43+ */
44+ private readonly _initialOptions : InitialReplayPluginOptions ;
3445
3546 private _replay ?: ReplayContainer ;
3647
@@ -92,12 +103,12 @@ export class Replay implements Integration {
92103 collectFonts : true ,
93104 } ;
94105
95- this . _options = {
106+ this . _initialOptions = {
96107 flushMinDelay,
97108 flushMaxDelay,
98109 stickySession,
99- sessionSampleRate : 0 ,
100- errorSampleRate : 0 ,
110+ sessionSampleRate,
111+ errorSampleRate,
101112 useCompression,
102113 maskAllText : typeof maskAllText === 'boolean' ? maskAllText : ! maskTextSelector ,
103114 blockAllMedia,
@@ -113,7 +124,7 @@ Instead, configure \`replaysSessionSampleRate\` directly in the SDK init options
113124Sentry.init({ replaysSessionSampleRate: ${ sessionSampleRate } })` ,
114125 ) ;
115126
116- this . _options . sessionSampleRate = sessionSampleRate ;
127+ this . _initialOptions . sessionSampleRate = sessionSampleRate ;
117128 }
118129
119130 if ( typeof errorSampleRate === 'number' ) {
@@ -125,17 +136,17 @@ Instead, configure \`replaysOnErrorSampleRate\` directly in the SDK init options
125136Sentry.init({ replaysOnErrorSampleRate: ${ errorSampleRate } })` ,
126137 ) ;
127138
128- this . _options . errorSampleRate = errorSampleRate ;
139+ this . _initialOptions . errorSampleRate = errorSampleRate ;
129140 }
130141
131- if ( this . _options . maskAllText ) {
142+ if ( this . _initialOptions . maskAllText ) {
132143 // `maskAllText` is a more user friendly option to configure
133144 // `maskTextSelector`. This means that all nodes will have their text
134145 // content masked.
135146 this . _recordingOptions . maskTextSelector = MASK_ALL_TEXT_SELECTOR ;
136147 }
137148
138- if ( this . _options . blockAllMedia ) {
149+ if ( this . _initialOptions . blockAllMedia ) {
139150 // `blockAllMedia` is a more user friendly option to configure blocking
140151 // embedded media elements
141152 this . _recordingOptions . blockSelector = ! this . _recordingOptions . blockSelector
@@ -221,25 +232,47 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
221232 /** Setup the integration. */
222233 private _setup ( ) : void {
223234 // Client is not available in constructor, so we need to wait until setupOnce
224- this . _loadReplayOptionsFromClient ( ) ;
235+ const finalOptions = loadReplayOptionsFromClient ( this . _initialOptions ) ;
225236
226237 this . _replay = new ReplayContainer ( {
227- options : this . _options ,
238+ options : finalOptions ,
228239 recordingOptions : this . _recordingOptions ,
229240 } ) ;
230241 }
242+ }
231243
232- /** Parse Replay-related options from SDK options */
233- private _loadReplayOptionsFromClient ( ) : void {
234- const client = getCurrentHub ( ) . getClient ( ) ;
235- const opt = client && ( client . getOptions ( ) as BrowserClientReplayOptions | undefined ) ;
244+ /** Parse Replay-related options from SDK options */
245+ function loadReplayOptionsFromClient ( initialOptions : InitialReplayPluginOptions ) : ReplayPluginOptions {
246+ const client = getCurrentHub ( ) . getClient ( ) ;
247+ const opt = client && ( client . getOptions ( ) as BrowserClientReplayOptions ) ;
236248
237- if ( opt && typeof opt . replaysSessionSampleRate === 'number' ) {
238- this . _options . sessionSampleRate = opt . replaysSessionSampleRate ;
239- }
249+ const finalOptions = { sessionSampleRate : 0 , errorSampleRate : 0 , ...dropUndefinedKeys ( initialOptions ) } ;
240250
241- if ( opt && typeof opt . replaysOnErrorSampleRate === 'number' ) {
242- this . _options . errorSampleRate = opt . replaysOnErrorSampleRate ;
243- }
251+ if ( ! opt ) {
252+ // eslint-disable-next-line no-console
253+ console . warn ( 'SDK client is not available.' ) ;
254+ return finalOptions ;
244255 }
256+
257+ if (
258+ initialOptions . sessionSampleRate == null && // TODO remove once deprecated rates are removed
259+ initialOptions . errorSampleRate == null && // TODO remove once deprecated rates are removed
260+ opt . replaysSessionSampleRate == null &&
261+ opt . replaysOnErrorSampleRate == null
262+ ) {
263+ // eslint-disable-next-line no-console
264+ console . warn (
265+ 'Replay is disabled because neither `replaysSessionSampleRate` nor `replaysOnErrorSampleRate` are set.' ,
266+ ) ;
267+ }
268+
269+ if ( typeof opt . replaysSessionSampleRate === 'number' ) {
270+ finalOptions . sessionSampleRate = opt . replaysSessionSampleRate ;
271+ }
272+
273+ if ( typeof opt . replaysOnErrorSampleRate === 'number' ) {
274+ finalOptions . errorSampleRate = opt . replaysOnErrorSampleRate ;
275+ }
276+
277+ return finalOptions ;
245278}
0 commit comments