@newrelic/browser-agent 1.306.0 → 1.307.0-rc.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 +9 -0
- package/dist/cjs/cdn/spa.js +4 -6
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/deny-list/deny-list.js +22 -36
- package/dist/cjs/common/harvest/harvester.js +2 -1
- package/dist/cjs/features/ajax/aggregate/index.js +1 -20
- package/dist/cjs/features/jserrors/aggregate/index.js +9 -67
- package/dist/cjs/features/soft_navigations/aggregate/index.js +26 -16
- package/dist/cjs/features/utils/agent-session.js +10 -0
- package/dist/cjs/features/utils/aggregate-base.js +1 -1
- package/dist/cjs/interfaces/registered-entity.js +2 -1
- package/dist/cjs/loaders/agent.js +5 -4
- package/dist/cjs/loaders/api/interaction.js +4 -4
- package/dist/cjs/loaders/api/register-api-types.js +1 -1
- package/dist/cjs/loaders/api/setUserId.js +13 -3
- package/dist/cjs/loaders/api-base.js +3 -2
- package/dist/cjs/loaders/browser-agent.js +6 -7
- package/dist/cjs/loaders/configure/configure.js +0 -3
- package/dist/esm/cdn/spa.js +2 -4
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/deny-list/deny-list.js +22 -36
- package/dist/esm/common/harvest/harvester.js +2 -1
- package/dist/esm/features/ajax/aggregate/index.js +1 -20
- package/dist/esm/features/jserrors/aggregate/index.js +9 -67
- package/dist/esm/features/soft_navigations/aggregate/index.js +26 -16
- package/dist/esm/features/utils/agent-session.js +10 -0
- package/dist/esm/features/utils/aggregate-base.js +1 -1
- package/dist/esm/interfaces/registered-entity.js +2 -1
- package/dist/esm/loaders/agent.js +5 -4
- package/dist/esm/loaders/api/interaction.js +5 -5
- package/dist/esm/loaders/api/register-api-types.js +1 -1
- package/dist/esm/loaders/api/setUserId.js +14 -4
- package/dist/esm/loaders/api-base.js +3 -2
- package/dist/esm/loaders/browser-agent.js +2 -3
- package/dist/esm/loaders/configure/configure.js +0 -3
- package/dist/types/common/deny-list/deny-list.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts +0 -1
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +0 -3
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/agent-session.d.ts.map +1 -1
- package/dist/types/interfaces/registered-entity.d.ts +2 -1
- package/dist/types/interfaces/registered-entity.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts +0 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/api/interaction.d.ts.map +1 -1
- package/dist/types/loaders/api/register-api-types.d.ts +2 -2
- package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
- package/dist/types/loaders/api/setUserId.d.ts.map +1 -1
- package/dist/types/loaders/api-base.d.ts +2 -1
- package/dist/types/loaders/api-base.d.ts.map +1 -1
- package/dist/types/loaders/browser-agent.d.ts.map +1 -1
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/cdn/spa.js +2 -4
- package/src/common/deny-list/deny-list.js +25 -40
- package/src/common/harvest/harvester.js +1 -1
- package/src/features/ajax/aggregate/index.js +2 -18
- package/src/features/jserrors/aggregate/index.js +8 -76
- package/src/features/soft_navigations/aggregate/index.js +26 -18
- package/src/features/utils/agent-session.js +11 -0
- package/src/features/utils/aggregate-base.js +1 -1
- package/src/interfaces/registered-entity.js +2 -1
- package/src/loaders/agent.js +5 -4
- package/src/loaders/api/interaction.js +5 -6
- package/src/loaders/api/register-api-types.js +1 -1
- package/src/loaders/api/setUserId.js +15 -4
- package/src/loaders/api-base.js +3 -2
- package/src/loaders/browser-agent.js +1 -3
- package/src/loaders/configure/configure.js +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
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.307.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.306.0...v1.307.0) (2026-01-06)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add resetSession option to setUserId() API ([#1646](https://github.com/newrelic/newrelic-browser-agent/issues/1646)) ([c284cfd](https://github.com/newrelic/newrelic-browser-agent/commit/c284cfde4a18fb9afa75c11b181944401a902e13))
|
|
12
|
+
* Ajax deny list wildcard support ([#1655](https://github.com/newrelic/newrelic-browser-agent/issues/1655)) ([61fa99b](https://github.com/newrelic/newrelic-browser-agent/commit/61fa99ba39334b85f7611a076943f15356f65364))
|
|
13
|
+
* Make soft navigations feature the default SPA ([#1638](https://github.com/newrelic/newrelic-browser-agent/issues/1638)) ([d93f3f3](https://github.com/newrelic/newrelic-browser-agent/commit/d93f3f388085b7e76292e79749977db19a10765a))
|
|
14
|
+
|
|
6
15
|
## [1.306.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.305.0...v1.306.0) (2025-12-16)
|
|
7
16
|
|
|
8
17
|
|
package/dist/cjs/cdn/spa.js
CHANGED
|
@@ -9,11 +9,10 @@ var _instrument5 = require("../features/ajax/instrument");
|
|
|
9
9
|
var _instrument6 = require("../features/session_trace/instrument");
|
|
10
10
|
var _instrument7 = require("../features/session_replay/instrument");
|
|
11
11
|
var _instrument8 = require("../features/soft_navigations/instrument");
|
|
12
|
-
var _instrument9 = require("../features/
|
|
13
|
-
var _instrument0 = require("../features/
|
|
14
|
-
var _instrument1 = require("../features/logging/instrument");
|
|
12
|
+
var _instrument9 = require("../features/generic_events/instrument");
|
|
13
|
+
var _instrument0 = require("../features/logging/instrument");
|
|
15
14
|
/**
|
|
16
|
-
* Copyright 2020-
|
|
15
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
17
16
|
* SPDX-License-Identifier: Apache-2.0
|
|
18
17
|
*/
|
|
19
18
|
|
|
@@ -22,7 +21,6 @@ var _instrument1 = require("../features/logging/instrument");
|
|
|
22
21
|
*/
|
|
23
22
|
|
|
24
23
|
new _agent.Agent({
|
|
25
|
-
features: [_instrument5.Instrument, _instrument.Instrument, _instrument2.Instrument, _instrument6.Instrument, _instrument7.Instrument, _instrument3.Instrument, _instrument4.Instrument,
|
|
26
|
-
],
|
|
24
|
+
features: [_instrument5.Instrument, _instrument.Instrument, _instrument2.Instrument, _instrument6.Instrument, _instrument7.Instrument, _instrument3.Instrument, _instrument4.Instrument, _instrument9.Instrument, _instrument0.Instrument, _instrument8.Instrument],
|
|
27
25
|
loaderType: 'spa'
|
|
28
26
|
});
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.
|
|
20
|
+
const VERSION = exports.VERSION = "1.307.0-rc.1";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.
|
|
20
|
+
const VERSION = exports.VERSION = "1.307.0-rc.1";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -26,12 +26,12 @@ var denyList = [];
|
|
|
26
26
|
function shouldCollectEvent(params) {
|
|
27
27
|
if (!params || hasUndefinedHostname(params)) return false;
|
|
28
28
|
if (denyList.length === 0) return true;
|
|
29
|
+
|
|
30
|
+
// short circuit if deny list contains just a wildcard
|
|
31
|
+
if (denyList[0].hostname === '*') return false;
|
|
29
32
|
for (var i = 0; i < denyList.length; i++) {
|
|
30
33
|
var parsed = denyList[i];
|
|
31
|
-
if (parsed.hostname
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
if (domainMatchesPattern(parsed.hostname, params.hostname) && comparePath(parsed.pathname, params.pathname)) {
|
|
34
|
+
if (parsed.hostname.test(params.hostname) && parsed.pathname.test(params.pathname)) {
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -54,6 +54,13 @@ function setDenyList(denyListConfig) {
|
|
|
54
54
|
let url = denyListConfig[i];
|
|
55
55
|
if (!url) continue; // ignore bad values like undefined or empty strings
|
|
56
56
|
|
|
57
|
+
// short circuit if deny list entry is just a wildcard
|
|
58
|
+
if (url === '*') {
|
|
59
|
+
denyList = [{
|
|
60
|
+
hostname: '*'
|
|
61
|
+
}];
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
57
64
|
if (url.indexOf('http://') === 0) {
|
|
58
65
|
url = url.substring(7);
|
|
59
66
|
} else if (url.indexOf('https://') === 0) {
|
|
@@ -66,45 +73,24 @@ function setDenyList(denyListConfig) {
|
|
|
66
73
|
pathname = url.substring(firstSlash);
|
|
67
74
|
} else {
|
|
68
75
|
host = url;
|
|
69
|
-
pathname = '';
|
|
76
|
+
pathname = '*';
|
|
70
77
|
}
|
|
71
78
|
let [hostname] = host.split(':');
|
|
72
79
|
denyList.push({
|
|
73
|
-
hostname,
|
|
74
|
-
pathname
|
|
80
|
+
hostname: convertToRegularExpression(hostname),
|
|
81
|
+
pathname: convertToRegularExpression(pathname, true)
|
|
75
82
|
});
|
|
76
83
|
}
|
|
77
84
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Returns true if the right side of `domain` (end of string) matches `pattern`.
|
|
80
|
-
* @param {string} pattern - a string to be matched against the end of `domain` string
|
|
81
|
-
* @param {string} domain - a domain string with no protocol or path (e.g., app1.example.com)
|
|
82
|
-
* @returns {boolean} `true` if domain matches pattern; else `false`
|
|
83
|
-
*/
|
|
84
|
-
function domainMatchesPattern(pattern, domain) {
|
|
85
|
-
if (pattern.length > domain.length) {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
return domain.indexOf(pattern) === domain.length - pattern.length;
|
|
89
|
-
}
|
|
90
85
|
|
|
91
86
|
/**
|
|
92
|
-
*
|
|
93
|
-
* @param {string}
|
|
94
|
-
* @param {
|
|
95
|
-
* @returns {
|
|
87
|
+
* Converts a deny list filter string into a regular expression object with wildcard support
|
|
88
|
+
* @param {string} filter - deny list filter to convert
|
|
89
|
+
* @param {boolean} [isPathname=false] - indicates if the filter is a pathname
|
|
90
|
+
* @returns {RegExp} - regular expression object built from the input string
|
|
96
91
|
*/
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (path.indexOf('/') === 0) {
|
|
102
|
-
path = path.substring(1);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// No path in pattern means match all paths.
|
|
106
|
-
if (pattern === '') {
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
return pattern === path;
|
|
92
|
+
function convertToRegularExpression(filter, isPathname = false) {
|
|
93
|
+
const newFilter = filter.replace(/[.+?^${}()|[\]\\]/g, m => '\\' + m) // use a replacer function to not break apm injection
|
|
94
|
+
.replace(/\*/g, '.*?'); // use lazy matching instead of greedy
|
|
95
|
+
return new RegExp((isPathname ? '^' : '') + newFilter + '$');
|
|
110
96
|
}
|
|
@@ -85,7 +85,8 @@ class Harvester {
|
|
|
85
85
|
featureName: aggregateInst.featureName,
|
|
86
86
|
endpointVersion: output.endpointVersion
|
|
87
87
|
});
|
|
88
|
-
output.ranSend = true;
|
|
88
|
+
output.ranSend = true; // Set to true if we attempted to send (even if send() returned false due to missing errorBeacon in tests)
|
|
89
|
+
|
|
89
90
|
return output;
|
|
90
91
|
|
|
91
92
|
/**
|
|
@@ -24,7 +24,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
24
24
|
constructor(agentRef) {
|
|
25
25
|
super(agentRef, _constants.FEATURE_NAME);
|
|
26
26
|
(0, _denyList.setDenyList)(agentRef.runtime.denyList);
|
|
27
|
-
this.underSpaEvents = {};
|
|
28
27
|
const classThis = this;
|
|
29
28
|
if (!agentRef.init.ajax.block_internal) {
|
|
30
29
|
// if the agent is tracking ITSELF, it can spawn endless ajax requests early if they are large from custom attributes, so we just disable early harvest for ajax in this case.
|
|
@@ -32,20 +31,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
32
31
|
} else {
|
|
33
32
|
super.customAttributesAreSeparate = true;
|
|
34
33
|
}
|
|
35
|
-
|
|
36
|
-
// --- v Used by old spa feature
|
|
37
|
-
this.ee.on('interactionDone', (interaction, wasSaved) => {
|
|
38
|
-
if (!this.underSpaEvents[interaction.id]) return;
|
|
39
|
-
if (!wasSaved) {
|
|
40
|
-
// if the ixn was saved, then its ajax reqs are part of the payload whereas if it was discarded, it should still be harvested in the ajax feature itself
|
|
41
|
-
this.underSpaEvents[interaction.id].forEach(item => this.events.add(item));
|
|
42
|
-
}
|
|
43
|
-
delete this.underSpaEvents[interaction.id];
|
|
44
|
-
});
|
|
45
|
-
// --- ^
|
|
46
|
-
// --- v Used by new soft nav
|
|
47
34
|
(0, _registerHandler.registerHandler)('returnAjax', event => this.events.add(event), this.featureName, this.ee);
|
|
48
|
-
// --- ^
|
|
49
35
|
(0, _registerHandler.registerHandler)('xhr', function () {
|
|
50
36
|
// the EE-drain system not only switches "this" but also passes a new EventContext with info. Should consider platform refactor to another system which passes a mutable context around separately and predictably to avoid problems like this.
|
|
51
37
|
classThis.storeXhr(...arguments, this); // this switches the context back to the class instance while passing the NR context as an argument -- see "ctx" in storeXhr
|
|
@@ -116,13 +102,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
116
102
|
if (event.gql) this.reportSupportabilityMetric('Ajax/Events/GraphQL/Bytes-Added', (0, _stringify.stringify)(event.gql).length);
|
|
117
103
|
const softNavInUse = Boolean(this.agentRef.features?.[_features.FEATURE_NAMES.softNav]);
|
|
118
104
|
if (softNavInUse) {
|
|
119
|
-
//
|
|
105
|
+
// when SN is running, pass the event w/ info to it for evaluation -- either part of an interaction or is given back
|
|
120
106
|
(0, _handle.handle)('ajax', [event, ctx], undefined, _features.FEATURE_NAMES.softNav, this.ee);
|
|
121
|
-
} else if (ctx.spaNode) {
|
|
122
|
-
// For old spa (when running), if the ajax happened inside an interaction, hold it until the interaction finishes
|
|
123
|
-
const interactionId = ctx.spaNode.interaction.id;
|
|
124
|
-
this.underSpaEvents[interactionId] ??= [];
|
|
125
|
-
this.underSpaEvents[interactionId].push(event);
|
|
126
107
|
} else {
|
|
127
108
|
this.events.add(event);
|
|
128
109
|
}
|
|
@@ -39,14 +39,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
39
39
|
this.stackReported = {};
|
|
40
40
|
this.observedAt = {};
|
|
41
41
|
this.pageviewReported = {};
|
|
42
|
-
this.bufferedErrorsUnderSpa = {};
|
|
43
42
|
this.errorOnPage = false;
|
|
44
|
-
|
|
45
|
-
// this will need to change to match whatever ee we use in the instrument
|
|
46
|
-
this.ee.on('interactionDone', (interaction, wasSaved) => this.onInteractionDone(interaction, wasSaved));
|
|
47
43
|
(0, _registerHandler.registerHandler)('err', (...args) => this.storeError(...args), this.featureName, this.ee);
|
|
48
44
|
(0, _registerHandler.registerHandler)('ierr', (...args) => this.storeError(...args), this.featureName, this.ee);
|
|
49
|
-
(0, _registerHandler.registerHandler)('
|
|
45
|
+
(0, _registerHandler.registerHandler)('returnJserror', (jsErrorEvent, softNavAttrs) => this.#storeJserrorForHarvest(jsErrorEvent, softNavAttrs), this.featureName, this.ee);
|
|
50
46
|
|
|
51
47
|
// 0 == off, 1 == on
|
|
52
48
|
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
@@ -193,43 +189,26 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
193
189
|
}
|
|
194
190
|
if (this.shouldAllowMainAgentToCapture(target)) {
|
|
195
191
|
const softNavInUse = Boolean(this.agentRef.features?.[_features.FEATURE_NAMES.softNav]);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (params.browserInteractionId && !params._softNavFinished) {
|
|
200
|
-
// hold onto the error until the in-progress interaction is done, eithered saved or discarded
|
|
201
|
-
this.bufferedErrorsUnderSpa[params.browserInteractionId] ??= [];
|
|
202
|
-
this.bufferedErrorsUnderSpa[params.browserInteractionId].push(jsErrorEvent);
|
|
203
|
-
} else if (params._interactionId != null) {
|
|
204
|
-
// same as above, except tailored for the way old spa does it
|
|
205
|
-
this.bufferedErrorsUnderSpa[params._interactionId] = this.bufferedErrorsUnderSpa[params._interactionId] || [];
|
|
206
|
-
this.bufferedErrorsUnderSpa[params._interactionId].push(jsErrorEvent);
|
|
192
|
+
if (softNavInUse) {
|
|
193
|
+
// pass the error to soft nav for evaluation - it will return it via 'returnJserror' when interaction is resolved
|
|
194
|
+
(0, _handle.handle)('jserror', [jsErrorEvent], undefined, _features.FEATURE_NAMES.softNav, this.ee);
|
|
207
195
|
} else {
|
|
208
|
-
|
|
209
|
-
// The old spa does not look up completed interactions at all, so there's no need to consider it.
|
|
210
|
-
this.#storeJserrorForHarvest(jsErrorEvent, params.browserInteractionId !== undefined, params._softNavAttributes);
|
|
196
|
+
this.#storeJserrorForHarvest(jsErrorEvent, false);
|
|
211
197
|
}
|
|
212
198
|
}
|
|
213
199
|
|
|
214
200
|
// always add directly if scoped to a sub-entity, the other pathways above will be deterministic if the main agent should procede
|
|
215
201
|
if (target) this.#storeJserrorForHarvest([...jsErrorEvent, target], false, params._softNavAttributes);
|
|
216
202
|
}
|
|
217
|
-
#storeJserrorForHarvest(errorInfoArr,
|
|
203
|
+
#storeJserrorForHarvest(errorInfoArr, softNavCustomAttrs = {}) {
|
|
218
204
|
let [type, bucketHash, params, newMetrics, localAttrs, target] = errorInfoArr;
|
|
219
205
|
const allCustomAttrs = {
|
|
220
206
|
/** MFE specific attributes if in "multiple" mode (ie consumer version 2) */
|
|
221
207
|
...(0, _mfe.getVersion2Attributes)(target, this)
|
|
222
208
|
};
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
delete params._softNavAttributes; // cleanup temp properties from synchronous evaluation; this is harmless when async from soft nav (properties DNE)
|
|
227
|
-
delete params._softNavFinished;
|
|
228
|
-
} else {
|
|
229
|
-
// interaction was cancelled -> error should not be associated OR there was no interaction
|
|
230
|
-
Object.entries(this.agentRef.info.jsAttributes).forEach(([k, v]) => setCustom(k, v));
|
|
231
|
-
delete params.browserInteractionId;
|
|
232
|
-
}
|
|
209
|
+
Object.entries(this.agentRef.info.jsAttributes).forEach(([k, v]) => setCustom(k, v));
|
|
210
|
+
Object.entries(softNavCustomAttrs).forEach(([k, v]) => setCustom(k, v)); // when an ixn finishes, it'll pass attrs specific to the ixn; if no associated ixn, this defaults to empty
|
|
211
|
+
if (params.browserInteractionId) bucketHash += params.browserInteractionId;
|
|
233
212
|
if (localAttrs) Object.entries(localAttrs).forEach(([k, v]) => setCustom(k, v)); // local custom attrs are applied in either case with the highest precedence
|
|
234
213
|
|
|
235
214
|
const jsAttributesHash = (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(allCustomAttrs));
|
|
@@ -249,42 +228,5 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
249
228
|
shouldAllowMainAgentToCapture(target) {
|
|
250
229
|
return !target || this.agentRef.init.api.duplicate_registered_data;
|
|
251
230
|
}
|
|
252
|
-
|
|
253
|
-
// TO-DO: Remove this function when old spa is taken out. #storeJserrorForHarvest handles the work with the softnav feature.
|
|
254
|
-
onInteractionDone(interaction, wasSaved) {
|
|
255
|
-
if (!this.bufferedErrorsUnderSpa[interaction.id] || this.blocked) return;
|
|
256
|
-
this.bufferedErrorsUnderSpa[interaction.id].forEach(item => {
|
|
257
|
-
var allCustomAttrs = {};
|
|
258
|
-
const localCustomAttrs = item[4];
|
|
259
|
-
Object.entries(interaction.root.attrs.custom || {}).forEach(setCustom); // tack on custom attrs from the interaction
|
|
260
|
-
Object.entries(localCustomAttrs || {}).forEach(setCustom);
|
|
261
|
-
var params = item[2];
|
|
262
|
-
if (wasSaved) {
|
|
263
|
-
params.browserInteractionId = interaction.root.attrs.id;
|
|
264
|
-
if (params._interactionNodeId) params.parentNodeId = params._interactionNodeId.toString();
|
|
265
|
-
}
|
|
266
|
-
delete params._interactionId;
|
|
267
|
-
delete params._interactionNodeId;
|
|
268
|
-
var hash = wasSaved ? item[1] + interaction.root.attrs.id : item[1];
|
|
269
|
-
var jsAttributesHash = (0, _stringHashCode.stringHashCode)((0, _stringify.stringify)(allCustomAttrs));
|
|
270
|
-
var aggregateHash = hash + ':' + jsAttributesHash;
|
|
271
|
-
this.events.add([item[0], aggregateHash, params, item[3], allCustomAttrs], item[5]);
|
|
272
|
-
function setCustom([key, val]) {
|
|
273
|
-
allCustomAttrs[key] = val && typeof val === 'object' ? (0, _stringify.stringify)(val) : val;
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
delete this.bufferedErrorsUnderSpa[interaction.id];
|
|
277
|
-
}
|
|
278
|
-
onSoftNavNotification(interactionId, wasFinished, softNavAttrs, interactionEndTime) {
|
|
279
|
-
if (this.blocked) return;
|
|
280
|
-
this.bufferedErrorsUnderSpa[interactionId]?.forEach(jsErrorEvent => {
|
|
281
|
-
// this should not modify the re-used softNavAttrs contents
|
|
282
|
-
if (!wasFinished) return this.#storeJserrorForHarvest(jsErrorEvent, false, softNavAttrs);
|
|
283
|
-
const startTime = jsErrorEvent[3].time; // in storeError fn, the newMetrics obj contains the time passed to & used by SN to seek the ixn
|
|
284
|
-
if (startTime > interactionEndTime) return this.#storeJserrorForHarvest(jsErrorEvent, false, softNavAttrs); // disassociate any error that ultimately falls outside the final ixn span
|
|
285
|
-
return this.#storeJserrorForHarvest(jsErrorEvent, true, softNavAttrs);
|
|
286
|
-
});
|
|
287
|
-
delete this.bufferedErrorsUnderSpa[interactionId]; // wipe the list of jserrors so they aren't duplicated by another call to the same id
|
|
288
|
-
}
|
|
289
231
|
}
|
|
290
232
|
exports.Aggregate = Aggregate;
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.Aggregate = void 0;
|
|
7
7
|
var _handle = require("../../../common/event-emitter/handle");
|
|
8
8
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
9
|
-
var _invoke = require("../../../common/util/invoke");
|
|
10
9
|
var _loadTime = require("../../../common/vitals/load-time");
|
|
11
10
|
var _features = require("../../../loaders/features/features");
|
|
12
11
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
@@ -193,25 +192,36 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
193
192
|
}
|
|
194
193
|
|
|
195
194
|
/**
|
|
196
|
-
*
|
|
197
|
-
* @param {
|
|
198
|
-
* @param {DOMHighResTimeStamp} timestamp time the jserror occurred
|
|
195
|
+
* Handles or redirects jserror event based on the interaction, if any, that it's tied to.
|
|
196
|
+
* @param {Array} jsErrorEvent the error event array from jserrors feature
|
|
199
197
|
*/
|
|
200
|
-
#handleJserror(
|
|
198
|
+
#handleJserror(jsErrorEvent) {
|
|
199
|
+
const timestamp = jsErrorEvent[3].time; // in storeError fn, the newMetrics obj contains the time of the error
|
|
201
200
|
const associatedInteraction = this.getInteractionFor(timestamp);
|
|
202
|
-
if (!associatedInteraction)
|
|
201
|
+
if (!associatedInteraction) {
|
|
202
|
+
// No interaction was happening when this error occurred, so give it back to jserrors feature for processing
|
|
203
|
+
return (0, _handle.handle)('returnJserror', [jsErrorEvent], undefined, _features.FEATURE_NAMES.jserrors, this.ee);
|
|
204
|
+
}
|
|
203
205
|
|
|
204
|
-
//
|
|
205
|
-
params.browserInteractionId = associatedInteraction.id;
|
|
206
|
+
// Store the error info to be returned when interaction finishes
|
|
206
207
|
if (associatedInteraction.status === _constants.INTERACTION_STATUS.FIN) {
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
params._softNavAttributes = associatedInteraction.customAttributes;
|
|
208
|
+
// Interaction already finished, return immediately with the interaction ID and attributes
|
|
209
|
+
processJserror.call(this, jsErrorEvent, associatedInteraction);
|
|
210
210
|
} else {
|
|
211
|
-
//
|
|
212
|
-
|
|
213
|
-
associatedInteraction.on('
|
|
214
|
-
|
|
211
|
+
// Interaction still in progress, wait for it to finish or be cancelled
|
|
212
|
+
associatedInteraction.on('finished', () => processJserror.call(this, jsErrorEvent, associatedInteraction));
|
|
213
|
+
associatedInteraction.on('cancelled', () => (0, _handle.handle)('returnJserror', [jsErrorEvent], undefined, _features.FEATURE_NAMES.jserrors, this.ee));
|
|
214
|
+
}
|
|
215
|
+
function processJserror(jsErrorEvent, parentInteraction) {
|
|
216
|
+
const finalEnd = parentInteraction.end;
|
|
217
|
+
if (timestamp > finalEnd) {
|
|
218
|
+
// check if error falls within the final interaction span, after any & all long task extension(s) are considered
|
|
219
|
+
return (0, _handle.handle)('returnJserror', [jsErrorEvent], undefined, _features.FEATURE_NAMES.jserrors, this.ee);
|
|
220
|
+
}
|
|
221
|
+
// Error is within the interaction span, return with the correct interaction ID set, plus any custom attributes from the interaction
|
|
222
|
+
const params = jsErrorEvent[2];
|
|
223
|
+
params.browserInteractionId = parentInteraction.id;
|
|
224
|
+
(0, _handle.handle)('returnJserror', [jsErrorEvent, parentInteraction.customAttributes], undefined, _features.FEATURE_NAMES.jserrors, this.ee);
|
|
215
225
|
}
|
|
216
226
|
}
|
|
217
227
|
#registerApiHandlers() {
|
|
@@ -226,7 +236,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
226
236
|
if (this.associatedInteraction?.trigger === _constants.IPL_TRIGGER_NAME) this.associatedInteraction = null; // the api get-interaction method cannot target IPL
|
|
227
237
|
if (!this.associatedInteraction) {
|
|
228
238
|
// This new api-driven interaction will be the target of any subsequent .interaction() call, until it is closed by EITHER .end() OR the regular url>dom change process.
|
|
229
|
-
this.associatedInteraction = thisClass.interactionInProgress = new _interaction.Interaction(_constants.API_TRIGGER_NAME, time, thisClass.latestRouteSetByApi);
|
|
239
|
+
this.associatedInteraction = thisClass.interactionInProgress = new _interaction.Interaction(_constants.API_TRIGGER_NAME, Math.floor(time), thisClass.latestRouteSetByApi);
|
|
230
240
|
thisClass.domObserver.observe(document.body, {
|
|
231
241
|
attributes: true,
|
|
232
242
|
childList: true,
|
|
@@ -12,6 +12,11 @@ var _localStorage = require("../../common/storage/local-storage.js");
|
|
|
12
12
|
var _constants = require("../../common/session/constants");
|
|
13
13
|
var _info = require("../../common/config/info");
|
|
14
14
|
var _attributeSize = require("../../common/util/attribute-size");
|
|
15
|
+
var _handle = require("../../common/event-emitter/handle");
|
|
16
|
+
var _constants2 = require("../../loaders/api/constants");
|
|
17
|
+
var _constants3 = require("../metrics/constants");
|
|
18
|
+
var _features = require("../../loaders/features/features");
|
|
19
|
+
var _sharedHandlers = require("../../loaders/api/sharedHandlers");
|
|
15
20
|
/**
|
|
16
21
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
17
22
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -59,6 +64,11 @@ function setupAgentSession(agentRef) {
|
|
|
59
64
|
(0, _registerHandler.registerHandler)('api-setUserId', (time, key, value) => {
|
|
60
65
|
agentRef.runtime.session.syncCustomAttribute(key, value);
|
|
61
66
|
}, 'session', sharedEE);
|
|
67
|
+
(0, _registerHandler.registerHandler)('api-setUserIdAndResetSession', value => {
|
|
68
|
+
agentRef.runtime.session.reset();
|
|
69
|
+
(0, _handle.handle)(_constants3.SUPPORTABILITY_METRIC_CHANNEL, ['API/' + _constants2.SET_USER_ID + '/resetSession/called'], undefined, _features.FEATURE_NAMES.metrics, sharedEE);
|
|
70
|
+
(0, _sharedHandlers.appendJsAttribute)(agentRef, 'enduser.id', value, _constants2.SET_USER_ID, true);
|
|
71
|
+
}, 'session', sharedEE);
|
|
62
72
|
(0, _registerHandler.registerHandler)('api-consent', accept => {
|
|
63
73
|
agentRef.runtime.session.write({
|
|
64
74
|
consent: accept === undefined ? true : accept
|
|
@@ -102,8 +102,9 @@ class RegisteredEntity {
|
|
|
102
102
|
* Adds a user-defined identifier string to subsequent events on the page for the registered taret.
|
|
103
103
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setuserid/}
|
|
104
104
|
* @param {string|null} value A string identifier for the end-user, useful for tying all browser events to specific users. The value parameter does not have to be unique. If IDs should be unique, the caller is responsible for that validation. Passing a null value unsets any existing user ID.
|
|
105
|
+
* @param {boolean} [resetSession=false] Optional param. Should not be used from a registered entity context. To reset a session when updating user id, must be initiated by the main agent.
|
|
105
106
|
*/
|
|
106
|
-
setUserId(value) {
|
|
107
|
+
setUserId(value, resetSession = false) {
|
|
107
108
|
/** this method will be overset once register is successful */
|
|
108
109
|
(0, _console.warn)(35, 'setUserId');
|
|
109
110
|
}
|
|
@@ -21,7 +21,7 @@ var _setApplicationVersion = require("./api/setApplicationVersion");
|
|
|
21
21
|
var _start = require("./api/start");
|
|
22
22
|
var _consent = require("./api/consent");
|
|
23
23
|
/**
|
|
24
|
-
* Copyright 2020-
|
|
24
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
25
25
|
* SPDX-License-Identifier: Apache-2.0
|
|
26
26
|
*/
|
|
27
27
|
|
|
@@ -70,7 +70,6 @@ class Agent extends _agentBase.AgentBase {
|
|
|
70
70
|
// NR1 creates an index on the rum call, and if not seen for a few days, will remove the browser app!
|
|
71
71
|
// Future work is being planned to evaluate removing this behavior from the backend, but for now we must ensure this call is made
|
|
72
72
|
this.desiredFeatures.add(_instrument.Instrument);
|
|
73
|
-
this.runSoftNavOverSpa = [...this.desiredFeatures].some(instr => instr.featureName === _features.FEATURE_NAMES.softNav);
|
|
74
73
|
(0, _configure.configure)(this, options, options.loaderType || 'agent'); // add api, exposed, and other config properties
|
|
75
74
|
|
|
76
75
|
/** assign base agent-level API definitions, feature-level APIs will be handled by the features to allow better code-splitting */
|
|
@@ -100,8 +99,10 @@ class Agent extends _agentBase.AgentBase {
|
|
|
100
99
|
featuresToStart.sort((a, b) => _features.featurePriority[a.featureName] - _features.featurePriority[b.featureName]);
|
|
101
100
|
featuresToStart.forEach(InstrumentCtor => {
|
|
102
101
|
if (!enabledFeatures[InstrumentCtor.featureName] && InstrumentCtor.featureName !== _features.FEATURE_NAMES.pageViewEvent) return; // PVE is required to run even if it's marked disabled
|
|
103
|
-
if (
|
|
104
|
-
|
|
102
|
+
if (InstrumentCtor.featureName === _features.FEATURE_NAMES.spa) {
|
|
103
|
+
(0, _console.warn)(67);
|
|
104
|
+
return; // Skip old SPA
|
|
105
|
+
}
|
|
105
106
|
const dependencies = (0, _featureDependencies.getFeatureDependencyNames)(InstrumentCtor.featureName);
|
|
106
107
|
const missingDependencies = dependencies.filter(featName => !(featName in this.features)); // any other feature(s) this depends on should've been initialized on prior iterations by priority order
|
|
107
108
|
if (missingDependencies.length > 0) {
|
|
@@ -23,12 +23,12 @@ function setupInteractionAPI(agent) {
|
|
|
23
23
|
function InteractionHandle() {}
|
|
24
24
|
const InteractionApiProto = InteractionHandle.prototype = {
|
|
25
25
|
createTracer: function (name, cb) {
|
|
26
|
+
// Primarily used by old SPA feature to create custom child tracers under an interaction.
|
|
27
|
+
// Soft navigations won't support Tracer nodes, but this fn should still work the same otherwise (e.g., run the orig cb).
|
|
26
28
|
var contextStore = {};
|
|
27
29
|
var ixn = this;
|
|
28
30
|
var hasCb = typeof cb === 'function';
|
|
29
31
|
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['API/createTracer/called'], undefined, _features.FEATURE_NAMES.metrics, agent.ee);
|
|
30
|
-
// Soft navigations won't support Tracer nodes, but this fn should still work the same otherwise (e.g., run the orig cb).
|
|
31
|
-
if (!agent.runSoftNavOverSpa) (0, _handle.handle)(_constants2.spaPrefix + 'tracer', [(0, _now.now)(), name, contextStore], ixn, _features.FEATURE_NAMES.spa, agent.ee);
|
|
32
32
|
return function () {
|
|
33
33
|
tracerEE.emit((hasCb ? '' : 'no-') + 'fn-start', [(0, _now.now)(), ixn, hasCb], contextStore);
|
|
34
34
|
if (hasCb) {
|
|
@@ -48,11 +48,11 @@ function setupInteractionAPI(agent) {
|
|
|
48
48
|
};
|
|
49
49
|
['actionText', 'setName', 'setAttribute', 'save', 'ignore', 'onEnd', 'getContext', 'end', 'get'].forEach(name => {
|
|
50
50
|
_sharedHandlers.setupAPI.apply(this, [name, function () {
|
|
51
|
-
(0, _handle.handle)(_constants2.spaPrefix + name, [
|
|
51
|
+
(0, _handle.handle)(_constants2.spaPrefix + name, [performance.now(), ...arguments], this, _features.FEATURE_NAMES.softNav, agent.ee);
|
|
52
52
|
return this;
|
|
53
53
|
}, agent, InteractionApiProto]);
|
|
54
54
|
});
|
|
55
55
|
(0, _sharedHandlers.setupAPI)(_constants2.SET_CURRENT_ROUTE_NAME, function () {
|
|
56
|
-
|
|
56
|
+
(0, _handle.handle)(_constants2.spaPrefix + 'routeName', [performance.now(), ...arguments], undefined, _features.FEATURE_NAMES.softNav, agent.ee);
|
|
57
57
|
}, agent);
|
|
58
58
|
}
|
|
@@ -18,7 +18,7 @@ exports.default = void 0;
|
|
|
18
18
|
* @property {(eventType: string, options?: {start: number, end: number, duration: number, customAttributes: object}) => ({start: number, end: number, duration: number, customAttributes: object})} measure - Measures a task that is recorded as a BrowserPerformance event.
|
|
19
19
|
* @property {(value: string | null) => void} setApplicationVersion - Add an application.version attribute to all outgoing data for the registered entity.
|
|
20
20
|
* @property {(name: string, value: string | number | boolean | null, persist?: boolean) => void} setCustomAttribute - Add a custom attribute to outgoing data for the registered entity.
|
|
21
|
-
* @property {(value: string | null) => void} setUserId - Add an enduser.id attribute to all outgoing API data for the registered entity.
|
|
21
|
+
* @property {(value: string | null, resetSession?: boolean) => void} setUserId - Add an enduser.id attribute to all outgoing API data for the registered entity. Note: a registered entity will not be able to initiate a session reset. It must be done from the main agent.
|
|
22
22
|
* @property {RegisterAPIMetadata} metadata - The metadata object containing the custom attributes and target information for the registered entity.
|
|
23
23
|
*/
|
|
24
24
|
/**
|
|
@@ -7,6 +7,7 @@ exports.setupSetUserIdAPI = setupSetUserIdAPI;
|
|
|
7
7
|
var _console = require("../../common/util/console");
|
|
8
8
|
var _constants = require("./constants");
|
|
9
9
|
var _sharedHandlers = require("./sharedHandlers");
|
|
10
|
+
var _handle = require("../../common/event-emitter/handle");
|
|
10
11
|
/**
|
|
11
12
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
12
13
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -15,14 +16,23 @@ var _sharedHandlers = require("./sharedHandlers");
|
|
|
15
16
|
function setupSetUserIdAPI(agent) {
|
|
16
17
|
/**
|
|
17
18
|
* Attach the 'enduser.id' attribute onto agent payloads. This may be used in NR queries to group all browser events by specific users.
|
|
18
|
-
* @param {string} value - unique user identifier; a null user id suggests none should exist
|
|
19
|
+
* @param {string|null} value - unique user identifier; a null user id suggests none should exist
|
|
20
|
+
* @param {boolean} [resetSession=false] - Optional param. When true, resets the current session ONLY when changing user id from an existing value to another value or null. If the current user id is null when calling the API, the session cannot be reset.
|
|
19
21
|
* @returns @see apiCall
|
|
20
22
|
*/
|
|
21
|
-
(0, _sharedHandlers.setupAPI)(_constants.SET_USER_ID, function (value) {
|
|
23
|
+
(0, _sharedHandlers.setupAPI)(_constants.SET_USER_ID, function (value, resetSession = false) {
|
|
22
24
|
if (!(typeof value === 'string' || value === null)) {
|
|
23
25
|
(0, _console.warn)(41, typeof value);
|
|
24
26
|
return;
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
const currUser = agent.info.jsAttributes['enduser.id'];
|
|
29
|
+
|
|
30
|
+
// reset session ONLY if we are updating the userid (from one value to another, or from a value to null/undefined)
|
|
31
|
+
const shouldAttemptReset = resetSession && currUser !== undefined && currUser !== null && currUser !== value;
|
|
32
|
+
if (shouldAttemptReset) {
|
|
33
|
+
(0, _handle.handle)(_constants.prefix + 'setUserIdAndResetSession', [value], undefined, 'session', agent.ee);
|
|
34
|
+
} else {
|
|
35
|
+
(0, _sharedHandlers.appendJsAttribute)(agent, 'enduser.id', value, _constants.SET_USER_ID, true);
|
|
36
|
+
}
|
|
27
37
|
}, agent);
|
|
28
38
|
}
|
|
@@ -89,9 +89,10 @@ class ApiBase {
|
|
|
89
89
|
* Adds a user-defined identifier string to subsequent events on the page.
|
|
90
90
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setuserid/}
|
|
91
91
|
* @param {string|null} value A string identifier for the end-user, useful for tying all browser events to specific users. The value parameter does not have to be unique. If IDs should be unique, the caller is responsible for that validation. Passing a null value unsets any existing user ID.
|
|
92
|
+
* @param {boolean} [resetSession=false] Optional param. When true, resets the current session ONLY when changing user id from an existing value to another value or null. If the current user id is null when calling the API, the session cannot be reset.
|
|
92
93
|
*/
|
|
93
|
-
setUserId(value) {
|
|
94
|
-
return this.#callMethod(_constants.SET_USER_ID, value);
|
|
94
|
+
setUserId(value, resetSession = false) {
|
|
95
|
+
return this.#callMethod(_constants.SET_USER_ID, value, resetSession);
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
/**
|
|
@@ -11,13 +11,12 @@ var _instrument3 = require("../features/metrics/instrument");
|
|
|
11
11
|
var _instrument4 = require("../features/jserrors/instrument");
|
|
12
12
|
var _instrument5 = require("../features/ajax/instrument");
|
|
13
13
|
var _instrument6 = require("../features/session_trace/instrument");
|
|
14
|
-
var _instrument7 = require("../features/
|
|
15
|
-
var _instrument8 = require("../features/
|
|
16
|
-
var _instrument9 = require("../features/
|
|
17
|
-
var _instrument0 = require("../features/
|
|
18
|
-
var _instrument1 = require("../features/soft_navigations/instrument");
|
|
14
|
+
var _instrument7 = require("../features/session_replay/instrument");
|
|
15
|
+
var _instrument8 = require("../features/generic_events/instrument");
|
|
16
|
+
var _instrument9 = require("../features/logging/instrument");
|
|
17
|
+
var _instrument0 = require("../features/soft_navigations/instrument");
|
|
19
18
|
/**
|
|
20
|
-
* Copyright 2020-
|
|
19
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
21
20
|
* SPDX-License-Identifier: Apache-2.0
|
|
22
21
|
*/
|
|
23
22
|
|
|
@@ -32,7 +31,7 @@ class BrowserAgent extends _agent.Agent {
|
|
|
32
31
|
constructor(options) {
|
|
33
32
|
super({
|
|
34
33
|
...options,
|
|
35
|
-
features: [_instrument5.Instrument, _instrument.Instrument, _instrument2.Instrument, _instrument6.Instrument, _instrument3.Instrument, _instrument4.Instrument,
|
|
34
|
+
features: [_instrument5.Instrument, _instrument.Instrument, _instrument2.Instrument, _instrument6.Instrument, _instrument3.Instrument, _instrument4.Instrument, _instrument0.Instrument, _instrument7.Instrument, _instrument8.Instrument, _instrument9.Instrument],
|
|
36
35
|
loaderType: 'browser-agent'
|
|
37
36
|
});
|
|
38
37
|
}
|
|
@@ -62,9 +62,6 @@ function configure(agent, opts = {}, loaderType, forceDrain) {
|
|
|
62
62
|
agent.beacons = [...internalTrafficList];
|
|
63
63
|
(0, _topLevelCallers.setTopLevelCallers)(agent); // no need to set global APIs on newrelic obj more than once
|
|
64
64
|
(0, _nreum.addToNREUM)('activatedFeatures', _featureFlags.activatedFeatures);
|
|
65
|
-
|
|
66
|
-
// Update if soft_navigations is allowed to run AND part of this agent build, used to override old spa functions.
|
|
67
|
-
agent.runSoftNavOverSpa &&= updatedInit.soft_navigations.enabled === true && updatedInit.feature_flags.includes('soft_nav');
|
|
68
65
|
}
|
|
69
66
|
runtime.denyList = [...(updatedInit.ajax.deny_list || []), ...(updatedInit.ajax.block_internal ? internalTrafficList : [])];
|
|
70
67
|
runtime.ptid = agent.agentIdentifier;
|
package/dist/esm/cdn/spa.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -16,11 +16,9 @@ import { Instrument as InstrumentXhr } from '../features/ajax/instrument';
|
|
|
16
16
|
import { Instrument as InstrumentSessionTrace } from '../features/session_trace/instrument';
|
|
17
17
|
import { Instrument as InstrumentSessionReplay } from '../features/session_replay/instrument';
|
|
18
18
|
import { Instrument as InstrumentSoftNav } from '../features/soft_navigations/instrument';
|
|
19
|
-
import { Instrument as InstrumentSpa } from '../features/spa/instrument';
|
|
20
19
|
import { Instrument as InstrumentGenericEvents } from '../features/generic_events/instrument';
|
|
21
20
|
import { Instrument as InstrumentLogs } from '../features/logging/instrument';
|
|
22
21
|
new Agent({
|
|
23
|
-
features: [InstrumentXhr, InstrumentPageViewEvent, InstrumentPageViewTiming, InstrumentSessionTrace, InstrumentSessionReplay, InstrumentMetrics, InstrumentErrors, InstrumentGenericEvents, InstrumentLogs, InstrumentSoftNav,
|
|
24
|
-
],
|
|
22
|
+
features: [InstrumentXhr, InstrumentPageViewEvent, InstrumentPageViewTiming, InstrumentSessionTrace, InstrumentSessionReplay, InstrumentMetrics, InstrumentErrors, InstrumentGenericEvents, InstrumentLogs, InstrumentSoftNav],
|
|
25
23
|
loaderType: 'spa'
|
|
26
24
|
});
|