@@ -50,9 +50,10 @@ export class ReplayContainer implements ReplayContainerInterface {
5050 public session : Session | undefined ;
5151
5252 /**
53- * Recording can happen in one of two modes:
54- * * session: Record the whole session, sending it continuously
55- * * error: Always keep the last 60s of recording, and when an error occurs, send it immediately
53+ * Recording can happen in one of three modes:
54+ * - session: Record the whole session, sending it continuously
55+ * - error: Always keep the last 60s of recording, and when an error occurs, send the replay
56+ * - buffer: Always keep the last 60s of recording, requires calling `capture()` to send the replay
5657 */
5758 public recordingMode : ReplayRecordingMode = 'session' ;
5859
@@ -155,49 +156,72 @@ export class ReplayContainer implements ReplayContainerInterface {
155156 }
156157
157158 /**
158- * Initializes the plugin.
159- *
160- * Creates or loads a session, attaches listeners to varying events (DOM,
161- * _performanceObserver, Recording, Sentry SDK, etc)
159+ * Initializes the plugin based on configuration options. Should not be called outside of constructor
162160 */
163- public start ( ) : void {
164- this . setInitialState ( ) ;
161+ public initializeSampling ( ) : void {
162+ const { errorSampleRate , sessionSampleRate } = this . _options ;
165163
166- if ( ! this . _loadAndCheckSession ( ) ) {
164+ // if neither sample rate is > 0, then do nothing
165+ if ( errorSampleRate <= 0 && sessionSampleRate <= 0 ) {
166+ return ;
167+ }
168+
169+ // Otherwise if there is _any_ sample rate set, try to load/create session
170+ const isSessionSampled = this . _loadAndCheckSession ( ) ;
171+
172+ if ( ! isSessionSampled ) {
173+ // This should only occur if `errorSampleRate` is 0 and was unsampled for
174+ // session-based replay. In this case there is nothing to do.
167175 return ;
168176 }
169177
170- // If there is no session, then something bad has happened - can't continue
171178 if ( ! this . session ) {
172- this . _handleException ( new Error ( 'No session found' ) ) ;
179+ // This should not happen, something wrong has occurred
180+ this . _handleException ( new Error ( 'Unable to initialize and create session' ) ) ;
173181 return ;
174182 }
175183
176- if ( ! this . session . sampled ) {
177- // If session was not sampled, then we do not initialize the integration at all.
184+ // Only call start if this session is sampled for session-based replays
185+ if ( this . session && this . session . sampled === 'session' ) {
186+ this . _initializeRecording ( ) ;
178187 return ;
179188 }
180189
181- // If session is sampled for errors, then we need to set the recordingMode
182- // to ' error', which will configure recording with different options.
190+ // If not sampled as session-based, it will always be sampled as
191+ // error-based if `errorSampleRate` is > 0
183192 if ( this . session . sampled === 'error' ) {
193+ // If session is sampled for errors, then we need to set the recordingMode
194+ // to 'error', which will configure recording with different options.
184195 this . recordingMode = 'error' ;
196+ this . _initializeRecording ( ) ;
185197 }
186198
187- // setup() is generally called on page load or manually - in both cases we
188- // should treat it as an activity
189- this . _updateSessionActivity ( ) ;
199+ // There should be no other cases
200+ }
190201
191- this . eventBuffer = createEventBuffer ( {
192- useCompression : this . _options . useCompression ,
193- } ) ;
202+ /**
203+ * Create and start a replay.
204+ *
205+ * Creates or loads a session, attaches listeners to varying events (DOM,
206+ * _performanceObserver, Recording, Sentry SDK, etc)
207+ */
208+ public start ( ) : void {
209+ // TODO: Should we allow you to call start if there is an existing replay in progress?
194210
195- this . _addListeners ( ) ;
211+ const previousSessionId = this . session && this . session . id ;
196212
197- // Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
198- this . _isEnabled = true ;
213+ const { session } = getSession ( {
214+ timeouts : this . timeouts ,
215+ stickySession : Boolean ( this . _options . stickySession ) ,
216+ currentSession : this . session ,
217+ sessionSampleRate : 1 ,
218+ errorSampleRate : 0 ,
219+ } ) ;
199220
200- this . startRecording ( ) ;
221+ session . previousSessionId = previousSessionId ;
222+ this . session = session ;
223+
224+ this . _initializeRecording ( ) ;
201225 }
202226
203227 /**
@@ -483,6 +507,30 @@ export class ReplayContainer implements ReplayContainerInterface {
483507 this . _context . urls . push ( url ) ;
484508 }
485509
510+ /**
511+ * Initialize and start all listeners to varying events (DOM,
512+ * Performance Observer, Recording, Sentry SDK, etc)
513+ */
514+ private _initializeRecording ( ) : void {
515+ this . setInitialState ( ) ;
516+
517+ // this method is generally called on page load or manually - in both cases
518+ // we should treat it as an activity
519+ this . _updateSessionActivity ( ) ;
520+
521+ this . eventBuffer = createEventBuffer ( {
522+ useCompression : this . _options . useCompression ,
523+ } ) ;
524+
525+ // TODO: we should probably remove listeners before adding listeners
526+ this . _addListeners ( ) ;
527+
528+ // Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
529+ this . _isEnabled = true ;
530+
531+ this . startRecording ( ) ;
532+ }
533+
486534 /** A wrapper to conditionally capture exceptions. */
487535 private _handleException ( error : unknown ) : void {
488536 __DEBUG_BUILD__ && logger . error ( '[Replay]' , error ) ;
0 commit comments