@newrelic/browser-agent 1.284.0 → 1.284.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 +8 -0
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/util/event-origin.js +36 -0
- package/dist/cjs/common/vitals/interaction-to-next-paint.js +1 -20
- package/dist/cjs/features/ajax/instrument/index.js +3 -2
- package/dist/cjs/features/page_view_timing/aggregate/index.js +31 -3
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +4 -21
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/util/event-origin.js +30 -0
- package/dist/esm/common/vitals/interaction-to-next-paint.js +1 -20
- package/dist/esm/features/ajax/instrument/index.js +3 -2
- package/dist/esm/features/page_view_timing/aggregate/index.js +32 -4
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +4 -21
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/util/event-origin.d.ts +13 -0
- package/dist/types/common/util/event-origin.d.ts.map +1 -0
- package/dist/types/common/vitals/interaction-to-next-paint.d.ts +0 -1
- package/dist/types/common/vitals/interaction-to-next-paint.d.ts.map +1 -1
- package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +12 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +0 -1
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/util/event-origin.js +36 -0
- package/src/common/vitals/interaction-to-next-paint.js +1 -20
- package/src/features/ajax/instrument/index.js +3 -2
- package/src/features/page_view_timing/aggregate/index.js +34 -4
- package/src/features/session_trace/aggregate/trace/storage.js +4 -28
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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.284.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.284.0...v1.284.1) (2025-03-11)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Console error on some cross-origin requests without NR CAT header ([#1407](https://github.com/newrelic/newrelic-browser-agent/issues/1407)) ([6660c44](https://github.com/newrelic/newrelic-browser-agent/commit/6660c4455f73bdd90da9946f48ca6c6b377a866f))
|
|
12
|
+
* Obtain FirstInteraction directly from performance API ([#1410](https://github.com/newrelic/newrelic-browser-agent/issues/1410)) ([22ef4ff](https://github.com/newrelic/newrelic-browser-agent/commit/22ef4ffaef72729f99ee615d4851870f51a129f7))
|
|
13
|
+
|
|
6
14
|
## [1.284.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.283.2...v1.284.0) (2025-03-04)
|
|
7
15
|
|
|
8
16
|
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.284.
|
|
20
|
+
const VERSION = exports.VERSION = "1.284.1";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.284.
|
|
20
|
+
const VERSION = exports.VERSION = "1.284.1";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.eventOrigin = eventOrigin;
|
|
7
|
+
/**
|
|
8
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
9
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Returns a string representing the origin of an event target. Used by SessionTrace and PageViewTiming features to assign a "better" target to events
|
|
14
|
+
* @param {*} t The target to derive the origin from.
|
|
15
|
+
* @param {*} [target] A known target to compare to. If supplied, and a derived origin could not be reached, this will be referenced.
|
|
16
|
+
* @param {*} [ee] An event emitter instance to use for context retrieval, which only applies to XMLHttpRequests.
|
|
17
|
+
* @returns {string} The derived origin of the event target.
|
|
18
|
+
*/
|
|
19
|
+
function eventOrigin(t, target, ee) {
|
|
20
|
+
let origin = 'unknown';
|
|
21
|
+
if (t && t instanceof XMLHttpRequest) {
|
|
22
|
+
const params = ee.context(t).params;
|
|
23
|
+
if (!params || !params.status || !params.method || !params.host || !params.pathname) return 'xhrOriginMissing';
|
|
24
|
+
origin = params.status + ' ' + params.method + ': ' + params.host + params.pathname;
|
|
25
|
+
} else if (t && typeof t.tagName === 'string') {
|
|
26
|
+
origin = t.tagName.toLowerCase();
|
|
27
|
+
if (t.id) origin += '#' + t.id;
|
|
28
|
+
if (t.className) {
|
|
29
|
+
for (let i = 0; i < t.classList.length; i++) origin += '.' + t.classList[i];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (origin === 'unknown') {
|
|
33
|
+
if (typeof target === 'string') origin = target;else if (target === document) origin = 'document';else if (target === window) origin = 'window';else if (target instanceof FileReader) origin = 'FileReader';
|
|
34
|
+
}
|
|
35
|
+
return origin;
|
|
36
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.interactionToNextPaint =
|
|
6
|
+
exports.interactionToNextPaint = void 0;
|
|
7
7
|
var _attribution = require("web-vitals/attribution");
|
|
8
8
|
var _vitalMetric = require("./vital-metric");
|
|
9
9
|
var _constants = require("./constants");
|
|
@@ -14,21 +14,7 @@ var _runtime = require("../constants/runtime");
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
const interactionToNextPaint = exports.interactionToNextPaint = new _vitalMetric.VitalMetric(_constants.VITAL_NAMES.INTERACTION_TO_NEXT_PAINT);
|
|
17
|
-
// Note: First Interaction is a legacy NR timing event, not an actual CWV metric
|
|
18
|
-
// ('fi' used to be detected via FID. It is now represented by the first INP)
|
|
19
|
-
const firstInteraction = exports.firstInteraction = new _vitalMetric.VitalMetric(_constants.VITAL_NAMES.FIRST_INTERACTION);
|
|
20
17
|
if (_runtime.isBrowserScope) {
|
|
21
|
-
const recordFirstInteraction = attribution => {
|
|
22
|
-
firstInteraction.update({
|
|
23
|
-
value: attribution.interactionTime,
|
|
24
|
-
attrs: {
|
|
25
|
-
type: attribution.interactionType,
|
|
26
|
-
eventTarget: attribution.interactionTarget,
|
|
27
|
-
loadState: attribution.loadState
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
};
|
|
31
|
-
|
|
32
18
|
/* Interaction-to-Next-Paint */
|
|
33
19
|
(0, _attribution.onINP)(({
|
|
34
20
|
value,
|
|
@@ -54,10 +40,5 @@ if (_runtime.isBrowserScope) {
|
|
|
54
40
|
value,
|
|
55
41
|
attrs
|
|
56
42
|
});
|
|
57
|
-
|
|
58
|
-
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
59
|
-
if (!firstInteraction.isValid && !_runtime.initiallyHidden) {
|
|
60
|
-
recordFirstInteraction(attribution);
|
|
61
|
-
}
|
|
62
43
|
});
|
|
63
44
|
}
|
|
@@ -30,6 +30,7 @@ var handlers = ['load', 'error', 'abort', 'timeout'];
|
|
|
30
30
|
var handlersLen = handlers.length;
|
|
31
31
|
var origRequest = (0, _nreum.gosNREUMOriginals)().o.REQ;
|
|
32
32
|
var origXHR = (0, _nreum.gosNREUMOriginals)().o.XHR;
|
|
33
|
+
const NR_CAT_HEADER = 'X-NewRelic-App-Data';
|
|
33
34
|
class Instrument extends _instrumentBase.InstrumentBase {
|
|
34
35
|
static featureName = _constants.FEATURE_NAME;
|
|
35
36
|
constructor(agentRef, auto = true) {
|
|
@@ -360,8 +361,8 @@ function subscribeToEvents(agentRef, ee, handler, dt) {
|
|
|
360
361
|
ctx.params.status = xhr.status;
|
|
361
362
|
var size = (0, _responseSize.responseSizeFromXhr)(xhr, ctx.lastSize);
|
|
362
363
|
if (size) ctx.metrics.rxSize = size;
|
|
363
|
-
if (ctx.sameOrigin) {
|
|
364
|
-
var header = xhr.getResponseHeader(
|
|
364
|
+
if (ctx.sameOrigin && xhr.getAllResponseHeaders().indexOf(NR_CAT_HEADER) >= 0) {
|
|
365
|
+
var header = xhr.getResponseHeader(NR_CAT_HEADER);
|
|
365
366
|
if (header) {
|
|
366
367
|
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC, ['Ajax/CrossApplicationTracing/Header/Seen'], undefined, _features.FEATURE_NAMES.metrics, ee);
|
|
367
368
|
ctx.params.cat = header.split(', ').pop();
|
|
@@ -18,6 +18,8 @@ var _largestContentfulPaint = require("../../../common/vitals/largest-contentful
|
|
|
18
18
|
var _timeToFirstByte = require("../../../common/vitals/time-to-first-byte");
|
|
19
19
|
var _pageVisibility = require("../../../common/window/page-visibility");
|
|
20
20
|
var _constants2 = require("../../../common/vitals/constants");
|
|
21
|
+
var _runtime = require("../../../common/constants/runtime");
|
|
22
|
+
var _eventOrigin = require("../../../common/util/event-origin");
|
|
21
23
|
/**
|
|
22
24
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
23
25
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -35,6 +37,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
35
37
|
constructor(agentRef) {
|
|
36
38
|
super(agentRef, _constants.FEATURE_NAME);
|
|
37
39
|
this.curSessEndRecorded = false;
|
|
40
|
+
this.firstIxnRecorded = false;
|
|
38
41
|
(0, _registerHandler.registerHandler)('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee);
|
|
39
42
|
// Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
|
|
40
43
|
(0, _registerHandler.registerHandler)('winPagehide', msTimestamp => this.addTiming('unload', msTimestamp, null), this.featureName, this.ee);
|
|
@@ -42,7 +45,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
42
45
|
_firstPaint.firstPaint.subscribe(this.#handleVitalMetric);
|
|
43
46
|
_firstContentfulPaint.firstContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
44
47
|
_largestContentfulPaint.largestContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
45
|
-
_interactionToNextPaint.firstInteraction.subscribe(this.#handleVitalMetric);
|
|
46
48
|
_interactionToNextPaint.interactionToNextPaint.subscribe(this.#handleVitalMetric);
|
|
47
49
|
_timeToFirstByte.timeToFirstByte.subscribe(({
|
|
48
50
|
attrs
|
|
@@ -92,12 +94,34 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
92
94
|
if (name !== _constants2.VITAL_NAMES.CUMULATIVE_LAYOUT_SHIFT && _cumulativeLayoutShift.cumulativeLayoutShift.current.value >= 0) {
|
|
93
95
|
attrs.cls = _cumulativeLayoutShift.cumulativeLayoutShift.current.value;
|
|
94
96
|
}
|
|
95
|
-
|
|
97
|
+
const timing = {
|
|
96
98
|
name,
|
|
97
99
|
value,
|
|
98
100
|
attrs
|
|
99
|
-
}
|
|
101
|
+
};
|
|
102
|
+
this.events.add(timing);
|
|
100
103
|
(0, _handle.handle)('pvtAdded', [name, value, attrs], undefined, _features.FEATURE_NAMES.sessionTrace, this.ee);
|
|
104
|
+
this.checkForFirstInteraction();
|
|
105
|
+
|
|
106
|
+
// makes testing easier
|
|
107
|
+
return timing;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Checks the performance API to see if the agent can set a first interaction event value
|
|
112
|
+
* @returns {void}
|
|
113
|
+
*/
|
|
114
|
+
checkForFirstInteraction() {
|
|
115
|
+
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
116
|
+
if (this.firstIxnRecorded || _runtime.initiallyHidden || !performance) return;
|
|
117
|
+
const firstInput = performance.getEntriesByType('first-input')[0];
|
|
118
|
+
if (!firstInput) return;
|
|
119
|
+
this.firstIxnRecorded = true;
|
|
120
|
+
this.addTiming('fi', firstInput.startTime, {
|
|
121
|
+
type: firstInput.name,
|
|
122
|
+
eventTarget: (0, _eventOrigin.eventOrigin)(firstInput.target),
|
|
123
|
+
loadState: document.readyState
|
|
124
|
+
});
|
|
101
125
|
}
|
|
102
126
|
appendGlobalCustomAttributes(timing) {
|
|
103
127
|
var timingAttributes = timing.attrs || {};
|
|
@@ -108,6 +132,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
108
132
|
}
|
|
109
133
|
});
|
|
110
134
|
}
|
|
135
|
+
preHarvestChecks() {
|
|
136
|
+
this.checkForFirstInteraction();
|
|
137
|
+
return super.preHarvestChecks();
|
|
138
|
+
}
|
|
111
139
|
|
|
112
140
|
// serialize array of timing data
|
|
113
141
|
serializer(eventBuffer) {
|
|
@@ -8,6 +8,7 @@ var _runtime = require("../../../../common/constants/runtime");
|
|
|
8
8
|
var _constants = require("../../../../common/session/constants");
|
|
9
9
|
var _now = require("../../../../common/timing/now");
|
|
10
10
|
var _parseUrl = require("../../../../common/url/parse-url");
|
|
11
|
+
var _eventOrigin = require("../../../../common/util/event-origin");
|
|
11
12
|
var _constants2 = require("../../constants");
|
|
12
13
|
var _node = require("./node");
|
|
13
14
|
/**
|
|
@@ -176,14 +177,14 @@ class TraceStorage {
|
|
|
176
177
|
try {
|
|
177
178
|
// webcomponents-lite.js can trigger an exception on currentEvent.target getter because
|
|
178
179
|
// it does not check currentEvent.currentTarget before calling getRootNode() on it
|
|
179
|
-
evt.o =
|
|
180
|
+
evt.o = (0, _eventOrigin.eventOrigin)(currentEvent.target, target, this.parent.ee);
|
|
180
181
|
} catch (e) {
|
|
181
|
-
evt.o =
|
|
182
|
+
evt.o = (0, _eventOrigin.eventOrigin)(null, target, this.parent.ee);
|
|
182
183
|
}
|
|
183
184
|
this.storeSTN(evt);
|
|
184
185
|
}
|
|
185
186
|
shouldIgnoreEvent(event, target) {
|
|
186
|
-
const origin =
|
|
187
|
+
const origin = (0, _eventOrigin.eventOrigin)(event.target, target, this.parent.ee);
|
|
187
188
|
if (event.type in ignoredEvents.global) return true;
|
|
188
189
|
if (!!ignoredEvents[origin] && ignoredEvents[origin].ignoreAll) return true;
|
|
189
190
|
return !!(!!ignoredEvents[origin] && event.type in ignoredEvents[origin]);
|
|
@@ -213,24 +214,6 @@ class TraceStorage {
|
|
|
213
214
|
return type;
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
|
-
evtOrigin(t, target) {
|
|
217
|
-
let origin = 'unknown';
|
|
218
|
-
if (t && t instanceof XMLHttpRequest) {
|
|
219
|
-
const params = this.parent.ee.context(t).params;
|
|
220
|
-
if (!params || !params.status || !params.method || !params.host || !params.pathname) return 'xhrOriginMissing';
|
|
221
|
-
origin = params.status + ' ' + params.method + ': ' + params.host + params.pathname;
|
|
222
|
-
} else if (t && typeof t.tagName === 'string') {
|
|
223
|
-
origin = t.tagName.toLowerCase();
|
|
224
|
-
if (t.id) origin += '#' + t.id;
|
|
225
|
-
if (t.className) {
|
|
226
|
-
for (let i = 0; i < t.classList.length; i++) origin += '.' + t.classList[i];
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (origin === 'unknown') {
|
|
230
|
-
if (typeof target === 'string') origin = target;else if (target === document) origin = 'document';else if (target === window) origin = 'window';else if (target instanceof FileReader) origin = 'FileReader';
|
|
231
|
-
}
|
|
232
|
-
return origin;
|
|
233
|
-
}
|
|
234
217
|
|
|
235
218
|
// Tracks when the window history API specified by wrap-history is used.
|
|
236
219
|
storeHist(path, old, time) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns a string representing the origin of an event target. Used by SessionTrace and PageViewTiming features to assign a "better" target to events
|
|
8
|
+
* @param {*} t The target to derive the origin from.
|
|
9
|
+
* @param {*} [target] A known target to compare to. If supplied, and a derived origin could not be reached, this will be referenced.
|
|
10
|
+
* @param {*} [ee] An event emitter instance to use for context retrieval, which only applies to XMLHttpRequests.
|
|
11
|
+
* @returns {string} The derived origin of the event target.
|
|
12
|
+
*/
|
|
13
|
+
export function eventOrigin(t, target, ee) {
|
|
14
|
+
let origin = 'unknown';
|
|
15
|
+
if (t && t instanceof XMLHttpRequest) {
|
|
16
|
+
const params = ee.context(t).params;
|
|
17
|
+
if (!params || !params.status || !params.method || !params.host || !params.pathname) return 'xhrOriginMissing';
|
|
18
|
+
origin = params.status + ' ' + params.method + ': ' + params.host + params.pathname;
|
|
19
|
+
} else if (t && typeof t.tagName === 'string') {
|
|
20
|
+
origin = t.tagName.toLowerCase();
|
|
21
|
+
if (t.id) origin += '#' + t.id;
|
|
22
|
+
if (t.className) {
|
|
23
|
+
for (let i = 0; i < t.classList.length; i++) origin += '.' + t.classList[i];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (origin === 'unknown') {
|
|
27
|
+
if (typeof target === 'string') origin = target;else if (target === document) origin = 'document';else if (target === window) origin = 'window';else if (target instanceof FileReader) origin = 'FileReader';
|
|
28
|
+
}
|
|
29
|
+
return origin;
|
|
30
|
+
}
|
|
@@ -5,23 +5,9 @@
|
|
|
5
5
|
import { onINP } from 'web-vitals/attribution';
|
|
6
6
|
import { VitalMetric } from './vital-metric';
|
|
7
7
|
import { VITAL_NAMES } from './constants';
|
|
8
|
-
import {
|
|
8
|
+
import { isBrowserScope } from '../constants/runtime';
|
|
9
9
|
export const interactionToNextPaint = new VitalMetric(VITAL_NAMES.INTERACTION_TO_NEXT_PAINT);
|
|
10
|
-
// Note: First Interaction is a legacy NR timing event, not an actual CWV metric
|
|
11
|
-
// ('fi' used to be detected via FID. It is now represented by the first INP)
|
|
12
|
-
export const firstInteraction = new VitalMetric(VITAL_NAMES.FIRST_INTERACTION);
|
|
13
10
|
if (isBrowserScope) {
|
|
14
|
-
const recordFirstInteraction = attribution => {
|
|
15
|
-
firstInteraction.update({
|
|
16
|
-
value: attribution.interactionTime,
|
|
17
|
-
attrs: {
|
|
18
|
-
type: attribution.interactionType,
|
|
19
|
-
eventTarget: attribution.interactionTarget,
|
|
20
|
-
loadState: attribution.loadState
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
};
|
|
24
|
-
|
|
25
11
|
/* Interaction-to-Next-Paint */
|
|
26
12
|
onINP(({
|
|
27
13
|
value,
|
|
@@ -47,10 +33,5 @@ if (isBrowserScope) {
|
|
|
47
33
|
value,
|
|
48
34
|
attrs
|
|
49
35
|
});
|
|
50
|
-
|
|
51
|
-
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
52
|
-
if (!firstInteraction.isValid && !initiallyHidden) {
|
|
53
|
-
recordFirstInteraction(attribution);
|
|
54
|
-
}
|
|
55
36
|
});
|
|
56
37
|
}
|
|
@@ -23,6 +23,7 @@ var handlers = ['load', 'error', 'abort', 'timeout'];
|
|
|
23
23
|
var handlersLen = handlers.length;
|
|
24
24
|
var origRequest = gosNREUMOriginals().o.REQ;
|
|
25
25
|
var origXHR = gosNREUMOriginals().o.XHR;
|
|
26
|
+
const NR_CAT_HEADER = 'X-NewRelic-App-Data';
|
|
26
27
|
export class Instrument extends InstrumentBase {
|
|
27
28
|
static featureName = FEATURE_NAME;
|
|
28
29
|
constructor(agentRef, auto = true) {
|
|
@@ -352,8 +353,8 @@ function subscribeToEvents(agentRef, ee, handler, dt) {
|
|
|
352
353
|
ctx.params.status = xhr.status;
|
|
353
354
|
var size = responseSizeFromXhr(xhr, ctx.lastSize);
|
|
354
355
|
if (size) ctx.metrics.rxSize = size;
|
|
355
|
-
if (ctx.sameOrigin) {
|
|
356
|
-
var header = xhr.getResponseHeader(
|
|
356
|
+
if (ctx.sameOrigin && xhr.getAllResponseHeaders().indexOf(NR_CAT_HEADER) >= 0) {
|
|
357
|
+
var header = xhr.getResponseHeader(NR_CAT_HEADER);
|
|
357
358
|
if (header) {
|
|
358
359
|
handle(SUPPORTABILITY_METRIC, ['Ajax/CrossApplicationTracing/Header/Seen'], undefined, FEATURE_NAMES.metrics, ee);
|
|
359
360
|
ctx.params.cat = header.split(', ').pop();
|
|
@@ -12,11 +12,13 @@ import { AggregateBase } from '../../utils/aggregate-base';
|
|
|
12
12
|
import { cumulativeLayoutShift } from '../../../common/vitals/cumulative-layout-shift';
|
|
13
13
|
import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint';
|
|
14
14
|
import { firstPaint } from '../../../common/vitals/first-paint';
|
|
15
|
-
import {
|
|
15
|
+
import { interactionToNextPaint } from '../../../common/vitals/interaction-to-next-paint';
|
|
16
16
|
import { largestContentfulPaint } from '../../../common/vitals/largest-contentful-paint';
|
|
17
17
|
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte';
|
|
18
18
|
import { subscribeToVisibilityChange } from '../../../common/window/page-visibility';
|
|
19
19
|
import { VITAL_NAMES } from '../../../common/vitals/constants';
|
|
20
|
+
import { initiallyHidden } from '../../../common/constants/runtime';
|
|
21
|
+
import { eventOrigin } from '../../../common/util/event-origin';
|
|
20
22
|
export class Aggregate extends AggregateBase {
|
|
21
23
|
static featureName = FEATURE_NAME;
|
|
22
24
|
#handleVitalMetric = ({
|
|
@@ -29,6 +31,7 @@ export class Aggregate extends AggregateBase {
|
|
|
29
31
|
constructor(agentRef) {
|
|
30
32
|
super(agentRef, FEATURE_NAME);
|
|
31
33
|
this.curSessEndRecorded = false;
|
|
34
|
+
this.firstIxnRecorded = false;
|
|
32
35
|
registerHandler('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee);
|
|
33
36
|
// Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
|
|
34
37
|
registerHandler('winPagehide', msTimestamp => this.addTiming('unload', msTimestamp, null), this.featureName, this.ee);
|
|
@@ -36,7 +39,6 @@ export class Aggregate extends AggregateBase {
|
|
|
36
39
|
firstPaint.subscribe(this.#handleVitalMetric);
|
|
37
40
|
firstContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
38
41
|
largestContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
39
|
-
firstInteraction.subscribe(this.#handleVitalMetric);
|
|
40
42
|
interactionToNextPaint.subscribe(this.#handleVitalMetric);
|
|
41
43
|
timeToFirstByte.subscribe(({
|
|
42
44
|
attrs
|
|
@@ -86,12 +88,34 @@ export class Aggregate extends AggregateBase {
|
|
|
86
88
|
if (name !== VITAL_NAMES.CUMULATIVE_LAYOUT_SHIFT && cumulativeLayoutShift.current.value >= 0) {
|
|
87
89
|
attrs.cls = cumulativeLayoutShift.current.value;
|
|
88
90
|
}
|
|
89
|
-
|
|
91
|
+
const timing = {
|
|
90
92
|
name,
|
|
91
93
|
value,
|
|
92
94
|
attrs
|
|
93
|
-
}
|
|
95
|
+
};
|
|
96
|
+
this.events.add(timing);
|
|
94
97
|
handle('pvtAdded', [name, value, attrs], undefined, FEATURE_NAMES.sessionTrace, this.ee);
|
|
98
|
+
this.checkForFirstInteraction();
|
|
99
|
+
|
|
100
|
+
// makes testing easier
|
|
101
|
+
return timing;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Checks the performance API to see if the agent can set a first interaction event value
|
|
106
|
+
* @returns {void}
|
|
107
|
+
*/
|
|
108
|
+
checkForFirstInteraction() {
|
|
109
|
+
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
110
|
+
if (this.firstIxnRecorded || initiallyHidden || !performance) return;
|
|
111
|
+
const firstInput = performance.getEntriesByType('first-input')[0];
|
|
112
|
+
if (!firstInput) return;
|
|
113
|
+
this.firstIxnRecorded = true;
|
|
114
|
+
this.addTiming('fi', firstInput.startTime, {
|
|
115
|
+
type: firstInput.name,
|
|
116
|
+
eventTarget: eventOrigin(firstInput.target),
|
|
117
|
+
loadState: document.readyState
|
|
118
|
+
});
|
|
95
119
|
}
|
|
96
120
|
appendGlobalCustomAttributes(timing) {
|
|
97
121
|
var timingAttributes = timing.attrs || {};
|
|
@@ -102,6 +126,10 @@ export class Aggregate extends AggregateBase {
|
|
|
102
126
|
}
|
|
103
127
|
});
|
|
104
128
|
}
|
|
129
|
+
preHarvestChecks() {
|
|
130
|
+
this.checkForFirstInteraction();
|
|
131
|
+
return super.preHarvestChecks();
|
|
132
|
+
}
|
|
105
133
|
|
|
106
134
|
// serialize array of timing data
|
|
107
135
|
serializer(eventBuffer) {
|
|
@@ -6,6 +6,7 @@ import { globalScope } from '../../../../common/constants/runtime';
|
|
|
6
6
|
import { MODE } from '../../../../common/session/constants';
|
|
7
7
|
import { now } from '../../../../common/timing/now';
|
|
8
8
|
import { parseUrl } from '../../../../common/url/parse-url';
|
|
9
|
+
import { eventOrigin } from '../../../../common/util/event-origin';
|
|
9
10
|
import { MAX_NODES_PER_HARVEST } from '../../constants';
|
|
10
11
|
import { TraceNode } from './node';
|
|
11
12
|
const ERROR_MODE_SECONDS_WINDOW = 30 * 1000; // sliding window of nodes to track when simply monitoring (but not harvesting) in error mode
|
|
@@ -169,14 +170,14 @@ export class TraceStorage {
|
|
|
169
170
|
try {
|
|
170
171
|
// webcomponents-lite.js can trigger an exception on currentEvent.target getter because
|
|
171
172
|
// it does not check currentEvent.currentTarget before calling getRootNode() on it
|
|
172
|
-
evt.o =
|
|
173
|
+
evt.o = eventOrigin(currentEvent.target, target, this.parent.ee);
|
|
173
174
|
} catch (e) {
|
|
174
|
-
evt.o =
|
|
175
|
+
evt.o = eventOrigin(null, target, this.parent.ee);
|
|
175
176
|
}
|
|
176
177
|
this.storeSTN(evt);
|
|
177
178
|
}
|
|
178
179
|
shouldIgnoreEvent(event, target) {
|
|
179
|
-
const origin =
|
|
180
|
+
const origin = eventOrigin(event.target, target, this.parent.ee);
|
|
180
181
|
if (event.type in ignoredEvents.global) return true;
|
|
181
182
|
if (!!ignoredEvents[origin] && ignoredEvents[origin].ignoreAll) return true;
|
|
182
183
|
return !!(!!ignoredEvents[origin] && event.type in ignoredEvents[origin]);
|
|
@@ -206,24 +207,6 @@ export class TraceStorage {
|
|
|
206
207
|
return type;
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
|
-
evtOrigin(t, target) {
|
|
210
|
-
let origin = 'unknown';
|
|
211
|
-
if (t && t instanceof XMLHttpRequest) {
|
|
212
|
-
const params = this.parent.ee.context(t).params;
|
|
213
|
-
if (!params || !params.status || !params.method || !params.host || !params.pathname) return 'xhrOriginMissing';
|
|
214
|
-
origin = params.status + ' ' + params.method + ': ' + params.host + params.pathname;
|
|
215
|
-
} else if (t && typeof t.tagName === 'string') {
|
|
216
|
-
origin = t.tagName.toLowerCase();
|
|
217
|
-
if (t.id) origin += '#' + t.id;
|
|
218
|
-
if (t.className) {
|
|
219
|
-
for (let i = 0; i < t.classList.length; i++) origin += '.' + t.classList[i];
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
if (origin === 'unknown') {
|
|
223
|
-
if (typeof target === 'string') origin = target;else if (target === document) origin = 'document';else if (target === window) origin = 'window';else if (target instanceof FileReader) origin = 'FileReader';
|
|
224
|
-
}
|
|
225
|
-
return origin;
|
|
226
|
-
}
|
|
227
210
|
|
|
228
211
|
// Tracks when the window history API specified by wrap-history is used.
|
|
229
212
|
storeHist(path, old, time) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/context/shared-context.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/obfuscate.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-jsonp.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-mutation.js","../src/common/wrap/wrap-promise.js","../src/common/wrap/wrap-timer.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/aggregate/websocket-detection.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/spa/constants.js","../src/features/spa/index.js","../src/features/spa/aggregate/index.js","../src/features/spa/aggregate/interaction-node.js","../src/features/spa/aggregate/interaction.js","../src/features/spa/aggregate/serializer.js","../src/features/spa/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/event-buffer.js","../src/features/utils/event-store-manager.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/features/utils/lazy-feature-loader.js","../src/features/utils/nr1-debugger.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/api-methods.js","../src/loaders/api/api.js","../src/loaders/api/apiAsync.js","../src/loaders/api/interaction-types.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.7.3"}
|
|
1
|
+
{"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/context/shared-context.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/obfuscate.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-jsonp.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-mutation.js","../src/common/wrap/wrap-promise.js","../src/common/wrap/wrap-timer.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/aggregate/websocket-detection.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/spa/constants.js","../src/features/spa/index.js","../src/features/spa/aggregate/index.js","../src/features/spa/aggregate/interaction-node.js","../src/features/spa/aggregate/interaction.js","../src/features/spa/aggregate/serializer.js","../src/features/spa/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/event-buffer.js","../src/features/utils/event-store-manager.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/features/utils/lazy-feature-loader.js","../src/features/utils/nr1-debugger.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/api-methods.js","../src/loaders/api/api.js","../src/loaders/api/apiAsync.js","../src/loaders/api/interaction-types.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.7.3"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Returns a string representing the origin of an event target. Used by SessionTrace and PageViewTiming features to assign a "better" target to events
|
|
7
|
+
* @param {*} t The target to derive the origin from.
|
|
8
|
+
* @param {*} [target] A known target to compare to. If supplied, and a derived origin could not be reached, this will be referenced.
|
|
9
|
+
* @param {*} [ee] An event emitter instance to use for context retrieval, which only applies to XMLHttpRequests.
|
|
10
|
+
* @returns {string} The derived origin of the event target.
|
|
11
|
+
*/
|
|
12
|
+
export function eventOrigin(t: any, target?: any, ee?: any): string;
|
|
13
|
+
//# sourceMappingURL=event-origin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-origin.d.ts","sourceRoot":"","sources":["../../../../src/common/util/event-origin.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,+BALW,GAAC,WACD,GAAC,OACD,GAAC,GACC,MAAM,CAyBlB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interaction-to-next-paint.d.ts","sourceRoot":"","sources":["../../../../src/common/vitals/interaction-to-next-paint.js"],"names":[],"mappings":"AASA,iDAA4F;
|
|
1
|
+
{"version":3,"file":"interaction-to-next-paint.d.ts","sourceRoot":"","sources":["../../../../src/common/vitals/interaction-to-next-paint.js"],"names":[],"mappings":"AASA,iDAA4F;4BAJhE,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/instrument/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/instrument/index.js"],"names":[],"mappings":"AA6BA;IACE,2BAAiC;IACjC,2CAkCC;IA/BC,OAA0C;IAE1C,8DAAkF;CA8BrF;AAkWD,qCAA8B;+BArZC,6BAA6B;mBAFzC,uBAAuB"}
|
|
@@ -2,13 +2,24 @@ export class Aggregate extends AggregateBase {
|
|
|
2
2
|
static featureName: string;
|
|
3
3
|
constructor(agentRef: any);
|
|
4
4
|
curSessEndRecorded: boolean;
|
|
5
|
+
firstIxnRecorded: boolean;
|
|
5
6
|
/**
|
|
6
7
|
* Add the time of _document visibilitychange to hidden_ to the next PVT harvest == NRDB pageHide attr.
|
|
7
8
|
* @param {number} timestamp
|
|
8
9
|
*/
|
|
9
10
|
endCurrentSession(timestamp: number): void;
|
|
10
|
-
addTiming(name: any, value: any, attrs: any):
|
|
11
|
+
addTiming(name: any, value: any, attrs: any): {
|
|
12
|
+
name: any;
|
|
13
|
+
value: any;
|
|
14
|
+
attrs: any;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Checks the performance API to see if the agent can set a first interaction event value
|
|
18
|
+
* @returns {void}
|
|
19
|
+
*/
|
|
20
|
+
checkForFirstInteraction(): void;
|
|
11
21
|
appendGlobalCustomAttributes(timing: any): void;
|
|
22
|
+
preHarvestChecks(): boolean;
|
|
12
23
|
serializer(eventBuffer: any): string;
|
|
13
24
|
#private;
|
|
14
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_timing/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_timing/aggregate/index.js"],"names":[],"mappings":"AAsBA;IACE,2BAAiC;IAMjC,2BA4BC;IA1BC,4BAA+B;IAC/B,0BAA6B;IA2B/B;;;OAGG;IACH,6BAFW,MAAM,QAOhB;IAED;;;;MA6BC;IAED;;;OAGG;IACH,4BAFa,IAAI,CAahB;IAED,gDAUC;IAED,4BAGC;IAGD,qCAuBC;;CACF;8BAtJ6B,4BAA4B"}
|
|
@@ -27,7 +27,6 @@ export class TraceStorage {
|
|
|
27
27
|
storeEvent(currentEvent: any, target: any, start: any, end: any): void;
|
|
28
28
|
shouldIgnoreEvent(event: any, target: any): boolean;
|
|
29
29
|
evtName(type: any): any;
|
|
30
|
-
evtOrigin(t: any, target: any): string;
|
|
31
30
|
storeHist(path: any, old: any, time: any): void;
|
|
32
31
|
storeResources(resources: any): void;
|
|
33
32
|
storeErrorAgg(type: any, name: any, params: any, metrics: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../../../src/features/session_trace/aggregate/trace/storage.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../../../src/features/session_trace/aggregate/trace/storage.js"],"names":[],"mappings":"AA8BA,+HAA+H;AAC/H;IAQE,yBAEC;IATD,kBAAa;IACb,UAAU;IACV,0BAA4B;IAC5B,wBAAmB;IACnB,2BAA4B;IAI1B,YAAoB;IAGtB,gGAAgG;IAChG,yBAcC;IAED;;;;OAIG;IACH,2BAHW,MAAM,GACJ,MAAM,CAsBlB;IAED,oEAAoE;IACpE;;;;MAgBC;IAED,mEA6BC;IAED,oDAEC;IAED,mEAuBC;IAGD,uEAcC;IAED,oDAKC;IAED,wBAwBC;IAGD,gDAEC;IAID,qCAaC;IAGD,qEAGC;IAGD,mEAGC;IAID,mBAEC;IAED,aAEC;IAED;;;;;;;QAEC;IAED,cAMC;IAED,mBAEC;IAED,kBAEC;;CACF"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns a string representing the origin of an event target. Used by SessionTrace and PageViewTiming features to assign a "better" target to events
|
|
8
|
+
* @param {*} t The target to derive the origin from.
|
|
9
|
+
* @param {*} [target] A known target to compare to. If supplied, and a derived origin could not be reached, this will be referenced.
|
|
10
|
+
* @param {*} [ee] An event emitter instance to use for context retrieval, which only applies to XMLHttpRequests.
|
|
11
|
+
* @returns {string} The derived origin of the event target.
|
|
12
|
+
*/
|
|
13
|
+
export function eventOrigin (t, target, ee) {
|
|
14
|
+
let origin = 'unknown'
|
|
15
|
+
|
|
16
|
+
if (t && t instanceof XMLHttpRequest) {
|
|
17
|
+
const params = ee.context(t).params
|
|
18
|
+
if (!params || !params.status || !params.method || !params.host || !params.pathname) return 'xhrOriginMissing'
|
|
19
|
+
origin = params.status + ' ' + params.method + ': ' + params.host + params.pathname
|
|
20
|
+
} else if (t && typeof (t.tagName) === 'string') {
|
|
21
|
+
origin = t.tagName.toLowerCase()
|
|
22
|
+
if (t.id) origin += '#' + t.id
|
|
23
|
+
if (t.className) {
|
|
24
|
+
for (let i = 0; i < t.classList.length; i++) origin += '.' + t.classList[i]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (origin === 'unknown') {
|
|
29
|
+
if (typeof target === 'string') origin = target
|
|
30
|
+
else if (target === document) origin = 'document'
|
|
31
|
+
else if (target === window) origin = 'window'
|
|
32
|
+
else if (target instanceof FileReader) origin = 'FileReader'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return origin
|
|
36
|
+
}
|
|
@@ -5,25 +5,11 @@
|
|
|
5
5
|
import { onINP } from 'web-vitals/attribution'
|
|
6
6
|
import { VitalMetric } from './vital-metric'
|
|
7
7
|
import { VITAL_NAMES } from './constants'
|
|
8
|
-
import {
|
|
8
|
+
import { isBrowserScope } from '../constants/runtime'
|
|
9
9
|
|
|
10
10
|
export const interactionToNextPaint = new VitalMetric(VITAL_NAMES.INTERACTION_TO_NEXT_PAINT)
|
|
11
|
-
// Note: First Interaction is a legacy NR timing event, not an actual CWV metric
|
|
12
|
-
// ('fi' used to be detected via FID. It is now represented by the first INP)
|
|
13
|
-
export const firstInteraction = new VitalMetric(VITAL_NAMES.FIRST_INTERACTION)
|
|
14
11
|
|
|
15
12
|
if (isBrowserScope) {
|
|
16
|
-
const recordFirstInteraction = (attribution) => {
|
|
17
|
-
firstInteraction.update({
|
|
18
|
-
value: attribution.interactionTime,
|
|
19
|
-
attrs: {
|
|
20
|
-
type: attribution.interactionType,
|
|
21
|
-
eventTarget: attribution.interactionTarget,
|
|
22
|
-
loadState: attribution.loadState
|
|
23
|
-
}
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
|
|
27
13
|
/* Interaction-to-Next-Paint */
|
|
28
14
|
onINP(({ value, attribution, id }) => {
|
|
29
15
|
const attrs = {
|
|
@@ -40,10 +26,5 @@ if (isBrowserScope) {
|
|
|
40
26
|
loadState: attribution.loadState
|
|
41
27
|
}
|
|
42
28
|
interactionToNextPaint.update({ value, attrs })
|
|
43
|
-
|
|
44
|
-
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
45
|
-
if (!firstInteraction.isValid && !initiallyHidden) {
|
|
46
|
-
recordFirstInteraction(attribution)
|
|
47
|
-
}
|
|
48
29
|
})
|
|
49
30
|
}
|
|
@@ -25,6 +25,7 @@ var handlersLen = handlers.length
|
|
|
25
25
|
|
|
26
26
|
var origRequest = gosNREUMOriginals().o.REQ
|
|
27
27
|
var origXHR = gosNREUMOriginals().o.XHR
|
|
28
|
+
const NR_CAT_HEADER = 'X-NewRelic-App-Data'
|
|
28
29
|
|
|
29
30
|
export class Instrument extends InstrumentBase {
|
|
30
31
|
static featureName = FEATURE_NAME
|
|
@@ -392,8 +393,8 @@ function subscribeToEvents (agentRef, ee, handler, dt) {
|
|
|
392
393
|
var size = responseSizeFromXhr(xhr, ctx.lastSize)
|
|
393
394
|
if (size) ctx.metrics.rxSize = size
|
|
394
395
|
|
|
395
|
-
if (ctx.sameOrigin) {
|
|
396
|
-
var header = xhr.getResponseHeader(
|
|
396
|
+
if (ctx.sameOrigin && xhr.getAllResponseHeaders().indexOf(NR_CAT_HEADER) >= 0) {
|
|
397
|
+
var header = xhr.getResponseHeader(NR_CAT_HEADER)
|
|
397
398
|
if (header) {
|
|
398
399
|
handle(SUPPORTABILITY_METRIC, ['Ajax/CrossApplicationTracing/Header/Seen'], undefined, FEATURE_NAMES.metrics, ee)
|
|
399
400
|
ctx.params.cat = header.split(', ').pop()
|
|
@@ -12,11 +12,13 @@ import { AggregateBase } from '../../utils/aggregate-base'
|
|
|
12
12
|
import { cumulativeLayoutShift } from '../../../common/vitals/cumulative-layout-shift'
|
|
13
13
|
import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint'
|
|
14
14
|
import { firstPaint } from '../../../common/vitals/first-paint'
|
|
15
|
-
import {
|
|
15
|
+
import { interactionToNextPaint } from '../../../common/vitals/interaction-to-next-paint'
|
|
16
16
|
import { largestContentfulPaint } from '../../../common/vitals/largest-contentful-paint'
|
|
17
17
|
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte'
|
|
18
18
|
import { subscribeToVisibilityChange } from '../../../common/window/page-visibility'
|
|
19
19
|
import { VITAL_NAMES } from '../../../common/vitals/constants'
|
|
20
|
+
import { initiallyHidden } from '../../../common/constants/runtime'
|
|
21
|
+
import { eventOrigin } from '../../../common/util/event-origin'
|
|
20
22
|
|
|
21
23
|
export class Aggregate extends AggregateBase {
|
|
22
24
|
static featureName = FEATURE_NAME
|
|
@@ -28,6 +30,7 @@ export class Aggregate extends AggregateBase {
|
|
|
28
30
|
constructor (agentRef) {
|
|
29
31
|
super(agentRef, FEATURE_NAME)
|
|
30
32
|
this.curSessEndRecorded = false
|
|
33
|
+
this.firstIxnRecorded = false
|
|
31
34
|
|
|
32
35
|
registerHandler('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee)
|
|
33
36
|
// Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
|
|
@@ -37,7 +40,6 @@ export class Aggregate extends AggregateBase {
|
|
|
37
40
|
firstPaint.subscribe(this.#handleVitalMetric)
|
|
38
41
|
firstContentfulPaint.subscribe(this.#handleVitalMetric)
|
|
39
42
|
largestContentfulPaint.subscribe(this.#handleVitalMetric)
|
|
40
|
-
firstInteraction.subscribe(this.#handleVitalMetric)
|
|
41
43
|
interactionToNextPaint.subscribe(this.#handleVitalMetric)
|
|
42
44
|
timeToFirstByte.subscribe(({ attrs }) => {
|
|
43
45
|
this.addTiming('load', Math.round(attrs.navigationEntry.loadEventEnd))
|
|
@@ -82,13 +84,36 @@ export class Aggregate extends AggregateBase {
|
|
|
82
84
|
attrs.cls = cumulativeLayoutShift.current.value
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
const timing = {
|
|
86
88
|
name,
|
|
87
89
|
value,
|
|
88
90
|
attrs
|
|
89
|
-
}
|
|
91
|
+
}
|
|
92
|
+
this.events.add(timing)
|
|
90
93
|
|
|
91
94
|
handle('pvtAdded', [name, value, attrs], undefined, FEATURE_NAMES.sessionTrace, this.ee)
|
|
95
|
+
|
|
96
|
+
this.checkForFirstInteraction()
|
|
97
|
+
|
|
98
|
+
// makes testing easier
|
|
99
|
+
return timing
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Checks the performance API to see if the agent can set a first interaction event value
|
|
104
|
+
* @returns {void}
|
|
105
|
+
*/
|
|
106
|
+
checkForFirstInteraction () {
|
|
107
|
+
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
108
|
+
if (this.firstIxnRecorded || initiallyHidden || !performance) return
|
|
109
|
+
const firstInput = performance.getEntriesByType('first-input')[0]
|
|
110
|
+
if (!firstInput) return
|
|
111
|
+
this.firstIxnRecorded = true
|
|
112
|
+
this.addTiming('fi', firstInput.startTime, {
|
|
113
|
+
type: firstInput.name,
|
|
114
|
+
eventTarget: eventOrigin(firstInput.target),
|
|
115
|
+
loadState: document.readyState
|
|
116
|
+
})
|
|
92
117
|
}
|
|
93
118
|
|
|
94
119
|
appendGlobalCustomAttributes (timing) {
|
|
@@ -103,6 +128,11 @@ export class Aggregate extends AggregateBase {
|
|
|
103
128
|
})
|
|
104
129
|
}
|
|
105
130
|
|
|
131
|
+
preHarvestChecks () {
|
|
132
|
+
this.checkForFirstInteraction()
|
|
133
|
+
return super.preHarvestChecks()
|
|
134
|
+
}
|
|
135
|
+
|
|
106
136
|
// serialize array of timing data
|
|
107
137
|
serializer (eventBuffer) {
|
|
108
138
|
var addString = getAddStringContext(this.agentIdentifier)
|
|
@@ -6,6 +6,7 @@ import { globalScope } from '../../../../common/constants/runtime'
|
|
|
6
6
|
import { MODE } from '../../../../common/session/constants'
|
|
7
7
|
import { now } from '../../../../common/timing/now'
|
|
8
8
|
import { parseUrl } from '../../../../common/url/parse-url'
|
|
9
|
+
import { eventOrigin } from '../../../../common/util/event-origin'
|
|
9
10
|
import { MAX_NODES_PER_HARVEST } from '../../constants'
|
|
10
11
|
import { TraceNode } from './node'
|
|
11
12
|
|
|
@@ -173,15 +174,15 @@ export class TraceStorage {
|
|
|
173
174
|
try {
|
|
174
175
|
// webcomponents-lite.js can trigger an exception on currentEvent.target getter because
|
|
175
176
|
// it does not check currentEvent.currentTarget before calling getRootNode() on it
|
|
176
|
-
evt.o =
|
|
177
|
+
evt.o = eventOrigin(currentEvent.target, target, this.parent.ee)
|
|
177
178
|
} catch (e) {
|
|
178
|
-
evt.o =
|
|
179
|
+
evt.o = eventOrigin(null, target, this.parent.ee)
|
|
179
180
|
}
|
|
180
181
|
this.storeSTN(evt)
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
shouldIgnoreEvent (event, target) {
|
|
184
|
-
const origin =
|
|
185
|
+
const origin = eventOrigin(event.target, target, this.parent.ee)
|
|
185
186
|
if (event.type in ignoredEvents.global) return true
|
|
186
187
|
if (!!ignoredEvents[origin] && ignoredEvents[origin].ignoreAll) return true
|
|
187
188
|
return !!(!!ignoredEvents[origin] && event.type in ignoredEvents[origin])
|
|
@@ -213,31 +214,6 @@ export class TraceStorage {
|
|
|
213
214
|
}
|
|
214
215
|
}
|
|
215
216
|
|
|
216
|
-
evtOrigin (t, target) {
|
|
217
|
-
let origin = 'unknown'
|
|
218
|
-
|
|
219
|
-
if (t && t instanceof XMLHttpRequest) {
|
|
220
|
-
const params = this.parent.ee.context(t).params
|
|
221
|
-
if (!params || !params.status || !params.method || !params.host || !params.pathname) return 'xhrOriginMissing'
|
|
222
|
-
origin = params.status + ' ' + params.method + ': ' + params.host + params.pathname
|
|
223
|
-
} else if (t && typeof (t.tagName) === 'string') {
|
|
224
|
-
origin = t.tagName.toLowerCase()
|
|
225
|
-
if (t.id) origin += '#' + t.id
|
|
226
|
-
if (t.className) {
|
|
227
|
-
for (let i = 0; i < t.classList.length; i++) origin += '.' + t.classList[i]
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (origin === 'unknown') {
|
|
232
|
-
if (typeof target === 'string') origin = target
|
|
233
|
-
else if (target === document) origin = 'document'
|
|
234
|
-
else if (target === window) origin = 'window'
|
|
235
|
-
else if (target instanceof FileReader) origin = 'FileReader'
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return origin
|
|
239
|
-
}
|
|
240
|
-
|
|
241
217
|
// Tracks when the window history API specified by wrap-history is used.
|
|
242
218
|
storeHist (path, old, time) {
|
|
243
219
|
this.storeSTN(new TraceNode('history.pushState', time, time, path, old))
|