@newrelic/browser-agent 1.279.0 → 1.280.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -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/vitals/constants.js +2 -5
- package/dist/cjs/common/vitals/first-input-delay.js +36 -0
- package/dist/cjs/features/generic_events/aggregate/index.js +11 -10
- package/dist/cjs/features/logging/aggregate/index.js +4 -3
- package/dist/cjs/features/page_view_timing/aggregate/index.js +3 -3
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +7 -0
- package/dist/cjs/loaders/agent.js +2 -3
- package/dist/cjs/loaders/micro-agent-base.js +2 -2
- package/dist/cjs/loaders/micro-agent.js +2 -3
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/vitals/constants.js +1 -4
- package/dist/esm/common/vitals/first-input-delay.js +29 -0
- package/dist/esm/features/generic_events/aggregate/index.js +11 -10
- package/dist/esm/features/logging/aggregate/index.js +4 -3
- package/dist/esm/features/page_view_timing/aggregate/index.js +3 -3
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +7 -0
- package/dist/esm/loaders/agent.js +2 -3
- package/dist/esm/loaders/micro-agent-base.js +2 -2
- package/dist/esm/loaders/micro-agent.js +2 -3
- package/dist/types/common/vitals/constants.d.ts +1 -4
- package/dist/types/common/vitals/first-input-delay.d.ts +3 -0
- package/dist/types/common/vitals/first-input-delay.d.ts.map +1 -0
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts +1 -2
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent-base.d.ts +0 -1
- package/dist/types/loaders/micro-agent-base.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent.d.ts +1 -2
- package/dist/types/loaders/micro-agent.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/common/vitals/constants.js +1 -5
- package/src/common/vitals/first-input-delay.js +28 -0
- package/src/features/generic_events/aggregate/index.js +11 -10
- package/src/features/logging/aggregate/index.js +4 -3
- package/src/features/page_view_timing/aggregate/index.js +3 -3
- package/src/features/session_trace/aggregate/trace/storage.js +5 -0
- package/src/loaders/agent.js +2 -3
- package/src/loaders/micro-agent-base.js +2 -2
- package/src/loaders/micro-agent.js +2 -3
- package/dist/cjs/common/vitals/first-interaction.js +0 -44
- package/dist/esm/common/vitals/first-interaction.js +0 -38
- package/dist/types/common/vitals/first-interaction.d.ts +0 -3
- package/dist/types/common/vitals/first-interaction.d.ts.map +0 -1
- package/src/common/vitals/first-interaction.js +0 -38
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
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.280.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.279.1...v1.280.0) (2025-01-31)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Remove agentIdentifier argument from agent constructors ([#1353](https://github.com/newrelic/newrelic-browser-agent/issues/1353)) ([cb866e5](https://github.com/newrelic/newrelic-browser-agent/commit/cb866e5678bf6aa898c082f2be83145a5014fd0e))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* Roll back to previous FirstInteraction implementation ([#1359](https://github.com/newrelic/newrelic-browser-agent/issues/1359)) ([c2e22ab](https://github.com/newrelic/newrelic-browser-agent/commit/c2e22ab49b00e9cfbeb54664a820e1aa4ed28a53))
|
|
17
|
+
|
|
18
|
+
## [1.279.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.279.0...v1.279.1) (2025-01-28)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* CLS timing node not being reported post new Harvester ([#1352](https://github.com/newrelic/newrelic-browser-agent/issues/1352)) ([5db1d97](https://github.com/newrelic/newrelic-browser-agent/commit/5db1d97a147c78bf93dee669ff9da95bb560d1db))
|
|
24
|
+
|
|
6
25
|
## [1.279.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.278.3...v1.279.0) (2025-01-24)
|
|
7
26
|
|
|
8
27
|
|
|
@@ -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.280.0";
|
|
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.
|
|
20
|
+
const VERSION = exports.VERSION = "1.280.0";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.VITAL_NAMES =
|
|
6
|
+
exports.VITAL_NAMES = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
9
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -11,12 +11,9 @@ exports.VITAL_NAMES = exports.PERFORMANCE_ENTRY_TYPE = void 0;
|
|
|
11
11
|
const VITAL_NAMES = exports.VITAL_NAMES = {
|
|
12
12
|
FIRST_PAINT: 'fp',
|
|
13
13
|
FIRST_CONTENTFUL_PAINT: 'fcp',
|
|
14
|
-
|
|
14
|
+
FIRST_INPUT_DELAY: 'fi',
|
|
15
15
|
LARGEST_CONTENTFUL_PAINT: 'lcp',
|
|
16
16
|
CUMULATIVE_LAYOUT_SHIFT: 'cls',
|
|
17
17
|
INTERACTION_TO_NEXT_PAINT: 'inp',
|
|
18
18
|
TIME_TO_FIRST_BYTE: 'ttfb'
|
|
19
|
-
};
|
|
20
|
-
const PERFORMANCE_ENTRY_TYPE = exports.PERFORMANCE_ENTRY_TYPE = {
|
|
21
|
-
FIRST_INPUT: 'first-input'
|
|
22
19
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.firstInputDelay = void 0;
|
|
7
|
+
var _attribution = require("web-vitals/attribution");
|
|
8
|
+
var _vitalMetric = require("./vital-metric");
|
|
9
|
+
var _constants = require("./constants");
|
|
10
|
+
var _runtime = require("../constants/runtime");
|
|
11
|
+
/**
|
|
12
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
13
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const firstInputDelay = exports.firstInputDelay = new _vitalMetric.VitalMetric(_constants.VITAL_NAMES.FIRST_INPUT_DELAY);
|
|
17
|
+
if (_runtime.isBrowserScope) {
|
|
18
|
+
(0, _attribution.onFID)(({
|
|
19
|
+
value,
|
|
20
|
+
attribution
|
|
21
|
+
}) => {
|
|
22
|
+
if (_runtime.initiallyHidden || firstInputDelay.isValid) return;
|
|
23
|
+
const attrs = {
|
|
24
|
+
type: attribution.eventType,
|
|
25
|
+
fid: Math.round(value),
|
|
26
|
+
eventTarget: attribution.eventTarget,
|
|
27
|
+
loadState: attribution.loadState
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// CWV will only report one (THE) first-input entry to us; fid isn't reported if there are no user interactions occurs before the *first* page hiding.
|
|
31
|
+
firstInputDelay.update({
|
|
32
|
+
value: attribution.eventTime,
|
|
33
|
+
attrs
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -18,6 +18,7 @@ var _userActionsAggregator = require("./user-actions/user-actions-aggregator");
|
|
|
18
18
|
var _iframe = require("../../../common/dom/iframe");
|
|
19
19
|
var _handle = require("../../../common/event-emitter/handle");
|
|
20
20
|
var _typeCheck = require("../../../common/util/type-check");
|
|
21
|
+
var _features = require("../../../loaders/features/features");
|
|
21
22
|
/**
|
|
22
23
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
23
24
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -134,7 +135,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
134
135
|
const observer = new PerformanceObserver(list => {
|
|
135
136
|
list.getEntries().forEach(entry => {
|
|
136
137
|
try {
|
|
137
|
-
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/' + type + '/Seen']);
|
|
138
|
+
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/' + type + '/Seen'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
138
139
|
const detailObj = agentRef.init.performance.capture_detail ? createDetailAttrs(entry.detail) : {};
|
|
139
140
|
this.addEvent({
|
|
140
141
|
...detailObj,
|
|
@@ -196,12 +197,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
196
197
|
if (this.agentRef.init.performance.resources.asset_types.length && !this.agentRef.init.performance.resources.asset_types.includes(entryObject.initiatorType)) return;
|
|
197
198
|
/** decide if the entryDomain is a first party domain */
|
|
198
199
|
firstParty = entryDomain === _runtime.globalScope?.location.hostname || agentRef.init.performance.resources.first_party_domains.includes(entryDomain);
|
|
199
|
-
if (firstParty) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/FirstPartyResource/Seen']);
|
|
200
|
-
if (isNr) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/NrResource/Seen']);
|
|
200
|
+
if (firstParty) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/FirstPartyResource/Seen'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
201
|
+
if (isNr) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/NrResource/Seen'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
201
202
|
} catch (err) {
|
|
202
203
|
// couldnt parse the URL, so firstParty will just default to false
|
|
203
204
|
}
|
|
204
|
-
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/Resource/Seen']);
|
|
205
|
+
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/Resource/Seen'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
205
206
|
const event = {
|
|
206
207
|
...entryObject,
|
|
207
208
|
eventType: 'BrowserPerformance',
|
|
@@ -287,12 +288,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
287
288
|
trackSupportabilityMetrics() {
|
|
288
289
|
/** track usage SMs to improve these experimental features */
|
|
289
290
|
const configPerfTag = 'Config/Performance/';
|
|
290
|
-
if (this.agentRef.init.performance.capture_marks) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMarks/Enabled']);
|
|
291
|
-
if (this.agentRef.init.performance.capture_measures) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMeasures/Enabled']);
|
|
292
|
-
if (this.agentRef.init.performance.resources.enabled) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/Enabled']);
|
|
293
|
-
if (this.agentRef.init.performance.resources.asset_types?.length !== 0) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/AssetTypes/Changed']);
|
|
294
|
-
if (this.agentRef.init.performance.resources.first_party_domains?.length !== 0) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/FirstPartyDomains/Changed']);
|
|
295
|
-
if (this.agentRef.init.performance.resources.ignore_newrelic === false) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/IgnoreNewrelic/Changed']);
|
|
291
|
+
if (this.agentRef.init.performance.capture_marks) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMarks/Enabled'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
292
|
+
if (this.agentRef.init.performance.capture_measures) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMeasures/Enabled'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
293
|
+
if (this.agentRef.init.performance.resources.enabled) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/Enabled'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
294
|
+
if (this.agentRef.init.performance.resources.asset_types?.length !== 0) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/AssetTypes/Changed'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
295
|
+
if (this.agentRef.init.performance.resources.first_party_domains?.length !== 0) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/FirstPartyDomains/Changed'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
296
|
+
if (this.agentRef.init.performance.resources.ignore_newrelic === false) (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/IgnoreNewrelic/Changed'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
296
297
|
}
|
|
297
298
|
}
|
|
298
299
|
exports.Aggregate = Aggregate;
|
|
@@ -15,6 +15,7 @@ var _log = require("../shared/log");
|
|
|
15
15
|
var _utils = require("../shared/utils");
|
|
16
16
|
var _traverse = require("../../../common/util/traverse");
|
|
17
17
|
var _agentConstants = require("../../../common/constants/agent-constants");
|
|
18
|
+
var _features = require("../../../loaders/features/features");
|
|
18
19
|
/**
|
|
19
20
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
20
21
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -59,17 +60,17 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
59
60
|
const failToHarvestMessage = 'Logging/Harvest/Failed/Seen';
|
|
60
61
|
if (logBytes > _agentConstants.MAX_PAYLOAD_SIZE) {
|
|
61
62
|
// cannot possibly send this, even with an empty buffer
|
|
62
|
-
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes]);
|
|
63
|
+
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
63
64
|
(0, _console.warn)(31, log.message.slice(0, 25) + '...');
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
67
|
if (this.events.wouldExceedMaxSize(logBytes)) {
|
|
67
|
-
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes]);
|
|
68
|
+
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
68
69
|
this.agentRef.runtime.harvester.triggerHarvestFor(this); // force a harvest synchronously to try adding again
|
|
69
70
|
}
|
|
70
71
|
if (!this.events.add(log)) {
|
|
71
72
|
// still failed after a harvest attempt despite not being too large would mean harvest failed with options.retry
|
|
72
|
-
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes]);
|
|
73
|
+
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
73
74
|
(0, _console.warn)(31, log.message.slice(0, 25) + '...');
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -12,8 +12,8 @@ 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");
|
|
15
16
|
var _firstPaint = require("../../../common/vitals/first-paint");
|
|
16
|
-
var _firstInteraction = require("../../../common/vitals/first-interaction");
|
|
17
17
|
var _interactionToNextPaint = require("../../../common/vitals/interaction-to-next-paint");
|
|
18
18
|
var _largestContentfulPaint = require("../../../common/vitals/largest-contentful-paint");
|
|
19
19
|
var _timeToFirstByte = require("../../../common/vitals/time-to-first-byte");
|
|
@@ -42,8 +42,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
42
42
|
this.waitForFlags([]).then(() => {
|
|
43
43
|
_firstPaint.firstPaint.subscribe(this.#handleVitalMetric);
|
|
44
44
|
_firstContentfulPaint.firstContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
45
|
+
_firstInputDelay.firstInputDelay.subscribe(this.#handleVitalMetric);
|
|
45
46
|
_largestContentfulPaint.largestContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
46
|
-
_firstInteraction.firstInteraction.subscribe(this.#handleVitalMetric);
|
|
47
47
|
_interactionToNextPaint.interactionToNextPaint.subscribe(this.#handleVitalMetric);
|
|
48
48
|
_timeToFirstByte.timeToFirstByte.subscribe(({
|
|
49
49
|
attrs
|
|
@@ -61,7 +61,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
61
61
|
} = _cumulativeLayoutShift.cumulativeLayoutShift.current;
|
|
62
62
|
if (value === undefined) return;
|
|
63
63
|
this.addTiming(name, value * 1000, attrs);
|
|
64
|
-
}, true); // CLS node should only reports on vis change rather than on every change
|
|
64
|
+
}, true, true); // CLS node should only reports on vis change rather than on every change
|
|
65
65
|
|
|
66
66
|
this.drain();
|
|
67
67
|
});
|
|
@@ -144,6 +144,13 @@ class TraceStorage {
|
|
|
144
144
|
this.storeTiming({
|
|
145
145
|
[name]: value
|
|
146
146
|
});
|
|
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
|
+
}
|
|
147
154
|
}
|
|
148
155
|
storeTiming(timingEntry, isAbsoluteTimestamp = false) {
|
|
149
156
|
if (!timingEntry) return;
|
|
@@ -35,10 +35,9 @@ var _runtime = require("../common/constants/runtime");
|
|
|
35
35
|
class Agent extends _agentBase.AgentBase {
|
|
36
36
|
/**
|
|
37
37
|
* @param {Object} options Options to initialize agent with
|
|
38
|
-
* @param {string} [agentIdentifier] Optional identifier of agent
|
|
39
38
|
*/
|
|
40
|
-
constructor(options
|
|
41
|
-
super(
|
|
39
|
+
constructor(options) {
|
|
40
|
+
super();
|
|
42
41
|
if (!_runtime.globalScope) {
|
|
43
42
|
// We could not determine the runtime environment. Short-circuite the agent here
|
|
44
43
|
// to avoid possible exceptions later that may cause issues with customer's application.
|
|
@@ -13,8 +13,8 @@ var _uniqueId = require("../common/ids/unique-id");
|
|
|
13
13
|
|
|
14
14
|
class MicroAgentBase {
|
|
15
15
|
agentIdentifier;
|
|
16
|
-
constructor(
|
|
17
|
-
this.agentIdentifier =
|
|
16
|
+
constructor() {
|
|
17
|
+
this.agentIdentifier = (0, _uniqueId.generateRandomHexString)(16);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -27,10 +27,9 @@ const nonAutoFeatures = [_features.FEATURE_NAMES.jserrors, _features.FEATURE_NAM
|
|
|
27
27
|
class MicroAgent extends _microAgentBase.MicroAgentBase {
|
|
28
28
|
/**
|
|
29
29
|
* @param {Object} options - Specifies features and runtime configuration,
|
|
30
|
-
* @param {string=} agentIdentifier - The optional unique ID of the agent.
|
|
31
30
|
*/
|
|
32
|
-
constructor(options
|
|
33
|
-
super(
|
|
31
|
+
constructor(options) {
|
|
32
|
+
super();
|
|
34
33
|
this.features = {};
|
|
35
34
|
(0, _nreum.setNREUMInitializedAgent)(this.agentIdentifier, this);
|
|
36
35
|
(0, _configure.configure)(this, {
|
|
@@ -5,12 +5,9 @@
|
|
|
5
5
|
export const VITAL_NAMES = {
|
|
6
6
|
FIRST_PAINT: 'fp',
|
|
7
7
|
FIRST_CONTENTFUL_PAINT: 'fcp',
|
|
8
|
-
|
|
8
|
+
FIRST_INPUT_DELAY: 'fi',
|
|
9
9
|
LARGEST_CONTENTFUL_PAINT: 'lcp',
|
|
10
10
|
CUMULATIVE_LAYOUT_SHIFT: 'cls',
|
|
11
11
|
INTERACTION_TO_NEXT_PAINT: 'inp',
|
|
12
12
|
TIME_TO_FIRST_BYTE: 'ttfb'
|
|
13
|
-
};
|
|
14
|
-
export const PERFORMANCE_ENTRY_TYPE = {
|
|
15
|
-
FIRST_INPUT: 'first-input'
|
|
16
13
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { onFID } from 'web-vitals/attribution';
|
|
6
|
+
import { VitalMetric } from './vital-metric';
|
|
7
|
+
import { VITAL_NAMES } from './constants';
|
|
8
|
+
import { initiallyHidden, isBrowserScope } from '../constants/runtime';
|
|
9
|
+
export const firstInputDelay = new VitalMetric(VITAL_NAMES.FIRST_INPUT_DELAY);
|
|
10
|
+
if (isBrowserScope) {
|
|
11
|
+
onFID(({
|
|
12
|
+
value,
|
|
13
|
+
attribution
|
|
14
|
+
}) => {
|
|
15
|
+
if (initiallyHidden || firstInputDelay.isValid) return;
|
|
16
|
+
const attrs = {
|
|
17
|
+
type: attribution.eventType,
|
|
18
|
+
fid: Math.round(value),
|
|
19
|
+
eventTarget: attribution.eventTarget,
|
|
20
|
+
loadState: attribution.loadState
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// CWV will only report one (THE) first-input entry to us; fid isn't reported if there are no user interactions occurs before the *first* page hiding.
|
|
24
|
+
firstInputDelay.update({
|
|
25
|
+
value: attribution.eventTime,
|
|
26
|
+
attrs
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -16,6 +16,7 @@ import { UserActionsAggregator } from './user-actions/user-actions-aggregator';
|
|
|
16
16
|
import { isIFrameWindow } from '../../../common/dom/iframe';
|
|
17
17
|
import { handle } from '../../../common/event-emitter/handle';
|
|
18
18
|
import { isPureObject } from '../../../common/util/type-check';
|
|
19
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
19
20
|
export class Aggregate extends AggregateBase {
|
|
20
21
|
static featureName = FEATURE_NAME;
|
|
21
22
|
constructor(agentRef) {
|
|
@@ -127,7 +128,7 @@ export class Aggregate extends AggregateBase {
|
|
|
127
128
|
const observer = new PerformanceObserver(list => {
|
|
128
129
|
list.getEntries().forEach(entry => {
|
|
129
130
|
try {
|
|
130
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/' + type + '/Seen']);
|
|
131
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/' + type + '/Seen'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
131
132
|
const detailObj = agentRef.init.performance.capture_detail ? createDetailAttrs(entry.detail) : {};
|
|
132
133
|
this.addEvent({
|
|
133
134
|
...detailObj,
|
|
@@ -189,12 +190,12 @@ export class Aggregate extends AggregateBase {
|
|
|
189
190
|
if (this.agentRef.init.performance.resources.asset_types.length && !this.agentRef.init.performance.resources.asset_types.includes(entryObject.initiatorType)) return;
|
|
190
191
|
/** decide if the entryDomain is a first party domain */
|
|
191
192
|
firstParty = entryDomain === globalScope?.location.hostname || agentRef.init.performance.resources.first_party_domains.includes(entryDomain);
|
|
192
|
-
if (firstParty) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/FirstPartyResource/Seen']);
|
|
193
|
-
if (isNr) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/NrResource/Seen']);
|
|
193
|
+
if (firstParty) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/FirstPartyResource/Seen'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
194
|
+
if (isNr) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/NrResource/Seen'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
194
195
|
} catch (err) {
|
|
195
196
|
// couldnt parse the URL, so firstParty will just default to false
|
|
196
197
|
}
|
|
197
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/Resource/Seen']);
|
|
198
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/Resource/Seen'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
198
199
|
const event = {
|
|
199
200
|
...entryObject,
|
|
200
201
|
eventType: 'BrowserPerformance',
|
|
@@ -280,11 +281,11 @@ export class Aggregate extends AggregateBase {
|
|
|
280
281
|
trackSupportabilityMetrics() {
|
|
281
282
|
/** track usage SMs to improve these experimental features */
|
|
282
283
|
const configPerfTag = 'Config/Performance/';
|
|
283
|
-
if (this.agentRef.init.performance.capture_marks) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMarks/Enabled']);
|
|
284
|
-
if (this.agentRef.init.performance.capture_measures) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMeasures/Enabled']);
|
|
285
|
-
if (this.agentRef.init.performance.resources.enabled) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/Enabled']);
|
|
286
|
-
if (this.agentRef.init.performance.resources.asset_types?.length !== 0) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/AssetTypes/Changed']);
|
|
287
|
-
if (this.agentRef.init.performance.resources.first_party_domains?.length !== 0) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/FirstPartyDomains/Changed']);
|
|
288
|
-
if (this.agentRef.init.performance.resources.ignore_newrelic === false) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/IgnoreNewrelic/Changed']);
|
|
284
|
+
if (this.agentRef.init.performance.capture_marks) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMarks/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
285
|
+
if (this.agentRef.init.performance.capture_measures) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMeasures/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
286
|
+
if (this.agentRef.init.performance.resources.enabled) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
287
|
+
if (this.agentRef.init.performance.resources.asset_types?.length !== 0) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/AssetTypes/Changed'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
288
|
+
if (this.agentRef.init.performance.resources.first_party_domains?.length !== 0) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/FirstPartyDomains/Changed'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
289
|
+
if (this.agentRef.init.performance.resources.ignore_newrelic === false) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/IgnoreNewrelic/Changed'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
289
290
|
}
|
|
290
291
|
}
|
|
@@ -13,6 +13,7 @@ import { Log } from '../shared/log';
|
|
|
13
13
|
import { isValidLogLevel } from '../shared/utils';
|
|
14
14
|
import { applyFnToProps } from '../../../common/util/traverse';
|
|
15
15
|
import { MAX_PAYLOAD_SIZE } from '../../../common/constants/agent-constants';
|
|
16
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
16
17
|
export class Aggregate extends AggregateBase {
|
|
17
18
|
static featureName = FEATURE_NAME;
|
|
18
19
|
constructor(agentRef) {
|
|
@@ -52,17 +53,17 @@ export class Aggregate extends AggregateBase {
|
|
|
52
53
|
const failToHarvestMessage = 'Logging/Harvest/Failed/Seen';
|
|
53
54
|
if (logBytes > MAX_PAYLOAD_SIZE) {
|
|
54
55
|
// cannot possibly send this, even with an empty buffer
|
|
55
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes]);
|
|
56
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
56
57
|
warn(31, log.message.slice(0, 25) + '...');
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
if (this.events.wouldExceedMaxSize(logBytes)) {
|
|
60
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes]);
|
|
61
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
61
62
|
this.agentRef.runtime.harvester.triggerHarvestFor(this); // force a harvest synchronously to try adding again
|
|
62
63
|
}
|
|
63
64
|
if (!this.events.add(log)) {
|
|
64
65
|
// still failed after a harvest attempt despite not being too large would mean harvest failed with options.retry
|
|
65
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes]);
|
|
66
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
66
67
|
warn(31, log.message.slice(0, 25) + '...');
|
|
67
68
|
}
|
|
68
69
|
}
|
|
@@ -11,8 +11,8 @@ 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';
|
|
14
15
|
import { firstPaint } from '../../../common/vitals/first-paint';
|
|
15
|
-
import { firstInteraction } from '../../../common/vitals/first-interaction';
|
|
16
16
|
import { interactionToNextPaint } from '../../../common/vitals/interaction-to-next-paint';
|
|
17
17
|
import { largestContentfulPaint } from '../../../common/vitals/largest-contentful-paint';
|
|
18
18
|
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte';
|
|
@@ -36,8 +36,8 @@ export class Aggregate extends AggregateBase {
|
|
|
36
36
|
this.waitForFlags([]).then(() => {
|
|
37
37
|
firstPaint.subscribe(this.#handleVitalMetric);
|
|
38
38
|
firstContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
39
|
+
firstInputDelay.subscribe(this.#handleVitalMetric);
|
|
39
40
|
largestContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
40
|
-
firstInteraction.subscribe(this.#handleVitalMetric);
|
|
41
41
|
interactionToNextPaint.subscribe(this.#handleVitalMetric);
|
|
42
42
|
timeToFirstByte.subscribe(({
|
|
43
43
|
attrs
|
|
@@ -55,7 +55,7 @@ export class Aggregate extends AggregateBase {
|
|
|
55
55
|
} = cumulativeLayoutShift.current;
|
|
56
56
|
if (value === undefined) return;
|
|
57
57
|
this.addTiming(name, value * 1000, attrs);
|
|
58
|
-
}, true); // CLS node should only reports on vis change rather than on every change
|
|
58
|
+
}, true, true); // CLS node should only reports on vis change rather than on every change
|
|
59
59
|
|
|
60
60
|
this.drain();
|
|
61
61
|
});
|
|
@@ -137,6 +137,13 @@ export class TraceStorage {
|
|
|
137
137
|
this.storeTiming({
|
|
138
138
|
[name]: value
|
|
139
139
|
});
|
|
140
|
+
if (hasFID(name, attrs)) this.storeEvent({
|
|
141
|
+
type: 'fid',
|
|
142
|
+
target: 'document'
|
|
143
|
+
}, 'document', value, value + attrs.fid);
|
|
144
|
+
function hasFID(name, attrs) {
|
|
145
|
+
return name === 'fi' && !!attrs && typeof attrs.fid === 'number';
|
|
146
|
+
}
|
|
140
147
|
}
|
|
141
148
|
storeTiming(timingEntry, isAbsoluteTimestamp = false) {
|
|
142
149
|
if (!timingEntry) return;
|
|
@@ -26,10 +26,9 @@ import { globalScope } from '../common/constants/runtime';
|
|
|
26
26
|
export class Agent extends AgentBase {
|
|
27
27
|
/**
|
|
28
28
|
* @param {Object} options Options to initialize agent with
|
|
29
|
-
* @param {string} [agentIdentifier] Optional identifier of agent
|
|
30
29
|
*/
|
|
31
|
-
constructor(options
|
|
32
|
-
super(
|
|
30
|
+
constructor(options) {
|
|
31
|
+
super();
|
|
33
32
|
if (!globalScope) {
|
|
34
33
|
// We could not determine the runtime environment. Short-circuite the agent here
|
|
35
34
|
// to avoid possible exceptions later that may cause issues with customer's application.
|
|
@@ -6,8 +6,8 @@ import { warn } from '../common/util/console';
|
|
|
6
6
|
import { generateRandomHexString } from '../common/ids/unique-id';
|
|
7
7
|
export class MicroAgentBase {
|
|
8
8
|
agentIdentifier;
|
|
9
|
-
constructor(
|
|
10
|
-
this.agentIdentifier =
|
|
9
|
+
constructor() {
|
|
10
|
+
this.agentIdentifier = generateRandomHexString(16);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -22,10 +22,9 @@ const nonAutoFeatures = [FEATURE_NAMES.jserrors, FEATURE_NAMES.genericEvents, FE
|
|
|
22
22
|
export class MicroAgent extends MicroAgentBase {
|
|
23
23
|
/**
|
|
24
24
|
* @param {Object} options - Specifies features and runtime configuration,
|
|
25
|
-
* @param {string=} agentIdentifier - The optional unique ID of the agent.
|
|
26
25
|
*/
|
|
27
|
-
constructor(options
|
|
28
|
-
super(
|
|
26
|
+
constructor(options) {
|
|
27
|
+
super();
|
|
29
28
|
this.features = {};
|
|
30
29
|
setNREUMInitializedAgent(this.agentIdentifier, this);
|
|
31
30
|
configure(this, {
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
export namespace VITAL_NAMES {
|
|
2
2
|
let FIRST_PAINT: string;
|
|
3
3
|
let FIRST_CONTENTFUL_PAINT: string;
|
|
4
|
-
let
|
|
4
|
+
let FIRST_INPUT_DELAY: string;
|
|
5
5
|
let LARGEST_CONTENTFUL_PAINT: string;
|
|
6
6
|
let CUMULATIVE_LAYOUT_SHIFT: string;
|
|
7
7
|
let INTERACTION_TO_NEXT_PAINT: string;
|
|
8
8
|
let TIME_TO_FIRST_BYTE: string;
|
|
9
9
|
}
|
|
10
|
-
export namespace PERFORMANCE_ENTRY_TYPE {
|
|
11
|
-
let FIRST_INPUT: string;
|
|
12
|
-
}
|
|
13
10
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-input-delay.d.ts","sourceRoot":"","sources":["../../../../src/common/vitals/first-input-delay.js"],"names":[],"mappings":"AASA,0CAA6E;4BAJjD,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/generic_events/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/generic_events/aggregate/index.js"],"names":[],"mappings":"AAoBA;IACE,2BAAiC;IACjC,2BA4LC;IA1LC,yBAA4B;IAC5B,gCAAkG;IAuC9F,4CAAuD;IAqJ7D;;;;;;;;;;;OAWG;IACH,eAHW,MAAM,YAAC,QA0CjB;IAED,qCAEC;IAED;;;MAEC;IAED,gCAEC;IAED,mCASC;CACF;8BAxR6B,4BAA4B;sCAMpB,wCAAwC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/aggregate/index.js"],"names":[],"mappings":"AAiBA;IACE,2BAAiC;IACjC,2BAWC;IAED,+EAgDC;IAED;;YAIM,0FAA0F;;;QAkB5F,0DAA0D;;QAM7D;IAED;;MAEC;CACF;8BA1G6B,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../../../src/features/session_trace/aggregate/trace/storage.js"],"names":[],"mappings":"AA6BA,+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,
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../../../src/features/session_trace/aggregate/trace/storage.js"],"names":[],"mappings":"AA6BA,+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,oDAOC;IAED,mEAuBC;IAGD,uEAcC;IAED,oDAKC;IAED,wBAwBC;IAED,uCAuBC;IAGD,gDAEC;IAID,qCAaC;IAGD,qEAGC;IAGD,mEAGC;IAID,mBAEC;IAED,aAEC;IAED;;;;;;;QAEC;IAED,cAMC;IAED,mBAEC;IAED,kBAEC;;CACF"}
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
export class Agent extends AgentBase {
|
|
6
6
|
/**
|
|
7
7
|
* @param {Object} options Options to initialize agent with
|
|
8
|
-
* @param {string} [agentIdentifier] Optional identifier of agent
|
|
9
8
|
*/
|
|
10
|
-
constructor(options: Object
|
|
9
|
+
constructor(options: Object);
|
|
11
10
|
features: {} | undefined;
|
|
12
11
|
desiredFeatures: Set<any> | undefined;
|
|
13
12
|
runSoftNavOverSpa: boolean | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/agent.js"],"names":[],"mappings":"AAqBA;;;GAGG;AACH;IACE
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/agent.js"],"names":[],"mappings":"AAqBA;;;GAGG;AACH;IACE;;OAEG;IACH,qBAFW,MAAM,EAyBhB;IAbC,yBAAkB;IAGlB,sCAAsD;IAMtD,uCAA6G;IAM/G;;;;;MAOC;IAED,yBAsCC;CACF;0BA7FyB,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"micro-agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent-base.js"],"names":[],"mappings":"AAOA;
|
|
1
|
+
{"version":3,"file":"micro-agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent-base.js"],"names":[],"mappings":"AAOA;IACE,wBAAe;IAkBf;;;;;OAKG;IACH,oBAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,6BAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,kCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,GAAC,IAAI,sCAKpC;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,8CAKtB;IAED;;;;OAIG;IACH,iBAFW,MAAM,GAAC,IAAI,OAIrB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,OAMrB;IAED;;;;OAIG;IACH,0BAFW,CAAC,KAAK,EAAE,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;;MAKE;IACF,aAHW,MAAM;2BACc,MAAM;gBAAU,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM;wBAInF;;CACF"}
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
export class MicroAgent extends MicroAgentBase {
|
|
7
7
|
/**
|
|
8
8
|
* @param {Object} options - Specifies features and runtime configuration,
|
|
9
|
-
* @param {string=} agentIdentifier - The optional unique ID of the agent.
|
|
10
9
|
*/
|
|
11
|
-
constructor(options: Object
|
|
10
|
+
constructor(options: Object);
|
|
12
11
|
features: {};
|
|
13
12
|
/**
|
|
14
13
|
* Starts a set of agent features if not running in "autoStart" mode
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"micro-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent.js"],"names":[],"mappings":"AAsBA;;;;GAIG;AACH;IACE
|
|
1
|
+
{"version":3,"file":"micro-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent.js"],"names":[],"mappings":"AAsBA;;;;GAIG;AACH;IACE;;OAEG;IACH,qBAFW,MAAM,EAsDhB;IAjDC,aAAkB;IAMlB;;;;OAIG;IACH,iEAmCC;IAKH;;;;;MAOC;CACF;+BAhF8B,oBAAoB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/browser-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.280.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
|
|
6
6
|
"description": "New Relic Browser Agent",
|
|
@@ -270,7 +270,7 @@
|
|
|
270
270
|
"wdio-lambdatest-service": "^4.0.0",
|
|
271
271
|
"webpack": "^5.89.0",
|
|
272
272
|
"webpack-bundle-analyzer": "^4.10.1",
|
|
273
|
-
"webpack-cli": "^
|
|
273
|
+
"webpack-cli": "^6.0.1",
|
|
274
274
|
"yargs": "^17.7.2"
|
|
275
275
|
},
|
|
276
276
|
"files": [
|
|
@@ -5,13 +5,9 @@
|
|
|
5
5
|
export const VITAL_NAMES = {
|
|
6
6
|
FIRST_PAINT: 'fp',
|
|
7
7
|
FIRST_CONTENTFUL_PAINT: 'fcp',
|
|
8
|
-
|
|
8
|
+
FIRST_INPUT_DELAY: 'fi',
|
|
9
9
|
LARGEST_CONTENTFUL_PAINT: 'lcp',
|
|
10
10
|
CUMULATIVE_LAYOUT_SHIFT: 'cls',
|
|
11
11
|
INTERACTION_TO_NEXT_PAINT: 'inp',
|
|
12
12
|
TIME_TO_FIRST_BYTE: 'ttfb'
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
export const PERFORMANCE_ENTRY_TYPE = {
|
|
16
|
-
FIRST_INPUT: 'first-input'
|
|
17
|
-
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { onFID } from 'web-vitals/attribution'
|
|
6
|
+
import { VitalMetric } from './vital-metric'
|
|
7
|
+
import { VITAL_NAMES } from './constants'
|
|
8
|
+
import { initiallyHidden, isBrowserScope } from '../constants/runtime'
|
|
9
|
+
|
|
10
|
+
export const firstInputDelay = new VitalMetric(VITAL_NAMES.FIRST_INPUT_DELAY)
|
|
11
|
+
|
|
12
|
+
if (isBrowserScope) {
|
|
13
|
+
onFID(({ value, attribution }) => {
|
|
14
|
+
if (initiallyHidden || firstInputDelay.isValid) return
|
|
15
|
+
const attrs = {
|
|
16
|
+
type: attribution.eventType,
|
|
17
|
+
fid: Math.round(value),
|
|
18
|
+
eventTarget: attribution.eventTarget,
|
|
19
|
+
loadState: attribution.loadState
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// CWV will only report one (THE) first-input entry to us; fid isn't reported if there are no user interactions occurs before the *first* page hiding.
|
|
23
|
+
firstInputDelay.update({
|
|
24
|
+
value: attribution.eventTime,
|
|
25
|
+
attrs
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
}
|
|
@@ -16,6 +16,7 @@ import { UserActionsAggregator } from './user-actions/user-actions-aggregator'
|
|
|
16
16
|
import { isIFrameWindow } from '../../../common/dom/iframe'
|
|
17
17
|
import { handle } from '../../../common/event-emitter/handle'
|
|
18
18
|
import { isPureObject } from '../../../common/util/type-check'
|
|
19
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
19
20
|
|
|
20
21
|
export class Aggregate extends AggregateBase {
|
|
21
22
|
static featureName = FEATURE_NAME
|
|
@@ -121,7 +122,7 @@ export class Aggregate extends AggregateBase {
|
|
|
121
122
|
const observer = new PerformanceObserver((list) => {
|
|
122
123
|
list.getEntries().forEach(entry => {
|
|
123
124
|
try {
|
|
124
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/' + type + '/Seen'])
|
|
125
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/' + type + '/Seen'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
125
126
|
const detailObj = agentRef.init.performance.capture_detail ? createDetailAttrs(entry.detail) : {}
|
|
126
127
|
this.addEvent({
|
|
127
128
|
...detailObj,
|
|
@@ -181,13 +182,13 @@ export class Aggregate extends AggregateBase {
|
|
|
181
182
|
if (this.agentRef.init.performance.resources.asset_types.length && !this.agentRef.init.performance.resources.asset_types.includes(entryObject.initiatorType)) return
|
|
182
183
|
/** decide if the entryDomain is a first party domain */
|
|
183
184
|
firstParty = entryDomain === globalScope?.location.hostname || agentRef.init.performance.resources.first_party_domains.includes(entryDomain)
|
|
184
|
-
if (firstParty) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/FirstPartyResource/Seen'])
|
|
185
|
-
if (isNr) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/NrResource/Seen'])
|
|
185
|
+
if (firstParty) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/FirstPartyResource/Seen'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
186
|
+
if (isNr) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/NrResource/Seen'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
186
187
|
} catch (err) {
|
|
187
188
|
// couldnt parse the URL, so firstParty will just default to false
|
|
188
189
|
}
|
|
189
190
|
|
|
190
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/Resource/Seen'])
|
|
191
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/Performance/Resource/Seen'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
191
192
|
const event = {
|
|
192
193
|
...entryObject,
|
|
193
194
|
eventType: 'BrowserPerformance',
|
|
@@ -278,11 +279,11 @@ export class Aggregate extends AggregateBase {
|
|
|
278
279
|
trackSupportabilityMetrics () {
|
|
279
280
|
/** track usage SMs to improve these experimental features */
|
|
280
281
|
const configPerfTag = 'Config/Performance/'
|
|
281
|
-
if (this.agentRef.init.performance.capture_marks) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMarks/Enabled'])
|
|
282
|
-
if (this.agentRef.init.performance.capture_measures) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMeasures/Enabled'])
|
|
283
|
-
if (this.agentRef.init.performance.resources.enabled) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/Enabled'])
|
|
284
|
-
if (this.agentRef.init.performance.resources.asset_types?.length !== 0) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/AssetTypes/Changed'])
|
|
285
|
-
if (this.agentRef.init.performance.resources.first_party_domains?.length !== 0) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/FirstPartyDomains/Changed'])
|
|
286
|
-
if (this.agentRef.init.performance.resources.ignore_newrelic === false) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/IgnoreNewrelic/Changed'])
|
|
282
|
+
if (this.agentRef.init.performance.capture_marks) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMarks/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
283
|
+
if (this.agentRef.init.performance.capture_measures) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'CaptureMeasures/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
284
|
+
if (this.agentRef.init.performance.resources.enabled) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
285
|
+
if (this.agentRef.init.performance.resources.asset_types?.length !== 0) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/AssetTypes/Changed'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
286
|
+
if (this.agentRef.init.performance.resources.first_party_domains?.length !== 0) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/FirstPartyDomains/Changed'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
287
|
+
if (this.agentRef.init.performance.resources.ignore_newrelic === false) handle(SUPPORTABILITY_METRIC_CHANNEL, [configPerfTag + 'Resources/IgnoreNewrelic/Changed'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
287
288
|
}
|
|
288
289
|
}
|
|
@@ -13,6 +13,7 @@ import { Log } from '../shared/log'
|
|
|
13
13
|
import { isValidLogLevel } from '../shared/utils'
|
|
14
14
|
import { applyFnToProps } from '../../../common/util/traverse'
|
|
15
15
|
import { MAX_PAYLOAD_SIZE } from '../../../common/constants/agent-constants'
|
|
16
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
16
17
|
|
|
17
18
|
export class Aggregate extends AggregateBase {
|
|
18
19
|
static featureName = FEATURE_NAME
|
|
@@ -63,18 +64,18 @@ export class Aggregate extends AggregateBase {
|
|
|
63
64
|
|
|
64
65
|
const failToHarvestMessage = 'Logging/Harvest/Failed/Seen'
|
|
65
66
|
if (logBytes > MAX_PAYLOAD_SIZE) { // cannot possibly send this, even with an empty buffer
|
|
66
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes])
|
|
67
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
67
68
|
warn(31, log.message.slice(0, 25) + '...')
|
|
68
69
|
return
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
if (this.events.wouldExceedMaxSize(logBytes)) {
|
|
72
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes])
|
|
73
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.events.byteSize() + logBytes], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
73
74
|
this.agentRef.runtime.harvester.triggerHarvestFor(this) // force a harvest synchronously to try adding again
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
if (!this.events.add(log)) { // still failed after a harvest attempt despite not being too large would mean harvest failed with options.retry
|
|
77
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes])
|
|
78
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, [failToHarvestMessage, logBytes], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
78
79
|
warn(31, log.message.slice(0, 25) + '...')
|
|
79
80
|
}
|
|
80
81
|
}
|
|
@@ -11,8 +11,8 @@ 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'
|
|
14
15
|
import { firstPaint } from '../../../common/vitals/first-paint'
|
|
15
|
-
import { firstInteraction } from '../../../common/vitals/first-interaction'
|
|
16
16
|
import { interactionToNextPaint } from '../../../common/vitals/interaction-to-next-paint'
|
|
17
17
|
import { largestContentfulPaint } from '../../../common/vitals/largest-contentful-paint'
|
|
18
18
|
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte'
|
|
@@ -37,8 +37,8 @@ export class Aggregate extends AggregateBase {
|
|
|
37
37
|
this.waitForFlags(([])).then(() => {
|
|
38
38
|
firstPaint.subscribe(this.#handleVitalMetric)
|
|
39
39
|
firstContentfulPaint.subscribe(this.#handleVitalMetric)
|
|
40
|
+
firstInputDelay.subscribe(this.#handleVitalMetric)
|
|
40
41
|
largestContentfulPaint.subscribe(this.#handleVitalMetric)
|
|
41
|
-
firstInteraction.subscribe(this.#handleVitalMetric)
|
|
42
42
|
interactionToNextPaint.subscribe(this.#handleVitalMetric)
|
|
43
43
|
timeToFirstByte.subscribe(({ attrs }) => {
|
|
44
44
|
this.addTiming('load', Math.round(attrs.navigationEntry.loadEventEnd))
|
|
@@ -50,7 +50,7 @@ export class Aggregate extends AggregateBase {
|
|
|
50
50
|
const { name, value, attrs } = cumulativeLayoutShift.current
|
|
51
51
|
if (value === undefined) return
|
|
52
52
|
this.addTiming(name, value * 1000, attrs)
|
|
53
|
-
}, true) // CLS node should only reports on vis change rather than on every change
|
|
53
|
+
}, true, true) // CLS node should only reports on vis change rather than on every change
|
|
54
54
|
|
|
55
55
|
this.drain()
|
|
56
56
|
})
|
|
@@ -136,6 +136,11 @@ export class TraceStorage {
|
|
|
136
136
|
|
|
137
137
|
processPVT (name, value, attrs) {
|
|
138
138
|
this.storeTiming({ [name]: value })
|
|
139
|
+
if (hasFID(name, attrs)) this.storeEvent({ type: 'fid', target: 'document' }, 'document', value, value + attrs.fid)
|
|
140
|
+
|
|
141
|
+
function hasFID (name, attrs) {
|
|
142
|
+
return name === 'fi' && !!attrs && typeof attrs.fid === 'number'
|
|
143
|
+
}
|
|
139
144
|
}
|
|
140
145
|
|
|
141
146
|
storeTiming (timingEntry, isAbsoluteTimestamp = false) {
|
package/src/loaders/agent.js
CHANGED
|
@@ -26,10 +26,9 @@ import { globalScope } from '../common/constants/runtime'
|
|
|
26
26
|
export class Agent extends AgentBase {
|
|
27
27
|
/**
|
|
28
28
|
* @param {Object} options Options to initialize agent with
|
|
29
|
-
* @param {string} [agentIdentifier] Optional identifier of agent
|
|
30
29
|
*/
|
|
31
|
-
constructor (options
|
|
32
|
-
super(
|
|
30
|
+
constructor (options) {
|
|
31
|
+
super()
|
|
33
32
|
|
|
34
33
|
if (!globalScope) {
|
|
35
34
|
// We could not determine the runtime environment. Short-circuite the agent here
|
|
@@ -8,8 +8,8 @@ import { generateRandomHexString } from '../common/ids/unique-id'
|
|
|
8
8
|
export class MicroAgentBase {
|
|
9
9
|
agentIdentifier
|
|
10
10
|
|
|
11
|
-
constructor (
|
|
12
|
-
this.agentIdentifier =
|
|
11
|
+
constructor () {
|
|
12
|
+
this.agentIdentifier = generateRandomHexString(16)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -28,10 +28,9 @@ const nonAutoFeatures = [
|
|
|
28
28
|
export class MicroAgent extends MicroAgentBase {
|
|
29
29
|
/**
|
|
30
30
|
* @param {Object} options - Specifies features and runtime configuration,
|
|
31
|
-
* @param {string=} agentIdentifier - The optional unique ID of the agent.
|
|
32
31
|
*/
|
|
33
|
-
constructor (options
|
|
34
|
-
super(
|
|
32
|
+
constructor (options) {
|
|
33
|
+
super()
|
|
35
34
|
|
|
36
35
|
this.features = {}
|
|
37
36
|
setNREUMInitializedAgent(this.agentIdentifier, this)
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.firstInteraction = void 0;
|
|
7
|
-
var _vitalMetric = require("./vital-metric");
|
|
8
|
-
var _constants = require("./constants");
|
|
9
|
-
var _runtime = require("../constants/runtime");
|
|
10
|
-
/**
|
|
11
|
-
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
12
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
// Note: First Interaction is a legacy NR timing event, not an actual CWV metric
|
|
16
|
-
const firstInteraction = exports.firstInteraction = new _vitalMetric.VitalMetric(_constants.VITAL_NAMES.FIRST_INTERACTION);
|
|
17
|
-
if (_runtime.isBrowserScope) {
|
|
18
|
-
try {
|
|
19
|
-
let observer;
|
|
20
|
-
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
21
|
-
if (PerformanceObserver.supportedEntryTypes.includes(_constants.PERFORMANCE_ENTRY_TYPE.FIRST_INPUT) && !_runtime.initiallyHidden) {
|
|
22
|
-
observer = new PerformanceObserver(list => {
|
|
23
|
-
const firstInput = list.getEntries()[0];
|
|
24
|
-
const attrs = {
|
|
25
|
-
type: firstInput.name,
|
|
26
|
-
eventTarget: firstInput.target
|
|
27
|
-
};
|
|
28
|
-
observer.disconnect();
|
|
29
|
-
if (!firstInteraction.isValid) {
|
|
30
|
-
firstInteraction.update({
|
|
31
|
-
value: firstInput.startTime,
|
|
32
|
-
attrs
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
observer.observe({
|
|
37
|
-
type: _constants.PERFORMANCE_ENTRY_TYPE.FIRST_INPUT,
|
|
38
|
-
buffered: true
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
} catch (e) {
|
|
42
|
-
// Do nothing.
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
import { VitalMetric } from './vital-metric';
|
|
6
|
-
import { VITAL_NAMES, PERFORMANCE_ENTRY_TYPE } from './constants';
|
|
7
|
-
import { initiallyHidden, isBrowserScope } from '../constants/runtime';
|
|
8
|
-
|
|
9
|
-
// Note: First Interaction is a legacy NR timing event, not an actual CWV metric
|
|
10
|
-
export const firstInteraction = new VitalMetric(VITAL_NAMES.FIRST_INTERACTION);
|
|
11
|
-
if (isBrowserScope) {
|
|
12
|
-
try {
|
|
13
|
-
let observer;
|
|
14
|
-
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
15
|
-
if (PerformanceObserver.supportedEntryTypes.includes(PERFORMANCE_ENTRY_TYPE.FIRST_INPUT) && !initiallyHidden) {
|
|
16
|
-
observer = new PerformanceObserver(list => {
|
|
17
|
-
const firstInput = list.getEntries()[0];
|
|
18
|
-
const attrs = {
|
|
19
|
-
type: firstInput.name,
|
|
20
|
-
eventTarget: firstInput.target
|
|
21
|
-
};
|
|
22
|
-
observer.disconnect();
|
|
23
|
-
if (!firstInteraction.isValid) {
|
|
24
|
-
firstInteraction.update({
|
|
25
|
-
value: firstInput.startTime,
|
|
26
|
-
attrs
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
observer.observe({
|
|
31
|
-
type: PERFORMANCE_ENTRY_TYPE.FIRST_INPUT,
|
|
32
|
-
buffered: true
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
} catch (e) {
|
|
36
|
-
// Do nothing.
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"first-interaction.d.ts","sourceRoot":"","sources":["../../../../src/common/vitals/first-interaction.js"],"names":[],"mappings":"AASA,2CAA8E;4BALlD,gBAAgB"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
import { VitalMetric } from './vital-metric'
|
|
6
|
-
import { VITAL_NAMES, PERFORMANCE_ENTRY_TYPE } from './constants'
|
|
7
|
-
import { initiallyHidden, isBrowserScope } from '../constants/runtime'
|
|
8
|
-
|
|
9
|
-
// Note: First Interaction is a legacy NR timing event, not an actual CWV metric
|
|
10
|
-
export const firstInteraction = new VitalMetric(VITAL_NAMES.FIRST_INTERACTION)
|
|
11
|
-
|
|
12
|
-
if (isBrowserScope) {
|
|
13
|
-
try {
|
|
14
|
-
let observer
|
|
15
|
-
// preserve the original behavior where FID is not reported if the page is hidden before the first interaction
|
|
16
|
-
if (PerformanceObserver.supportedEntryTypes.includes(PERFORMANCE_ENTRY_TYPE.FIRST_INPUT) && !initiallyHidden) {
|
|
17
|
-
observer = new PerformanceObserver((list) => {
|
|
18
|
-
const firstInput = list.getEntries()[0]
|
|
19
|
-
|
|
20
|
-
const attrs = {
|
|
21
|
-
type: firstInput.name,
|
|
22
|
-
eventTarget: firstInput.target
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
observer.disconnect()
|
|
26
|
-
if (!firstInteraction.isValid) {
|
|
27
|
-
firstInteraction.update({
|
|
28
|
-
value: firstInput.startTime,
|
|
29
|
-
attrs
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
})
|
|
33
|
-
observer.observe({ type: PERFORMANCE_ENTRY_TYPE.FIRST_INPUT, buffered: true })
|
|
34
|
-
}
|
|
35
|
-
} catch (e) {
|
|
36
|
-
// Do nothing.
|
|
37
|
-
}
|
|
38
|
-
}
|