@newrelic/browser-agent 1.320.0 → 1.320.1-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 +8 -0
- package/dist/cjs/common/config/runtime.js +1 -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/event-listener/event-listener-opts.js +1 -1
- package/dist/cjs/common/harvest/connector.js +200 -0
- package/dist/cjs/common/harvest/harvester.js +5 -8
- package/dist/cjs/common/harvest/send.js +8 -7
- package/dist/cjs/common/payloads/payloads.js +3 -2
- package/dist/cjs/common/serialize/bel-serializer.js +17 -4
- package/dist/cjs/common/timer/interaction-timer.js +2 -2
- package/dist/cjs/common/unload/eol.js +3 -3
- package/dist/cjs/common/util/console.js +2 -1
- package/dist/cjs/common/util/feature-flags.js +2 -1
- package/dist/cjs/common/v2/mfe-vitals.js +34 -11
- package/dist/cjs/common/window/page-visibility.js +1 -1
- package/dist/cjs/features/ajax/aggregate/index.js +19 -8
- package/dist/cjs/features/page_view_event/aggregate/index.js +2 -6
- package/dist/cjs/features/page_view_event/aggregate_v2/index.js +109 -0
- package/dist/cjs/features/page_view_event/instrument/index.js +6 -1
- package/dist/cjs/features/page_view_timing/aggregate/index.js +33 -14
- package/dist/cjs/features/session_replay/instrument/index.js +9 -0
- package/dist/cjs/features/session_replay/shared/recorder.js +2 -1
- package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +16 -4
- package/dist/cjs/features/soft_navigations/aggregate/interaction.js +10 -3
- package/dist/cjs/features/utils/aggregate-base.js +0 -12
- package/dist/cjs/features/utils/instrument-base.js +72 -29
- package/dist/cjs/loaders/agent.js +2 -1
- package/dist/cjs/loaders/api/consent.js +2 -2
- package/dist/cjs/loaders/features/features.js +2 -1
- package/dist/esm/common/config/runtime.js +1 -0
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/event-listener/event-listener-opts.js +1 -1
- package/dist/esm/common/harvest/connector.js +193 -0
- package/dist/esm/common/harvest/harvester.js +5 -8
- package/dist/esm/common/harvest/send.js +10 -9
- package/dist/esm/common/payloads/payloads.js +3 -2
- package/dist/esm/common/serialize/bel-serializer.js +17 -4
- package/dist/esm/common/timer/interaction-timer.js +2 -2
- package/dist/esm/common/unload/eol.js +3 -3
- package/dist/esm/common/util/console.js +2 -1
- package/dist/esm/common/util/feature-flags.js +2 -1
- package/dist/esm/common/v2/mfe-vitals.js +34 -11
- package/dist/esm/common/window/page-visibility.js +1 -1
- package/dist/esm/features/ajax/aggregate/index.js +19 -8
- package/dist/esm/features/page_view_event/aggregate/index.js +2 -6
- package/dist/esm/features/page_view_event/aggregate_v2/index.js +100 -0
- package/dist/esm/features/page_view_event/instrument/index.js +6 -1
- package/dist/esm/features/page_view_timing/aggregate/index.js +33 -14
- package/dist/esm/features/session_replay/instrument/index.js +9 -0
- package/dist/esm/features/session_replay/shared/recorder.js +2 -1
- package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +16 -4
- package/dist/esm/features/soft_navigations/aggregate/interaction.js +10 -3
- package/dist/esm/features/utils/aggregate-base.js +0 -12
- package/dist/esm/features/utils/instrument-base.js +71 -28
- package/dist/esm/loaders/agent.js +2 -1
- package/dist/esm/loaders/api/consent.js +2 -2
- package/dist/esm/loaders/features/features.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/config/runtime.d.ts.map +1 -1
- package/dist/types/common/event-listener/event-listener-opts.d.ts +1 -1
- package/dist/types/common/harvest/connector.d.ts +6 -0
- package/dist/types/common/harvest/connector.d.ts.map +1 -0
- package/dist/types/common/harvest/harvester.d.ts.map +1 -1
- package/dist/types/common/harvest/send.d.ts.map +1 -1
- package/dist/types/common/payloads/payloads.d.ts +3 -2
- package/dist/types/common/payloads/payloads.d.ts.map +1 -1
- package/dist/types/common/serialize/bel-serializer.d.ts +9 -1
- package/dist/types/common/serialize/bel-serializer.d.ts.map +1 -1
- package/dist/types/common/unload/eol.d.ts +1 -1
- package/dist/types/common/unload/eol.d.ts.map +1 -1
- package/dist/types/common/util/console.d.ts +2 -1
- package/dist/types/common/util/console.d.ts.map +1 -1
- package/dist/types/common/v2/mfe-vitals.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate_v2/index.d.ts +20 -0
- package/dist/types/features/page_view_event/aggregate_v2/index.d.ts.map +1 -0
- package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +0 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/instrument/index.d.ts +1 -0
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/interaction.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +0 -5
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/features/features.d.ts +1 -0
- package/dist/types/loaders/features/features.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/common/config/runtime.js +1 -0
- package/src/common/event-listener/event-listener-opts.js +1 -1
- package/src/common/harvest/connector.js +168 -0
- package/src/common/harvest/harvester.js +7 -9
- package/src/common/harvest/send.js +9 -7
- package/src/common/payloads/payloads.js +3 -2
- package/src/common/serialize/bel-serializer.js +13 -4
- package/src/common/timer/interaction-timer.js +2 -2
- package/src/common/unload/eol.js +3 -3
- package/src/common/util/console.js +2 -1
- package/src/common/util/feature-flags.js +1 -1
- package/src/common/v2/mfe-vitals.js +39 -12
- package/src/common/window/page-visibility.js +1 -1
- package/src/features/ajax/aggregate/index.js +12 -9
- package/src/features/page_view_event/aggregate/index.js +2 -6
- package/src/features/page_view_event/aggregate_v2/index.js +97 -0
- package/src/features/page_view_event/instrument/index.js +6 -1
- package/src/features/page_view_timing/aggregate/index.js +24 -15
- package/src/features/session_replay/instrument/index.js +9 -0
- package/src/features/session_replay/shared/recorder.js +2 -1
- package/src/features/soft_navigations/aggregate/ajax-node.js +10 -7
- package/src/features/soft_navigations/aggregate/interaction.js +6 -5
- package/src/features/utils/aggregate-base.js +0 -12
- package/src/features/utils/instrument-base.js +71 -25
- package/src/loaders/agent.js +2 -1
- package/src/loaders/api/consent.js +2 -2
- package/src/loaders/features/features.js +1 -0
|
@@ -152,6 +152,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
152
152
|
if (!eventBuffer.length) return;
|
|
153
153
|
const {
|
|
154
154
|
addString,
|
|
155
|
+
addStringRaw,
|
|
155
156
|
addStringWithTruncation
|
|
156
157
|
} = (0, _payloads.createStringAdders)(_belSerializer.getAddStringContext, this.obfuscator);
|
|
157
158
|
let payload = 'bel.7;';
|
|
@@ -165,11 +166,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
165
166
|
// callbackEnd
|
|
166
167
|
(0, _belSerializer.numeric)(0),
|
|
167
168
|
// no callbackDuration for non-SPA events
|
|
168
|
-
|
|
169
|
+
addStringRaw(event.method), (0, _belSerializer.numeric)(event.status), addString(event.domain), addString(event.path), (0, _belSerializer.numeric)(event.requestSize), (0, _belSerializer.numeric)(event.responseSize), event.type === 'fetch' ? 1 : '', addStringRaw(0),
|
|
169
170
|
// nodeId
|
|
170
|
-
(0, _belSerializer.nullable)(event.spanId,
|
|
171
|
+
(0, _belSerializer.nullable)(event.spanId, addStringRaw, true) +
|
|
171
172
|
// guid
|
|
172
|
-
(0, _belSerializer.nullable)(event.traceId,
|
|
173
|
+
(0, _belSerializer.nullable)(event.traceId, addStringRaw, true) +
|
|
173
174
|
// traceId
|
|
174
175
|
(0, _belSerializer.nullable)(event.spanTimestamp, _belSerializer.numeric, false) // timestamp
|
|
175
176
|
];
|
|
@@ -179,14 +180,21 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
179
180
|
const jsAttributes = this.agentRef.info.jsAttributes;
|
|
180
181
|
|
|
181
182
|
// Regular attributes: obfuscate only
|
|
182
|
-
|
|
183
|
+
let regularAttrs = (0, _belSerializer.addCustomAttributes)({
|
|
183
184
|
...(jsAttributes || {}),
|
|
184
|
-
[_constants.AJAX_ID]: event[_constants.AJAX_ID],
|
|
185
|
-
// all AjaxRequest events should have a unique identifier to allow for easier grouping and analysis in the UI
|
|
186
185
|
...(event.targetAttributes || {}),
|
|
187
186
|
// used to supply the version 2 attributes, either MFE target or duplication attributes for the main agent app
|
|
188
187
|
...(event.gql || {})
|
|
189
|
-
},
|
|
188
|
+
}, {
|
|
189
|
+
addKey: addStringRaw,
|
|
190
|
+
addVal: addString
|
|
191
|
+
});
|
|
192
|
+
regularAttrs.push(...(0, _belSerializer.addCustomAttributes)({
|
|
193
|
+
[_constants.AJAX_ID]: event[_constants.AJAX_ID] // all AjaxRequest events should have a unique identifier to allow for easier grouping and analysis in the UI
|
|
194
|
+
}, {
|
|
195
|
+
addKey: addStringRaw,
|
|
196
|
+
addVal: addStringRaw
|
|
197
|
+
}));
|
|
190
198
|
|
|
191
199
|
// Payload attributes: obfuscate then truncate
|
|
192
200
|
const payloadAttrs = (0, _belSerializer.addCustomAttributes)({
|
|
@@ -205,7 +213,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
205
213
|
...(event.responseHeaders ? {
|
|
206
214
|
responseHeaders: event.responseHeaders
|
|
207
215
|
} : {})
|
|
208
|
-
},
|
|
216
|
+
}, {
|
|
217
|
+
addKey: addStringRaw,
|
|
218
|
+
addVal: addStringWithTruncation
|
|
219
|
+
});
|
|
209
220
|
const attrParts = [...regularAttrs, ...payloadAttrs];
|
|
210
221
|
fields.unshift((0, _belSerializer.numeric)(attrParts.length));
|
|
211
222
|
insert += fields.join(',');
|
|
@@ -140,9 +140,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
140
140
|
return queryParameters;
|
|
141
141
|
};
|
|
142
142
|
this.events.add(body);
|
|
143
|
-
if (this.agentRef.runtime.harvester.triggerHarvestFor(this
|
|
144
|
-
sendEmptyBody: true
|
|
145
|
-
}).ranSend) this.sentRum = true;
|
|
143
|
+
if (this.agentRef.runtime.harvester.triggerHarvestFor(this).ranSend) this.sentRum = true;
|
|
146
144
|
}
|
|
147
145
|
serializer(eventBuffer) {
|
|
148
146
|
// this is necessary because PVE sends a single item rather than an array; in the case of undefined, this prevents sending [null] as body
|
|
@@ -183,9 +181,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
183
181
|
|
|
184
182
|
if (this.isRetrying && this.retries++ < 1) {
|
|
185
183
|
// Only retry once
|
|
186
|
-
setTimeout(() => this.agentRef.runtime.harvester.triggerHarvestFor(this,
|
|
187
|
-
sendEmptyBody: true
|
|
188
|
-
}), 5000); // Retry sending the RUM event after 5 seconds
|
|
184
|
+
setTimeout(() => this.agentRef.runtime.harvester.triggerHarvestFor(this), 5000); // Retry sending the RUM event after 5 seconds
|
|
189
185
|
return;
|
|
190
186
|
}
|
|
191
187
|
if (status >= 400 || status === 0) {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Aggregate = void 0;
|
|
7
|
+
var _runtime = require("../../../common/constants/runtime");
|
|
8
|
+
var _navTiming = require("../../../common/timing/nav-timing");
|
|
9
|
+
var _stringify = require("../../../common/util/stringify");
|
|
10
|
+
var CONSTANTS = _interopRequireWildcard(require("../constants"));
|
|
11
|
+
var _initializedFeatures = require("../aggregate/initialized-features");
|
|
12
|
+
var _aggregateBase = require("../../utils/aggregate-base");
|
|
13
|
+
var _firstContentfulPaint = require("../../../common/vitals/first-contentful-paint");
|
|
14
|
+
var _firstPaint = require("../../../common/vitals/first-paint");
|
|
15
|
+
var _timeToFirstByte = require("../../../common/vitals/time-to-first-byte");
|
|
16
|
+
var _obfuscate = require("../../../common/util/obfuscate");
|
|
17
|
+
var _webdriverDetection = require("../../../common/util/webdriver-detection");
|
|
18
|
+
var _events = require("../../../common/constants/events");
|
|
19
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
20
|
+
/**
|
|
21
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
22
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
class Aggregate extends _aggregateBase.AggregateBase {
|
|
26
|
+
static featureName = CONSTANTS.FEATURE_NAME;
|
|
27
|
+
#timeToFirstByte = 0;
|
|
28
|
+
#firstByteToWindowLoad = 0; // our "frontend" duration
|
|
29
|
+
#firstByteToDomContent = 0; // our "dom processing" duration
|
|
30
|
+
#obfuscator;
|
|
31
|
+
constructor(agentRef) {
|
|
32
|
+
super(agentRef, CONSTANTS.FEATURE_NAME);
|
|
33
|
+
this.#obfuscator = new _obfuscate.Obfuscator(agentRef, _events.EVENT_TYPES.PVE);
|
|
34
|
+
if (_runtime.isBrowserScope) {
|
|
35
|
+
_timeToFirstByte.timeToFirstByte.subscribe(({
|
|
36
|
+
value,
|
|
37
|
+
attrs
|
|
38
|
+
}) => {
|
|
39
|
+
const navEntry = attrs.navigationEntry;
|
|
40
|
+
this.#timeToFirstByte = Math.max(value, this.#timeToFirstByte);
|
|
41
|
+
this.#firstByteToWindowLoad = Math.max(Math.round(navEntry.loadEventEnd - this.#timeToFirstByte), this.#firstByteToWindowLoad); // our "frontend" duration
|
|
42
|
+
this.#firstByteToDomContent = Math.max(Math.round(navEntry.domContentLoadedEventEnd - this.#timeToFirstByte), this.#firstByteToDomContent); // our "dom processing" duration
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
this.waitForFlags([]).then(() => {
|
|
46
|
+
const body = this.#obfuscator.traverseAndObfuscateEvents({
|
|
47
|
+
ja: {
|
|
48
|
+
...agentRef.info.jsAttributes,
|
|
49
|
+
webdriverDetected: _webdriverDetection.webdriverDetected
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
this.events.add(body);
|
|
53
|
+
this.drain();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
queryStringsBuilder() {
|
|
57
|
+
const info = this.agentRef.info;
|
|
58
|
+
const measures = {};
|
|
59
|
+
if (info.queueTime) measures.qt = info.queueTime;
|
|
60
|
+
if (info.applicationTime) measures.ap = info.applicationTime;
|
|
61
|
+
|
|
62
|
+
// These 3 values should've been recorded after load and before this func runs. They are part of the minimum required for PageView events to be created.
|
|
63
|
+
// Following PR #428, which demands that the BA must drive entity indexing, these need to be sent even outside of the main window context where PerformanceTiming
|
|
64
|
+
// or PerformanceNavigationTiming do not exists. Hence, they'll be filled in by 0s instead in, for example, worker threads that still init the PVE module.
|
|
65
|
+
measures.be = this.#timeToFirstByte;
|
|
66
|
+
measures.fe = this.#firstByteToWindowLoad;
|
|
67
|
+
measures.dc = this.#firstByteToDomContent;
|
|
68
|
+
const queryParameters = {
|
|
69
|
+
at: info.atts,
|
|
70
|
+
af: (0, _initializedFeatures.getActivatedFeaturesFlags)(this.agentRef).join(','),
|
|
71
|
+
igp: this.agentRef.runtime.appMetadata.igp,
|
|
72
|
+
...measures,
|
|
73
|
+
fp: _firstPaint.firstPaint.current.value,
|
|
74
|
+
fcp: _firstContentfulPaint.firstContentfulPaint.current.value
|
|
75
|
+
};
|
|
76
|
+
if (_runtime.globalScope.performance) {
|
|
77
|
+
const navTimingEntry = (0, _runtime.getNavigationEntry)();
|
|
78
|
+
if (navTimingEntry) {
|
|
79
|
+
// Navigation Timing level 2 API that replaced PerformanceTiming & PerformanceNavigation
|
|
80
|
+
const perf = {
|
|
81
|
+
timing: (0, _navTiming.addPT)(_runtime.originTime, navTimingEntry, {}),
|
|
82
|
+
navigation: (0, _navTiming.addPN)(navTimingEntry, {})
|
|
83
|
+
};
|
|
84
|
+
queryParameters.perf = (0, _stringify.stringify)(perf);
|
|
85
|
+
} else if (typeof PerformanceTiming !== 'undefined') {
|
|
86
|
+
// Modern Safari iFrames and Safari pre-15 do not support level 2 timing.
|
|
87
|
+
const perf = {
|
|
88
|
+
timing: (0, _navTiming.addPT)(_runtime.originTime, _runtime.globalScope.performance.timing, {}, true),
|
|
89
|
+
navigation: (0, _navTiming.addPN)(_runtime.globalScope.performance.navigation, {})
|
|
90
|
+
};
|
|
91
|
+
queryParameters.perf = (0, _stringify.stringify)(perf);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const {
|
|
95
|
+
correctedOriginTime
|
|
96
|
+
} = this.agentRef.runtime.timeKeeper;
|
|
97
|
+
if (correctedOriginTime) queryParameters.timestamp = correctedOriginTime; // a "PageView" is set to represent the page's (server adjusted) origin time rather than when event is recorded/harvested
|
|
98
|
+
|
|
99
|
+
return queryParameters;
|
|
100
|
+
}
|
|
101
|
+
get harvestEndpointVersion() {
|
|
102
|
+
return 2;
|
|
103
|
+
}
|
|
104
|
+
serializer(eventBuffer) {
|
|
105
|
+
// this is necessary because PVE sends a single item rather than an array; in the case of undefined, this prevents sending [null] as body
|
|
106
|
+
return eventBuffer[0];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.Aggregate = Aggregate;
|
|
@@ -24,7 +24,12 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
24
24
|
|
|
25
25
|
/** feature specific APIs */
|
|
26
26
|
(0, _setPageViewName.setupSetPageViewNameAPI)(agentRef);
|
|
27
|
-
this.importAggregator(agentRef, () =>
|
|
27
|
+
this.importAggregator(agentRef, () => {
|
|
28
|
+
if (agentRef.init.feature_flags.includes('rum_v2')) {
|
|
29
|
+
return Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "page_view_event-aggregate" */'../aggregate_v2')));
|
|
30
|
+
}
|
|
31
|
+
return Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "page_view_event-aggregate" */'../aggregate')));
|
|
32
|
+
});
|
|
28
33
|
}
|
|
29
34
|
setupInspectionEvents() {
|
|
30
35
|
const dispatch = (evt, name) => {
|
|
@@ -24,6 +24,7 @@ var _loadTime = require("../../../common/vitals/load-time");
|
|
|
24
24
|
var _webdriverDetection = require("../../../common/util/webdriver-detection");
|
|
25
25
|
var _cleanUrl = require("../../../common/url/clean-url");
|
|
26
26
|
var _events = require("../../../common/constants/events");
|
|
27
|
+
var _payloads = require("../../../common/payloads/payloads");
|
|
27
28
|
/**
|
|
28
29
|
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
29
30
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -71,7 +72,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
71
72
|
} = _cumulativeLayoutShift.cumulativeLayoutShift.current;
|
|
72
73
|
if (value === undefined) return;
|
|
73
74
|
this.addTiming(name, value * 1000, attrs);
|
|
74
|
-
}, true, true); // CLS node should only
|
|
75
|
+
}, true, true); // CLS node should only report on vis change rather than on every change.
|
|
76
|
+
/* NOTE: the capture=true is required -- empirically verified against a real browser (Chrome) for CLS
|
|
77
|
+
timing node to reliably be in the same final harvest as the rest, alongside Harvester#startTimer's
|
|
78
|
+
queueMicrotask deferral of the EOL harvest itself. Dropping this flag caused CLS to be split into its own,
|
|
79
|
+
separate, later harvest instead of going out together with pageHide/INP. */
|
|
75
80
|
|
|
76
81
|
this.drain();
|
|
77
82
|
});
|
|
@@ -104,6 +109,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
104
109
|
if (name !== _constants2.VITAL_NAMES.CUMULATIVE_LAYOUT_SHIFT && _cumulativeLayoutShift.cumulativeLayoutShift.current.value >= 0) {
|
|
105
110
|
attrs.cls = _cumulativeLayoutShift.cumulativeLayoutShift.current.value;
|
|
106
111
|
}
|
|
112
|
+
attrs.webdriverDetected = _webdriverDetection.webdriverDetected;
|
|
107
113
|
const timing = {
|
|
108
114
|
name,
|
|
109
115
|
value,
|
|
@@ -133,15 +139,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
133
139
|
loadState: document.readyState
|
|
134
140
|
});
|
|
135
141
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
Object.entries(this.agentRef.info.jsAttributes || {}).forEach(([key, val]) => {
|
|
140
|
-
if (reservedAttributes.indexOf(key) < 0) {
|
|
141
|
-
timingAttributes[key] = val;
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
timingAttributes.webdriverDetected = _webdriverDetection.webdriverDetected;
|
|
142
|
+
#getGlobalCustomAttributes() {
|
|
143
|
+
const reservedAttributes = ['size', 'eid', 'cls', 'type', 'fid', 'elTag', 'elUrl', 'net-type', 'net-etype', 'net-rtt', 'net-dlink', 'webdriverDetected'];
|
|
144
|
+
return Object.fromEntries(Object.entries(this.agentRef.info.jsAttributes || {}).filter(([key]) => !reservedAttributes.includes(key)));
|
|
145
145
|
}
|
|
146
146
|
preHarvestChecks() {
|
|
147
147
|
this.checkForFirstInteraction();
|
|
@@ -151,15 +151,34 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
151
151
|
// serialize array of timing data
|
|
152
152
|
serializer(eventBuffer) {
|
|
153
153
|
if (!eventBuffer?.length) return '';
|
|
154
|
-
|
|
154
|
+
const {
|
|
155
|
+
addString,
|
|
156
|
+
addStringRaw
|
|
157
|
+
} = (0, _payloads.createStringAdders)(_belSerializer.getAddStringContext, this.obfuscator);
|
|
158
|
+
const keepOrigValue = {
|
|
159
|
+
addKey: addStringRaw,
|
|
160
|
+
addVal: addStringRaw
|
|
161
|
+
};
|
|
162
|
+
const obfuscateValue = {
|
|
163
|
+
addKey: addStringRaw,
|
|
164
|
+
addVal: addString
|
|
165
|
+
};
|
|
155
166
|
var payload = 'bel.6;';
|
|
156
167
|
for (var i = 0; i < eventBuffer.length; i++) {
|
|
157
168
|
var timing = eventBuffer[i];
|
|
158
169
|
payload += 'e,';
|
|
159
|
-
payload +=
|
|
170
|
+
payload += addStringRaw(timing.name) + ',';
|
|
160
171
|
payload += (0, _belSerializer.nullable)(timing.value, _belSerializer.numeric, false) + ',';
|
|
161
|
-
this
|
|
162
|
-
|
|
172
|
+
const userAttrs = this.#getGlobalCustomAttributes();
|
|
173
|
+
const {
|
|
174
|
+
pageUrl,
|
|
175
|
+
...systemReservedAttrs
|
|
176
|
+
} = timing.attrs || {};
|
|
177
|
+
var attrParts = (0, _belSerializer.addCustomAttributes)(systemReservedAttrs, keepOrigValue);
|
|
178
|
+
attrParts.push(...(0, _belSerializer.addCustomAttributes)(userAttrs, obfuscateValue));
|
|
179
|
+
if (pageUrl) attrParts.push(...(0, _belSerializer.addCustomAttributes)({
|
|
180
|
+
pageUrl
|
|
181
|
+
}, obfuscateValue));
|
|
163
182
|
if (attrParts && attrParts.length > 0) {
|
|
164
183
|
payload += (0, _belSerializer.numeric)(attrParts.length) + ';' + attrParts.join(';');
|
|
165
184
|
}
|
|
@@ -44,6 +44,10 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
44
44
|
recorder.startRecording(_constants2.TRIGGERS.PRELOAD, session?.sessionReplayMode);
|
|
45
45
|
}); // could handle specific fail-state behaviors with a .catch block here
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
// If the aggregate never successfully loads (missing session prerequisite, or the aggregate module itself
|
|
49
|
+
// fails to import/construct), any preload recording that already started needs to be stopped.
|
|
50
|
+
this.abortHandler = this.#abort;
|
|
47
51
|
this.importAggregator(this.agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "session_replay-aggregate" */'../aggregate'))), this);
|
|
48
52
|
|
|
49
53
|
/** If the recorder is running, we can pass error events on to the agg to help it switch to full mode later */
|
|
@@ -108,6 +112,11 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
108
112
|
}); // could handle specific fail-state behaviors with a .catch block here
|
|
109
113
|
}
|
|
110
114
|
}
|
|
115
|
+
|
|
116
|
+
/** Stops any preload recording that already started if the aggregate never ends up successfully loading. */
|
|
117
|
+
#abort() {
|
|
118
|
+
this.recorder?.stopRecording();
|
|
119
|
+
}
|
|
111
120
|
}
|
|
112
121
|
exports.Instrument = Instrument;
|
|
113
122
|
const SessionReplay = exports.SessionReplay = Instrument;
|
|
@@ -216,7 +216,8 @@ class Recorder {
|
|
|
216
216
|
|
|
217
217
|
// We are making an effort to try to keep payloads manageable for unloading. If they reach the unload limit before their interval,
|
|
218
218
|
// it will send immediately. This often happens on the first snapshot, which can be significantly larger than the other payloads.
|
|
219
|
-
|
|
219
|
+
// (the aggregate may not exist yet/at all if its own bootstrap hasn't finished or failed -- nothing to harvest for in that case.)
|
|
220
|
+
if ((this.events.hasSnapshot && this.events.hasMeta || payloadSize > _agentConstants.IDEAL_PAYLOAD_SIZE) && !this.isErrorMode && this.srInstrument.featAggregate) {
|
|
220
221
|
// if we've made it to the ideal size of ~16kb before the interval timer, we should send early.
|
|
221
222
|
this.agentRef.runtime.harvester.triggerHarvestFor(this.srInstrument.featAggregate);
|
|
222
223
|
}
|
|
@@ -48,6 +48,7 @@ class AjaxNode extends _belNode.BelNode {
|
|
|
48
48
|
serialize(parentStartTimestamp, agentRef, ajaxObfuscator) {
|
|
49
49
|
const {
|
|
50
50
|
addString,
|
|
51
|
+
addStringRaw,
|
|
51
52
|
addStringWithTruncation
|
|
52
53
|
} = (0, _payloads.createStringAdders)(_belSerializer.getAddStringContext, ajaxObfuscator);
|
|
53
54
|
const nodeList = [];
|
|
@@ -63,13 +64,21 @@ class AjaxNode extends _belNode.BelNode {
|
|
|
63
64
|
// callbackEnd is relative to end
|
|
64
65
|
(0, _belSerializer.numeric)(this.callbackDuration),
|
|
65
66
|
// not relative
|
|
66
|
-
|
|
67
|
+
addStringRaw(this.method), (0, _belSerializer.numeric)(this.status), addString(this.domain), addString(this.path), (0, _belSerializer.numeric)(this.txSize), (0, _belSerializer.numeric)(this.rxSize), this.requestedWith, addStringRaw(this.nodeId), (0, _belSerializer.nullable)(this.spanId, addStringRaw, true) + (0, _belSerializer.nullable)(this.traceId, addStringRaw, true) + (0, _belSerializer.nullable)(this.spanTimestamp, _belSerializer.numeric)];
|
|
67
68
|
// Regular attributes: obfuscate only
|
|
68
69
|
const regularAttrs = (0, _belSerializer.addCustomAttributes)({
|
|
69
|
-
[_constants.AJAX_ID]: this[_constants.AJAX_ID],
|
|
70
70
|
...(this.targetAttributes || {}),
|
|
71
71
|
...(this.gql || {})
|
|
72
|
-
},
|
|
72
|
+
}, {
|
|
73
|
+
addKey: addStringRaw,
|
|
74
|
+
addVal: addString
|
|
75
|
+
});
|
|
76
|
+
regularAttrs.push(...(0, _belSerializer.addCustomAttributes)({
|
|
77
|
+
[_constants.AJAX_ID]: this[_constants.AJAX_ID]
|
|
78
|
+
}, {
|
|
79
|
+
addKey: addStringRaw,
|
|
80
|
+
addVal: addStringRaw
|
|
81
|
+
}));
|
|
73
82
|
|
|
74
83
|
// Payload attributes: obfuscate then truncate
|
|
75
84
|
const payloadAttrs = (0, _belSerializer.addCustomAttributes)({
|
|
@@ -88,7 +97,10 @@ class AjaxNode extends _belNode.BelNode {
|
|
|
88
97
|
...(this.responseHeaders ? {
|
|
89
98
|
responseHeaders: this.responseHeaders
|
|
90
99
|
} : {})
|
|
91
|
-
},
|
|
100
|
+
}, {
|
|
101
|
+
addKey: addStringRaw,
|
|
102
|
+
addVal: addStringWithTruncation
|
|
103
|
+
});
|
|
92
104
|
let allAttachedNodes = [...regularAttrs, ...payloadAttrs];
|
|
93
105
|
this.children.forEach(node => allAttachedNodes.push(node.serialize())); // no children is expected under ajax nodes at this time
|
|
94
106
|
|
|
@@ -11,6 +11,7 @@ var _now = require("../../../common/timing/now");
|
|
|
11
11
|
var _cleanUrl = require("../../../common/url/clean-url");
|
|
12
12
|
var _constants = require("../constants");
|
|
13
13
|
var _belNode = require("./bel-node");
|
|
14
|
+
var _payloads = require("../../../common/payloads/payloads");
|
|
14
15
|
/**
|
|
15
16
|
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
16
17
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -133,7 +134,10 @@ class Interaction extends _belNode.BelNode {
|
|
|
133
134
|
*/
|
|
134
135
|
serialize(firstStartTimeOfPayload, agentRef, interactionObfuscator, ajaxObfuscator) {
|
|
135
136
|
const isFirstIxnOfPayload = firstStartTimeOfPayload === undefined;
|
|
136
|
-
const
|
|
137
|
+
const {
|
|
138
|
+
addString,
|
|
139
|
+
addStringRaw
|
|
140
|
+
} = (0, _payloads.createStringAdders)(_belSerializer.getAddStringContext, interactionObfuscator);
|
|
137
141
|
const nodeList = [];
|
|
138
142
|
let ixnType;
|
|
139
143
|
if (this.trigger === _constants.IPL_TRIGGER_NAME) ixnType = _constants.INTERACTION_TYPE.INITIAL_PAGE_LOAD;else if (this.newURL !== this.oldURL) ixnType = _constants.INTERACTION_TYPE.ROUTE_CHANGE;else ixnType = _constants.INTERACTION_TYPE.UNSPECIFIED;
|
|
@@ -149,12 +153,15 @@ class Interaction extends _belNode.BelNode {
|
|
|
149
153
|
// callbackEnd -- relative to start; not used by BrowserInteraction events so these are always 0
|
|
150
154
|
(0, _belSerializer.numeric)(0),
|
|
151
155
|
// not relative; always 0 for BrowserInteraction
|
|
152
|
-
|
|
156
|
+
addStringRaw(this.trigger), addString((0, _cleanUrl.cleanURL)(this.initialPageURL, true)), addString((0, _cleanUrl.cleanURL)(this.oldURL, true)), addString((0, _cleanUrl.cleanURL)(this.newURL, true)), addString(this.customName), ixnType, (0, _belSerializer.nullable)(this.queueTime, _belSerializer.numeric, true) + (0, _belSerializer.nullable)(this.appTime, _belSerializer.numeric, true) + (0, _belSerializer.nullable)(this.oldRoute, addString, true) + (0, _belSerializer.nullable)(this.newRoute, addString, true) + addStringRaw(this.id), addStringRaw(this.nodeId), (0, _belSerializer.nullable)(this.firstPaint, _belSerializer.numeric, true) + (0, _belSerializer.nullable)(this.firstContentfulPaint, _belSerializer.numeric)];
|
|
153
157
|
const customAttributes = {
|
|
154
158
|
...agentRef.info.jsAttributes,
|
|
155
159
|
...this.customAttributes
|
|
156
160
|
}; // attrs specific to this interaction should have precedence over the general custom attrs
|
|
157
|
-
const allAttachedNodes = (0, _belSerializer.addCustomAttributes)(customAttributes || {},
|
|
161
|
+
const allAttachedNodes = (0, _belSerializer.addCustomAttributes)(customAttributes || {}, {
|
|
162
|
+
addKey: addStringRaw,
|
|
163
|
+
addVal: addString
|
|
164
|
+
}); // start with all custom attributes
|
|
158
165
|
if (agentRef.info.atts) allAttachedNodes.push('a,' + addString(agentRef.info.atts)); // add apm provided attributes
|
|
159
166
|
/* Querypack encoder+decoder quirkiness:
|
|
160
167
|
- If first ixn node of payload is being processed, its children's start time must be offset by this node's start. (firstStartTime should be undefined.)
|
|
@@ -7,7 +7,6 @@ exports.AggregateBase = void 0;
|
|
|
7
7
|
var _featureBase = require("./feature-base");
|
|
8
8
|
var _drain = require("../../common/drain/drain");
|
|
9
9
|
var _features = require("../../loaders/features/features");
|
|
10
|
-
var _harvester = require("../../common/harvest/harvester");
|
|
11
10
|
var _eventBuffer = require("./event-buffer");
|
|
12
11
|
var _handle = require("../../common/event-emitter/handle");
|
|
13
12
|
var _constants = require("../metrics/constants");
|
|
@@ -27,7 +26,6 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
27
26
|
*/
|
|
28
27
|
constructor(agentRef, featureName) {
|
|
29
28
|
super(agentRef, featureName);
|
|
30
|
-
this.doOnceForAllAggregate(agentRef);
|
|
31
29
|
|
|
32
30
|
/** @type {Boolean} indicates if custom attributes are combined in each event payload for size estimation purposes. this is set to true in derived classes that need to evaluate custom attributes separately from the event payload */
|
|
33
31
|
this.customAttributesAreSeparate = false;
|
|
@@ -179,16 +177,6 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
179
177
|
this.events.clearSave(this.harvestOpts);
|
|
180
178
|
}
|
|
181
179
|
|
|
182
|
-
/**
|
|
183
|
-
* These are actions related to shared resources that should be initialized once by whichever feature Aggregate subclass loads first.
|
|
184
|
-
* This method should run after checkConfiguration, which may reset the agent's info/runtime object that is used here.
|
|
185
|
-
*/
|
|
186
|
-
doOnceForAllAggregate(agentRef) {
|
|
187
|
-
// Note: obfuscator is now created per-feature for their specific event types
|
|
188
|
-
|
|
189
|
-
if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new _harvester.Harvester(agentRef);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
180
|
/**
|
|
193
181
|
* Report a supportability metric
|
|
194
182
|
* @param {*} metricName The tag of the name matching the Angler aggregation tag
|
|
@@ -27,6 +27,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
27
27
|
* Inherits `blocked` behavior from [FeatureBase]{@link ./feature-base}.
|
|
28
28
|
*/
|
|
29
29
|
const checkedAgents = new WeakSet();
|
|
30
|
+
const runtimeBootstrapPromises = new WeakMap();
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Base class for instrumenting a feature.
|
|
@@ -102,32 +103,14 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
102
103
|
this.loadedSuccessfully(false);
|
|
103
104
|
return;
|
|
104
105
|
}
|
|
105
|
-
let session;
|
|
106
106
|
try {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const {
|
|
110
|
-
setupAgentSession
|
|
111
|
-
} = await Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "session-manager" */'./agent-session')));
|
|
112
|
-
session = setupAgentSession(agentRef);
|
|
113
|
-
}
|
|
107
|
+
// in the interest of keeping loader file size small, some modules are lazy-loaded as part of the larger async chunk
|
|
108
|
+
await ensureRuntimeBootstrap(agentRef, this.ee, this.featureName);
|
|
114
109
|
} catch (e) {
|
|
115
|
-
(0, _console.warn)(
|
|
116
|
-
this.ee.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (agentRef.init.api.register.allow_iframe_bridge) {
|
|
120
|
-
try {
|
|
121
|
-
// This chunk doesn't exist in the lite build (see webpack IgnorePlugin config) since none
|
|
122
|
-
// of lite's features wire up agent.register -- guard against that rather than letting an
|
|
123
|
-
// unhandled rejection surface if this flag is ever set on a lite page.
|
|
124
|
-
const {
|
|
125
|
-
setupIframeMFEMessageListener
|
|
126
|
-
} = await Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "iframe-message-handler" */'../../loaders/configure/iframe-message-handler')));
|
|
127
|
-
setupIframeMFEMessageListener(agentRef);
|
|
128
|
-
} catch (e) {
|
|
129
|
-
(0, _console.warn)(23, e);
|
|
130
|
-
}
|
|
110
|
+
(0, _console.warn)(79, e);
|
|
111
|
+
this.ee.abort(); // failed Connector or Harvester will cause entire agent to shutdown
|
|
112
|
+
this.loadedSuccessfully(false);
|
|
113
|
+
return;
|
|
131
114
|
}
|
|
132
115
|
|
|
133
116
|
/**
|
|
@@ -135,7 +118,8 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
135
118
|
* it's only responsible for aborting its one specific feature, rather than all.
|
|
136
119
|
*/
|
|
137
120
|
try {
|
|
138
|
-
if (!this.#shouldImportAgg(this.featureName, session, agentRef.init)) {
|
|
121
|
+
if (!this.#shouldImportAgg(this.featureName, agentRef.runtime.session, agentRef.init)) {
|
|
122
|
+
this.abortHandler?.();
|
|
139
123
|
(0, _drain.drain)(this.agentRef, this.featureName);
|
|
140
124
|
this.loadedSuccessfully(false); // aggregate module isn't loaded at all
|
|
141
125
|
return;
|
|
@@ -144,15 +128,14 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
144
128
|
Aggregate
|
|
145
129
|
} = await fetchAggregator();
|
|
146
130
|
this.featAggregate = new Aggregate(agentRef, argsObjFromInstrument);
|
|
147
|
-
agentRef.runtime.harvester.initializedAggregates.push(this.featAggregate); // "subscribe" the feature to future harvest intervals
|
|
131
|
+
agentRef.runtime.harvester.initializedAggregates.push(this.featAggregate); // "subscribe" the feature to future harvest intervals
|
|
148
132
|
this.loadedSuccessfully(true);
|
|
149
133
|
} catch (e) {
|
|
150
134
|
(0, _console.warn)(34, e);
|
|
151
|
-
this.abortHandler?.();
|
|
135
|
+
this.abortHandler?.();
|
|
152
136
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
153
137
|
(0, _drain.drain)(this.agentRef, this.featureName, true);
|
|
154
138
|
this.loadedSuccessfully(false);
|
|
155
|
-
if (this.ee) this.ee.abort();
|
|
156
139
|
}
|
|
157
140
|
};
|
|
158
141
|
|
|
@@ -212,4 +195,64 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
212
195
|
}
|
|
213
196
|
}
|
|
214
197
|
}
|
|
215
|
-
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Lazily initializes the shared runtime bootstrap for a given agent exactly once. This loads session setup, Connector, and
|
|
201
|
+
* Harvester through shared async chunks and returns the same in-flight Promise to any concurrent callers.
|
|
202
|
+
*
|
|
203
|
+
* Session setup failures are reported but do not stop bootstrap. Connector or Harvester failures are allowed to bubble so the caller can abort the agent.
|
|
204
|
+
*
|
|
205
|
+
* @param {Object} agentRef - The agent reference object.
|
|
206
|
+
* @param {Object} ee - The feature event emitter used for error reporting.
|
|
207
|
+
* @param {string} featureName - The feature name used when reporting session setup errors.
|
|
208
|
+
* @returns {Promise<void>} Resolves when the shared bootstrap completes.
|
|
209
|
+
*/
|
|
210
|
+
exports.InstrumentBase = InstrumentBase;
|
|
211
|
+
async function ensureRuntimeBootstrap(agentRef, ee, featureName) {
|
|
212
|
+
if (runtimeBootstrapPromises.has(agentRef)) return runtimeBootstrapPromises.get(agentRef);
|
|
213
|
+
const bootstrapPromise = (async () => {
|
|
214
|
+
if ((0, _featureGates.canEnableSessionTracking)(agentRef.init)) {
|
|
215
|
+
try {
|
|
216
|
+
const {
|
|
217
|
+
setupAgentSession
|
|
218
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "session-manager" */'./agent-session')));
|
|
219
|
+
setupAgentSession(agentRef); // sets agentRef.runtime.session, if successful
|
|
220
|
+
} catch (e) {
|
|
221
|
+
(0, _console.warn)(20, e);
|
|
222
|
+
ee.emit('internal-error', [e]);
|
|
223
|
+
(0, _handle.handle)(_agentConstants.SESSION_ERROR, [e], undefined, featureName, ee);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (agentRef.init.api.register.allow_iframe_bridge) {
|
|
227
|
+
try {
|
|
228
|
+
// This chunk doesn't exist in the lite build (see webpack IgnorePlugin config) since none
|
|
229
|
+
// of lite's features wire up agent.register -- guard against that rather than letting an
|
|
230
|
+
// unhandled rejection surface if this flag is ever set on a lite page.
|
|
231
|
+
const {
|
|
232
|
+
setupIframeMFEMessageListener
|
|
233
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "iframe-message-handler" */'../../loaders/configure/iframe-message-handler')));
|
|
234
|
+
setupIframeMFEMessageListener(agentRef);
|
|
235
|
+
} catch (e) {
|
|
236
|
+
(0, _console.warn)(23, e);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const [{
|
|
240
|
+
Connector
|
|
241
|
+
}, {
|
|
242
|
+
Harvester
|
|
243
|
+
}] = await Promise.all([Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "connector" */'../../common/harvest/connector'))), Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "harvester" */'../../common/harvest/harvester')))]);
|
|
244
|
+
agentRef.runtime.connector = new Connector(agentRef);
|
|
245
|
+
agentRef.runtime.harvester = new Harvester(agentRef);
|
|
246
|
+
|
|
247
|
+
/* Wait for auto-started features' aggregates to load before starting the harvest timer, so Harvester's EOL
|
|
248
|
+
listener registers after aggregate-level listeners like web-vitals' CWV APIs. Not awaited here to avoid
|
|
249
|
+
deadlock, since every feature awaits this same bootstrap promise before its own aggregate load.
|
|
250
|
+
Only auto-started features are waited on: an autoStart:false feature only registers in drainRegistry once
|
|
251
|
+
`start` is called, so filtering on that registry excludes any feature that's never started instead of
|
|
252
|
+
blocking startTimer() forever. */
|
|
253
|
+
const autoStartedFeatures = Object.values(agentRef.features).filter(feature => agentRef.runtime.drainRegistry.has(feature.featureName));
|
|
254
|
+
Promise.all(autoStartedFeatures.map(feature => feature.onAggregateImported)).then(() => agentRef.runtime.harvester.startTimer());
|
|
255
|
+
})();
|
|
256
|
+
runtimeBootstrapPromises.set(agentRef, bootstrapPromise);
|
|
257
|
+
await bootstrapPromise;
|
|
258
|
+
}
|
|
@@ -96,9 +96,10 @@ class Agent extends _agentBase.AgentBase {
|
|
|
96
96
|
try {
|
|
97
97
|
const enabledFeatures = (0, _enabledFeatures.getEnabledFeatures)(this.init);
|
|
98
98
|
const featuresToStart = [...this.desiredFeatures];
|
|
99
|
+
const isRumV2Enabled = this.init.feature_flags.includes('rum_v2');
|
|
99
100
|
featuresToStart.sort((a, b) => _features.featurePriority[a.featureName] - _features.featurePriority[b.featureName]);
|
|
100
101
|
featuresToStart.forEach(InstrumentCtor => {
|
|
101
|
-
if (!enabledFeatures[InstrumentCtor.featureName] && InstrumentCtor.featureName !== _features.FEATURE_NAMES.pageViewEvent) return; // PVE is required to run even if it's marked disabled
|
|
102
|
+
if (!enabledFeatures[InstrumentCtor.featureName] && (isRumV2Enabled || InstrumentCtor.featureName !== _features.FEATURE_NAMES.pageViewEvent)) return; // PVE is required to run even if it's marked disabled unless rum_v2 is enabled
|
|
102
103
|
|
|
103
104
|
const dependencies = (0, _featureDependencies.getFeatureDependencyNames)(InstrumentCtor.featureName);
|
|
104
105
|
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
|
|
@@ -9,7 +9,7 @@ var _sharedHandlers = require("./sharedHandlers");
|
|
|
9
9
|
var _handle = require("../../common/event-emitter/handle");
|
|
10
10
|
var _console = require("../../common/util/console");
|
|
11
11
|
/**
|
|
12
|
-
* Copyright 2020-
|
|
12
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
13
13
|
* SPDX-License-Identifier: Apache-2.0
|
|
14
14
|
*/
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ function setupConsentAPI(agent) {
|
|
|
29
29
|
pveInst.onAggregateImported.then(loaded => {
|
|
30
30
|
const pveAgg = pveInst.featAggregate;
|
|
31
31
|
if (loaded && !pveAgg.sentRum) {
|
|
32
|
-
pveAgg.sendRum();
|
|
32
|
+
pveAgg.sendRum?.(); // only the old v1 aggregate has a sendRum method that acts as a blocker for the rest of the agent; v2 aggregate will auto report when harvester becomes unblocked
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
35
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.featurePriority = exports.RUM = exports.LOGS = exports.JSERRORS = exports.FEATURE_TO_ENDPOINT = exports.FEATURE_NAMES = exports.EVENTS = exports.BLOBS = void 0;
|
|
6
|
+
exports.featurePriority = exports.RUM = exports.LOGS = exports.JSERRORS = exports.FEATURE_TO_ENDPOINT = exports.FEATURE_NAMES = exports.EVENTS = exports.CONNECT = exports.BLOBS = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
9
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -14,6 +14,7 @@ const EVENTS = exports.EVENTS = 'events';
|
|
|
14
14
|
const JSERRORS = exports.JSERRORS = 'jserrors';
|
|
15
15
|
const BLOBS = exports.BLOBS = 'browser/blobs';
|
|
16
16
|
const RUM = exports.RUM = 'rum';
|
|
17
|
+
const CONNECT = exports.CONNECT = 'connect';
|
|
17
18
|
const LOGS = exports.LOGS = 'browser/logs';
|
|
18
19
|
const FEATURE_NAMES = exports.FEATURE_NAMES = {
|
|
19
20
|
ajax: 'ajax',
|