@@ -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 ,
@@ -29,6 +28,7 @@ import { createBreadcrumb } from './util/createBreadcrumb';
29
28
import { createPerformanceEntries } from './util/createPerformanceEntries' ;
30
29
import { createPerformanceSpans } from './util/createPerformanceSpans' ;
31
30
import { debounce } from './util/debounce' ;
31
+ import { getHandleRecordingEmit } from './util/handleRecordingEmit' ;
32
32
import { isExpired } from './util/isExpired' ;
33
33
import { isSessionExpired } from './util/isSessionExpired' ;
34
34
import { overwriteRecordDroppedEvent , restoreRecordDroppedEvent } from './util/monkeyPatchRecordDroppedEvent' ;
@@ -145,7 +145,7 @@ export class ReplayContainer implements ReplayContainerInterface {
145
145
* _performanceObserver, Recording, Sentry SDK, etc)
146
146
*/
147
147
public start ( ) : void {
148
- this . _setInitialState ( ) ;
148
+ this . setInitialState ( ) ;
149
149
150
150
if ( ! this . _loadAndCheckSession ( ) ) {
151
151
return ;
@@ -197,7 +197,7 @@ export class ReplayContainer implements ReplayContainerInterface {
197
197
// Without this, it would record forever, until an error happens, which we don't want
198
198
// instead, we'll always keep the last 60 seconds of replay before an error happened
199
199
...( this . recordingMode === 'error' && { checkoutEveryNms : ERROR_CHECKOUT_TIME } ) ,
200
- emit : this . _handleRecordingEmit ,
200
+ emit : getHandleRecordingEmit ( this ) ,
201
201
} ) ;
202
202
} catch ( err ) {
203
203
this . _handleException ( err ) ;
@@ -393,6 +393,25 @@ export class ReplayContainer implements ReplayContainerInterface {
393
393
return false ;
394
394
}
395
395
396
+ /**
397
+ * Capture some initial state that can change throughout the lifespan of the
398
+ * replay. This is required because otherwise they would be captured at the
399
+ * first flush.
400
+ */
401
+ public setInitialState ( ) : void {
402
+ const urlPath = `${ WINDOW . location . pathname } ${ WINDOW . location . hash } ${ WINDOW . location . search } ` ;
403
+ const url = `${ WINDOW . location . origin } ${ urlPath } ` ;
404
+
405
+ this . performanceEvents = [ ] ;
406
+
407
+ // Reset _context as well
408
+ this . _clearContext ( ) ;
409
+
410
+ this . _context . initialUrl = url ;
411
+ this . _context . initialTimestamp = new Date ( ) . getTime ( ) ;
412
+ this . _context . urls . push ( url ) ;
413
+ }
414
+
396
415
/** A wrapper to conditionally capture exceptions. */
397
416
private _handleException ( error : unknown ) : void {
398
417
__DEBUG_BUILD__ && logger . error ( '[Replay]' , error ) ;
@@ -418,7 +437,7 @@ export class ReplayContainer implements ReplayContainerInterface {
418
437
// If session was newly created (i.e. was not loaded from storage), then
419
438
// enable flag to create the root replay
420
439
if ( type === 'new' ) {
421
- this . _setInitialState ( ) ;
440
+ this . setInitialState ( ) ;
422
441
}
423
442
424
443
const currentSessionId = this . getSessionId ( ) ;
@@ -436,25 +455,6 @@ export class ReplayContainer implements ReplayContainerInterface {
436
455
return true ;
437
456
}
438
457
439
- /**
440
- * Capture some initial state that can change throughout the lifespan of the
441
- * replay. This is required because otherwise they would be captured at the
442
- * first flush.
443
- */
444
- private _setInitialState ( ) : void {
445
- const urlPath = `${ WINDOW . location . pathname } ${ WINDOW . location . hash } ${ WINDOW . location . search } ` ;
446
- const url = `${ WINDOW . location . origin } ${ urlPath } ` ;
447
-
448
- this . performanceEvents = [ ] ;
449
-
450
- // Reset _context as well
451
- this . _clearContext ( ) ;
452
-
453
- this . _context . initialUrl = url ;
454
- this . _context . initialTimestamp = new Date ( ) . getTime ( ) ;
455
- this . _context . urls . push ( url ) ;
456
- }
457
-
458
458
/**
459
459
* Adds listeners to record events for the replay
460
460
*/
@@ -506,72 +506,6 @@ export class ReplayContainer implements ReplayContainerInterface {
506
506
}
507
507
}
508
508
509
- /**
510
- * Handler for recording events.
511
- *
512
- * Adds to event buffer, and has varying flushing behaviors if the event was a checkout.
513
- */
514
- private _handleRecordingEmit : ( event : RecordingEvent , isCheckout ?: boolean ) => void = (
515
- event : RecordingEvent ,
516
- isCheckout ?: boolean ,
517
- ) => {
518
- // If this is false, it means session is expired, create and a new session and wait for checkout
519
- if ( ! this . checkAndHandleExpiredSession ( ) ) {
520
- __DEBUG_BUILD__ && logger . error ( '[Replay] Received replay event after session expired.' ) ;
521
-
522
- return ;
523
- }
524
-
525
- this . addUpdate ( ( ) => {
526
- // The session is always started immediately on pageload/init, but for
527
- // error-only replays, it should reflect the most recent checkout
528
- // when an error occurs. Clear any state that happens before this current
529
- // checkout. This needs to happen before `addEvent()` which updates state
530
- // dependent on this reset.
531
- if ( this . recordingMode === 'error' && event . type === 2 ) {
532
- this . _setInitialState ( ) ;
533
- }
534
-
535
- // We need to clear existing events on a checkout, otherwise they are
536
- // incremental event updates and should be appended
537
- void addEvent ( this , event , isCheckout ) ;
538
-
539
- // Different behavior for full snapshots (type=2), ignore other event types
540
- // See https://github.com/rrweb-io/rrweb/blob/d8f9290ca496712aa1e7d472549480c4e7876594/packages/rrweb/src/types.ts#L16
541
- if ( event . type !== 2 ) {
542
- return false ;
543
- }
544
-
545
- // If there is a previousSessionId after a full snapshot occurs, then
546
- // the replay session was started due to session expiration. The new session
547
- // is started before triggering a new checkout and contains the id
548
- // of the previous session. Do not immediately flush in this case
549
- // to avoid capturing only the checkout and instead the replay will
550
- // be captured if they perform any follow-up actions.
551
- if ( this . session && this . session . previousSessionId ) {
552
- return true ;
553
- }
554
-
555
- // See note above re: session start needs to reflect the most recent
556
- // checkout.
557
- if ( this . recordingMode === 'error' && this . session && this . _context . earliestEvent ) {
558
- this . session . started = this . _context . earliestEvent ;
559
- this . _maybeSaveSession ( ) ;
560
- }
561
-
562
- // Flush immediately so that we do not miss the first segment, otherwise
563
- // it can prevent loading on the UI. This will cause an increase in short
564
- // replays (e.g. opening and closing a tab quickly), but these can be
565
- // filtered on the UI.
566
- if ( this . recordingMode === 'session' ) {
567
- // We want to ensure the worker is ready, as otherwise we'd always send the first event uncompressed
568
- void this . flushImmediate ( ) ;
569
- }
570
-
571
- return true ;
572
- } ) ;
573
- } ;
574
-
575
509
/**
576
510
* Handle when visibility of the page content changes. Opening a new tab will
577
511
* cause the state to change to hidden because of content of current page will
0 commit comments