@@ -16,7 +16,6 @@ import type {
16
16
EventBuffer ,
17
17
InternalEventContext ,
18
18
PopEventContext ,
19
- RecordingEvent ,
20
19
RecordingOptions ,
21
20
ReplayContainer as ReplayContainerInterface ,
22
21
ReplayPluginOptions ,
@@ -30,6 +29,7 @@ import { createBreadcrumb } from './util/createBreadcrumb';
30
29
import { createPerformanceEntries } from './util/createPerformanceEntries' ;
31
30
import { createPerformanceSpans } from './util/createPerformanceSpans' ;
32
31
import { debounce } from './util/debounce' ;
32
+ import { getHandleRecordingEmit } from './util/handleRecordingEmit' ;
33
33
import { isExpired } from './util/isExpired' ;
34
34
import { isSessionExpired } from './util/isSessionExpired' ;
35
35
import { overwriteRecordDroppedEvent , restoreRecordDroppedEvent } from './util/monkeyPatchRecordDroppedEvent' ;
@@ -155,7 +155,7 @@ export class ReplayContainer implements ReplayContainerInterface {
155
155
* _performanceObserver, Recording, Sentry SDK, etc)
156
156
*/
157
157
public start ( ) : void {
158
- this . _setInitialState ( ) ;
158
+ this . setInitialState ( ) ;
159
159
160
160
if ( ! this . _loadAndCheckSession ( ) ) {
161
161
return ;
@@ -207,7 +207,7 @@ export class ReplayContainer implements ReplayContainerInterface {
207
207
// Without this, it would record forever, until an error happens, which we don't want
208
208
// instead, we'll always keep the last 60 seconds of replay before an error happened
209
209
...( this . recordingMode === 'error' && { checkoutEveryNms : ERROR_CHECKOUT_TIME } ) ,
210
- emit : this . _handleRecordingEmit ,
210
+ emit : getHandleRecordingEmit ( this ) ,
211
211
onMutation : ( mutations : unknown [ ] ) => {
212
212
if ( this . _options . _experiments . captureMutationSize ) {
213
213
const count = mutations . length ;
@@ -420,6 +420,25 @@ export class ReplayContainer implements ReplayContainerInterface {
420
420
return false ;
421
421
}
422
422
423
+ /**
424
+ * Capture some initial state that can change throughout the lifespan of the
425
+ * replay. This is required because otherwise they would be captured at the
426
+ * first flush.
427
+ */
428
+ public setInitialState ( ) : void {
429
+ const urlPath = `${ WINDOW . location . pathname } ${ WINDOW . location . hash } ${ WINDOW . location . search } ` ;
430
+ const url = `${ WINDOW . location . origin } ${ urlPath } ` ;
431
+
432
+ this . performanceEvents = [ ] ;
433
+
434
+ // Reset _context as well
435
+ this . _clearContext ( ) ;
436
+
437
+ this . _context . initialUrl = url ;
438
+ this . _context . initialTimestamp = new Date ( ) . getTime ( ) ;
439
+ this . _context . urls . push ( url ) ;
440
+ }
441
+
423
442
/** A wrapper to conditionally capture exceptions. */
424
443
private _handleException ( error : unknown ) : void {
425
444
__DEBUG_BUILD__ && logger . error ( '[Replay]' , error ) ;
@@ -445,7 +464,7 @@ export class ReplayContainer implements ReplayContainerInterface {
445
464
// If session was newly created (i.e. was not loaded from storage), then
446
465
// enable flag to create the root replay
447
466
if ( type === 'new' ) {
448
- this . _setInitialState ( ) ;
467
+ this . setInitialState ( ) ;
449
468
}
450
469
451
470
const currentSessionId = this . getSessionId ( ) ;
@@ -463,25 +482,6 @@ export class ReplayContainer implements ReplayContainerInterface {
463
482
return true ;
464
483
}
465
484
466
- /**
467
- * Capture some initial state that can change throughout the lifespan of the
468
- * replay. This is required because otherwise they would be captured at the
469
- * first flush.
470
- */
471
- private _setInitialState ( ) : void {
472
- const urlPath = `${ WINDOW . location . pathname } ${ WINDOW . location . hash } ${ WINDOW . location . search } ` ;
473
- const url = `${ WINDOW . location . origin } ${ urlPath } ` ;
474
-
475
- this . performanceEvents = [ ] ;
476
-
477
- // Reset _context as well
478
- this . _clearContext ( ) ;
479
-
480
- this . _context . initialUrl = url ;
481
- this . _context . initialTimestamp = new Date ( ) . getTime ( ) ;
482
- this . _context . urls . push ( url ) ;
483
- }
484
-
485
485
/**
486
486
* Adds listeners to record events for the replay
487
487
*/
@@ -533,72 +533,6 @@ export class ReplayContainer implements ReplayContainerInterface {
533
533
}
534
534
}
535
535
536
- /**
537
- * Handler for recording events.
538
- *
539
- * Adds to event buffer, and has varying flushing behaviors if the event was a checkout.
540
- */
541
- private _handleRecordingEmit : ( event : RecordingEvent , isCheckout ?: boolean ) => void = (
542
- event : RecordingEvent ,
543
- isCheckout ?: boolean ,
544
- ) => {
545
- // If this is false, it means session is expired, create and a new session and wait for checkout
546
- if ( ! this . checkAndHandleExpiredSession ( ) ) {
547
- __DEBUG_BUILD__ && logger . warn ( '[Replay] Received replay event after session expired.' ) ;
548
-
549
- return ;
550
- }
551
-
552
- this . addUpdate ( ( ) => {
553
- // The session is always started immediately on pageload/init, but for
554
- // error-only replays, it should reflect the most recent checkout
555
- // when an error occurs. Clear any state that happens before this current
556
- // checkout. This needs to happen before `addEvent()` which updates state
557
- // dependent on this reset.
558
- if ( this . recordingMode === 'error' && event . type === 2 ) {
559
- this . _setInitialState ( ) ;
560
- }
561
-
562
- // We need to clear existing events on a checkout, otherwise they are
563
- // incremental event updates and should be appended
564
- void addEvent ( this , event , isCheckout ) ;
565
-
566
- // Different behavior for full snapshots (type=2), ignore other event types
567
- // See https://github.com/rrweb-io/rrweb/blob/d8f9290ca496712aa1e7d472549480c4e7876594/packages/rrweb/src/types.ts#L16
568
- if ( event . type !== 2 ) {
569
- return false ;
570
- }
571
-
572
- // If there is a previousSessionId after a full snapshot occurs, then
573
- // the replay session was started due to session expiration. The new session
574
- // is started before triggering a new checkout and contains the id
575
- // of the previous session. Do not immediately flush in this case
576
- // to avoid capturing only the checkout and instead the replay will
577
- // be captured if they perform any follow-up actions.
578
- if ( this . session && this . session . previousSessionId ) {
579
- return true ;
580
- }
581
-
582
- // See note above re: session start needs to reflect the most recent
583
- // checkout.
584
- if ( this . recordingMode === 'error' && this . session && this . _context . earliestEvent ) {
585
- this . session . started = this . _context . earliestEvent ;
586
- this . _maybeSaveSession ( ) ;
587
- }
588
-
589
- // Flush immediately so that we do not miss the first segment, otherwise
590
- // it can prevent loading on the UI. This will cause an increase in short
591
- // replays (e.g. opening and closing a tab quickly), but these can be
592
- // filtered on the UI.
593
- if ( this . recordingMode === 'session' ) {
594
- // We want to ensure the worker is ready, as otherwise we'd always send the first event uncompressed
595
- void this . flushImmediate ( ) ;
596
- }
597
-
598
- return true ;
599
- } ) ;
600
- } ;
601
-
602
536
/**
603
537
* Handle when visibility of the page content changes. Opening a new tab will
604
538
* cause the state to change to hidden because of content of current page will
0 commit comments