From 32408bc89ba4720056411c20894ad665c426fa08 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 13 Feb 2021 20:40:30 -0600 Subject: [PATCH 1/8] Added support for inactive threshold --- src/replay/index.ts | 79 ++++++++++++++++++++++----------------- src/types.ts | 2 + typings/replay/index.d.ts | 2 + typings/types.d.ts | 2 + 4 files changed, 51 insertions(+), 34 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 95a15a4e..0f726eef 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -101,6 +101,7 @@ export class Replayer { private emitter: Emitter = mitt(); + private nextTimestamp: number | null; private nextUserInteractionEvent: eventWithTime | null; // tslint:disable-next-line: variable-name @@ -135,6 +136,7 @@ export class Replayer { pauseAnimation: true, mouseTail: defaultMouseTailConfig, logConfig: defaultLogConfig, + inactiveThreshold: 0.02, }; this.config = Object.assign({}, defaultConfig, config); if (!this.config.logConfig.replayLogger) @@ -253,21 +255,34 @@ export class Replayer { if ( _event.timestamp! - currEvent.timestamp! > SKIP_TIME_THRESHOLD) { - allPeriods.push({startTime: currEvent.timestamp!, endTime: _event.timestamp!, active: false}) + allPeriods.push({startTime: currEvent.timestamp!, endTime: _event.timestamp!, duration: _event.timestamp! - currEvent.timestamp!, active: false}) } else { - allPeriods.push({startTime: currEvent.timestamp!, endTime: _event.timestamp!, active: true}) + allPeriods.push({startTime: currEvent.timestamp!, endTime: _event.timestamp!, duration: _event.timestamp! - currEvent.timestamp!, active: true}) } } // Merges continuous active/inactive ranges + const mergedIntervals: Array = []; let currEvent = allPeriods[0]; for (let i = 1; i < allPeriods.length; i++) { if (allPeriods[i].active != allPeriods[i-1].active) { - this.activityIntervals.push({startTime: currEvent.startTime, endTime: allPeriods[i-1].endTime, active: allPeriods[i-1].active}) + mergedIntervals.push({startTime: currEvent.startTime, endTime: allPeriods[i-1].endTime, duration: allPeriods[i-1].endTime - currEvent.startTime, active: allPeriods[i-1].active}) currEvent = allPeriods[i]; } } if (currEvent && allPeriods.length > 0) { - this.activityIntervals.push({startTime: currEvent.startTime, endTime: allPeriods[allPeriods.length-1].endTime, active: allPeriods[allPeriods.length-1].active}) + mergedIntervals.push({startTime: currEvent.startTime, endTime: allPeriods[allPeriods.length-1].endTime, duration: allPeriods[allPeriods.length-1].endTime - currEvent.startTime, active: allPeriods[allPeriods.length-1].active}) + } + // Merges inactive segments that are less than a threshold into surrounding active sessions (start: 18 segments) + const metadata = this.getMetaData(); + currEvent = mergedIntervals[0]; + for (let i = 1; i < mergedIntervals.length; i++) { + if ((!mergedIntervals[i].active && mergedIntervals[i].duration > this.config.inactiveThreshold * metadata.totalTime) || (!mergedIntervals[i-1].active && mergedIntervals[i-1].duration > this.config.inactiveThreshold * metadata.totalTime)) { + this.activityIntervals.push({startTime: currEvent.startTime, endTime: mergedIntervals[i-1].endTime, duration: mergedIntervals[i-1].endTime - currEvent.startTime, active: mergedIntervals[i-1].active}) + currEvent = mergedIntervals[i]; + } + } + if (currEvent && mergedIntervals.length > 0) { + this.activityIntervals.push({startTime: currEvent.startTime, endTime: mergedIntervals[mergedIntervals.length-1].endTime, duration: mergedIntervals[mergedIntervals.length-1].endTime - currEvent.startTime, active: mergedIntervals[mergedIntervals.length-1].active}) } } @@ -355,6 +370,7 @@ export class Replayer { ?.getElementsByTagName('html')[0] .classList.remove('rrweb-paused'); this.emitter.emit(ReplayerEvents.Start); + this.isTimestampInactive(this.getMetaData().startTime + timeOffset, true); } public pause(timeOffset?: number) { @@ -485,36 +501,7 @@ export class Replayer { // do not check skip in sync return; } - if (event === this.nextUserInteractionEvent) { - this.nextUserInteractionEvent = null; - this.backToNormal(); - } - if (this.config.skipInactive && !this.nextUserInteractionEvent) { - for (const _event of this.service.state.context.events) { - if (_event.timestamp! <= event.timestamp!) { - continue; - } - if (this.isUserInteraction(_event)) { - if ( - _event.delay! - event.delay! > - SKIP_TIME_THRESHOLD * - this.speedService.state.context.timer.speed - ) { - this.nextUserInteractionEvent = _event; - } - break; - } - } - if (this.nextUserInteractionEvent) { - const skipTime = - this.nextUserInteractionEvent.delay! - event.delay!; - const payload = { - speed: Math.min(Math.round(skipTime / SKIP_TIME_INTERVAL), 360), - }; - this.speedService.send({ type: 'FAST_FORWARD', payload }); - this.emitter.emit(ReplayerEvents.SkipStart, payload); - } - } + this.isTimestampInactive(event.timestamp); }; break; default: @@ -552,6 +539,30 @@ export class Replayer { return wrappedCastFn; } + private isTimestampInactive(timestamp: number, resetNext?: boolean) { + if (timestamp === this.nextTimestamp || resetNext) { + this.nextTimestamp = null; + this.backToNormal(); + } + if (this.config.skipInactive && !this.nextTimestamp) { + for (const interval of this.activityIntervals) { + if (timestamp >= interval.startTime! && timestamp < interval.endTime! && !(interval.active)) { + this.nextTimestamp = interval.endTime; + break; + } + } + if (this.nextTimestamp) { + const skipTime = + this.nextTimestamp! - timestamp!; + const payload = { + speed: Math.min(Math.round(skipTime / SKIP_TIME_INTERVAL), 360), + }; + this.speedService.send({ type: 'FAST_FORWARD', payload }); + this.emitter.emit(ReplayerEvents.SkipStart, payload); + } + } + } + private rebuildFullSnapshot( event: fullSnapshotEvent & { timestamp: number }, isSync: boolean = false, diff --git a/src/types.ts b/src/types.ts index bb14767a..919b445d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,6 +20,7 @@ export enum EventType { export type SessionInterval = { startTime: number; endTime: number; + duration: number; active: boolean; } @@ -502,6 +503,7 @@ export type playerConfig = { }; unpackFn?: UnpackFn; logConfig: LogReplayConfig; + inactiveThreshold: number; }; export type LogReplayConfig = { diff --git a/typings/replay/index.d.ts b/typings/replay/index.d.ts index ac3def5e..8c942b03 100644 --- a/typings/replay/index.d.ts +++ b/typings/replay/index.d.ts @@ -13,6 +13,7 @@ export declare class Replayer { private mouseTail; private tailPositions; private emitter; + private nextTimestamp; private nextUserInteractionEvent; private legacy_missingNodeRetryMap; private treeIndex; @@ -37,6 +38,7 @@ export declare class Replayer { private setupDom; private handleResize; private getCastFn; + private isTimestampInactive; private rebuildFullSnapshot; private waitForStylesheetLoad; private preloadAllImages; diff --git a/typings/types.d.ts b/typings/types.d.ts index dafe5811..199e684a 100644 --- a/typings/types.d.ts +++ b/typings/types.d.ts @@ -13,6 +13,7 @@ export declare enum EventType { export declare type SessionInterval = { startTime: number; endTime: number; + duration: number; active: boolean; }; export declare type domContentLoadedEvent = { @@ -365,6 +366,7 @@ export declare type playerConfig = { }; unpackFn?: UnpackFn; logConfig: LogReplayConfig; + inactiveThreshold: number; }; export declare type LogReplayConfig = { level?: Array | undefined; From a83de51ec567f624638bc9f78846ee5d8bfa5a25 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 13 Feb 2021 20:42:11 -0600 Subject: [PATCH 2/8] Updated version num --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3724354b..15d3025a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@highlight-run/rrweb", - "version": "0.9.23", + "version": "0.9.24", "description": "record and replay the web", "scripts": { "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.test.ts", From 599d268dd6dbf7ba3d53e2ce6ed1b691d598abfb Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 13 Feb 2021 20:53:31 -0600 Subject: [PATCH 3/8] Prettified --- src/replay/index.ts | 84 +++++++++++++++++++++++++++++++++++---------- src/types.ts | 2 +- 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 0f726eef..1ccbca20 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -248,41 +248,84 @@ export class Replayer { // Preprocessing to get all active/inactive segments in a session const allPeriods: Array = []; const firstEvent = this.service.state.context.events[0]; - const userInteractionEvents = [firstEvent, ...this.service.state.context.events.filter((ev) => this.isUserInteraction(ev))] + const userInteractionEvents = [ + firstEvent, + ...this.service.state.context.events.filter((ev) => + this.isUserInteraction(ev), + ), + ]; for (let i = 1; i < userInteractionEvents.length; i++) { - const currEvent = userInteractionEvents[i - 1] - const _event = userInteractionEvents[i] - if ( - _event.timestamp! - currEvent.timestamp! > - SKIP_TIME_THRESHOLD) { - allPeriods.push({startTime: currEvent.timestamp!, endTime: _event.timestamp!, duration: _event.timestamp! - currEvent.timestamp!, active: false}) - } else { - allPeriods.push({startTime: currEvent.timestamp!, endTime: _event.timestamp!, duration: _event.timestamp! - currEvent.timestamp!, active: true}) - } + const currEvent = userInteractionEvents[i - 1]; + const _event = userInteractionEvents[i]; + if (_event.timestamp! - currEvent.timestamp! > SKIP_TIME_THRESHOLD) { + allPeriods.push({ + startTime: currEvent.timestamp!, + endTime: _event.timestamp!, + duration: _event.timestamp! - currEvent.timestamp!, + active: false, + }); + } else { + allPeriods.push({ + startTime: currEvent.timestamp!, + endTime: _event.timestamp!, + duration: _event.timestamp! - currEvent.timestamp!, + active: true, + }); + } } // Merges continuous active/inactive ranges const mergedIntervals: Array = []; let currEvent = allPeriods[0]; for (let i = 1; i < allPeriods.length; i++) { - if (allPeriods[i].active != allPeriods[i-1].active) { - mergedIntervals.push({startTime: currEvent.startTime, endTime: allPeriods[i-1].endTime, duration: allPeriods[i-1].endTime - currEvent.startTime, active: allPeriods[i-1].active}) + if (allPeriods[i].active != allPeriods[i - 1].active) { + mergedIntervals.push({ + startTime: currEvent.startTime, + endTime: allPeriods[i - 1].endTime, + duration: allPeriods[i - 1].endTime - currEvent.startTime, + active: allPeriods[i - 1].active, + }); currEvent = allPeriods[i]; } } if (currEvent && allPeriods.length > 0) { - mergedIntervals.push({startTime: currEvent.startTime, endTime: allPeriods[allPeriods.length-1].endTime, duration: allPeriods[allPeriods.length-1].endTime - currEvent.startTime, active: allPeriods[allPeriods.length-1].active}) + mergedIntervals.push({ + startTime: currEvent.startTime, + endTime: allPeriods[allPeriods.length - 1].endTime, + duration: + allPeriods[allPeriods.length - 1].endTime - currEvent.startTime, + active: allPeriods[allPeriods.length - 1].active, + }); } // Merges inactive segments that are less than a threshold into surrounding active sessions (start: 18 segments) const metadata = this.getMetaData(); currEvent = mergedIntervals[0]; for (let i = 1; i < mergedIntervals.length; i++) { - if ((!mergedIntervals[i].active && mergedIntervals[i].duration > this.config.inactiveThreshold * metadata.totalTime) || (!mergedIntervals[i-1].active && mergedIntervals[i-1].duration > this.config.inactiveThreshold * metadata.totalTime)) { - this.activityIntervals.push({startTime: currEvent.startTime, endTime: mergedIntervals[i-1].endTime, duration: mergedIntervals[i-1].endTime - currEvent.startTime, active: mergedIntervals[i-1].active}) + if ( + (!mergedIntervals[i].active && + mergedIntervals[i].duration > + this.config.inactiveThreshold * metadata.totalTime) || + (!mergedIntervals[i - 1].active && + mergedIntervals[i - 1].duration > + this.config.inactiveThreshold * metadata.totalTime) + ) { + this.activityIntervals.push({ + startTime: currEvent.startTime, + endTime: mergedIntervals[i - 1].endTime, + duration: mergedIntervals[i - 1].endTime - currEvent.startTime, + active: mergedIntervals[i - 1].active, + }); currEvent = mergedIntervals[i]; } } if (currEvent && mergedIntervals.length > 0) { - this.activityIntervals.push({startTime: currEvent.startTime, endTime: mergedIntervals[mergedIntervals.length-1].endTime, duration: mergedIntervals[mergedIntervals.length-1].endTime - currEvent.startTime, active: mergedIntervals[mergedIntervals.length-1].active}) + this.activityIntervals.push({ + startTime: currEvent.startTime, + endTime: mergedIntervals[mergedIntervals.length - 1].endTime, + duration: + mergedIntervals[mergedIntervals.length - 1].endTime - + currEvent.startTime, + active: mergedIntervals[mergedIntervals.length - 1].active, + }); } } @@ -546,14 +589,17 @@ export class Replayer { } if (this.config.skipInactive && !this.nextTimestamp) { for (const interval of this.activityIntervals) { - if (timestamp >= interval.startTime! && timestamp < interval.endTime! && !(interval.active)) { + if ( + timestamp >= interval.startTime! && + timestamp < interval.endTime! && + !interval.active + ) { this.nextTimestamp = interval.endTime; break; } } if (this.nextTimestamp) { - const skipTime = - this.nextTimestamp! - timestamp!; + const skipTime = this.nextTimestamp! - timestamp!; const payload = { speed: Math.min(Math.round(skipTime / SKIP_TIME_INTERVAL), 360), }; diff --git a/src/types.ts b/src/types.ts index 919b445d..c53304e9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -22,7 +22,7 @@ export type SessionInterval = { endTime: number; duration: number; active: boolean; -} +}; export type domContentLoadedEvent = { type: EventType.DomContentLoaded; From 63d4c4c5da2157304f4f4f9c3bd56f9a1be57fcf Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 16 Feb 2021 00:07:20 -0600 Subject: [PATCH 4/8] Fixed names --- package.json | 2 +- src/replay/index.ts | 37 +++++++++++++++++++------------------ typings/replay/index.d.ts | 2 +- typings/snapshot/types.d.ts | 4 +--- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index aba71d2e..b7f191b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@highlight-run/rrweb", - "version": "0.9.24", + "version": "0.9.25", "description": "record and replay the web", "scripts": { "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.test.ts", diff --git a/src/replay/index.ts b/src/replay/index.ts index 1ccbca20..bd83c14c 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -246,7 +246,7 @@ export class Replayer { }, 1); } // Preprocessing to get all active/inactive segments in a session - const allPeriods: Array = []; + const allIntervals: Array = []; const firstEvent = this.service.state.context.events[0]; const userInteractionEvents = [ firstEvent, @@ -258,14 +258,14 @@ export class Replayer { const currEvent = userInteractionEvents[i - 1]; const _event = userInteractionEvents[i]; if (_event.timestamp! - currEvent.timestamp! > SKIP_TIME_THRESHOLD) { - allPeriods.push({ + allIntervals.push({ startTime: currEvent.timestamp!, endTime: _event.timestamp!, duration: _event.timestamp! - currEvent.timestamp!, active: false, }); } else { - allPeriods.push({ + allIntervals.push({ startTime: currEvent.timestamp!, endTime: _event.timestamp!, duration: _event.timestamp! - currEvent.timestamp!, @@ -275,28 +275,29 @@ export class Replayer { } // Merges continuous active/inactive ranges const mergedIntervals: Array = []; - let currEvent = allPeriods[0]; - for (let i = 1; i < allPeriods.length; i++) { - if (allPeriods[i].active != allPeriods[i - 1].active) { + let currEvent = allIntervals[0]; + for (let i = 1; i < allIntervals.length; i++) { + if (allIntervals[i].active != allIntervals[i - 1].active) { mergedIntervals.push({ startTime: currEvent.startTime, - endTime: allPeriods[i - 1].endTime, - duration: allPeriods[i - 1].endTime - currEvent.startTime, - active: allPeriods[i - 1].active, + endTime: allIntervals[i - 1].endTime, + duration: allIntervals[i - 1].endTime - currEvent.startTime, + active: allIntervals[i - 1].active, }); - currEvent = allPeriods[i]; + currEvent = allIntervals[i]; } } - if (currEvent && allPeriods.length > 0) { + if (currEvent && allIntervals.length > 0) { mergedIntervals.push({ startTime: currEvent.startTime, - endTime: allPeriods[allPeriods.length - 1].endTime, + endTime: allIntervals[allIntervals.length - 1].endTime, duration: - allPeriods[allPeriods.length - 1].endTime - currEvent.startTime, - active: allPeriods[allPeriods.length - 1].active, + allIntervals[allIntervals.length - 1].endTime - currEvent.startTime, + active: allIntervals[allIntervals.length - 1].active, }); } - // Merges inactive segments that are less than a threshold into surrounding active sessions (start: 18 segments) + // Merges inactive segments that are less than a threshold into surrounding active sessions + // TODO: Change this from a 3n pass to n const metadata = this.getMetaData(); currEvent = mergedIntervals[0]; for (let i = 1; i < mergedIntervals.length; i++) { @@ -413,7 +414,7 @@ export class Replayer { ?.getElementsByTagName('html')[0] .classList.remove('rrweb-paused'); this.emitter.emit(ReplayerEvents.Start); - this.isTimestampInactive(this.getMetaData().startTime + timeOffset, true); + this.handleInactivity(this.getMetaData().startTime + timeOffset, true); } public pause(timeOffset?: number) { @@ -544,7 +545,7 @@ export class Replayer { // do not check skip in sync return; } - this.isTimestampInactive(event.timestamp); + this.handleInactivity(event.timestamp); }; break; default: @@ -582,7 +583,7 @@ export class Replayer { return wrappedCastFn; } - private isTimestampInactive(timestamp: number, resetNext?: boolean) { + private handleInactivity(timestamp: number, resetNext?: boolean) { if (timestamp === this.nextTimestamp || resetNext) { this.nextTimestamp = null; this.backToNormal(); diff --git a/typings/replay/index.d.ts b/typings/replay/index.d.ts index 8c942b03..03ea87bc 100644 --- a/typings/replay/index.d.ts +++ b/typings/replay/index.d.ts @@ -38,7 +38,7 @@ export declare class Replayer { private setupDom; private handleResize; private getCastFn; - private isTimestampInactive; + private handleInactivity; private rebuildFullSnapshot; private waitForStylesheetLoad; private preloadAllImages; diff --git a/typings/snapshot/types.d.ts b/typings/snapshot/types.d.ts index 8efab817..256abba5 100644 --- a/typings/snapshot/types.d.ts +++ b/typings/snapshot/types.d.ts @@ -40,9 +40,7 @@ export declare type commentNode = { type: NodeType.Comment; textContent: string; }; -export declare type serializedNode = (documentNode | documentTypeNode | elementNode | textNode | cdataNode | commentNode) & { - rootId?: number; -}; +export declare type serializedNode = documentNode | documentTypeNode | elementNode | textNode | cdataNode | commentNode; export declare type serializedNodeWithId = serializedNode & { id: number; }; From 9c60cd5e6d83f4eb3e9e2b8abc23ff699cd4ea4b Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 16 Feb 2021 00:09:58 -0600 Subject: [PATCH 5/8] Fixed name --- src/replay/index.ts | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index bd83c14c..849f2ea3 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -255,51 +255,51 @@ export class Replayer { ), ]; for (let i = 1; i < userInteractionEvents.length; i++) { - const currEvent = userInteractionEvents[i - 1]; + const currentInterval = userInteractionEvents[i - 1]; const _event = userInteractionEvents[i]; - if (_event.timestamp! - currEvent.timestamp! > SKIP_TIME_THRESHOLD) { + if (_event.timestamp! - currentInterval.timestamp! > SKIP_TIME_THRESHOLD) { allIntervals.push({ - startTime: currEvent.timestamp!, + startTime: currentInterval.timestamp!, endTime: _event.timestamp!, - duration: _event.timestamp! - currEvent.timestamp!, + duration: _event.timestamp! - currentInterval.timestamp!, active: false, }); } else { allIntervals.push({ - startTime: currEvent.timestamp!, + startTime: currentInterval.timestamp!, endTime: _event.timestamp!, - duration: _event.timestamp! - currEvent.timestamp!, + duration: _event.timestamp! - currentInterval.timestamp!, active: true, }); } } // Merges continuous active/inactive ranges const mergedIntervals: Array = []; - let currEvent = allIntervals[0]; + let currentInterval = allIntervals[0]; for (let i = 1; i < allIntervals.length; i++) { if (allIntervals[i].active != allIntervals[i - 1].active) { mergedIntervals.push({ - startTime: currEvent.startTime, + startTime: currentInterval.startTime, endTime: allIntervals[i - 1].endTime, - duration: allIntervals[i - 1].endTime - currEvent.startTime, + duration: allIntervals[i - 1].endTime - currentInterval.startTime, active: allIntervals[i - 1].active, }); - currEvent = allIntervals[i]; + currentInterval = allIntervals[i]; } } - if (currEvent && allIntervals.length > 0) { + if (currentInterval && allIntervals.length > 0) { mergedIntervals.push({ - startTime: currEvent.startTime, + startTime: currentInterval.startTime, endTime: allIntervals[allIntervals.length - 1].endTime, duration: - allIntervals[allIntervals.length - 1].endTime - currEvent.startTime, + allIntervals[allIntervals.length - 1].endTime - currentInterval.startTime, active: allIntervals[allIntervals.length - 1].active, }); } // Merges inactive segments that are less than a threshold into surrounding active sessions // TODO: Change this from a 3n pass to n const metadata = this.getMetaData(); - currEvent = mergedIntervals[0]; + currentInterval = mergedIntervals[0]; for (let i = 1; i < mergedIntervals.length; i++) { if ( (!mergedIntervals[i].active && @@ -310,21 +310,21 @@ export class Replayer { this.config.inactiveThreshold * metadata.totalTime) ) { this.activityIntervals.push({ - startTime: currEvent.startTime, + startTime: currentInterval.startTime, endTime: mergedIntervals[i - 1].endTime, - duration: mergedIntervals[i - 1].endTime - currEvent.startTime, + duration: mergedIntervals[i - 1].endTime - currentInterval.startTime, active: mergedIntervals[i - 1].active, }); - currEvent = mergedIntervals[i]; + currentInterval = mergedIntervals[i]; } } - if (currEvent && mergedIntervals.length > 0) { + if (currentInterval && mergedIntervals.length > 0) { this.activityIntervals.push({ - startTime: currEvent.startTime, + startTime: currentInterval.startTime, endTime: mergedIntervals[mergedIntervals.length - 1].endTime, duration: mergedIntervals[mergedIntervals.length - 1].endTime - - currEvent.startTime, + currentInterval.startTime, active: mergedIntervals[mergedIntervals.length - 1].active, }); } From b20e17491a4eb1e6ef764c3fd7ac08bc77e9db7d Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 16 Feb 2021 09:31:42 -0600 Subject: [PATCH 6/8] Renamed --- src/replay/index.ts | 14 +++++++------- typings/replay/index.d.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 849f2ea3..02a07561 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -101,7 +101,7 @@ export class Replayer { private emitter: Emitter = mitt(); - private nextTimestamp: number | null; + private inactiveEndTimestamp: number | null; private nextUserInteractionEvent: eventWithTime | null; // tslint:disable-next-line: variable-name @@ -584,23 +584,23 @@ export class Replayer { } private handleInactivity(timestamp: number, resetNext?: boolean) { - if (timestamp === this.nextTimestamp || resetNext) { - this.nextTimestamp = null; + if (timestamp === this.inactiveEndTimestamp || resetNext) { + this.inactiveEndTimestamp = null; this.backToNormal(); } - if (this.config.skipInactive && !this.nextTimestamp) { + if (this.config.skipInactive && !this.inactiveEndTimestamp) { for (const interval of this.activityIntervals) { if ( timestamp >= interval.startTime! && timestamp < interval.endTime! && !interval.active ) { - this.nextTimestamp = interval.endTime; + this.inactiveEndTimestamp = interval.endTime; break; } } - if (this.nextTimestamp) { - const skipTime = this.nextTimestamp! - timestamp!; + if (this.inactiveEndTimestamp) { + const skipTime = this.inactiveEndTimestamp! - timestamp!; const payload = { speed: Math.min(Math.round(skipTime / SKIP_TIME_INTERVAL), 360), }; diff --git a/typings/replay/index.d.ts b/typings/replay/index.d.ts index 03ea87bc..ed05fee3 100644 --- a/typings/replay/index.d.ts +++ b/typings/replay/index.d.ts @@ -13,7 +13,7 @@ export declare class Replayer { private mouseTail; private tailPositions; private emitter; - private nextTimestamp; + private inactiveEndTimestamp; private nextUserInteractionEvent; private legacy_missingNodeRetryMap; private treeIndex; From 453f3b7182e64eedcaf8b0dc3f107fe315b17914 Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 16 Feb 2021 11:21:20 -0600 Subject: [PATCH 7/8] Cleaned code and added handling for edge cases --- src/replay/index.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 02a07561..6e331d52 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -102,7 +102,6 @@ export class Replayer { private emitter: Emitter = mitt(); private inactiveEndTimestamp: number | null; - private nextUserInteractionEvent: eventWithTime | null; // tslint:disable-next-line: variable-name private legacy_missingNodeRetryMap: missingNodeMap = {}; @@ -247,17 +246,21 @@ export class Replayer { } // Preprocessing to get all active/inactive segments in a session const allIntervals: Array = []; - const firstEvent = this.service.state.context.events[0]; + const metadata = this.getMetaData(); const userInteractionEvents = [ - firstEvent, + { timestamp: metadata.startTime }, ...this.service.state.context.events.filter((ev) => this.isUserInteraction(ev), ), + { timestamp: metadata.endTime }, ]; for (let i = 1; i < userInteractionEvents.length; i++) { const currentInterval = userInteractionEvents[i - 1]; const _event = userInteractionEvents[i]; - if (_event.timestamp! - currentInterval.timestamp! > SKIP_TIME_THRESHOLD) { + if ( + _event.timestamp! - currentInterval.timestamp! > + SKIP_TIME_THRESHOLD + ) { allIntervals.push({ startTime: currentInterval.timestamp!, endTime: _event.timestamp!, @@ -292,13 +295,13 @@ export class Replayer { startTime: currentInterval.startTime, endTime: allIntervals[allIntervals.length - 1].endTime, duration: - allIntervals[allIntervals.length - 1].endTime - currentInterval.startTime, + allIntervals[allIntervals.length - 1].endTime - + currentInterval.startTime, active: allIntervals[allIntervals.length - 1].active, }); } // Merges inactive segments that are less than a threshold into surrounding active sessions // TODO: Change this from a 3n pass to n - const metadata = this.getMetaData(); currentInterval = mergedIntervals[0]; for (let i = 1; i < mergedIntervals.length; i++) { if ( @@ -1447,7 +1450,7 @@ export class Replayer { } private backToNormal() { - this.nextUserInteractionEvent = null; + this.inactiveEndTimestamp = null; if (this.speedService.state.matches('normal')) { return; } From af4b1e6d697f83621e71f4cf97c8e2953544db84 Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 16 Feb 2021 11:21:36 -0600 Subject: [PATCH 8/8] Updated package num --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7f191b6..8e7f0e9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@highlight-run/rrweb", - "version": "0.9.25", + "version": "0.9.26", "description": "record and replay the web", "scripts": { "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.test.ts",