@newrelic/browser-agent 1.283.2 → 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 +23 -0
- package/LICENSE +1 -1
- package/dist/cjs/common/constants/env.cdn.js +2 -2
- package/dist/cjs/common/constants/env.npm.js +2 -2
- package/dist/cjs/common/util/event-origin.js +36 -0
- package/dist/cjs/common/vitals/constants.js +1 -1
- package/dist/cjs/features/ajax/instrument/index.js +3 -2
- package/dist/cjs/features/jserrors/shared/cast-error.js +5 -5
- package/dist/cjs/features/metrics/aggregate/index.js +3 -0
- package/dist/cjs/features/metrics/instrument/index.js +7 -0
- package/dist/cjs/features/page_view_timing/aggregate/index.js +31 -4
- package/dist/cjs/features/session_replay/shared/stylesheet-evaluator.js +1 -1
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +4 -28
- package/dist/esm/common/constants/env.cdn.js +2 -2
- package/dist/esm/common/constants/env.npm.js +2 -2
- package/dist/esm/common/util/event-origin.js +30 -0
- package/dist/esm/common/vitals/constants.js +1 -1
- package/dist/esm/features/ajax/instrument/index.js +3 -2
- package/dist/esm/features/jserrors/shared/cast-error.js +5 -5
- package/dist/esm/features/metrics/aggregate/index.js +3 -0
- package/dist/esm/features/metrics/instrument/index.js +12 -2
- package/dist/esm/features/page_view_timing/aggregate/index.js +31 -4
- package/dist/esm/features/session_replay/shared/stylesheet-evaluator.js +1 -1
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +4 -28
- 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/constants.d.ts +1 -1
- package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/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 +3 -3
- package/src/common/util/event-origin.js +36 -0
- package/src/common/vitals/constants.js +1 -1
- package/src/common/vitals/interaction-to-next-paint.js +1 -1
- package/src/features/ajax/instrument/index.js +3 -2
- package/src/features/jserrors/shared/cast-error.js +5 -5
- package/src/features/metrics/aggregate/index.js +3 -0
- package/src/features/metrics/instrument/index.js +14 -2
- package/src/features/page_view_timing/aggregate/index.js +33 -4
- package/src/features/session_replay/shared/stylesheet-evaluator.js +1 -1
- package/src/features/session_trace/aggregate/trace/storage.js +4 -33
- package/dist/cjs/common/vitals/first-input-delay.js +0 -36
- package/dist/esm/common/vitals/first-input-delay.js +0 -29
- package/dist/types/common/vitals/first-input-delay.d.ts +0 -3
- package/dist/types/common/vitals/first-input-delay.d.ts.map +0 -1
- package/src/common/vitals/first-input-delay.js +0 -28
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@
|
|
|
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
|
+
|
|
14
|
+
## [1.284.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.283.2...v1.284.0) (2025-03-04)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* Remove FID, replace first interaction detection with INP ([#1395](https://github.com/newrelic/newrelic-browser-agent/issues/1395)) ([436ce94](https://github.com/newrelic/newrelic-browser-agent/commit/436ce94eac45e3e28d6b3be6fe9f9fcb15ac1e9b))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
* bump web-vitals from 4.2.3 to 4.2.4 ([#1379](https://github.com/newrelic/newrelic-browser-agent/issues/1379)) ([d0b5b83](https://github.com/newrelic/newrelic-browser-agent/commit/d0b5b83ec50755771e9d4afbf984937f5ab00458))
|
|
25
|
+
* Deduplicate Prefixes on Unhandled Promise Rejection Messages ([#1397](https://github.com/newrelic/newrelic-browser-agent/issues/1397)) ([474fc4f](https://github.com/newrelic/newrelic-browser-agent/commit/474fc4fbc6f7b3fe6b396ce86acaaa1bc712e5fd))
|
|
26
|
+
* Guard against non-CSSStyleSheet when fixing sheets for replay ([#1396](https://github.com/newrelic/newrelic-browser-agent/issues/1396)) ([b929aba](https://github.com/newrelic/newrelic-browser-agent/commit/b929abafb5ab04287fc1f0a07397ff739f314c38))
|
|
27
|
+
* Upgrade rrweb to 18 ([#1383](https://github.com/newrelic/newrelic-browser-agent/issues/1383)) ([46b691b](https://github.com/newrelic/newrelic-browser-agent/commit/46b691b671d2090f47707eea6dfa5ae8f31d0c7b))
|
|
28
|
+
|
|
6
29
|
## [1.283.2](https://github.com/newrelic/newrelic-browser-agent/compare/v1.283.1...v1.283.2) (2025-02-21)
|
|
7
30
|
|
|
8
31
|
|
package/LICENSE
CHANGED
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright New Relic, Inc. All rights reserved.
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
|
@@ -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.
|
|
20
|
+
const VERSION = exports.VERSION = "1.284.1";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -33,4 +33,4 @@ const DIST_METHOD = exports.DIST_METHOD = 'CDN';
|
|
|
33
33
|
/**
|
|
34
34
|
* Exposes the lib version of rrweb
|
|
35
35
|
*/
|
|
36
|
-
const RRWEB_VERSION = exports.RRWEB_VERSION = "^2.0.0-alpha.
|
|
36
|
+
const RRWEB_VERSION = exports.RRWEB_VERSION = "^2.0.0-alpha.18";
|
|
@@ -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.
|
|
20
|
+
const VERSION = exports.VERSION = "1.284.1";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -34,4 +34,4 @@ const DIST_METHOD = exports.DIST_METHOD = 'NPM';
|
|
|
34
34
|
/**
|
|
35
35
|
* Exposes the lib version of rrweb
|
|
36
36
|
*/
|
|
37
|
-
const RRWEB_VERSION = exports.RRWEB_VERSION = "^2.0.0-alpha.
|
|
37
|
+
const RRWEB_VERSION = exports.RRWEB_VERSION = "^2.0.0-alpha.18";
|
|
@@ -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
|
+
}
|
|
@@ -11,7 +11,7 @@ exports.VITAL_NAMES = void 0;
|
|
|
11
11
|
const VITAL_NAMES = exports.VITAL_NAMES = {
|
|
12
12
|
FIRST_PAINT: 'fp',
|
|
13
13
|
FIRST_CONTENTFUL_PAINT: 'fcp',
|
|
14
|
-
|
|
14
|
+
FIRST_INTERACTION: 'fi',
|
|
15
15
|
LARGEST_CONTENTFUL_PAINT: 'lcp',
|
|
16
16
|
CUMULATIVE_LAYOUT_SHIFT: 'cls',
|
|
17
17
|
INTERACTION_TO_NEXT_PAINT: 'inp',
|
|
@@ -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();
|
|
@@ -37,7 +37,7 @@ function castError(error) {
|
|
|
37
37
|
* @returns {Error} An Error object with the message as the casted reason
|
|
38
38
|
*/
|
|
39
39
|
function castPromiseRejectionEvent(promiseRejectionEvent) {
|
|
40
|
-
const prefix = 'Unhandled Promise Rejection';
|
|
40
|
+
const prefix = 'Unhandled Promise Rejection: ';
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* If the casted return value is falsy like this, it will get dropped and not produce an error event for harvest.
|
|
@@ -47,14 +47,14 @@ function castPromiseRejectionEvent(promiseRejectionEvent) {
|
|
|
47
47
|
if (!promiseRejectionEvent?.reason) return;
|
|
48
48
|
if (canTrustError(promiseRejectionEvent.reason)) {
|
|
49
49
|
try {
|
|
50
|
-
promiseRejectionEvent.reason.message = prefix +
|
|
51
|
-
return castError(promiseRejectionEvent.reason);
|
|
50
|
+
if (!promiseRejectionEvent.reason.message.startsWith(prefix)) promiseRejectionEvent.reason.message = prefix + promiseRejectionEvent.reason.message;
|
|
52
51
|
} catch (e) {
|
|
53
|
-
|
|
52
|
+
// failed to modify the message, do nothing else
|
|
54
53
|
}
|
|
54
|
+
return castError(promiseRejectionEvent.reason);
|
|
55
55
|
}
|
|
56
56
|
const error = castError(promiseRejectionEvent.reason);
|
|
57
|
-
error.message
|
|
57
|
+
if (!(error.message || '').startsWith(prefix)) error.message = prefix + error.message;
|
|
58
58
|
return error;
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -135,6 +135,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
// webdriver detection
|
|
139
|
+
if (navigator.webdriver) this.storeSupportabilityMetrics('Generic/WebDriver/Detected');
|
|
140
|
+
|
|
138
141
|
// WATCHABLE_WEB_SOCKET_EVENTS.forEach(tag => {
|
|
139
142
|
// registerHandler('buffered-' + WEBSOCKET_TAG + tag, (...args) => {
|
|
140
143
|
// handleWebsocketEvents(this.storeSupportabilityMetrics.bind(this), tag, ...args)
|
|
@@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.Metrics = exports.Instrument = void 0;
|
|
7
|
+
var _runtime = require("../../../common/constants/runtime");
|
|
8
|
+
var _handle = require("../../../common/event-emitter/handle");
|
|
7
9
|
var _instrumentBase = require("../../utils/instrument-base");
|
|
8
10
|
var _constants = require("../constants");
|
|
9
11
|
/**
|
|
@@ -26,6 +28,11 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
26
28
|
// })
|
|
27
29
|
// })
|
|
28
30
|
|
|
31
|
+
if (_runtime.isBrowserScope) {
|
|
32
|
+
document.addEventListener('securitypolicyviolation', e => {
|
|
33
|
+
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/CSPViolation/Detected'], undefined, this.featureName, this.ee);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
29
36
|
this.importAggregator(agentRef);
|
|
30
37
|
}
|
|
31
38
|
}
|
|
@@ -12,13 +12,14 @@ var _features = require("../../../loaders/features/features");
|
|
|
12
12
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
13
13
|
var _cumulativeLayoutShift = require("../../../common/vitals/cumulative-layout-shift");
|
|
14
14
|
var _firstContentfulPaint = require("../../../common/vitals/first-contentful-paint");
|
|
15
|
-
var _firstInputDelay = require("../../../common/vitals/first-input-delay");
|
|
16
15
|
var _firstPaint = require("../../../common/vitals/first-paint");
|
|
17
16
|
var _interactionToNextPaint = require("../../../common/vitals/interaction-to-next-paint");
|
|
18
17
|
var _largestContentfulPaint = require("../../../common/vitals/largest-contentful-paint");
|
|
19
18
|
var _timeToFirstByte = require("../../../common/vitals/time-to-first-byte");
|
|
20
19
|
var _pageVisibility = require("../../../common/window/page-visibility");
|
|
21
20
|
var _constants2 = require("../../../common/vitals/constants");
|
|
21
|
+
var _runtime = require("../../../common/constants/runtime");
|
|
22
|
+
var _eventOrigin = require("../../../common/util/event-origin");
|
|
22
23
|
/**
|
|
23
24
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
24
25
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -36,13 +37,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
36
37
|
constructor(agentRef) {
|
|
37
38
|
super(agentRef, _constants.FEATURE_NAME);
|
|
38
39
|
this.curSessEndRecorded = false;
|
|
40
|
+
this.firstIxnRecorded = false;
|
|
39
41
|
(0, _registerHandler.registerHandler)('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee);
|
|
40
42
|
// Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
|
|
41
43
|
(0, _registerHandler.registerHandler)('winPagehide', msTimestamp => this.addTiming('unload', msTimestamp, null), this.featureName, this.ee);
|
|
42
44
|
this.waitForFlags([]).then(() => {
|
|
43
45
|
_firstPaint.firstPaint.subscribe(this.#handleVitalMetric);
|
|
44
46
|
_firstContentfulPaint.firstContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
45
|
-
_firstInputDelay.firstInputDelay.subscribe(this.#handleVitalMetric);
|
|
46
47
|
_largestContentfulPaint.largestContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
47
48
|
_interactionToNextPaint.interactionToNextPaint.subscribe(this.#handleVitalMetric);
|
|
48
49
|
_timeToFirstByte.timeToFirstByte.subscribe(({
|
|
@@ -93,12 +94,34 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
93
94
|
if (name !== _constants2.VITAL_NAMES.CUMULATIVE_LAYOUT_SHIFT && _cumulativeLayoutShift.cumulativeLayoutShift.current.value >= 0) {
|
|
94
95
|
attrs.cls = _cumulativeLayoutShift.cumulativeLayoutShift.current.value;
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
+
const timing = {
|
|
97
98
|
name,
|
|
98
99
|
value,
|
|
99
100
|
attrs
|
|
100
|
-
}
|
|
101
|
+
};
|
|
102
|
+
this.events.add(timing);
|
|
101
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
|
+
});
|
|
102
125
|
}
|
|
103
126
|
appendGlobalCustomAttributes(timing) {
|
|
104
127
|
var timingAttributes = timing.attrs || {};
|
|
@@ -109,6 +132,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
109
132
|
}
|
|
110
133
|
});
|
|
111
134
|
}
|
|
135
|
+
preHarvestChecks() {
|
|
136
|
+
this.checkForFirstInteraction();
|
|
137
|
+
return super.preHarvestChecks();
|
|
138
|
+
}
|
|
112
139
|
|
|
113
140
|
// serialize array of timing data
|
|
114
141
|
serializer(eventBuffer) {
|
|
@@ -30,7 +30,7 @@ class StylesheetEvaluator {
|
|
|
30
30
|
this.#brokenSheets = [];
|
|
31
31
|
if (_runtime.isBrowserScope) {
|
|
32
32
|
for (let i = 0; i < Object.keys(document.styleSheets).length; i++) {
|
|
33
|
-
if (!this.#evaluated.has(document.styleSheets[i])) {
|
|
33
|
+
if (!this.#evaluated.has(document.styleSheets[i]) && document.styleSheets[i] instanceof CSSStyleSheet) {
|
|
34
34
|
this.#evaluated.add(document.styleSheets[i]);
|
|
35
35
|
try {
|
|
36
36
|
// eslint-disable-next-line
|
|
@@ -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
|
/**
|
|
@@ -144,13 +145,6 @@ class TraceStorage {
|
|
|
144
145
|
this.storeTiming({
|
|
145
146
|
[name]: value
|
|
146
147
|
});
|
|
147
|
-
if (hasFID(name, attrs)) this.storeEvent({
|
|
148
|
-
type: 'fid',
|
|
149
|
-
target: 'document'
|
|
150
|
-
}, 'document', value, value + attrs.fid);
|
|
151
|
-
function hasFID(name, attrs) {
|
|
152
|
-
return name === 'fi' && !!attrs && typeof attrs.fid === 'number';
|
|
153
|
-
}
|
|
154
148
|
}
|
|
155
149
|
storeTiming(timingEntry, isAbsoluteTimestamp = false) {
|
|
156
150
|
if (!timingEntry) return;
|
|
@@ -183,14 +177,14 @@ class TraceStorage {
|
|
|
183
177
|
try {
|
|
184
178
|
// webcomponents-lite.js can trigger an exception on currentEvent.target getter because
|
|
185
179
|
// it does not check currentEvent.currentTarget before calling getRootNode() on it
|
|
186
|
-
evt.o =
|
|
180
|
+
evt.o = (0, _eventOrigin.eventOrigin)(currentEvent.target, target, this.parent.ee);
|
|
187
181
|
} catch (e) {
|
|
188
|
-
evt.o =
|
|
182
|
+
evt.o = (0, _eventOrigin.eventOrigin)(null, target, this.parent.ee);
|
|
189
183
|
}
|
|
190
184
|
this.storeSTN(evt);
|
|
191
185
|
}
|
|
192
186
|
shouldIgnoreEvent(event, target) {
|
|
193
|
-
const origin =
|
|
187
|
+
const origin = (0, _eventOrigin.eventOrigin)(event.target, target, this.parent.ee);
|
|
194
188
|
if (event.type in ignoredEvents.global) return true;
|
|
195
189
|
if (!!ignoredEvents[origin] && ignoredEvents[origin].ignoreAll) return true;
|
|
196
190
|
return !!(!!ignoredEvents[origin] && event.type in ignoredEvents[origin]);
|
|
@@ -220,24 +214,6 @@ class TraceStorage {
|
|
|
220
214
|
return type;
|
|
221
215
|
}
|
|
222
216
|
}
|
|
223
|
-
evtOrigin(t, target) {
|
|
224
|
-
let origin = 'unknown';
|
|
225
|
-
if (t && t instanceof XMLHttpRequest) {
|
|
226
|
-
const params = this.parent.ee.context(t).params;
|
|
227
|
-
if (!params || !params.status || !params.method || !params.host || !params.pathname) return 'xhrOriginMissing';
|
|
228
|
-
origin = params.status + ' ' + params.method + ': ' + params.host + params.pathname;
|
|
229
|
-
} else if (t && typeof t.tagName === 'string') {
|
|
230
|
-
origin = t.tagName.toLowerCase();
|
|
231
|
-
if (t.id) origin += '#' + t.id;
|
|
232
|
-
if (t.className) {
|
|
233
|
-
for (let i = 0; i < t.classList.length; i++) origin += '.' + t.classList[i];
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
if (origin === 'unknown') {
|
|
237
|
-
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';
|
|
238
|
-
}
|
|
239
|
-
return origin;
|
|
240
|
-
}
|
|
241
217
|
|
|
242
218
|
// Tracks when the window history API specified by wrap-history is used.
|
|
243
219
|
storeHist(path, old, time) {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/**
|
|
12
12
|
* Exposes the version of the agent
|
|
13
13
|
*/
|
|
14
|
-
export const VERSION = "1.
|
|
14
|
+
export const VERSION = "1.284.1";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Exposes the build type of the agent
|
|
@@ -27,4 +27,4 @@ export const DIST_METHOD = 'CDN';
|
|
|
27
27
|
/**
|
|
28
28
|
* Exposes the lib version of rrweb
|
|
29
29
|
*/
|
|
30
|
-
export const RRWEB_VERSION = "^2.0.0-alpha.
|
|
30
|
+
export const RRWEB_VERSION = "^2.0.0-alpha.18";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/**
|
|
12
12
|
* Exposes the version of the agent
|
|
13
13
|
*/
|
|
14
|
-
export const VERSION = "1.
|
|
14
|
+
export const VERSION = "1.284.1";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Exposes the build type of the agent
|
|
@@ -28,4 +28,4 @@ export const DIST_METHOD = 'NPM';
|
|
|
28
28
|
/**
|
|
29
29
|
* Exposes the lib version of rrweb
|
|
30
30
|
*/
|
|
31
|
-
export const RRWEB_VERSION = "^2.0.0-alpha.
|
|
31
|
+
export const RRWEB_VERSION = "^2.0.0-alpha.18";
|
|
@@ -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
|
+
}
|
|
@@ -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();
|
|
@@ -29,7 +29,7 @@ export function castError(error) {
|
|
|
29
29
|
* @returns {Error} An Error object with the message as the casted reason
|
|
30
30
|
*/
|
|
31
31
|
export function castPromiseRejectionEvent(promiseRejectionEvent) {
|
|
32
|
-
const prefix = 'Unhandled Promise Rejection';
|
|
32
|
+
const prefix = 'Unhandled Promise Rejection: ';
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* If the casted return value is falsy like this, it will get dropped and not produce an error event for harvest.
|
|
@@ -39,14 +39,14 @@ export function castPromiseRejectionEvent(promiseRejectionEvent) {
|
|
|
39
39
|
if (!promiseRejectionEvent?.reason) return;
|
|
40
40
|
if (canTrustError(promiseRejectionEvent.reason)) {
|
|
41
41
|
try {
|
|
42
|
-
promiseRejectionEvent.reason.message = prefix +
|
|
43
|
-
return castError(promiseRejectionEvent.reason);
|
|
42
|
+
if (!promiseRejectionEvent.reason.message.startsWith(prefix)) promiseRejectionEvent.reason.message = prefix + promiseRejectionEvent.reason.message;
|
|
44
43
|
} catch (e) {
|
|
45
|
-
|
|
44
|
+
// failed to modify the message, do nothing else
|
|
46
45
|
}
|
|
46
|
+
return castError(promiseRejectionEvent.reason);
|
|
47
47
|
}
|
|
48
48
|
const error = castError(promiseRejectionEvent.reason);
|
|
49
|
-
error.message
|
|
49
|
+
if (!(error.message || '').startsWith(prefix)) error.message = prefix + error.message;
|
|
50
50
|
return error;
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -128,6 +128,9 @@ export class Aggregate extends AggregateBase {
|
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// webdriver detection
|
|
132
|
+
if (navigator.webdriver) this.storeSupportabilityMetrics('Generic/WebDriver/Detected');
|
|
133
|
+
|
|
131
134
|
// WATCHABLE_WEB_SOCKET_EVENTS.forEach(tag => {
|
|
132
135
|
// registerHandler('buffered-' + WEBSOCKET_TAG + tag, (...args) => {
|
|
133
136
|
// handleWebsocketEvents(this.storeSupportabilityMetrics.bind(this), tag, ...args)
|
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { isBrowserScope } from '../../../common/constants/runtime';
|
|
7
|
+
import { handle } from '../../../common/event-emitter/handle';
|
|
8
|
+
import { InstrumentBase } from '../../utils/instrument-base';
|
|
9
|
+
import { FEATURE_NAME,
|
|
10
|
+
// WATCHABLE_WEB_SOCKET_EVENTS,
|
|
11
|
+
SUPPORTABILITY_METRIC_CHANNEL } from '../constants';
|
|
6
12
|
// import { handle } from '../../../common/event-emitter/handle'
|
|
7
13
|
// import { WEBSOCKET_TAG, wrapWebSocket } from '../../../common/wrap/wrap-websocket'
|
|
8
|
-
|
|
9
|
-
import { FEATURE_NAME } from '../constants';
|
|
14
|
+
|
|
10
15
|
export class Instrument extends InstrumentBase {
|
|
11
16
|
static featureName = FEATURE_NAME;
|
|
12
17
|
constructor(agentRef, auto = true) {
|
|
@@ -19,6 +24,11 @@ export class Instrument extends InstrumentBase {
|
|
|
19
24
|
// })
|
|
20
25
|
// })
|
|
21
26
|
|
|
27
|
+
if (isBrowserScope) {
|
|
28
|
+
document.addEventListener('securitypolicyviolation', e => {
|
|
29
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/CSPViolation/Detected'], undefined, this.featureName, this.ee);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
22
32
|
this.importAggregator(agentRef);
|
|
23
33
|
}
|
|
24
34
|
}
|
|
@@ -11,13 +11,14 @@ import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
|
11
11
|
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
|
-
import { firstInputDelay } from '../../../common/vitals/first-input-delay';
|
|
15
14
|
import { firstPaint } from '../../../common/vitals/first-paint';
|
|
16
15
|
import { interactionToNextPaint } from '../../../common/vitals/interaction-to-next-paint';
|
|
17
16
|
import { largestContentfulPaint } from '../../../common/vitals/largest-contentful-paint';
|
|
18
17
|
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte';
|
|
19
18
|
import { subscribeToVisibilityChange } from '../../../common/window/page-visibility';
|
|
20
19
|
import { VITAL_NAMES } from '../../../common/vitals/constants';
|
|
20
|
+
import { initiallyHidden } from '../../../common/constants/runtime';
|
|
21
|
+
import { eventOrigin } from '../../../common/util/event-origin';
|
|
21
22
|
export class Aggregate extends AggregateBase {
|
|
22
23
|
static featureName = FEATURE_NAME;
|
|
23
24
|
#handleVitalMetric = ({
|
|
@@ -30,13 +31,13 @@ export class Aggregate extends AggregateBase {
|
|
|
30
31
|
constructor(agentRef) {
|
|
31
32
|
super(agentRef, FEATURE_NAME);
|
|
32
33
|
this.curSessEndRecorded = false;
|
|
34
|
+
this.firstIxnRecorded = false;
|
|
33
35
|
registerHandler('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee);
|
|
34
36
|
// Add the time of _window pagehide event_ firing to the next PVT harvest == NRDB windowUnload attr:
|
|
35
37
|
registerHandler('winPagehide', msTimestamp => this.addTiming('unload', msTimestamp, null), this.featureName, this.ee);
|
|
36
38
|
this.waitForFlags([]).then(() => {
|
|
37
39
|
firstPaint.subscribe(this.#handleVitalMetric);
|
|
38
40
|
firstContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
39
|
-
firstInputDelay.subscribe(this.#handleVitalMetric);
|
|
40
41
|
largestContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
41
42
|
interactionToNextPaint.subscribe(this.#handleVitalMetric);
|
|
42
43
|
timeToFirstByte.subscribe(({
|
|
@@ -87,12 +88,34 @@ export class Aggregate extends AggregateBase {
|
|
|
87
88
|
if (name !== VITAL_NAMES.CUMULATIVE_LAYOUT_SHIFT && cumulativeLayoutShift.current.value >= 0) {
|
|
88
89
|
attrs.cls = cumulativeLayoutShift.current.value;
|
|
89
90
|
}
|
|
90
|
-
|
|
91
|
+
const timing = {
|
|
91
92
|
name,
|
|
92
93
|
value,
|
|
93
94
|
attrs
|
|
94
|
-
}
|
|
95
|
+
};
|
|
96
|
+
this.events.add(timing);
|
|
95
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
|
+
});
|
|
96
119
|
}
|
|
97
120
|
appendGlobalCustomAttributes(timing) {
|
|
98
121
|
var timingAttributes = timing.attrs || {};
|
|
@@ -103,6 +126,10 @@ export class Aggregate extends AggregateBase {
|
|
|
103
126
|
}
|
|
104
127
|
});
|
|
105
128
|
}
|
|
129
|
+
preHarvestChecks() {
|
|
130
|
+
this.checkForFirstInteraction();
|
|
131
|
+
return super.preHarvestChecks();
|
|
132
|
+
}
|
|
106
133
|
|
|
107
134
|
// serialize array of timing data
|
|
108
135
|
serializer(eventBuffer) {
|
|
@@ -23,7 +23,7 @@ class StylesheetEvaluator {
|
|
|
23
23
|
this.#brokenSheets = [];
|
|
24
24
|
if (isBrowserScope) {
|
|
25
25
|
for (let i = 0; i < Object.keys(document.styleSheets).length; i++) {
|
|
26
|
-
if (!this.#evaluated.has(document.styleSheets[i])) {
|
|
26
|
+
if (!this.#evaluated.has(document.styleSheets[i]) && document.styleSheets[i] instanceof CSSStyleSheet) {
|
|
27
27
|
this.#evaluated.add(document.styleSheets[i]);
|
|
28
28
|
try {
|
|
29
29
|
// eslint-disable-next-line
|