@newrelic/browser-agent 1.255.0 → 1.256.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/cjs/common/constants/env.cdn.js +2 -2
- package/dist/cjs/common/constants/env.npm.js +2 -2
- package/dist/cjs/common/constants/runtime.js +1 -1
- package/dist/cjs/common/session/session-entity.js +2 -1
- package/dist/cjs/common/timer/interaction-timer.js +16 -2
- package/dist/cjs/common/timing/time-keeper.js +1 -2
- package/dist/cjs/features/jserrors/aggregate/index.js +16 -6
- package/dist/cjs/features/jserrors/instrument/index.js +8 -3
- package/dist/cjs/features/session_replay/aggregate/index.js +48 -29
- package/dist/cjs/features/session_replay/constants.js +2 -1
- package/dist/cjs/features/session_replay/instrument/index.js +9 -2
- package/dist/cjs/features/session_replay/shared/recorder-events.js +1 -9
- package/dist/cjs/features/session_replay/shared/recorder.js +22 -50
- package/dist/cjs/features/session_replay/shared/utils.js +12 -0
- package/dist/cjs/loaders/api/api.js +7 -1
- package/dist/esm/common/constants/env.cdn.js +2 -2
- package/dist/esm/common/constants/env.npm.js +2 -2
- package/dist/esm/common/constants/runtime.js +1 -1
- package/dist/esm/common/session/session-entity.js +2 -1
- package/dist/esm/common/timer/interaction-timer.js +16 -2
- package/dist/esm/common/timing/time-keeper.js +1 -3
- package/dist/esm/features/jserrors/aggregate/index.js +16 -6
- package/dist/esm/features/jserrors/instrument/index.js +8 -3
- package/dist/esm/features/session_replay/aggregate/index.js +48 -29
- package/dist/esm/features/session_replay/constants.js +2 -1
- package/dist/esm/features/session_replay/instrument/index.js +9 -2
- package/dist/esm/features/session_replay/shared/recorder-events.js +1 -9
- package/dist/esm/features/session_replay/shared/recorder.js +23 -51
- package/dist/esm/features/session_replay/shared/utils.js +11 -0
- package/dist/esm/loaders/api/api.js +7 -1
- package/dist/types/common/constants/runtime.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/timer/interaction-timer.d.ts +2 -0
- package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +2 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +5 -2
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/constants.d.ts +1 -0
- package/dist/types/features/session_replay/constants.d.ts.map +1 -1
- package/dist/types/features/session_replay/instrument/index.d.ts +1 -0
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder-events.d.ts +0 -8
- package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +1 -17
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/utils.d.ts +8 -0
- package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/common/constants/runtime.js +1 -1
- package/src/common/session/session-entity.js +2 -1
- package/src/common/timer/interaction-timer.js +17 -2
- package/src/common/timing/time-keeper.js +1 -3
- package/src/features/jserrors/aggregate/index.js +15 -6
- package/src/features/jserrors/instrument/index.js +9 -4
- package/src/features/session_replay/aggregate/index.js +43 -25
- package/src/features/session_replay/constants.js +2 -1
- package/src/features/session_replay/instrument/index.js +7 -2
- package/src/features/session_replay/shared/recorder-events.js +1 -6
- package/src/features/session_replay/shared/recorder.js +21 -27
- package/src/features/session_replay/shared/utils.js +12 -0
- package/src/loaders/api/api.js +10 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/runtime.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,qCAEqB;AAErB;;GAEG;AACH,oCAeK;AAEL,oDAUI;AAEJ,oDAA6F;AAE7F,sCAA2F;AAE3F,qCAAyD;AAEzD,4BAA8E;AAE9E;;;;;;GAMG;AACH,iCAAwE;AAExE,+BAOI;AAEJ,2BAA2E;AAE3E,yCAAqE;AAErE,
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/runtime.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,qCAEqB;AAErB;;GAEG;AACH,oCAeK;AAEL,oDAUI;AAEJ,oDAA6F;AAE7F,sCAA2F;AAE3F,qCAAyD;AAEzD,4BAA8E;AAE9E;;;;;;GAMG;AACH,iCAAwE;AAExE,+BAOI;AAEJ,2BAA2E;AAE3E,yCAAqE;AAErE,4BAAgE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-entity.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-entity.js"],"names":[],"mappings":"AA6BA;IACE;;;;;OAKG;IACH,uBA0BC;IApBC,qBAAsC;IACtC,aAAsB;IACtB,UAAe;IAGf,SAAc;IAEd,QAAiC;IAenC;;;;
|
|
1
|
+
{"version":3,"file":"session-entity.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-entity.js"],"names":[],"mappings":"AA6BA;IACE;;;;;OAKG;IACH,uBA0BC;IApBC,qBAAsC;IACtC,aAAsB;IACtB,UAAe;IAGf,SAAc;IAEd,QAAiC;IAenC;;;;aAyEC;IAlEC,8BAA0B;IAC1B,+BAA4B;IAc1B,gCAOqC;IAUrC,4CAkBsC;IAexC,iCAAuB;IAIzB,wBAEC;IAED,sBAEC;IAED;;;OAGG;IACH,QAFa,MAAM,CA6BlB;IAED;;;;;;OAMG;IACH,YAHW,MAAM,GACJ,MAAM,CAkBlB;IAED,gBAuBC;IAED;;OAEG;IACH,gBAIC;IAED;;;OAGG;IACH,qBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,gBAHW,MAAM,GACJ,OAAO,CAKnB;IAED,yDAUC;IAED,6DAIC;IAED;;;OAGG;IACH,6BAHW,MAAM,GACJ,MAAM,CAIlB;IAED,gDAaC;IAHG,YAAuD;CAI5D;sBArSqB,gBAAgB;iCAGL,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interaction-timer.d.ts","sourceRoot":"","sources":["../../../../src/common/timer/interaction-timer.js"],"names":[],"mappings":"AAKA;IAGI,aAAuF;IACvF,eAA6F;IAC7F,cAA0F;
|
|
1
|
+
{"version":3,"file":"interaction-timer.d.ts","sourceRoot":"","sources":["../../../../src/common/timer/interaction-timer.js"],"names":[],"mappings":"AAKA;IAGI,aAAuF;IACvF,eAA6F;IAC7F,cAA0F;IAE1F,mDAAmD;IACnD,iBAAmC;IAGnC,gCAA4B;IAM1B,6CAA4C;IAO1C,QAAiB;IAEjB,kDAIC;IAoBP,cAQC;IAED,cAIC;IAED,eAeC;IAED,gCAMC;CACF;sBA/FqB,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;IA+BE,oBAEC;IAED,yBAEC;IAED,kCAEC;IAED;;;;;OAKG;IACH,8BAJsB,cAAc,aACf,MAAM,WACR,MAAM,QAoBxB;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAIlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAIjB;;CACF"}
|
|
@@ -10,6 +10,7 @@ export class Aggregate extends AggregateBase {
|
|
|
10
10
|
bufferedErrorsUnderSpa: {};
|
|
11
11
|
currentBody: {} | null | undefined;
|
|
12
12
|
errorOnPage: boolean;
|
|
13
|
+
replayAborted: boolean;
|
|
13
14
|
onHarvestStarted(options: any): {
|
|
14
15
|
body: {} | null;
|
|
15
16
|
qs: {};
|
|
@@ -25,7 +26,7 @@ export class Aggregate extends AggregateBase {
|
|
|
25
26
|
* @returns {string} A canonical stack string built from the URLs and function names in the given `stackInfo` object.
|
|
26
27
|
*/
|
|
27
28
|
buildCanonicalStackString(stackInfo: StackInfo): string;
|
|
28
|
-
storeError(err: any, time: any, internal: any, customAttributes: any): void;
|
|
29
|
+
storeError(err: any, time: any, internal: any, customAttributes: any, hasReplay: any): void;
|
|
29
30
|
onInteractionDone(interaction: any, wasSaved: any): void;
|
|
30
31
|
onSoftNavNotification(interactionId: any, wasFinished: any, softNavAttrs: any): void;
|
|
31
32
|
#private;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"AAyBA;;GAEG;AAEH;IACE,2BAAiC;IACjC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"AAyBA;;GAEG;AAEH;IACE,2BAAiC;IACjC,mDAmCC;IAhCC,kBAAuB;IACvB,eAAoB;IACpB,qBAA0B;IAC1B,2BAAgC;IAChC,mCAA4B;IAC5B,qBAAwB;IACxB,uBAA0B;IA4B5B;;;MA2BC;IAED,qCAWC;IAED,8BAEC;IAED,oEAMC;IAED;;;;;;OAMG;IACH,qCAHW,SAAS,GACP,MAAM,CAgBlB;IAED,4FAsFC;IA4BD,yDA6BC;IAED,qFAOC;;CACF;wBAhRY,OAAO,0BAA0B,EAAE,SAAS;8BAN3B,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/instrument/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/instrument/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAAiC;IAKjC,mEA+CC;IA1CG,2CAA0C;IAwC5C,yBAA+B;;CAoFlC;+BAjJ8B,6BAA6B"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export class Aggregate extends AggregateBase {
|
|
2
2
|
static featureName: string;
|
|
3
3
|
constructor(agentIdentifier: any, aggregator: any, args: any);
|
|
4
|
+
mode: number;
|
|
4
5
|
/** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
|
|
5
6
|
harvestTimeSeconds: any;
|
|
6
7
|
/** Set once the recorder has fully initialized after flag checks and sampling */
|
|
@@ -9,14 +10,15 @@ export class Aggregate extends AggregateBase {
|
|
|
9
10
|
gzipper: typeof import("fflate").gzipSync | undefined;
|
|
10
11
|
/** populated with the u8 string lib async */
|
|
11
12
|
u8: typeof import("fflate").strToU8 | undefined;
|
|
12
|
-
mode: any;
|
|
13
13
|
/** set by BCS response */
|
|
14
14
|
entitled: boolean;
|
|
15
15
|
/** set at BCS response, stored in runtime */
|
|
16
16
|
timeKeeper: any;
|
|
17
17
|
recorder: any;
|
|
18
|
+
preloaded: boolean;
|
|
19
|
+
errorNoticed: any;
|
|
18
20
|
scheduler: HarvestScheduler;
|
|
19
|
-
|
|
21
|
+
handleError(e: any): void;
|
|
20
22
|
switchToFull(): void;
|
|
21
23
|
/**
|
|
22
24
|
* Evaluate entitlements and sampling before starting feature mechanics, importing and configuring recording library, and setting storage state
|
|
@@ -41,6 +43,7 @@ export class Aggregate extends AggregateBase {
|
|
|
41
43
|
};
|
|
42
44
|
body: any;
|
|
43
45
|
}[] | undefined;
|
|
46
|
+
getCorrectedTimestamp(node: any): any;
|
|
44
47
|
getHarvestContents(recorderEvents: any): {
|
|
45
48
|
qs: {
|
|
46
49
|
browser_monitoring_key: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AAgCA;IACE,2BAAiC;IAIjC,8DAsGC;IAzGD,aAAe;IAKb,8GAA8G;IAC9G,wBAAgH;IAChH,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IAEnB,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,cAA8B;IAC9B,mBAAgC;IAChC,kBAA+C;IA4B/C,4BAKQ;IAmDV,0BAMC;IAED,qBAWC;IAED;;;;;;;OAOG;IACH,iCALW,OAAO,cACP,OAAO,iBACP,OAAO,GACL,IAAI,CA8DhB;IAED,2BASC;IAED;;;;;;;;;;;;oBAiDC;IAED,sCAIC;IAED;;;;;;;;;;MAoEC;IAED,qCAOC;IAED;;;;OAIG;IACH,mCAKC;IAED,yDAAyD;IACzD,yBAUC;IAED,yCAGC;CACF;8BAxY6B,4BAA4B;iCAHzB,2CAA2C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/session_replay/constants.js"],"names":[],"mappings":"AAGA,kCAAuD
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/session_replay/constants.js"],"names":[],"mappings":"AAGA,kCAAuD;;;;;;AAQvD,mCAAmC;;;;;;;;;AASnC,uCAAuC;AACvC,uCAAuC;AACvC,iCAAiC;AACjC,uCAAuC;AACvC,2GAA2G;AAC3G;;EAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BtF,0CAA0C;AAC1C,uCAAuC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/instrument/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAAiC;IACjC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/instrument/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAAiC;IACjC,mEAiBC;IAPK,sBAAwB;IAwB5B,4DAA0F;;CAK7F;+BA7C8B,6BAA6B"}
|
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
export class RecorderEvents {
|
|
2
|
-
constructor({ canCorrectTimestamps }: {
|
|
3
|
-
canCorrectTimestamps: any;
|
|
4
|
-
});
|
|
5
2
|
/** The buffer to hold recorder event nodes */
|
|
6
3
|
events: any[];
|
|
7
4
|
/** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs.
|
|
8
5
|
* cycle timestamps are used as fallbacks if event timestamps cannot be used
|
|
9
6
|
*/
|
|
10
7
|
cycleTimestamp: number;
|
|
11
|
-
/** Payload metadata -- Whether timestamps can be corrected, defaults as false, can be set to true if timekeeper is present at init time. Used to determine
|
|
12
|
-
* if harvest needs to re-loop through nodes and correct them before sending. Ideal behavior is to correct them as they flow into the recorder
|
|
13
|
-
* to prevent re-looping, but is not always possible since the timekeeper is not set until after page load and the recorder can be preloaded.
|
|
14
|
-
*/
|
|
15
|
-
canCorrectTimestamps: boolean;
|
|
16
8
|
/** A value which increments with every new mutation node reported. Resets after a harvest is sent */
|
|
17
9
|
payloadBytesEstimation: number;
|
|
18
10
|
/** Payload metadata -- Should indicate that the payload being sent has a full DOM snapshot. This can happen
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder-events.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder-events.js"],"names":[],"mappings":"AAAA;
|
|
1
|
+
{"version":3,"file":"recorder-events.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder-events.js"],"names":[],"mappings":"AAAA;IAEI,8CAA8C;IAC9C,cAAgB;IAChB;;OAEG;IACH,uBAAgC;IAChC,qGAAqG;IACrG,+BAA+B;IAC/B;;;MAGE;IACF,qBAAwB;IACxB,4IAA4I;IAC5I,iBAAoB;IACpB,+HAA+H;IAC/H,kBAAqB;IACrB,0FAA0F;IAC1F,+BAAiC;IAGnC,sBAEC;CACF"}
|
|
@@ -15,31 +15,15 @@ export class Recorder {
|
|
|
15
15
|
/** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
|
|
16
16
|
stopRecording: () => void;
|
|
17
17
|
getEvents(): {
|
|
18
|
-
events: CorrectedSessionReplayEvent[];
|
|
19
18
|
type: string;
|
|
19
|
+
events: any[];
|
|
20
20
|
cycleTimestamp: number;
|
|
21
|
-
canCorrectTimestamps: boolean;
|
|
22
21
|
payloadBytesEstimation: number;
|
|
23
22
|
hasSnapshot: boolean;
|
|
24
23
|
hasMeta: boolean;
|
|
25
24
|
hasError: boolean;
|
|
26
25
|
inlinedAllStylesheets: boolean;
|
|
27
|
-
} | {
|
|
28
|
-
events: any[];
|
|
29
|
-
type: string;
|
|
30
|
-
cycleTimestamp: number;
|
|
31
|
-
payloadBytesEstimation: number;
|
|
32
|
-
hasError: boolean;
|
|
33
|
-
hasMeta: boolean;
|
|
34
|
-
hasSnapshot: boolean;
|
|
35
|
-
inlinedAllStylesheets: boolean;
|
|
36
26
|
};
|
|
37
|
-
/**
|
|
38
|
-
* Returns time-corrected events. If the events were correctable from the beginning, this correction will have already been applied.
|
|
39
|
-
* @param {SessionReplayEvent[]} events The array of buffered SR nodes
|
|
40
|
-
* @returns {CorrectedSessionReplayEvent[]}
|
|
41
|
-
*/
|
|
42
|
-
returnCorrectTimestamps(events: SessionReplayEvent[]): CorrectedSessionReplayEvent[];
|
|
43
27
|
/** Clears the buffer (this.#events), and resets all payload metadata properties */
|
|
44
28
|
clearBuffer(): void;
|
|
45
29
|
/** Begin recording using configured recording lib */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAYA;IAUE,yBAkBC;IAdC,iEAAiE;IACjE,mBAAsB;IACtB,6DAA6D;IAC7D,oCAAuC;IACvC,kIAAkI;IAClI,kBAAqB;IACrB,sDAAsD;IACtD,YAAoB;IACpB,oEAAoE;IACpE,6BAAqH;IACrH,0FAA0F;IAC1F,eAA6C;IAC7C,uIAAuI;IACvI,0BAAyE;IAG3E;;;;;;;;;MAYC;IAED,mFAAmF;IACnF,oBAKC;IAED,qDAAqD;IACrD,uBAiCC;IAED;;;;;OAKG;IACH,yCA0BC;IAED,0HAA0H;IAC1H,yCAgDC;IAED,0HAA0H;IAC1H,yBAOC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED;;;SAGK;IACL,oCAGC;;CACF;+BAjN8B,mBAAmB"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export function isPreloadAllowed(agentId: any): any;
|
|
2
2
|
export function canImportReplayAgg(agentId: any, sessionMgr: any): boolean;
|
|
3
|
+
export function buildNRMetaNode(timestamp: any, timeKeeper: any): {
|
|
4
|
+
originalTimestamp: any;
|
|
5
|
+
correctedTimestamp: any;
|
|
6
|
+
timestampDiff: number;
|
|
7
|
+
timeKeeperOriginTime: any;
|
|
8
|
+
timeKeeperCorrectedOriginTime: any;
|
|
9
|
+
timeKeeperDiff: number;
|
|
10
|
+
};
|
|
3
11
|
export function enableSessionTracking(agentId: any): boolean;
|
|
4
12
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/utils.js"],"names":[],"mappings":"AAWA,oDAEC;AAED,2EAGC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/utils.js"],"names":[],"mappings":"AAWA,oDAEC;AAED,2EAGC;AAED;;;;;;;EAUC;AA3BM,6DAA+H"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"AAmBA,2CAeC;AAID;;;;IAuDE;;;;OAIG;qBAFQ,MAAM;IAWjB;;;;OAIG;iCAFQ,MAAM,GAAC,IAAI;;;;;EA0GvB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/browser-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.256.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
|
|
6
6
|
"description": "New Relic Browser Agent",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"dependencies": {
|
|
169
169
|
"core-js": "^3.26.0",
|
|
170
170
|
"fflate": "^0.7.4",
|
|
171
|
-
"rrweb": "2.0.0-alpha.
|
|
171
|
+
"rrweb": "2.0.0-alpha.12",
|
|
172
172
|
"web-vitals": "^3.1.0"
|
|
173
173
|
},
|
|
174
174
|
"devDependencies": {
|
|
@@ -74,4 +74,4 @@ export const isIE = Boolean(isBrowserScope && window.document.documentMode) // d
|
|
|
74
74
|
|
|
75
75
|
export const supportsSendBeacon = !!globalScope.navigator?.sendBeacon
|
|
76
76
|
|
|
77
|
-
export const offset = Math.floor(
|
|
77
|
+
export const offset = Math.floor(Date.now() - performance.now())
|
|
@@ -117,7 +117,8 @@ export class SessionEntity {
|
|
|
117
117
|
this.write(getModeledObject(this.state, model))
|
|
118
118
|
},
|
|
119
119
|
ee: this.ee,
|
|
120
|
-
refreshEvents: ['click', 'keydown', 'scroll']
|
|
120
|
+
refreshEvents: ['click', 'keydown', 'scroll'],
|
|
121
|
+
readStorage: () => this.storage.get(this.lookupKey)
|
|
121
122
|
}, this.state.inactiveAt - Date.now())
|
|
122
123
|
} else {
|
|
123
124
|
this.state.inactiveAt = Infinity
|
|
@@ -10,6 +10,9 @@ export class InteractionTimer extends Timer {
|
|
|
10
10
|
this.onRefresh = typeof opts.onRefresh === 'function' ? opts.onRefresh : () => { /* noop */ }
|
|
11
11
|
this.onResume = typeof opts.onResume === 'function' ? opts.onResume : () => { /* noop */ }
|
|
12
12
|
|
|
13
|
+
/** used to double-check LS state at resume time */
|
|
14
|
+
this.readStorage = opts.readStorage
|
|
15
|
+
|
|
13
16
|
// used by pause/resume
|
|
14
17
|
this.remainingMs = undefined
|
|
15
18
|
|
|
@@ -67,8 +70,20 @@ export class InteractionTimer extends Timer {
|
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
resume () {
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
try {
|
|
74
|
+
const lsData = this.readStorage()
|
|
75
|
+
const obj = typeof lsData === 'string' ? JSON.parse(lsData) : lsData
|
|
76
|
+
if (isExpired(obj.expiresAt) || isExpired(obj.inactiveAt)) this.end()
|
|
77
|
+
else {
|
|
78
|
+
this.refresh()
|
|
79
|
+
this.onResume() // emit resume event after state updated
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
this.end()
|
|
83
|
+
}
|
|
84
|
+
function isExpired (timestamp) {
|
|
85
|
+
return Date.now() > timestamp
|
|
86
|
+
}
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
refresh (cb, ms) {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { globalScope } from '../constants/runtime'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Class used to adjust the timestamp of harvested data to New Relic server time. This
|
|
5
3
|
* is done by tracking the performance timings of the RUM call and applying a calculation
|
|
@@ -33,7 +31,7 @@ export class TimeKeeper {
|
|
|
33
31
|
#ready = false
|
|
34
32
|
|
|
35
33
|
constructor () {
|
|
36
|
-
this.#originTime =
|
|
34
|
+
this.#originTime = Date.now() - performance.now()
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
get ready () {
|
|
@@ -38,10 +38,13 @@ export class Aggregate extends AggregateBase {
|
|
|
38
38
|
this.bufferedErrorsUnderSpa = {}
|
|
39
39
|
this.currentBody = undefined
|
|
40
40
|
this.errorOnPage = false
|
|
41
|
+
this.replayAborted = false
|
|
41
42
|
|
|
42
43
|
// this will need to change to match whatever ee we use in the instrument
|
|
43
44
|
this.ee.on('interactionDone', (interaction, wasSaved) => this.onInteractionDone(interaction, wasSaved))
|
|
44
45
|
|
|
46
|
+
this.ee.on('REPLAY_ABORTED', () => { this.replayAborted = true })
|
|
47
|
+
|
|
45
48
|
register('err', (...args) => this.storeError(...args), this.featureName, this.ee)
|
|
46
49
|
register('ierr', (...args) => this.storeError(...args), this.featureName, this.ee)
|
|
47
50
|
register('softNavFlush', (interactionId, wasFinished, softNavAttrs) =>
|
|
@@ -78,9 +81,16 @@ export class Aggregate extends AggregateBase {
|
|
|
78
81
|
payload.qs.ri = releaseIds
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
if (body && body.err && body.err.length
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
if (body && body.err && body.err.length) {
|
|
85
|
+
if (this.replayAborted) {
|
|
86
|
+
body.err.forEach((e) => {
|
|
87
|
+
delete e.params?.hasReplay
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
if (!this.errorOnPage) {
|
|
91
|
+
payload.qs.pve = '1'
|
|
92
|
+
this.errorOnPage = true
|
|
93
|
+
}
|
|
84
94
|
}
|
|
85
95
|
return payload
|
|
86
96
|
}
|
|
@@ -133,7 +143,7 @@ export class Aggregate extends AggregateBase {
|
|
|
133
143
|
return canonicalStackString
|
|
134
144
|
}
|
|
135
145
|
|
|
136
|
-
storeError (err, time, internal, customAttributes) {
|
|
146
|
+
storeError (err, time, internal, customAttributes, hasReplay) {
|
|
137
147
|
// are we in an interaction
|
|
138
148
|
time = time || now()
|
|
139
149
|
const agentRuntime = getRuntime(this.agentIdentifier)
|
|
@@ -189,7 +199,7 @@ export class Aggregate extends AggregateBase {
|
|
|
189
199
|
this.pageviewReported[bucketHash] = true
|
|
190
200
|
}
|
|
191
201
|
|
|
192
|
-
if (
|
|
202
|
+
if (hasReplay && !this.replayAborted) params.hasReplay = hasReplay
|
|
193
203
|
params.firstOccurrenceTimestamp = this.observedAt[bucketHash]
|
|
194
204
|
params.timestamp = this.observedAt[bucketHash]
|
|
195
205
|
|
|
@@ -199,7 +209,6 @@ export class Aggregate extends AggregateBase {
|
|
|
199
209
|
// Trace sends the error in its payload, and both trace & replay simply listens for any error to occur.
|
|
200
210
|
const jsErrorEvent = [type, bucketHash, params, newMetrics, customAttributes]
|
|
201
211
|
handle('errorAgg', jsErrorEvent, undefined, FEATURE_NAMES.sessionTrace, this.ee)
|
|
202
|
-
handle('errorAgg', jsErrorEvent, undefined, FEATURE_NAMES.sessionReplay, this.ee)
|
|
203
212
|
// still send EE events for other features such as above, but stop this one from aggregating internal data
|
|
204
213
|
if (this.blocked) return
|
|
205
214
|
|
|
@@ -12,11 +12,13 @@ import { eventListenerOpts } from '../../../common/event-listener/event-listener
|
|
|
12
12
|
import { stringify } from '../../../common/util/stringify'
|
|
13
13
|
import { UncaughtError } from './uncaught-error'
|
|
14
14
|
import { now } from '../../../common/timing/now'
|
|
15
|
+
import { SR_EVENT_EMITTER_TYPES } from '../../session_replay/constants'
|
|
15
16
|
|
|
16
17
|
export class Instrument extends InstrumentBase {
|
|
17
18
|
static featureName = FEATURE_NAME
|
|
18
19
|
|
|
19
20
|
#seenErrors = new Set()
|
|
21
|
+
#replayRunning = false
|
|
20
22
|
|
|
21
23
|
constructor (agentIdentifier, aggregator, auto = true) {
|
|
22
24
|
super(agentIdentifier, aggregator, FEATURE_NAME, auto)
|
|
@@ -36,13 +38,16 @@ export class Instrument extends InstrumentBase {
|
|
|
36
38
|
|
|
37
39
|
this.ee.on('internal-error', (error) => {
|
|
38
40
|
if (!this.abortHandler) return
|
|
39
|
-
handle('ierr', [this.#castError(error), now(), true], undefined, FEATURE_NAMES.jserrors, this.ee)
|
|
41
|
+
handle('ierr', [this.#castError(error), now(), true, {}, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
this.ee.on(SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, (isRunning) => {
|
|
45
|
+
this.#replayRunning = isRunning
|
|
40
46
|
})
|
|
41
47
|
|
|
42
48
|
globalScope.addEventListener('unhandledrejection', (promiseRejectionEvent) => {
|
|
43
49
|
if (!this.abortHandler) return
|
|
44
|
-
|
|
45
|
-
handle('err', [this.#castPromiseRejectionEvent(promiseRejectionEvent), now(), false, { unhandledPromiseRejection: 1 }], undefined, FEATURE_NAMES.jserrors, this.ee)
|
|
50
|
+
handle('err', [this.#castPromiseRejectionEvent(promiseRejectionEvent), now(), false, { unhandledPromiseRejection: 1 }, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
|
|
46
51
|
}, eventListenerOpts(false, this.removeOnAbort?.signal))
|
|
47
52
|
|
|
48
53
|
globalScope.addEventListener('error', (errorEvent) => {
|
|
@@ -57,7 +62,7 @@ export class Instrument extends InstrumentBase {
|
|
|
57
62
|
return
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
handle('err', [this.#castErrorEvent(errorEvent), now()], undefined, FEATURE_NAMES.jserrors, this.ee)
|
|
65
|
+
handle('err', [this.#castErrorEvent(errorEvent), now(), false, {}, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
|
|
61
66
|
}, eventListenerOpts(false, this.removeOnAbort?.signal))
|
|
62
67
|
|
|
63
68
|
this.abortHandler = this.#abort // we also use this as a flag to denote that the feature is active or on and handling errors
|
|
@@ -28,9 +28,12 @@ import { stringify } from '../../../common/util/stringify'
|
|
|
28
28
|
import { stylesheetEvaluator } from '../shared/stylesheet-evaluator'
|
|
29
29
|
import { deregisterDrain } from '../../../common/drain/drain'
|
|
30
30
|
import { now } from '../../../common/timing/now'
|
|
31
|
+
import { buildNRMetaNode } from '../shared/utils'
|
|
31
32
|
|
|
32
33
|
export class Aggregate extends AggregateBase {
|
|
33
34
|
static featureName = FEATURE_NAME
|
|
35
|
+
mode = MODE.OFF
|
|
36
|
+
|
|
34
37
|
// pass the recorder into the aggregator
|
|
35
38
|
constructor (agentIdentifier, aggregator, args) {
|
|
36
39
|
super(agentIdentifier, aggregator, FEATURE_NAME)
|
|
@@ -44,9 +47,6 @@ export class Aggregate extends AggregateBase {
|
|
|
44
47
|
this.gzipper = undefined
|
|
45
48
|
/** populated with the u8 string lib async */
|
|
46
49
|
this.u8 = undefined
|
|
47
|
-
/** the mode to start in. Defaults to off */
|
|
48
|
-
const { session } = getRuntime(this.agentIdentifier)
|
|
49
|
-
this.mode = session.state.sessionReplayMode || MODE.OFF
|
|
50
50
|
|
|
51
51
|
/** set by BCS response */
|
|
52
52
|
this.entitled = false
|
|
@@ -54,13 +54,13 @@ export class Aggregate extends AggregateBase {
|
|
|
54
54
|
this.timeKeeper = undefined
|
|
55
55
|
|
|
56
56
|
this.recorder = args?.recorder
|
|
57
|
-
|
|
57
|
+
this.preloaded = !!this.recorder
|
|
58
|
+
this.errorNoticed = args?.errorNoticed || false
|
|
58
59
|
|
|
59
60
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
60
61
|
|
|
61
62
|
// The SessionEntity class can emit a message indicating the session was cleared and reset (expiry, inactivity). This feature must abort and never resume if that occurs.
|
|
62
63
|
this.ee.on(SESSION_EVENTS.RESET, () => {
|
|
63
|
-
this.scheduler.runHarvest()
|
|
64
64
|
this.abort(ABORT_REASONS.RESET)
|
|
65
65
|
})
|
|
66
66
|
|
|
@@ -104,17 +104,6 @@ export class Aggregate extends AggregateBase {
|
|
|
104
104
|
this.forceStop(this.mode !== MODE.ERROR)
|
|
105
105
|
}, this.featureName, this.ee)
|
|
106
106
|
|
|
107
|
-
// Wait for an error to be reported. This currently is wrapped around the "Error" feature. This is a feature-feature dependency.
|
|
108
|
-
// This was to ensure that all errors, including those on the page before load and those handled with "noticeError" are accounted for. Needs evalulation
|
|
109
|
-
registerHandler('errorAgg', (e) => {
|
|
110
|
-
this.errorNoticed = true
|
|
111
|
-
if (this.recorder) this.recorder.currentBufferTarget.hasError = true
|
|
112
|
-
// run once
|
|
113
|
-
if (this.mode === MODE.ERROR && globalScope?.document.visibilityState === 'visible') {
|
|
114
|
-
this.switchToFull()
|
|
115
|
-
}
|
|
116
|
-
}, this.featureName, this.ee)
|
|
117
|
-
|
|
118
107
|
const { error_sampling_rate, sampling_rate, autoStart, block_selector, mask_text_selector, mask_all_inputs, inline_stylesheet, inline_images, collect_fonts } = getConfigurationValue(this.agentIdentifier, 'session_replay')
|
|
119
108
|
|
|
120
109
|
this.waitForFlags(['sr']).then(([flagOn]) => {
|
|
@@ -150,6 +139,14 @@ export class Aggregate extends AggregateBase {
|
|
|
150
139
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/ErrorSamplingRate/Value', error_sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
151
140
|
}
|
|
152
141
|
|
|
142
|
+
handleError (e) {
|
|
143
|
+
if (this.recorder) this.recorder.currentBufferTarget.hasError = true
|
|
144
|
+
// run once
|
|
145
|
+
if (this.mode === MODE.ERROR && globalScope?.document.visibilityState === 'visible') {
|
|
146
|
+
this.switchToFull()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
153
150
|
switchToFull () {
|
|
154
151
|
this.mode = MODE.FULL
|
|
155
152
|
// if the error was noticed AFTER the recorder was already imported....
|
|
@@ -210,12 +207,13 @@ export class Aggregate extends AggregateBase {
|
|
|
210
207
|
} catch (err) {
|
|
211
208
|
return this.abort(ABORT_REASONS.IMPORT)
|
|
212
209
|
}
|
|
210
|
+
} else {
|
|
211
|
+
this.recorder.parent = this
|
|
213
212
|
}
|
|
214
213
|
|
|
215
214
|
// If an error was noticed before the mode could be set (like in the early lifecycle of the page), immediately set to FULL mode
|
|
216
|
-
if (this.mode === MODE.ERROR && this.errorNoticed)
|
|
217
|
-
|
|
218
|
-
}
|
|
215
|
+
if (this.mode === MODE.ERROR && this.errorNoticed) this.mode = MODE.FULL
|
|
216
|
+
if (!this.preloaded) this.ee.on('err', e => this.handleError(e))
|
|
219
217
|
|
|
220
218
|
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
221
219
|
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
@@ -255,16 +253,29 @@ export class Aggregate extends AggregateBase {
|
|
|
255
253
|
return
|
|
256
254
|
}
|
|
257
255
|
|
|
256
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Harvest/Attempts'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
257
|
+
|
|
258
258
|
let len = 0
|
|
259
259
|
if (!!this.gzipper && !!this.u8) {
|
|
260
|
-
payload.body = this.gzipper(this.u8(`[${payload.body.map(e => {
|
|
261
|
-
if (e.__serialized) return
|
|
262
|
-
|
|
260
|
+
payload.body = this.gzipper(this.u8(`[${payload.body.map(({ __serialized, ...e }) => {
|
|
261
|
+
if (e.__newrelic && __serialized) return __serialized
|
|
262
|
+
const output = { ...e }
|
|
263
|
+
if (!output.__newrelic) {
|
|
264
|
+
output.__newrelic = buildNRMetaNode(e.timestamp, this.timeKeeper)
|
|
265
|
+
output.timestamp = this.timeKeeper.correctAbsoluteTimestamp(e.timestamp)
|
|
266
|
+
}
|
|
267
|
+
return stringify(output)
|
|
263
268
|
}).join(',')}]`))
|
|
264
269
|
len = payload.body.length
|
|
265
270
|
this.scheduler.opts.gzip = true
|
|
266
271
|
} else {
|
|
267
|
-
payload.body = payload.body.map(({ __serialized, ...node }) =>
|
|
272
|
+
payload.body = payload.body.map(({ __serialized, ...node }) => {
|
|
273
|
+
if (node.__newrelic) return node
|
|
274
|
+
const output = { ...node }
|
|
275
|
+
output.__newrelic = buildNRMetaNode(node.timestamp, this.timeKeeper)
|
|
276
|
+
output.timestamp = this.timeKeeper.correctAbsoluteTimestamp(node.timestamp)
|
|
277
|
+
return output
|
|
278
|
+
})
|
|
268
279
|
len = stringify(payload.body).length
|
|
269
280
|
this.scheduler.opts.gzip = false
|
|
270
281
|
}
|
|
@@ -281,6 +292,12 @@ export class Aggregate extends AggregateBase {
|
|
|
281
292
|
return [payload]
|
|
282
293
|
}
|
|
283
294
|
|
|
295
|
+
getCorrectedTimestamp (node) {
|
|
296
|
+
if (!node.timestamp) return
|
|
297
|
+
if (node.__newrelic) return node.timestamp
|
|
298
|
+
return this.timeKeeper.correctAbsoluteTimestamp(node.timestamp)
|
|
299
|
+
}
|
|
300
|
+
|
|
284
301
|
getHarvestContents (recorderEvents) {
|
|
285
302
|
recorderEvents ??= this.recorder.getEvents()
|
|
286
303
|
let events = recorderEvents.events
|
|
@@ -308,8 +325,8 @@ export class Aggregate extends AggregateBase {
|
|
|
308
325
|
|
|
309
326
|
const relativeNow = now()
|
|
310
327
|
|
|
311
|
-
const firstEventTimestamp = events[0]
|
|
312
|
-
const lastEventTimestamp = events[events.length - 1]
|
|
328
|
+
const firstEventTimestamp = this.getCorrectedTimestamp(events[0]) // from rrweb node
|
|
329
|
+
const lastEventTimestamp = this.getCorrectedTimestamp(events[events.length - 1]) // from rrweb node
|
|
313
330
|
const firstTimestamp = firstEventTimestamp || this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp) // from rrweb node || from when the harvest cycle started
|
|
314
331
|
const lastTimestamp = lastEventTimestamp || this.timeKeeper.convertRelativeTimestamp(relativeNow)
|
|
315
332
|
|
|
@@ -341,6 +358,7 @@ export class Aggregate extends AggregateBase {
|
|
|
341
358
|
invalidStylesheetsDetected: stylesheetEvaluator.invalidStylesheetsDetected,
|
|
342
359
|
inlinedAllStylesheets: recorderEvents.inlinedAllStylesheets,
|
|
343
360
|
'rrweb.version': RRWEB_VERSION,
|
|
361
|
+
'payload.type': recorderEvents.type,
|
|
344
362
|
// customer-defined data should go last so that if it exceeds the query param padding limit it will be truncated instead of important attrs
|
|
345
363
|
...(endUserId && { 'enduser.id': endUserId })
|
|
346
364
|
// The Query Param is being arbitrarily limited in length here. It is also applied when estimating the size of the payload in getPayloadSize()
|
|
@@ -24,6 +24,11 @@ export class Instrument extends InstrumentBase {
|
|
|
24
24
|
} catch (err) { }
|
|
25
25
|
|
|
26
26
|
if (this.#canPreloadRecorder(session)) {
|
|
27
|
+
/** If this is preloaded, set up a buffer, if not, later when sampling we will set up a .on for live events */
|
|
28
|
+
this.ee.on('err', (e) => {
|
|
29
|
+
this.errorNoticed = true
|
|
30
|
+
if (this.featAggregate) this.featAggregate.handleError()
|
|
31
|
+
})
|
|
27
32
|
this.#startRecording(session?.sessionReplayMode)
|
|
28
33
|
} else {
|
|
29
34
|
this.importAggregator()
|
|
@@ -45,9 +50,9 @@ export class Instrument extends InstrumentBase {
|
|
|
45
50
|
|
|
46
51
|
async #startRecording (mode) {
|
|
47
52
|
const { Recorder } = (await import(/* webpackChunkName: "recorder" */'../shared/recorder'))
|
|
48
|
-
this.recorder = new Recorder({ mode, agentIdentifier: this.agentIdentifier })
|
|
53
|
+
this.recorder = new Recorder({ mode, agentIdentifier: this.agentIdentifier, ee: this.ee })
|
|
49
54
|
this.recorder.startRecording()
|
|
50
55
|
this.abortHandler = this.recorder.stopRecording
|
|
51
|
-
this.importAggregator({ recorder: this.recorder })
|
|
56
|
+
this.importAggregator({ recorder: this.recorder, errorNoticed: this.errorNoticed })
|
|
52
57
|
}
|
|
53
58
|
}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
export class RecorderEvents {
|
|
2
|
-
constructor (
|
|
2
|
+
constructor () {
|
|
3
3
|
/** The buffer to hold recorder event nodes */
|
|
4
4
|
this.events = []
|
|
5
5
|
/** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs.
|
|
6
6
|
* cycle timestamps are used as fallbacks if event timestamps cannot be used
|
|
7
7
|
*/
|
|
8
8
|
this.cycleTimestamp = Date.now()
|
|
9
|
-
/** Payload metadata -- Whether timestamps can be corrected, defaults as false, can be set to true if timekeeper is present at init time. Used to determine
|
|
10
|
-
* if harvest needs to re-loop through nodes and correct them before sending. Ideal behavior is to correct them as they flow into the recorder
|
|
11
|
-
* to prevent re-looping, but is not always possible since the timekeeper is not set until after page load and the recorder can be preloaded.
|
|
12
|
-
*/
|
|
13
|
-
this.canCorrectTimestamps = !!canCorrectTimestamps
|
|
14
9
|
/** A value which increments with every new mutation node reported. Resets after a harvest is sent */
|
|
15
10
|
this.payloadBytesEstimation = 0
|
|
16
11
|
/** Payload metadata -- Should indicate that the payload being sent has a full DOM snapshot. This can happen
|