@@ -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
} ) ;
212
212
} catch ( err ) {
213
213
this . _handleException ( err ) ;
@@ -403,6 +403,25 @@ export class ReplayContainer implements ReplayContainerInterface {
403
403
return false ;
404
404
}
405
405
406
+ /**
407
+ * Capture some initial state that can change throughout the lifespan of the
408
+ * replay. This is required because otherwise they would be captured at the
409
+ * first flush.
410
+ */
411
+ public setInitialState ( ) : void {
412
+ const urlPath = `${ WINDOW . location . pathname } ${ WINDOW . location . hash } ${ WINDOW . location . search } ` ;
413
+ const url = `${ WINDOW . location . origin } ${ urlPath } ` ;
414
+
415
+ this . performanceEvents = [ ] ;
416
+
417
+ // Reset _context as well
418
+ this . _clearContext ( ) ;
419
+
420
+ this . _context . initialUrl = url ;
421
+ this . _context . initialTimestamp = new Date ( ) . getTime ( ) ;
422
+ this . _context . urls . push ( url ) ;
423
+ }
424
+
406
425
/** A wrapper to conditionally capture exceptions. */
407
426
private _handleException ( error : unknown ) : void {
408
427
__DEBUG_BUILD__ && logger . error ( '[Replay]' , error ) ;
@@ -428,7 +447,7 @@ export class ReplayContainer implements ReplayContainerInterface {
428
447
// If session was newly created (i.e. was not loaded from storage), then
429
448
// enable flag to create the root replay
430
449
if ( type === 'new' ) {
431
- this . _setInitialState ( ) ;
450
+ this . setInitialState ( ) ;
432
451
}
433
452
434
453
const currentSessionId = this . getSessionId ( ) ;
@@ -446,25 +465,6 @@ export class ReplayContainer implements ReplayContainerInterface {
446
465
return true ;
447
466
}
448
467
449
- /**
450
- * Capture some initial state that can change throughout the lifespan of the
451
- * replay. This is required because otherwise they would be captured at the
452
- * first flush.
453
- */
454
- private _setInitialState ( ) : void {
455
- const urlPath = `${ WINDOW . location . pathname } ${ WINDOW . location . hash } ${ WINDOW . location . search } ` ;
456
- const url = `${ WINDOW . location . origin } ${ urlPath } ` ;
457
-
458
- this . performanceEvents = [ ] ;
459
-
460
- // Reset _context as well
461
- this . _clearContext ( ) ;
462
-
463
- this . _context . initialUrl = url ;
464
- this . _context . initialTimestamp = new Date ( ) . getTime ( ) ;
465
- this . _context . urls . push ( url ) ;
466
- }
467
-
468
468
/**
469
469
* Adds listeners to record events for the replay
470
470
*/
@@ -516,72 +516,6 @@ export class ReplayContainer implements ReplayContainerInterface {
516
516
}
517
517
}
518
518
519
- /**
520
- * Handler for recording events.
521
- *
522
- * Adds to event buffer, and has varying flushing behaviors if the event was a checkout.
523
- */
524
- private _handleRecordingEmit : ( event : RecordingEvent , isCheckout ?: boolean ) => void = (
525
- event : RecordingEvent ,
526
- isCheckout ?: boolean ,
527
- ) => {
528
- // If this is false, it means session is expired, create and a new session and wait for checkout
529
- if ( ! this . checkAndHandleExpiredSession ( ) ) {
530
- __DEBUG_BUILD__ && logger . warn ( '[Replay] Received replay event after session expired.' ) ;
531
-
532
- return ;
533
- }
534
-
535
- this . addUpdate ( ( ) => {
536
- // The session is always started immediately on pageload/init, but for
537
- // error-only replays, it should reflect the most recent checkout
538
- // when an error occurs. Clear any state that happens before this current
539
- // checkout. This needs to happen before `addEvent()` which updates state
540
- // dependent on this reset.
541
- if ( this . recordingMode === 'error' && event . type === 2 ) {
542
- this . _setInitialState ( ) ;
543
- }
544
-
545
- // We need to clear existing events on a checkout, otherwise they are
546
- // incremental event updates and should be appended
547
- void addEvent ( this , event , isCheckout ) ;
548
-
549
- // Different behavior for full snapshots (type=2), ignore other event types
550
- // See https://github.com/rrweb-io/rrweb/blob/d8f9290ca496712aa1e7d472549480c4e7876594/packages/rrweb/src/types.ts#L16
551
- if ( event . type !== 2 ) {
552
- return false ;
553
- }
554
-
555
- // If there is a previousSessionId after a full snapshot occurs, then
556
- // the replay session was started due to session expiration. The new session
557
- // is started before triggering a new checkout and contains the id
558
- // of the previous session. Do not immediately flush in this case
559
- // to avoid capturing only the checkout and instead the replay will
560
- // be captured if they perform any follow-up actions.
561
- if ( this . session && this . session . previousSessionId ) {
562
- return true ;
563
- }
564
-
565
- // See note above re: session start needs to reflect the most recent
566
- // checkout.
567
- if ( this . recordingMode === 'error' && this . session && this . _context . earliestEvent ) {
568
- this . session . started = this . _context . earliestEvent ;
569
- this . _maybeSaveSession ( ) ;
570
- }
571
-
572
- // Flush immediately so that we do not miss the first segment, otherwise
573
- // it can prevent loading on the UI. This will cause an increase in short
574
- // replays (e.g. opening and closing a tab quickly), but these can be
575
- // filtered on the UI.
576
- if ( this . recordingMode === 'session' ) {
577
- // We want to ensure the worker is ready, as otherwise we'd always send the first event uncompressed
578
- void this . flushImmediate ( ) ;
579
- }
580
-
581
- return true ;
582
- } ) ;
583
- } ;
584
-
585
519
/**
586
520
* Handle when visibility of the page content changes. Opening a new tab will
587
521
* cause the state to change to hidden because of content of current page will
0 commit comments