@newrelic/browser-agent 1.266.0 → 1.268.0
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 +29 -0
- package/dist/cjs/common/config/init.js +4 -3
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/dom/iframe.js +10 -0
- package/dist/cjs/common/dom/selector-path.js +48 -0
- package/dist/cjs/common/event-listener/event-listener-opts.js +4 -26
- package/dist/cjs/common/timing/time-keeper.js +14 -12
- package/dist/cjs/common/util/stringify.js +3 -1
- package/dist/cjs/common/vitals/interaction-to-next-paint.js +11 -3
- package/dist/cjs/common/vitals/largest-contentful-paint.js +3 -1
- package/dist/cjs/features/generic_events/aggregate/index.js +80 -9
- package/dist/cjs/features/generic_events/aggregate/user-actions/aggregated-user-action.js +39 -0
- package/dist/cjs/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +77 -0
- package/dist/cjs/features/generic_events/constants.js +6 -2
- package/dist/cjs/features/generic_events/instrument/index.js +12 -1
- package/dist/cjs/features/jserrors/aggregate/index.js +2 -2
- package/dist/cjs/features/logging/aggregate/index.js +1 -1
- package/dist/cjs/features/metrics/aggregate/index.js +2 -1
- package/dist/cjs/features/page_view_event/aggregate/index.js +10 -10
- package/dist/cjs/features/session_replay/aggregate/index.js +6 -6
- package/dist/cjs/features/session_replay/shared/recorder.js +22 -14
- package/dist/cjs/features/session_replay/shared/stylesheet-evaluator.js +5 -4
- package/dist/cjs/features/session_trace/aggregate/index.js +6 -4
- package/dist/cjs/features/utils/event-buffer.js +2 -1
- package/dist/cjs/loaders/browser-agent.js +2 -1
- package/dist/esm/common/config/init.js +4 -3
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/dom/iframe.js +4 -0
- package/dist/esm/common/dom/selector-path.js +41 -0
- package/dist/esm/common/event-listener/event-listener-opts.js +4 -27
- package/dist/esm/common/timing/time-keeper.js +14 -11
- package/dist/esm/common/util/stringify.js +3 -1
- package/dist/esm/common/vitals/interaction-to-next-paint.js +11 -3
- package/dist/esm/common/vitals/largest-contentful-paint.js +3 -1
- package/dist/esm/features/generic_events/aggregate/index.js +82 -11
- package/dist/esm/features/generic_events/aggregate/user-actions/aggregated-user-action.js +32 -0
- package/dist/esm/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +70 -0
- package/dist/esm/features/generic_events/constants.js +5 -1
- package/dist/esm/features/generic_events/instrument/index.js +14 -3
- package/dist/esm/features/jserrors/aggregate/index.js +2 -2
- package/dist/esm/features/logging/aggregate/index.js +1 -1
- package/dist/esm/features/metrics/aggregate/index.js +2 -1
- package/dist/esm/features/page_view_event/aggregate/index.js +10 -10
- package/dist/esm/features/session_replay/aggregate/index.js +6 -6
- package/dist/esm/features/session_replay/shared/recorder.js +22 -14
- package/dist/esm/features/session_replay/shared/stylesheet-evaluator.js +5 -4
- package/dist/esm/features/session_trace/aggregate/index.js +6 -4
- package/dist/esm/features/utils/event-buffer.js +2 -1
- package/dist/esm/loaders/browser-agent.js +2 -1
- package/dist/types/common/dom/iframe.d.ts +2 -0
- package/dist/types/common/dom/iframe.d.ts.map +1 -0
- package/dist/types/common/dom/selector-path.d.ts +2 -0
- package/dist/types/common/dom/selector-path.d.ts.map +1 -0
- package/dist/types/common/event-listener/event-listener-opts.d.ts +2 -2
- package/dist/types/common/event-listener/event-listener-opts.d.ts.map +1 -1
- package/dist/types/common/timing/time-keeper.d.ts +8 -1
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
- package/dist/types/common/util/stringify.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts +16 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/user-actions/aggregated-user-action.d.ts +22 -0
- package/dist/types/features/generic_events/aggregate/user-actions/aggregated-user-action.d.ts.map +1 -0
- package/dist/types/features/generic_events/aggregate/user-actions/user-actions-aggregator.d.ts +12 -0
- package/dist/types/features/generic_events/aggregate/user-actions/user-actions-aggregator.d.ts.map +1 -0
- package/dist/types/features/generic_events/constants.d.ts +4 -0
- package/dist/types/features/generic_events/constants.d.ts.map +1 -1
- package/dist/types/features/generic_events/instrument/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +2 -2
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/stylesheet-evaluator.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/event-buffer.d.ts +2 -1
- package/dist/types/features/utils/event-buffer.d.ts.map +1 -1
- package/dist/types/loaders/browser-agent.d.ts.map +1 -1
- package/package.json +5 -2
- package/src/common/config/init.js +2 -2
- package/src/common/dom/iframe.js +4 -0
- package/src/common/dom/selector-path.js +45 -0
- package/src/common/event-listener/event-listener-opts.js +5 -30
- package/src/common/timing/__mocks__/time-keeper.js +1 -0
- package/src/common/timing/time-keeper.js +14 -12
- package/src/common/util/stringify.js +3 -1
- package/src/common/vitals/interaction-to-next-paint.js +9 -3
- package/src/common/vitals/largest-contentful-paint.js +2 -1
- package/src/features/generic_events/aggregate/index.js +74 -14
- package/src/features/generic_events/aggregate/user-actions/aggregated-user-action.js +33 -0
- package/src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +73 -0
- package/src/features/generic_events/constants.js +6 -0
- package/src/features/generic_events/instrument/index.js +19 -3
- package/src/features/jserrors/aggregate/index.js +2 -6
- package/src/features/logging/aggregate/index.js +1 -3
- package/src/features/metrics/aggregate/index.js +2 -1
- package/src/features/page_view_event/aggregate/index.js +10 -14
- package/src/features/session_replay/aggregate/index.js +7 -10
- package/src/features/session_replay/shared/recorder.js +23 -14
- package/src/features/session_replay/shared/stylesheet-evaluator.js +5 -4
- package/src/features/session_trace/aggregate/index.js +6 -10
- package/src/features/utils/event-buffer.js +2 -1
- package/src/loaders/browser-agent.js +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,35 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.268.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.267.0...v1.268.0) (2024-10-08)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add UserAction to GenericEvents ([#1186](https://github.com/newrelic/newrelic-browser-agent/issues/1186)) ([1b0bb1d](https://github.com/newrelic/newrelic-browser-agent/commit/1b0bb1dd992674f77c41a73449b64b022cdfc83c))
|
|
12
|
+
* Aggregate UserActions ([#1195](https://github.com/newrelic/newrelic-browser-agent/issues/1195)) ([b5e4c6d](https://github.com/newrelic/newrelic-browser-agent/commit/b5e4c6dcdcfce3ab88132f2a1d82d4d02ab7640b))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* Always return a string for custom stringify method ([#1207](https://github.com/newrelic/newrelic-browser-agent/issues/1207)) ([94a9a0b](https://github.com/newrelic/newrelic-browser-agent/commit/94a9a0b465e9ea34132317236d47ac9f62ee4051))
|
|
18
|
+
* Force generic events feature to clear buffer when unloading ([#1202](https://github.com/newrelic/newrelic-browser-agent/issues/1202)) ([d3fac07](https://github.com/newrelic/newrelic-browser-agent/commit/d3fac07379d18c98e9838152a31a482ff25fe5bf))
|
|
19
|
+
|
|
20
|
+
## [1.267.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.266.0...v1.267.0) (2024-09-23)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
* add soft navigations to Browser-Agent loader ([#1191](https://github.com/newrelic/newrelic-browser-agent/issues/1191)) ([fd033a7](https://github.com/newrelic/newrelic-browser-agent/commit/fd033a7be52fed01e5a67a5f8060cf6ec080c769))
|
|
26
|
+
* Improve notifications of stylesheet status for session replay ([#1190](https://github.com/newrelic/newrelic-browser-agent/issues/1190)) ([a21b939](https://github.com/newrelic/newrelic-browser-agent/commit/a21b939884697fc4951e6d4cdaceecaa9b000810))
|
|
27
|
+
* Update TimeKeeper Source of Truth ([#1181](https://github.com/newrelic/newrelic-browser-agent/issues/1181)) ([60d63cf](https://github.com/newrelic/newrelic-browser-agent/commit/60d63cf416529d700abaa6fa36ba3e64402b35a9))
|
|
28
|
+
* Upgrade to web-vitals v4 ([#1193](https://github.com/newrelic/newrelic-browser-agent/issues/1193)) ([81349b8](https://github.com/newrelic/newrelic-browser-agent/commit/81349b82f5befd88f425cce1dee06f08fcea8a05))
|
|
29
|
+
|
|
30
|
+
### Bug Fixes
|
|
31
|
+
|
|
32
|
+
* Improve reliability of customMasker ([#1197](https://github.com/newrelic/newrelic-browser-agent/issues/1197)) ([9f2ef1f](https://github.com/newrelic/newrelic-browser-agent/commit/9f2ef1f7d0e5dceaf61745a47849a3b2cc930c53))
|
|
33
|
+
* Stringify now returns an empty string if failed to transform ([#1198](https://github.com/newrelic/newrelic-browser-agent/issues/1198)) ([310937a](https://github.com/newrelic/newrelic-browser-agent/commit/310937ae20a004f91f3ccb4ba6b1d1b230d92632))
|
|
34
|
+
|
|
6
35
|
## [1.266.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.265.1...v1.266.0) (2024-09-16)
|
|
7
36
|
|
|
8
37
|
|
|
@@ -80,6 +80,9 @@ const model = () => {
|
|
|
80
80
|
page_action: {
|
|
81
81
|
enabled: true
|
|
82
82
|
},
|
|
83
|
+
user_actions: {
|
|
84
|
+
enabled: true
|
|
85
|
+
},
|
|
83
86
|
page_view_event: {
|
|
84
87
|
enabled: true,
|
|
85
88
|
autoStart: true
|
|
@@ -117,10 +120,8 @@ const model = () => {
|
|
|
117
120
|
// serialize fonts for collection without public asset url, this is currently broken in RRWeb -- https://github.com/rrweb-io/rrweb/issues/1304. When fixed, revisit with test cases
|
|
118
121
|
inline_images: false,
|
|
119
122
|
// serialize images for collection without public asset url -- right now this is only useful for testing as it easily generates payloads too large to be harvested
|
|
120
|
-
inline_stylesheet: true,
|
|
121
|
-
// serialize css for collection without public asset url
|
|
122
123
|
fix_stylesheets: true,
|
|
123
|
-
// fetch missing stylesheet resources for inlining
|
|
124
|
+
// fetch missing stylesheet resources for inlining
|
|
124
125
|
// recording config settings
|
|
125
126
|
mask_all_inputs: true,
|
|
126
127
|
// this has a getter/setter to facilitate validation of the selectors
|
|
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
12
12
|
/**
|
|
13
13
|
* Exposes the version of the agent
|
|
14
14
|
*/
|
|
15
|
-
const VERSION = exports.VERSION = "1.
|
|
15
|
+
const VERSION = exports.VERSION = "1.268.0";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the build type of the agent
|
|
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
12
12
|
/**
|
|
13
13
|
* Exposes the version of the agent
|
|
14
14
|
*/
|
|
15
|
-
const VERSION = exports.VERSION = "1.
|
|
15
|
+
const VERSION = exports.VERSION = "1.268.0";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the build type of the agent
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.generateSelectorPath = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Generates a CSS selector path for the given element, if possible
|
|
9
|
+
* @param {HTMLElement} elem
|
|
10
|
+
* @param {boolean} includeId
|
|
11
|
+
* @param {boolean} includeClass
|
|
12
|
+
* @returns {string|undefined}
|
|
13
|
+
*/
|
|
14
|
+
const generateSelectorPath = elem => {
|
|
15
|
+
if (!elem) return;
|
|
16
|
+
const getNthOfTypeIndex = node => {
|
|
17
|
+
try {
|
|
18
|
+
let i = 1;
|
|
19
|
+
const {
|
|
20
|
+
tagName
|
|
21
|
+
} = node;
|
|
22
|
+
while (node.previousElementSibling) {
|
|
23
|
+
if (node.previousElementSibling.tagName === tagName) i++;
|
|
24
|
+
node = node.previousElementSibling;
|
|
25
|
+
}
|
|
26
|
+
return i;
|
|
27
|
+
} catch (err) {
|
|
28
|
+
// do nothing for now. An invalid child count will make the path selector not return a nth-of-type selector statement
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
let pathSelector = '';
|
|
32
|
+
let index = getNthOfTypeIndex(elem);
|
|
33
|
+
try {
|
|
34
|
+
while (elem?.tagName) {
|
|
35
|
+
const {
|
|
36
|
+
id,
|
|
37
|
+
localName
|
|
38
|
+
} = elem;
|
|
39
|
+
const selector = [localName, id ? "#".concat(id) : '', pathSelector ? ">".concat(pathSelector) : ''].join('');
|
|
40
|
+
pathSelector = selector;
|
|
41
|
+
elem = elem.parentNode;
|
|
42
|
+
}
|
|
43
|
+
} catch (err) {
|
|
44
|
+
// do nothing for now
|
|
45
|
+
}
|
|
46
|
+
return pathSelector ? index ? "".concat(pathSelector, ":nth-of-type(").concat(index, ")") : pathSelector : undefined;
|
|
47
|
+
};
|
|
48
|
+
exports.generateSelectorPath = generateSelectorPath;
|
|
@@ -6,34 +6,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.documentAddEventListener = documentAddEventListener;
|
|
7
7
|
exports.eventListenerOpts = eventListenerOpts;
|
|
8
8
|
exports.windowAddEventListener = windowAddEventListener;
|
|
9
|
-
var _runtime = require("../constants/runtime");
|
|
10
|
-
/*
|
|
11
|
-
* See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#safely_detecting_option_support
|
|
12
|
-
*/
|
|
13
|
-
let passiveSupported = false;
|
|
14
|
-
let signalSupported = false;
|
|
15
|
-
try {
|
|
16
|
-
const options = {
|
|
17
|
-
get passive() {
|
|
18
|
-
// this function will be called when the browser attempts to access the passive property
|
|
19
|
-
passiveSupported = true;
|
|
20
|
-
return false;
|
|
21
|
-
},
|
|
22
|
-
get signal() {
|
|
23
|
-
signalSupported = true;
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
_runtime.globalScope.addEventListener('test', null, options);
|
|
28
|
-
_runtime.globalScope.removeEventListener('test', null, options);
|
|
29
|
-
} catch (err) {}
|
|
30
9
|
function eventListenerOpts(useCapture, abortSignal) {
|
|
31
|
-
return
|
|
32
|
-
capture:
|
|
33
|
-
passive:
|
|
34
|
-
// passive defaults to false
|
|
10
|
+
return {
|
|
11
|
+
capture: useCapture,
|
|
12
|
+
passive: false,
|
|
35
13
|
signal: abortSignal
|
|
36
|
-
}
|
|
14
|
+
};
|
|
37
15
|
}
|
|
38
16
|
|
|
39
17
|
/** Do not use this within the worker context. */
|
|
@@ -6,8 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.TimeKeeper = void 0;
|
|
7
7
|
var _runtime = require("../constants/runtime");
|
|
8
8
|
var _runtime2 = require("../config/runtime");
|
|
9
|
-
const rfc2616Regex = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0-3][0-9]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-9]{4}) ([01][0-9]|2[0-3])(:[0-5][0-9]){2} GMT$/;
|
|
10
|
-
|
|
11
9
|
/**
|
|
12
10
|
* Class used to adjust the timestamp of harvested data to New Relic server time. This
|
|
13
11
|
* is done by tracking the performance timings of the RUM call and applying a calculation
|
|
@@ -58,26 +56,21 @@ class TimeKeeper {
|
|
|
58
56
|
* @param rumRequest {XMLHttpRequest} The xhr for the rum request
|
|
59
57
|
* @param startTime {number} The start time of the RUM request
|
|
60
58
|
* @param endTime {number} The end time of the RUM request
|
|
59
|
+
* @param nrServerTime {number} the unix number value of the NR server time in MS, returned in the RUM request body
|
|
61
60
|
*/
|
|
62
|
-
processRumRequest(rumRequest, startTime, endTime) {
|
|
61
|
+
processRumRequest(rumRequest, startTime, endTime, nrServerTime) {
|
|
63
62
|
this.processStoredDiff(); // Check session entity for stored time diff
|
|
64
63
|
if (this.#ready) return; // Server time calculated from session entity
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
if (!responseDateHeader) {
|
|
68
|
-
throw new Error('Missing date header on rum response.');
|
|
69
|
-
}
|
|
70
|
-
if (!rfc2616Regex.test(responseDateHeader)) {
|
|
71
|
-
throw new Error('Date header invalid format.');
|
|
72
|
-
}
|
|
65
|
+
if (!nrServerTime) throw new Error('nrServerTime not found');
|
|
73
66
|
const medianRumOffset = (endTime - startTime) / 2;
|
|
74
67
|
const serverOffset = startTime + medianRumOffset;
|
|
75
68
|
|
|
76
69
|
// Corrected page origin time
|
|
77
|
-
this.#correctedOriginTime = Math.floor(
|
|
70
|
+
this.#correctedOriginTime = Math.floor(nrServerTime - serverOffset);
|
|
78
71
|
this.#localTimeDiff = _runtime.originTime - this.#correctedOriginTime;
|
|
79
72
|
if (isNaN(this.#correctedOriginTime)) {
|
|
80
|
-
throw new Error('
|
|
73
|
+
throw new Error('Failed to correct browser time to server time');
|
|
81
74
|
}
|
|
82
75
|
this.#session?.write({
|
|
83
76
|
serverTimeDiff: this.#localTimeDiff
|
|
@@ -114,6 +107,15 @@ class TimeKeeper {
|
|
|
114
107
|
return timestamp - this.#localTimeDiff;
|
|
115
108
|
}
|
|
116
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Corrects relative timestamp to NR server time (epoch).
|
|
112
|
+
* @param {DOMHighResTimeStamp} relativeTime
|
|
113
|
+
* @returns {number}
|
|
114
|
+
*/
|
|
115
|
+
correctRelativeTimestamp(relativeTime) {
|
|
116
|
+
return this.correctAbsoluteTimestamp(this.convertRelativeTimestamp(relativeTime));
|
|
117
|
+
}
|
|
118
|
+
|
|
117
119
|
/** Process the session entity and use the info to set the main time calculations if present */
|
|
118
120
|
processStoredDiff() {
|
|
119
121
|
if (this.#ready) return; // Time diff has already been calculated
|
|
@@ -36,12 +36,14 @@ const getCircularReplacer = () => {
|
|
|
36
36
|
*/
|
|
37
37
|
function stringify(val) {
|
|
38
38
|
try {
|
|
39
|
-
return JSON.stringify(val, getCircularReplacer());
|
|
39
|
+
return JSON.stringify(val, getCircularReplacer()) ?? '';
|
|
40
40
|
} catch (e) {
|
|
41
41
|
try {
|
|
42
42
|
_contextualEe.ee.emit('internal-error', [e]);
|
|
43
43
|
} catch (err) {
|
|
44
44
|
// do nothing
|
|
45
45
|
}
|
|
46
|
+
// return a string so that downstream users of the method do not throw errors
|
|
47
|
+
return '';
|
|
46
48
|
}
|
|
47
49
|
}
|
|
@@ -18,9 +18,17 @@ if (_runtime.isBrowserScope) {
|
|
|
18
18
|
}) => {
|
|
19
19
|
const attrs = {
|
|
20
20
|
metricId: id,
|
|
21
|
-
eventTarget: attribution.
|
|
22
|
-
|
|
23
|
-
eventTime: attribution.
|
|
21
|
+
eventTarget: attribution.interactionTarget,
|
|
22
|
+
// event* attrs deprecated in v4, kept for NR backwards compatibility
|
|
23
|
+
eventTime: attribution.interactionTime,
|
|
24
|
+
// event* attrs deprecated in v4, kept for NR backwards compatibility
|
|
25
|
+
interactionTarget: attribution.interactionTarget,
|
|
26
|
+
interactionTime: attribution.interactionTime,
|
|
27
|
+
interactionType: attribution.interactionType,
|
|
28
|
+
inputDelay: attribution.inputDelay,
|
|
29
|
+
nextPaintTime: attribution.nextPaintTime,
|
|
30
|
+
processingDuration: attribution.processingDuration,
|
|
31
|
+
presentationDelay: attribution.presentationDelay,
|
|
24
32
|
loadState: attribution.loadState
|
|
25
33
|
};
|
|
26
34
|
interactionToNextPaint.update({
|
|
@@ -26,7 +26,9 @@ if (_runtime.isBrowserScope) {
|
|
|
26
26
|
element: attribution.element,
|
|
27
27
|
timeToFirstByte: attribution.timeToFirstByte,
|
|
28
28
|
resourceLoadDelay: attribution.resourceLoadDelay,
|
|
29
|
-
|
|
29
|
+
resourceLoadDuration: attribution.resourceLoadDuration,
|
|
30
|
+
resourceLoadTime: attribution.resourceLoadDuration,
|
|
31
|
+
// kept for NR backwards compatibility, deprecated in v3->v4
|
|
30
32
|
elementRenderDelay: attribution.elementRenderDelay
|
|
31
33
|
};
|
|
32
34
|
if (attribution.url) attrs.elUrl = (0, _cleanUrl.cleanURL)(attribution.url);
|
|
@@ -21,6 +21,8 @@ var _constants2 = require("../../metrics/constants");
|
|
|
21
21
|
var _eventBuffer = require("../../utils/event-buffer");
|
|
22
22
|
var _traverse = require("../../../common/util/traverse");
|
|
23
23
|
var _agentConstants = require("../../../common/constants/agent-constants");
|
|
24
|
+
var _userActionsAggregator = require("./user-actions/user-actions-aggregator");
|
|
25
|
+
var _iframe = require("../../../common/dom/iframe");
|
|
24
26
|
/*
|
|
25
27
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
26
28
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -31,8 +33,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
31
33
|
static featureName = _constants.FEATURE_NAME;
|
|
32
34
|
constructor(agentIdentifier, aggregator) {
|
|
33
35
|
super(agentIdentifier, aggregator, _constants.FEATURE_NAME);
|
|
36
|
+
const agentInit = (0, _init.getConfiguration)(this.agentIdentifier);
|
|
34
37
|
this.eventsPerHarvest = 1000;
|
|
35
|
-
this.harvestTimeSeconds =
|
|
38
|
+
this.harvestTimeSeconds = agentInit.generic_events.harvestTimeSeconds;
|
|
36
39
|
this.referrerUrl = _runtime2.isBrowserScope && document.referrer ? (0, _cleanUrl.cleanURL)(document.referrer) : undefined;
|
|
37
40
|
this.events = new _eventBuffer.EventBuffer();
|
|
38
41
|
this.#agentRuntime = (0, _runtime.getRuntime)(this.agentIdentifier);
|
|
@@ -42,16 +45,16 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
42
45
|
(0, _drain.deregisterDrain)(this.agentIdentifier, this.featureName);
|
|
43
46
|
return;
|
|
44
47
|
}
|
|
45
|
-
|
|
48
|
+
const preHarvestMethods = [];
|
|
49
|
+
if (agentInit.page_action.enabled) {
|
|
46
50
|
(0, _registerHandler.registerHandler)('api-addPageAction', (timestamp, name, attributes) => {
|
|
47
51
|
this.addEvent({
|
|
48
52
|
...attributes,
|
|
49
53
|
eventType: 'PageAction',
|
|
50
|
-
timestamp: Math.floor(this.#agentRuntime.timeKeeper.
|
|
54
|
+
timestamp: Math.floor(this.#agentRuntime.timeKeeper.correctRelativeTimestamp(timestamp)),
|
|
51
55
|
timeSinceLoad: timestamp / 1000,
|
|
52
56
|
actionName: name,
|
|
53
57
|
referrerUrl: this.referrerUrl,
|
|
54
|
-
currentUrl: (0, _cleanUrl.cleanURL)('' + location),
|
|
55
58
|
...(_runtime2.isBrowserScope && {
|
|
56
59
|
browserWidth: window.document.documentElement?.clientWidth,
|
|
57
60
|
browserHeight: window.document.documentElement?.clientHeight
|
|
@@ -59,16 +62,83 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
59
62
|
});
|
|
60
63
|
}, this.featureName, this.ee);
|
|
61
64
|
}
|
|
65
|
+
if (_runtime2.isBrowserScope && agentInit.user_actions.enabled) {
|
|
66
|
+
this.userActionAggregator = new _userActionsAggregator.UserActionsAggregator();
|
|
67
|
+
this.addUserAction = aggregatedUserAction => {
|
|
68
|
+
try {
|
|
69
|
+
/** The aggregator process only returns an event when it is "done" aggregating -
|
|
70
|
+
* so we still need to validate that an event was given to this method before we try to add */
|
|
71
|
+
if (aggregatedUserAction?.event) {
|
|
72
|
+
const {
|
|
73
|
+
target,
|
|
74
|
+
timeStamp,
|
|
75
|
+
type
|
|
76
|
+
} = aggregatedUserAction.event;
|
|
77
|
+
this.addEvent({
|
|
78
|
+
eventType: 'UserAction',
|
|
79
|
+
timestamp: Math.floor(this.#agentRuntime.timeKeeper.correctRelativeTimestamp(timeStamp)),
|
|
80
|
+
action: type,
|
|
81
|
+
actionCount: aggregatedUserAction.count,
|
|
82
|
+
actionDuration: aggregatedUserAction.relativeMs[aggregatedUserAction.relativeMs.length - 1],
|
|
83
|
+
actionMs: aggregatedUserAction.relativeMs,
|
|
84
|
+
rageClick: aggregatedUserAction.rageClick,
|
|
85
|
+
target: aggregatedUserAction.selectorPath,
|
|
86
|
+
...((0, _iframe.isIFrameWindow)(window) && {
|
|
87
|
+
iframe: true
|
|
88
|
+
}),
|
|
89
|
+
...(target?.id && {
|
|
90
|
+
targetId: target.id
|
|
91
|
+
}),
|
|
92
|
+
...(target?.tagName && {
|
|
93
|
+
targetTag: target.tagName
|
|
94
|
+
}),
|
|
95
|
+
...(target?.type && {
|
|
96
|
+
targetType: target.type
|
|
97
|
+
}),
|
|
98
|
+
...(target?.className && {
|
|
99
|
+
targetClass: target.className
|
|
100
|
+
})
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
} catch (e) {
|
|
104
|
+
// do nothing for now
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
(0, _registerHandler.registerHandler)('ua', evt => {
|
|
108
|
+
/** the processor will return the previously aggregated event if it has been completed by processing the current event */
|
|
109
|
+
this.addUserAction(this.userActionAggregator.process(evt));
|
|
110
|
+
}, this.featureName, this.ee);
|
|
111
|
+
preHarvestMethods.push((options = {}) => {
|
|
112
|
+
/** send whatever UserActions have been aggregated up to this point
|
|
113
|
+
* if we are in a final harvest. By accessing the aggregationEvent, the aggregation is then force-cleared */
|
|
114
|
+
if (options.isFinalHarvest) this.addUserAction(this.userActionAggregator.aggregationEvent);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
62
117
|
this.harvestScheduler = new _harvestScheduler.HarvestScheduler('ins', {
|
|
63
118
|
onFinished: (...args) => this.onHarvestFinished(...args)
|
|
64
119
|
}, this);
|
|
65
|
-
this.harvestScheduler.harvest.on('ins', (...args) =>
|
|
120
|
+
this.harvestScheduler.harvest.on('ins', (...args) => {
|
|
121
|
+
preHarvestMethods.forEach(fn => fn(...args));
|
|
122
|
+
return this.onHarvestStarted(...args);
|
|
123
|
+
});
|
|
66
124
|
this.harvestScheduler.startTimer(this.harvestTimeSeconds, 0);
|
|
67
125
|
this.drain();
|
|
68
126
|
});
|
|
69
127
|
}
|
|
70
128
|
|
|
71
129
|
// WARNING: Insights times are in seconds. EXCEPT timestamp, which is in ms.
|
|
130
|
+
/** Some keys are set by the query params or request headers sent with the harvest and override the body values, so check those before adding new standard body values...
|
|
131
|
+
* see harvest.js#baseQueryString for more info on the query params
|
|
132
|
+
* Notably:
|
|
133
|
+
* * name: set by the `t=` query param
|
|
134
|
+
* * appId: set by the `a=` query param
|
|
135
|
+
* * standalone: set by the `sa=` query param
|
|
136
|
+
* * session: set by the `s=` query param
|
|
137
|
+
* * sessionTraceId: set by the `ptid=` query param
|
|
138
|
+
* * userAgent*: set by the userAgent header
|
|
139
|
+
* @param {object=} obj the event object for storing in the event buffer
|
|
140
|
+
* @returns void
|
|
141
|
+
*/
|
|
72
142
|
addEvent(obj = {}) {
|
|
73
143
|
if (!obj || !Object.keys(obj).length) return;
|
|
74
144
|
if (!obj.eventType) {
|
|
@@ -81,9 +151,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
81
151
|
}
|
|
82
152
|
const defaultEventAttributes = {
|
|
83
153
|
/** should be overridden by the event-specific attributes, but just in case -- set it to now() */
|
|
84
|
-
timestamp: Math.floor(this.#agentRuntime.timeKeeper.
|
|
85
|
-
/** all generic events require
|
|
86
|
-
pageUrl: (0, _cleanUrl.cleanURL)(
|
|
154
|
+
timestamp: Math.floor(this.#agentRuntime.timeKeeper.correctRelativeTimestamp((0, _now.now)())),
|
|
155
|
+
/** all generic events require pageUrl(s) */
|
|
156
|
+
pageUrl: (0, _cleanUrl.cleanURL)('' + _runtime2.initialLocation),
|
|
157
|
+
currentUrl: (0, _cleanUrl.cleanURL)('' + location)
|
|
87
158
|
};
|
|
88
159
|
const eventAttributes = {
|
|
89
160
|
/** Agent-level custom attributes */
|
|
@@ -111,7 +182,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
111
182
|
ins: this.events.buffer
|
|
112
183
|
}, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string')
|
|
113
184
|
};
|
|
114
|
-
if (options.retry) this.events.hold();
|
|
185
|
+
if (options.retry) this.events.hold();else this.events.clear();
|
|
115
186
|
return payload;
|
|
116
187
|
}
|
|
117
188
|
onHarvestFinished(result) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.AggregatedUserAction = void 0;
|
|
7
|
+
var _constants = require("../../constants");
|
|
8
|
+
class AggregatedUserAction {
|
|
9
|
+
constructor(evt, selectorPath) {
|
|
10
|
+
this.event = evt;
|
|
11
|
+
this.count = 1;
|
|
12
|
+
this.originMs = Math.floor(evt.timeStamp);
|
|
13
|
+
this.relativeMs = [0];
|
|
14
|
+
this.selectorPath = selectorPath;
|
|
15
|
+
this.rageClick = undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Aggregates the count and maintains the relative MS array for matching events
|
|
20
|
+
* Will determine if a rage click was observed as part of the aggregation
|
|
21
|
+
* @param {Event} evt
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
aggregate(evt) {
|
|
25
|
+
this.count++;
|
|
26
|
+
this.relativeMs.push(Math.floor(evt.timeStamp - this.originMs));
|
|
27
|
+
if (this.isRageClick()) this.rageClick = true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Determines if the current set of relative ms values constitutes a rage click
|
|
32
|
+
* @returns {boolean}
|
|
33
|
+
*/
|
|
34
|
+
isRageClick() {
|
|
35
|
+
const len = this.relativeMs.length;
|
|
36
|
+
return this.event.type === 'click' && len >= _constants.RAGE_CLICK_THRESHOLD_EVENTS && this.relativeMs[len - 1] - this.relativeMs[len - _constants.RAGE_CLICK_THRESHOLD_EVENTS] < _constants.RAGE_CLICK_THRESHOLD_MS;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.AggregatedUserAction = AggregatedUserAction;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.UserActionsAggregator = void 0;
|
|
7
|
+
var _selectorPath = require("../../../../common/dom/selector-path");
|
|
8
|
+
var _constants = require("../../constants");
|
|
9
|
+
var _aggregatedUserAction = require("./aggregated-user-action");
|
|
10
|
+
class UserActionsAggregator {
|
|
11
|
+
/** @type {AggregatedUserAction=} */
|
|
12
|
+
#aggregationEvent = undefined;
|
|
13
|
+
#aggregationKey = '';
|
|
14
|
+
get aggregationEvent() {
|
|
15
|
+
// if this is accessed externally, we need to be done aggregating on it
|
|
16
|
+
// to prevent potential mutability and duplication issues, so the state is cleared upon returning.
|
|
17
|
+
// This value may need to be accessed during an unload harvest.
|
|
18
|
+
const finishedEvent = this.#aggregationEvent;
|
|
19
|
+
this.#aggregationKey = '';
|
|
20
|
+
this.#aggregationEvent = undefined;
|
|
21
|
+
return finishedEvent;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Process the event and determine if a new aggregation set should be made or if it should increment the current aggregation
|
|
26
|
+
* @param {Event} evt The event supplied by the addEventListener callback
|
|
27
|
+
* @returns {AggregatedUserAction|undefined} The previous aggregation set if it has been completed by processing the current event
|
|
28
|
+
*/
|
|
29
|
+
process(evt) {
|
|
30
|
+
if (!evt) return;
|
|
31
|
+
const selectorPath = getSelectorPath(evt);
|
|
32
|
+
const aggregationKey = getAggregationKey(evt, selectorPath);
|
|
33
|
+
if (!!aggregationKey && aggregationKey === this.#aggregationKey) {
|
|
34
|
+
// an aggregation exists already, so lets just continue to increment
|
|
35
|
+
this.#aggregationEvent.aggregate(evt);
|
|
36
|
+
} else {
|
|
37
|
+
// return the prev existing one (if there is one)
|
|
38
|
+
const finishedEvent = this.#aggregationEvent;
|
|
39
|
+
// then set as this new event aggregation
|
|
40
|
+
this.#aggregationKey = aggregationKey;
|
|
41
|
+
this.#aggregationEvent = new _aggregatedUserAction.AggregatedUserAction(evt, selectorPath);
|
|
42
|
+
return finishedEvent;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Generates a selector path for the event, starting with simple cases like window or document and getting more complex for dom-tree traversals as needed.
|
|
49
|
+
* Will return a random selector path value if no other path can be determined, to force the aggregator to skip aggregation for this event.
|
|
50
|
+
* @param {Event} evt
|
|
51
|
+
* @returns {string}
|
|
52
|
+
*/
|
|
53
|
+
exports.UserActionsAggregator = UserActionsAggregator;
|
|
54
|
+
function getSelectorPath(evt) {
|
|
55
|
+
let selectorPath;
|
|
56
|
+
if (_constants.OBSERVED_WINDOW_EVENTS.includes(evt.type) || evt.target === window) selectorPath = 'window';else if (evt.target === document) selectorPath = 'document';
|
|
57
|
+
// if still no selectorPath, generate one from target tree that includes elem ids
|
|
58
|
+
else selectorPath = (0, _selectorPath.generateSelectorPath)(evt.target);
|
|
59
|
+
// if STILL no selectorPath, it will return undefined which will skip aggregation for this event
|
|
60
|
+
return selectorPath;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Returns an aggregation key based on the event type and the selector path of the event's target.
|
|
65
|
+
* Scrollend events are aggregated into one set, no matter what.
|
|
66
|
+
* @param {Event} evt
|
|
67
|
+
* @param {string} selectorPath
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function getAggregationKey(evt, selectorPath) {
|
|
71
|
+
let aggregationKey = evt.type;
|
|
72
|
+
/** aggregate all scrollends into one set (if sequential), no matter what their target is
|
|
73
|
+
* the aggregation group's selector path with be reflected as the first one observed
|
|
74
|
+
* due to the way the aggregation logic works (by storing the initial value and aggregating it) */
|
|
75
|
+
if (evt.type !== 'scrollend') aggregationKey += '-' + selectorPath;
|
|
76
|
+
return aggregationKey;
|
|
77
|
+
}
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.MAX_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = exports.FEATURE_NAME = void 0;
|
|
6
|
+
exports.RAGE_CLICK_THRESHOLD_MS = exports.RAGE_CLICK_THRESHOLD_EVENTS = exports.OBSERVED_WINDOW_EVENTS = exports.OBSERVED_EVENTS = exports.MAX_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = exports.FEATURE_NAME = void 0;
|
|
7
7
|
var _features = require("../../loaders/features/features");
|
|
8
8
|
const FEATURE_NAME = exports.FEATURE_NAME = _features.FEATURE_NAMES.genericEvents;
|
|
9
9
|
const IDEAL_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = 64000;
|
|
10
|
-
const MAX_PAYLOAD_SIZE = exports.MAX_PAYLOAD_SIZE = 1000000;
|
|
10
|
+
const MAX_PAYLOAD_SIZE = exports.MAX_PAYLOAD_SIZE = 1000000;
|
|
11
|
+
const OBSERVED_EVENTS = exports.OBSERVED_EVENTS = ['auxclick', 'click', 'copy', 'keydown', 'paste', 'scrollend'];
|
|
12
|
+
const OBSERVED_WINDOW_EVENTS = exports.OBSERVED_WINDOW_EVENTS = ['focus', 'blur'];
|
|
13
|
+
const RAGE_CLICK_THRESHOLD_EVENTS = exports.RAGE_CLICK_THRESHOLD_EVENTS = 4;
|
|
14
|
+
const RAGE_CLICK_THRESHOLD_MS = exports.RAGE_CLICK_THRESHOLD_MS = 1000;
|
|
@@ -5,7 +5,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.Instrument = exports.GenericEvents = void 0;
|
|
7
7
|
var _init = require("../../../common/config/init");
|
|
8
|
+
var _runtime = require("../../../common/constants/runtime");
|
|
8
9
|
var _drain = require("../../../common/drain/drain");
|
|
10
|
+
var _handle = require("../../../common/event-emitter/handle");
|
|
11
|
+
var _eventListenerOpts = require("../../../common/event-listener/event-listener-opts");
|
|
9
12
|
var _instrumentBase = require("../../utils/instrument-base");
|
|
10
13
|
var _constants = require("../constants");
|
|
11
14
|
/* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
@@ -16,9 +19,17 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
16
19
|
static featureName = _constants.FEATURE_NAME;
|
|
17
20
|
constructor(agentIdentifier, aggregator, auto = true) {
|
|
18
21
|
super(agentIdentifier, aggregator, _constants.FEATURE_NAME, auto);
|
|
19
|
-
const
|
|
22
|
+
const agentInit = (0, _init.getConfiguration)(this.agentIdentifier);
|
|
23
|
+
const genericEventSourceConfigs = [agentInit.page_action.enabled, agentInit.user_actions.enabled
|
|
20
24
|
// other future generic event source configs to go here, like M&Ms, PageResouce, etc.
|
|
21
25
|
];
|
|
26
|
+
if (_runtime.isBrowserScope && agentInit.user_actions.enabled) {
|
|
27
|
+
_constants.OBSERVED_EVENTS.forEach(eventType => (0, _eventListenerOpts.windowAddEventListener)(eventType, evt => (0, _handle.handle)('ua', [evt], undefined, this.featureName, this.ee), true));
|
|
28
|
+
_constants.OBSERVED_WINDOW_EVENTS.forEach(eventType => (0, _eventListenerOpts.windowAddEventListener)(eventType, evt => (0, _handle.handle)('ua', [evt], undefined, this.featureName, this.ee))
|
|
29
|
+
// Capture is not used here so that we don't get element focus/blur events, only the window's as they do not bubble. They are also not cancellable, so no worries about being front of line.
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
22
33
|
/** If any of the sources are active, import the aggregator. otherwise deregister */
|
|
23
34
|
if (genericEventSourceConfigs.some(x => x)) this.importAggregator();else (0, _drain.deregisterDrain)(this.agentIdentifier, this.featureName);
|
|
24
35
|
}
|
|
@@ -167,7 +167,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
167
167
|
if (!this.stackReported[bucketHash]) {
|
|
168
168
|
this.stackReported[bucketHash] = true;
|
|
169
169
|
params.stack_trace = (0, _formatStackTrace.truncateSize)(stackInfo.stackString);
|
|
170
|
-
this.observedAt[bucketHash] = Math.floor(agentRuntime.timeKeeper.
|
|
170
|
+
this.observedAt[bucketHash] = Math.floor(agentRuntime.timeKeeper.correctRelativeTimestamp(time));
|
|
171
171
|
} else {
|
|
172
172
|
params.browser_stack_hash = (0, _stringHashCode.stringHashCode)(stackInfo.stackString);
|
|
173
173
|
}
|
|
@@ -183,7 +183,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
183
183
|
this.pageviewReported[bucketHash] = true;
|
|
184
184
|
}
|
|
185
185
|
params.firstOccurrenceTimestamp = this.observedAt[bucketHash];
|
|
186
|
-
params.timestamp = Math.floor(agentRuntime.timeKeeper.
|
|
186
|
+
params.timestamp = Math.floor(agentRuntime.timeKeeper.correctRelativeTimestamp(time));
|
|
187
187
|
var type = internal ? 'ierr' : 'err';
|
|
188
188
|
var newMetrics = {
|
|
189
189
|
time
|
|
@@ -66,7 +66,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
if (typeof message !== 'string' || !message) return (0, _console.warn)(32);
|
|
69
|
-
const log = new _log.Log(Math.floor(this.#agentRuntime.timeKeeper.
|
|
69
|
+
const log = new _log.Log(Math.floor(this.#agentRuntime.timeKeeper.correctRelativeTimestamp(timestamp)), message, attributes, level);
|
|
70
70
|
const logBytes = log.message.length + (0, _stringify.stringify)(log.attributes).length + log.level.length + 10; // timestamp == 10 chars
|
|
71
71
|
|
|
72
72
|
if (!this.bufferedLogs.canMerge(logBytes)) {
|
|
@@ -16,6 +16,7 @@ var _eventListenerOpts = require("../../../common/event-listener/event-listener-
|
|
|
16
16
|
var _runtime2 = require("../../../common/constants/runtime");
|
|
17
17
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
18
18
|
var _drain = require("../../../common/drain/drain");
|
|
19
|
+
var _iframe = require("../../../common/dom/iframe");
|
|
19
20
|
// import { WEBSOCKET_TAG } from '../../../common/wrap/wrap-websocket'
|
|
20
21
|
// import { handleWebsocketEvents } from './websocket-detection'
|
|
21
22
|
|
|
@@ -111,7 +112,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
111
112
|
if (proxy.assets) this.storeSupportabilityMetrics('Config/AssetsUrl/Changed');
|
|
112
113
|
if (proxy.beacon) this.storeSupportabilityMetrics('Config/BeaconUrl/Changed');
|
|
113
114
|
if (_runtime2.isBrowserScope && window.MutationObserver) {
|
|
114
|
-
if (
|
|
115
|
+
if ((0, _iframe.isIFrameWindow)(window)) {
|
|
115
116
|
this.storeSupportabilityMetrics('Generic/Runtime/IFrame/Detected');
|
|
116
117
|
}
|
|
117
118
|
const preExistingVideos = window.document.querySelectorAll('video').length;
|