@newrelic/browser-agent 1.302.0-rc.0 → 1.302.0-rc.10
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/dist/cjs/common/config/init-types.js +2 -0
- package/dist/cjs/common/config/init.js +3 -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/harvest/harvester.js +13 -9
- package/dist/cjs/common/harvest/types.js +0 -1
- package/dist/cjs/common/session/session-entity.js +4 -2
- package/dist/cjs/common/util/mfe.js +4 -0
- package/dist/cjs/common/wrap/wrap-promise.js +10 -5
- package/dist/cjs/features/generic_events/aggregate/index.js +4 -4
- package/dist/cjs/features/logging/aggregate/index.js +1 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +84 -22
- package/dist/cjs/features/page_view_event/instrument/index.js +0 -4
- package/dist/cjs/features/session_replay/aggregate/index.js +3 -2
- package/dist/cjs/features/session_replay/constants.js +2 -6
- package/dist/cjs/features/session_replay/instrument/index.js +3 -2
- package/dist/cjs/features/utils/agent-session.js +13 -0
- package/dist/cjs/features/utils/instrument-base.js +7 -8
- package/dist/cjs/interfaces/registered-entity.js +21 -0
- package/dist/cjs/loaders/agent.js +2 -0
- package/dist/cjs/loaders/api/consent.js +24 -0
- package/dist/cjs/loaders/api/constants.js +3 -2
- package/dist/cjs/loaders/api/measure.js +36 -35
- package/dist/cjs/loaders/api/recordCustomEvent.js +5 -3
- package/dist/cjs/loaders/api/register-api-types.js +10 -9
- package/dist/cjs/loaders/api/register.js +16 -0
- package/dist/cjs/loaders/api-base.js +14 -7
- package/dist/esm/common/config/init-types.js +2 -0
- package/dist/esm/common/config/init.js +3 -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/harvest/harvester.js +13 -9
- package/dist/esm/common/harvest/types.js +0 -1
- package/dist/esm/common/session/session-entity.js +4 -2
- package/dist/esm/common/util/mfe.js +3 -0
- package/dist/esm/common/wrap/wrap-promise.js +10 -5
- package/dist/esm/features/generic_events/aggregate/index.js +4 -4
- package/dist/esm/features/logging/aggregate/index.js +1 -2
- package/dist/esm/features/page_view_event/aggregate/index.js +84 -22
- package/dist/esm/features/page_view_event/instrument/index.js +0 -4
- package/dist/esm/features/session_replay/aggregate/index.js +4 -3
- package/dist/esm/features/session_replay/constants.js +1 -5
- package/dist/esm/features/session_replay/instrument/index.js +4 -3
- package/dist/esm/features/utils/agent-session.js +13 -0
- package/dist/esm/features/utils/instrument-base.js +7 -8
- package/dist/esm/interfaces/registered-entity.js +21 -0
- package/dist/esm/loaders/agent.js +2 -0
- package/dist/esm/loaders/api/consent.js +17 -0
- package/dist/esm/loaders/api/constants.js +2 -1
- package/dist/esm/loaders/api/measure.js +35 -35
- package/dist/esm/loaders/api/recordCustomEvent.js +4 -3
- package/dist/esm/loaders/api/register-api-types.js +10 -9
- package/dist/esm/loaders/api/register.js +17 -1
- package/dist/esm/loaders/api-base.js +15 -8
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/config/init-types.d.ts +6 -0
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/harvest/harvester.d.ts.map +1 -1
- package/dist/types/common/harvest/types.d.ts +0 -2
- package/dist/types/common/harvest/types.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/util/mfe.d.ts +1 -0
- package/dist/types/common/util/mfe.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +22 -3
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/constants.d.ts +1 -5
- package/dist/types/features/session_replay/constants.d.ts.map +1 -1
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/utils/agent-session.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts +1 -0
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/interfaces/registered-entity.d.ts +25 -0
- package/dist/types/interfaces/registered-entity.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/api/consent.d.ts +2 -0
- package/dist/types/loaders/api/consent.d.ts.map +1 -0
- package/dist/types/loaders/api/constants.d.ts +1 -0
- package/dist/types/loaders/api/constants.d.ts.map +1 -1
- package/dist/types/loaders/api/measure.d.ts +3 -0
- package/dist/types/loaders/api/measure.d.ts.map +1 -1
- package/dist/types/loaders/api/recordCustomEvent.d.ts +1 -0
- package/dist/types/loaders/api/recordCustomEvent.d.ts.map +1 -1
- package/dist/types/loaders/api/register-api-types.d.ts +28 -11
- package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
- package/dist/types/loaders/api/register.d.ts.map +1 -1
- package/dist/types/loaders/api-base.d.ts +20 -15
- package/dist/types/loaders/api-base.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/common/config/init-types.js +2 -0
- package/src/common/config/init.js +1 -0
- package/src/common/harvest/harvester.js +11 -8
- package/src/common/harvest/types.js +0 -1
- package/src/common/session/session-entity.js +6 -2
- package/src/common/util/mfe.js +4 -0
- package/src/common/wrap/wrap-promise.js +16 -6
- package/src/features/generic_events/aggregate/index.js +4 -4
- package/src/features/logging/aggregate/index.js +1 -1
- package/src/features/page_view_event/aggregate/index.js +79 -15
- package/src/features/page_view_event/instrument/index.js +0 -4
- package/src/features/session_replay/aggregate/index.js +4 -3
- package/src/features/session_replay/constants.js +1 -5
- package/src/features/session_replay/instrument/index.js +4 -3
- package/src/features/utils/agent-session.js +12 -0
- package/src/features/utils/instrument-base.js +7 -9
- package/src/interfaces/registered-entity.js +21 -0
- package/src/loaders/agent.js +2 -0
- package/src/loaders/api/consent.js +18 -0
- package/src/loaders/api/constants.js +1 -0
- package/src/loaders/api/measure.js +34 -33
- package/src/loaders/api/recordCustomEvent.js +5 -3
- package/src/loaders/api/register-api-types.js +10 -9
- package/src/loaders/api/register.js +8 -1
- package/src/loaders/api-base.js +15 -8
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.measure = measure;
|
|
6
7
|
exports.setupMeasureAPI = setupMeasureAPI;
|
|
7
8
|
var _handle = require("../../common/event-emitter/handle");
|
|
8
9
|
var _now = require("../../common/timing/now");
|
|
@@ -16,45 +17,45 @@ var _sharedHandlers = require("./sharedHandlers");
|
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
function setupMeasureAPI(agent) {
|
|
19
|
-
(0, _sharedHandlers.setupAPI)(_constants.MEASURE,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
(0, _sharedHandlers.setupAPI)(_constants.MEASURE, (name, options) => measure(name, options, agent), agent);
|
|
21
|
+
}
|
|
22
|
+
function measure(name, options, agentRef, target, timestamp = (0, _now.now)()) {
|
|
23
|
+
const {
|
|
24
|
+
start,
|
|
25
|
+
end,
|
|
26
|
+
customAttributes
|
|
27
|
+
} = options || {};
|
|
28
|
+
const returnObj = {
|
|
29
|
+
customAttributes: customAttributes || {}
|
|
30
|
+
};
|
|
31
|
+
if (typeof returnObj.customAttributes !== 'object' || typeof name !== 'string' || name.length === 0) {
|
|
32
|
+
(0, _console.warn)(57);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
/**
|
|
35
37
|
* getValueFromTiming - Helper function to extract a numeric value from a supplied option.
|
|
36
38
|
* @param {Number|PerformanceMark} [timing] The timing value
|
|
37
39
|
* @param {Number} [d] The default value to return if timing is invalid
|
|
38
40
|
* @returns {Number} The timing value or the default value
|
|
39
41
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}, agent);
|
|
42
|
+
const getValueFromTiming = (timing, d) => {
|
|
43
|
+
if (timing == null) return d;
|
|
44
|
+
if (typeof timing === 'number') return timing;
|
|
45
|
+
if (timing instanceof PerformanceMark) return timing.startTime;
|
|
46
|
+
return Number.NaN;
|
|
47
|
+
};
|
|
48
|
+
returnObj.start = getValueFromTiming(start, 0);
|
|
49
|
+
returnObj.end = getValueFromTiming(end, timestamp);
|
|
50
|
+
if (Number.isNaN(returnObj.start) || Number.isNaN(returnObj.end)) {
|
|
51
|
+
(0, _console.warn)(57);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
returnObj.duration = returnObj.end - returnObj.start;
|
|
55
|
+
if (returnObj.duration < 0) {
|
|
56
|
+
(0, _console.warn)(58);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
(0, _handle.handle)(_constants.prefix + _constants.MEASURE, [returnObj, name, target], undefined, _features.FEATURE_NAMES.genericEvents, agentRef.ee);
|
|
60
|
+
return returnObj;
|
|
60
61
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.recordCustomEvent = recordCustomEvent;
|
|
6
7
|
exports.setupRecordCustomEventAPI = setupRecordCustomEventAPI;
|
|
7
8
|
var _handle = require("../../common/event-emitter/handle");
|
|
8
9
|
var _now = require("../../common/timing/now");
|
|
@@ -15,7 +16,8 @@ var _sharedHandlers = require("./sharedHandlers");
|
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
18
|
function setupRecordCustomEventAPI(agent) {
|
|
18
|
-
(0, _sharedHandlers.setupAPI)(_constants.RECORD_CUSTOM_EVENT,
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
(0, _sharedHandlers.setupAPI)(_constants.RECORD_CUSTOM_EVENT, (eventType, attributes) => recordCustomEvent(eventType, attributes, agent), agent);
|
|
20
|
+
}
|
|
21
|
+
function recordCustomEvent(eventType, attributes = {}, agentRef, target, timestamp = (0, _now.now)()) {
|
|
22
|
+
(0, _handle.handle)(_constants.prefix + _constants.RECORD_CUSTOM_EVENT, [timestamp, eventType, attributes, target], undefined, _features.FEATURE_NAMES.genericEvents, agentRef.ee);
|
|
21
23
|
}
|
|
@@ -10,19 +10,20 @@ exports.default = void 0;
|
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
12
|
* @typedef {Object} RegisterAPI
|
|
13
|
-
* @property {
|
|
14
|
-
* @property {
|
|
15
|
-
* @property {
|
|
16
|
-
* @property {
|
|
17
|
-
* @property {
|
|
18
|
-
* @property {
|
|
13
|
+
* @property {(name: string, attributes?: object) => void} addPageAction - Add a page action for the registered entity.
|
|
14
|
+
* @property {(message: string, options?: { customAttributes?: object, level?: 'ERROR' | 'TRACE' | 'DEBUG' | 'INFO' | 'WARN'}) => void} log - Capture a log for the registered entity.
|
|
15
|
+
* @property {(error: Error | string, customAttributes?: object) => void} noticeError - Notice an error for the registered entity.
|
|
16
|
+
* @property {(eventType: string, attributes?: Object) => void} recordCustomEvent - Record a custom event for the registered entity.
|
|
17
|
+
* @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.
|
|
18
|
+
* @property {(value: string | null) => void} setApplicationVersion - Add an application.version attribute to all outgoing data for the registered entity.
|
|
19
|
+
* @property {(name: string, value: string | number | boolean | null, persist?: boolean) => void} setCustomAttribute - Add a custom attribute to outgoing data for the registered entity.
|
|
20
|
+
* @property {(value: string | null) => void} setUserId - Add an enduser.id attribute to all outgoing API data for the registered entity.
|
|
19
21
|
* @property {RegisterAPIMetadata} metadata - The metadata object containing the custom attributes and target information for the registered entity.
|
|
20
22
|
*/
|
|
21
23
|
/**
|
|
22
24
|
* @typedef {Object} RegisterAPIConstructor
|
|
23
|
-
* @property {
|
|
24
|
-
* @property {string}
|
|
25
|
-
* @property {string} opts.name - The readable name for the registered entity. This will be assigned to any synthesized entities.
|
|
25
|
+
* @property {string|number} id - The unique id for the registered entity. This will be assigned to any synthesized entities.
|
|
26
|
+
* @property {string} name - The readable name for the registered entity. This will be assigned to any synthesized entities.
|
|
26
27
|
*/
|
|
27
28
|
/**
|
|
28
29
|
* @typedef {Object} RegisterAPIMetadata
|
|
@@ -17,6 +17,8 @@ var _log = require("./log");
|
|
|
17
17
|
var _addPageAction = require("./addPageAction");
|
|
18
18
|
var _noticeError = require("./noticeError");
|
|
19
19
|
var _invoke = require("../../common/util/invoke");
|
|
20
|
+
var _measure = require("./measure");
|
|
21
|
+
var _recordCustomEvent = require("./recordCustomEvent");
|
|
20
22
|
/**
|
|
21
23
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
22
24
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -86,6 +88,9 @@ function buildRegisterApi(agentRef, target) {
|
|
|
86
88
|
/** primary cases that can block the register API from working at init time */
|
|
87
89
|
if (!agentRef.init.api.allow_registered_children) block((0, _invoke.single)(() => (0, _console.warn)(55)));
|
|
88
90
|
if (!(0, _mfe.isValidMFETarget)(target)) block((0, _invoke.single)(() => (0, _console.warn)(48, target)));
|
|
91
|
+
if (!(0, _mfe.hasValidValue)(target.id) || !(0, _mfe.hasValidValue)(target.name)) {
|
|
92
|
+
block((0, _invoke.single)(() => (0, _console.warn)(48, target)));
|
|
93
|
+
}
|
|
89
94
|
|
|
90
95
|
/** @type {RegisterAPI} */
|
|
91
96
|
const api = {
|
|
@@ -100,10 +105,21 @@ function buildRegisterApi(agentRef, target) {
|
|
|
100
105
|
...(options.customAttributes || {})
|
|
101
106
|
}
|
|
102
107
|
}, agentRef], target),
|
|
108
|
+
measure: (name, options = {}) => report(_measure.measure, [name, {
|
|
109
|
+
...options,
|
|
110
|
+
customAttributes: {
|
|
111
|
+
...attrs,
|
|
112
|
+
...(options.customAttributes || {})
|
|
113
|
+
}
|
|
114
|
+
}, agentRef], target),
|
|
103
115
|
noticeError: (error, attributes = {}) => report(_noticeError.noticeError, [error, {
|
|
104
116
|
...attrs,
|
|
105
117
|
...attributes
|
|
106
118
|
}, agentRef], target),
|
|
119
|
+
recordCustomEvent: (eventType, attributes = {}) => report(_recordCustomEvent.recordCustomEvent, [eventType, {
|
|
120
|
+
...attrs,
|
|
121
|
+
...attributes
|
|
122
|
+
}, agentRef], target),
|
|
107
123
|
setApplicationVersion: value => setLocalValue('application.version', value),
|
|
108
124
|
setCustomAttribute: (key, value) => setLocalValue(key, value),
|
|
109
125
|
setUserId: value => setLocalValue('enduser.id', value),
|
|
@@ -37,11 +37,8 @@ class ApiBase {
|
|
|
37
37
|
* It is not recommended for use in production environments and will not receive support for issues.
|
|
38
38
|
*
|
|
39
39
|
* Registers an external caller to report through the base agent to a different target than the base agent.
|
|
40
|
-
* @param {
|
|
41
|
-
|
|
42
|
-
* @param {string} target.applicationID The applicationID to report data to
|
|
43
|
-
* @param {string=} target.entityGuid The entityGuid to report data to
|
|
44
|
-
* @returns {object} Returns an object that contains the available API methods and configurations to use with the external caller. See loaders/api/api.js for more information.
|
|
40
|
+
* @param {import('./api/register-api-types').RegisterAPIConstructor} target the target object to report data to
|
|
41
|
+
@returns {import('./api/register-api-types').RegisterAPI} Returns an object that contains the available API methods and configurations to use with the external caller. See loaders/api/api.js for more information.
|
|
45
42
|
*/
|
|
46
43
|
register(target) {
|
|
47
44
|
return this.#callMethod(_constants.REGISTER, target);
|
|
@@ -51,7 +48,7 @@ class ApiBase {
|
|
|
51
48
|
* Records a custom event with a specified eventType and attributes.
|
|
52
49
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/recordCustomEvent/}
|
|
53
50
|
* @param {string} eventType The eventType to store the event as.
|
|
54
|
-
* @param {
|
|
51
|
+
* @param {Object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}.
|
|
55
52
|
*/
|
|
56
53
|
recordCustomEvent(eventType, attributes) {
|
|
57
54
|
return this.#callMethod(_constants.RECORD_CUSTOM_EVENT, eventType, attributes);
|
|
@@ -227,11 +224,21 @@ class ApiBase {
|
|
|
227
224
|
* Measures a task that is recorded as a BrowserPerformance event.
|
|
228
225
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/measure/}
|
|
229
226
|
* @param {string} name The name of the task
|
|
230
|
-
* @param {object
|
|
227
|
+
* @param {{start: number, end: number, duration: number, customAttributes: object}} [options] An object used to control the way the measure API operates
|
|
231
228
|
* @returns {{start: number, end: number, duration: number, customAttributes: object}} Measurement details
|
|
232
229
|
*/
|
|
233
230
|
measure(name, options) {
|
|
234
231
|
return this.#callMethod(_constants.MEASURE, name, options);
|
|
235
232
|
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Accepts or rejects consent when the agent is configured to require consent before harvesting.
|
|
236
|
+
* The consent state is stored in session storage inside the NRBA_SESSION object.
|
|
237
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/consent/}
|
|
238
|
+
* @param {boolean?} accept Whether to accept or reject consent. Defaults to true (accept) if left undefined.
|
|
239
|
+
*/
|
|
240
|
+
consent(accept) {
|
|
241
|
+
return this.#callMethod(_constants.CONSENT, accept);
|
|
242
|
+
}
|
|
236
243
|
}
|
|
237
244
|
exports.ApiBase = ApiBase;
|
|
@@ -84,6 +84,8 @@
|
|
|
84
84
|
* @property {boolean} [spa.enabled] - Turn on/off the single page application feature (on by default). NOTE: the SPA feature is deprecated and under removal procedure.
|
|
85
85
|
* @property {boolean} [spa.autoStart] - If true, the agent will automatically start the single page application feature. Otherwise, it will be in a deferred state until the `start` API method is called.
|
|
86
86
|
* @property {boolean} [ssl] - If explicitly false, the agent will use HTTP instead of HTTPS. This setting should NOT be used.
|
|
87
|
+
* @property {Object} [browser_consent_mode]
|
|
88
|
+
* @property {boolean} [browser_consent_mode.enabled] - If true, the agent will use consent mode for whether to allow or disallow data harvest.
|
|
87
89
|
* @property {Object} [user_actions]
|
|
88
90
|
* @property {boolean} [user_actions.enabled] - Must be true to allow UserAction events to be captured.
|
|
89
91
|
* @property {Array<string>} [user_actions.elementAttributes] - List of HTML Element properties to be captured with UserAction events' target elements. This may help to identify the source element being interacted with in the UI.
|
|
@@ -17,8 +17,10 @@ import { stringify } from '../util/stringify';
|
|
|
17
17
|
import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../util/submit-data';
|
|
18
18
|
import { activatedFeatures } from '../util/feature-flags';
|
|
19
19
|
import { dispatchGlobalEvent } from '../dispatch/global-event';
|
|
20
|
-
const
|
|
21
|
-
const
|
|
20
|
+
const RETRY = 'Harvester/Retry/';
|
|
21
|
+
const RETRY_ATTEMPTED = RETRY + 'Attempted/';
|
|
22
|
+
const RETRY_FAILED = RETRY + 'Failed/';
|
|
23
|
+
const RETRY_SUCCEEDED = RETRY + 'Succeeded/';
|
|
22
24
|
export class Harvester {
|
|
23
25
|
#started = false;
|
|
24
26
|
initializedAggregates = [];
|
|
@@ -59,11 +61,11 @@ export class Harvester {
|
|
|
59
61
|
endpointVersion: aggregateInst.harvestEndpointVersion || 1
|
|
60
62
|
};
|
|
61
63
|
if (aggregateInst.blocked) return output;
|
|
64
|
+
if (this.agentRef.init?.browser_consent_mode?.enabled && !this.agentRef.runtime?.session?.state?.consent) return output;
|
|
62
65
|
const submitMethod = getSubmitMethod(localOpts);
|
|
63
66
|
if (!submitMethod) return output;
|
|
64
67
|
const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === xhrMethod; // always retry all features harvests except for final
|
|
65
|
-
output.payload =
|
|
66
|
-
|
|
68
|
+
output.payload = aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts);
|
|
67
69
|
if (!output.payload) return output;
|
|
68
70
|
send(this.agentRef, {
|
|
69
71
|
endpoint: FEATURE_TO_ENDPOINT[aggregateInst.featureName],
|
|
@@ -85,7 +87,9 @@ export class Harvester {
|
|
|
85
87
|
function cbFinished(result) {
|
|
86
88
|
if (aggregateInst.harvestOpts.prevAttemptCode) {
|
|
87
89
|
// this means we just retried a harvest that last failed
|
|
88
|
-
handle(SUPPORTABILITY_METRIC_CHANNEL, [
|
|
90
|
+
const reportSM = message => handle(SUPPORTABILITY_METRIC_CHANNEL, [message], undefined, FEATURE_NAMES.metrics, aggregateInst.ee);
|
|
91
|
+
reportSM(RETRY_ATTEMPTED + aggregateInst.featureName);
|
|
92
|
+
reportSM((result.retry ? RETRY_FAILED : RETRY_SUCCEEDED) + aggregateInst.harvestOpts.prevAttemptCode);
|
|
89
93
|
delete aggregateInst.harvestOpts.prevAttemptCode; // always reset last observation so we don't falsely report again next harvest
|
|
90
94
|
// In case this re-attempt failed again, that'll be handled (re-marked again) next.
|
|
91
95
|
}
|
|
@@ -175,9 +179,9 @@ export function send(agentRef, {
|
|
|
175
179
|
status: this.status,
|
|
176
180
|
retry: shouldRetry(this.status),
|
|
177
181
|
fullUrl,
|
|
178
|
-
xhr: this
|
|
182
|
+
xhr: this,
|
|
183
|
+
responseText: this.responseText
|
|
179
184
|
};
|
|
180
|
-
if (localOpts.needResponse) cbResult.responseText = this.responseText;
|
|
181
185
|
cbFinished(cbResult);
|
|
182
186
|
|
|
183
187
|
/** temporary audit of consistency of harvest metadata flags */
|
|
@@ -191,9 +195,9 @@ export function send(agentRef, {
|
|
|
191
195
|
status,
|
|
192
196
|
retry: shouldRetry(status),
|
|
193
197
|
fullUrl,
|
|
194
|
-
fetchResponse: response
|
|
198
|
+
fetchResponse: response,
|
|
199
|
+
responseText: await response.text()
|
|
195
200
|
};
|
|
196
|
-
if (localOpts.needResponse) cbResult.responseText = await response.text();
|
|
197
201
|
cbFinished(cbResult);
|
|
198
202
|
/** temporary audit of consistency of harvest metadata flags */
|
|
199
203
|
if (!shouldRetry(status)) trackHarvestMetadata();
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
* @property {HarvestEndpointIdentifier} endpoint The endpoint to use (jserrors, events, resources etc.)
|
|
25
25
|
* @property {HarvestPayload} payload Object representing payload.
|
|
26
26
|
* @property {object} localOpts Additional options for sending data
|
|
27
|
-
* @property {boolean} localOpts.needResponse Specify whether the caller expects a response data.
|
|
28
27
|
* @property {boolean} localOpts.isFinalHarvest Specify whether the call is a final harvest during page unload.
|
|
29
28
|
* @property {boolean} localOpts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
|
|
30
29
|
* @property {boolean} localOpts.forceNoRetry Don't save the buffered data in the case of a need to retry the transmission.
|
|
@@ -33,7 +33,8 @@ const model = {
|
|
|
33
33
|
serverTimeDiff: null,
|
|
34
34
|
// set by TimeKeeper; "undefined" value will not be stringified and stored but "null" will
|
|
35
35
|
custom: {},
|
|
36
|
-
numOfResets: 0
|
|
36
|
+
numOfResets: 0,
|
|
37
|
+
consent: false // set by consent() API call
|
|
37
38
|
};
|
|
38
39
|
export class SessionEntity {
|
|
39
40
|
/**
|
|
@@ -84,7 +85,8 @@ export class SessionEntity {
|
|
|
84
85
|
}) {
|
|
85
86
|
/** Ensure that certain properties are preserved across a reset if already set */
|
|
86
87
|
const persistentAttributes = {
|
|
87
|
-
serverTimeDiff: this.state.serverTimeDiff || model.serverTimeDiff
|
|
88
|
+
serverTimeDiff: this.state.serverTimeDiff || model.serverTimeDiff,
|
|
89
|
+
consent: this.state.consent || model.consent
|
|
88
90
|
};
|
|
89
91
|
this.state = {};
|
|
90
92
|
this.sync({
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
export function isValidMFETarget(target = {}) {
|
|
11
11
|
return !!(target.id && target.name);
|
|
12
12
|
}
|
|
13
|
+
export function hasValidValue(val) {
|
|
14
|
+
return typeof val === 'string' && val.trim().length < 501 || typeof val === 'number';
|
|
15
|
+
}
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* When given a valid target, returns an object with the MFE payload attributes. Returns an empty object otherwise.
|
|
@@ -129,12 +129,17 @@ export function wrapPromise(sharedEE) {
|
|
|
129
129
|
});
|
|
130
130
|
promiseEE.on('propagate', function (val, overwrite, trigger) {
|
|
131
131
|
if (!this.getCtx || overwrite) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
const selfStore = this;
|
|
133
|
+
const parentStore = val instanceof Promise ? promiseEE.context(val) : null;
|
|
134
|
+
let cachedCtx;
|
|
135
|
+
this.getCtx = function getCtx() {
|
|
136
|
+
if (cachedCtx) return cachedCtx;
|
|
137
|
+
if (parentStore && parentStore !== selfStore) {
|
|
138
|
+
cachedCtx = typeof parentStore.getCtx === 'function' ? parentStore.getCtx() : parentStore;
|
|
139
|
+
} else {
|
|
140
|
+
cachedCtx = selfStore;
|
|
136
141
|
}
|
|
137
|
-
return
|
|
142
|
+
return cachedCtx;
|
|
138
143
|
};
|
|
139
144
|
}
|
|
140
145
|
});
|
|
@@ -28,13 +28,13 @@ export class Aggregate extends AggregateBase {
|
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
this.#trackSupportabilityMetrics();
|
|
31
|
-
registerHandler('api-recordCustomEvent', (timestamp, eventType, attributes) => {
|
|
31
|
+
registerHandler('api-recordCustomEvent', (timestamp, eventType, attributes, target) => {
|
|
32
32
|
if (RESERVED_EVENT_TYPES.includes(eventType)) return warn(46);
|
|
33
33
|
this.addEvent({
|
|
34
34
|
eventType,
|
|
35
35
|
timestamp: this.toEpoch(timestamp),
|
|
36
36
|
...attributes
|
|
37
|
-
});
|
|
37
|
+
}, target);
|
|
38
38
|
}, this.featureName, this.ee);
|
|
39
39
|
if (agentRef.init.page_action.enabled) {
|
|
40
40
|
registerHandler('api-addPageAction', (timestamp, name, attributes, target) => {
|
|
@@ -231,7 +231,7 @@ export class Aggregate extends AggregateBase {
|
|
|
231
231
|
}
|
|
232
232
|
}, this.featureName, this.ee);
|
|
233
233
|
}
|
|
234
|
-
registerHandler('api-measure', (args, n) => {
|
|
234
|
+
registerHandler('api-measure', (args, n, target) => {
|
|
235
235
|
const {
|
|
236
236
|
start,
|
|
237
237
|
duration,
|
|
@@ -245,7 +245,7 @@ export class Aggregate extends AggregateBase {
|
|
|
245
245
|
entryDuration: duration,
|
|
246
246
|
entryType: 'measure'
|
|
247
247
|
};
|
|
248
|
-
this.addEvent(event);
|
|
248
|
+
this.addEvent(event, target);
|
|
249
249
|
}, this.featureName, this.ee);
|
|
250
250
|
this.drain();
|
|
251
251
|
});
|
|
@@ -97,8 +97,7 @@ export class Aggregate extends AggregateBase {
|
|
|
97
97
|
common: {
|
|
98
98
|
/** Attributes in the `common` section are added to `all` logs generated in the payload */
|
|
99
99
|
attributes: {
|
|
100
|
-
...this.agentRef.info.jsAttributes,
|
|
101
|
-
// user-provided custom attributes
|
|
100
|
+
...applyFnToProps(this.agentRef.info.jsAttributes, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string'),
|
|
102
101
|
...(this.harvestEndpointVersion === 1 && {
|
|
103
102
|
'entity.guid': this.agentRef.runtime.appMetadata.agents[0].entityGuid,
|
|
104
103
|
appId: this.agentRef.info.applicationID
|
|
@@ -17,14 +17,19 @@ import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte';
|
|
|
17
17
|
import { now } from '../../../common/timing/now';
|
|
18
18
|
import { TimeKeeper } from '../../../common/timing/time-keeper';
|
|
19
19
|
import { applyFnToProps } from '../../../common/util/traverse';
|
|
20
|
+
import { send } from '../../../common/harvest/harvester';
|
|
21
|
+
import { FEATURE_NAMES, FEATURE_TO_ENDPOINT } from '../../../loaders/features/features';
|
|
22
|
+
import { getSubmitMethod } from '../../../common/util/submit-data';
|
|
20
23
|
export class Aggregate extends AggregateBase {
|
|
21
24
|
static featureName = CONSTANTS.FEATURE_NAME;
|
|
22
25
|
constructor(agentRef) {
|
|
23
26
|
super(agentRef, CONSTANTS.FEATURE_NAME);
|
|
27
|
+
this.sentRum = false; // flag to facilitate calling sendRum() once externally (by the consent API in agent-session.js)
|
|
28
|
+
|
|
24
29
|
this.timeToFirstByte = 0;
|
|
25
30
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
26
31
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
27
|
-
|
|
32
|
+
this.retries = 0;
|
|
28
33
|
if (!isValid(agentRef.info)) {
|
|
29
34
|
this.ee.abort();
|
|
30
35
|
return warn(43);
|
|
@@ -52,12 +57,8 @@ export class Aggregate extends AggregateBase {
|
|
|
52
57
|
*
|
|
53
58
|
* @param {Function} cb A function to run once the RUM call has finished - Defaults to activateFeatures
|
|
54
59
|
* @param {*} customAttributes custom attributes to attach to the RUM call - Defaults to info.js
|
|
55
|
-
* @param {*} target The target to harvest to
|
|
56
60
|
*/
|
|
57
|
-
sendRum(customAttributes = this.agentRef.info.jsAttributes
|
|
58
|
-
licenseKey: this.agentRef.info.licenseKey,
|
|
59
|
-
applicationID: this.agentRef.info.applicationID
|
|
60
|
-
}) {
|
|
61
|
+
sendRum(customAttributes = this.agentRef.info.jsAttributes) {
|
|
61
62
|
const info = this.agentRef.info;
|
|
62
63
|
const measures = {};
|
|
63
64
|
if (info.queueTime) measures.qt = info.queueTime;
|
|
@@ -108,27 +109,30 @@ export class Aggregate extends AggregateBase {
|
|
|
108
109
|
}
|
|
109
110
|
queryParameters.fp = firstPaint.current.value;
|
|
110
111
|
queryParameters.fcp = firstContentfulPaint.current.value;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
needResponse: true,
|
|
112
|
+
this.queryStringsBuilder = () => {
|
|
113
|
+
// this will be called by AggregateBase.makeHarvestPayload every time harvest is triggered to be qs
|
|
114
|
+
this.rumStartTime = now(); // this should be reset at the beginning of each RUM call for proper timeKeeper calculation in coordination with postHarvestCleanup
|
|
115
|
+
const timeKeeper = this.agentRef.runtime.timeKeeper;
|
|
116
|
+
if (timeKeeper?.ready) {
|
|
117
|
+
queryParameters.timestamp = Math.floor(timeKeeper.correctRelativeTimestamp(this.rumStartTime));
|
|
118
|
+
}
|
|
119
|
+
return queryParameters;
|
|
120
|
+
};
|
|
121
|
+
this.events.add(body);
|
|
122
|
+
if (this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
125
123
|
sendEmptyBody: true
|
|
126
|
-
});
|
|
124
|
+
}).ranSend) this.sentRum = true;
|
|
125
|
+
}
|
|
126
|
+
serializer(eventBuffer) {
|
|
127
|
+
// this is necessary because PVE sends a single item rather than an array; in the case of undefined, this prevents sending [null] as body
|
|
128
|
+
return eventBuffer[0];
|
|
127
129
|
}
|
|
128
130
|
postHarvestCleanup({
|
|
131
|
+
sent,
|
|
129
132
|
status,
|
|
130
133
|
responseText,
|
|
131
|
-
xhr
|
|
134
|
+
xhr,
|
|
135
|
+
retry
|
|
132
136
|
}) {
|
|
133
137
|
const rumEndTime = now();
|
|
134
138
|
let app, flags;
|
|
@@ -141,8 +145,65 @@ export class Aggregate extends AggregateBase {
|
|
|
141
145
|
// wont set entity stuff here, if main agent will later abort, if registered agent, nothing will happen
|
|
142
146
|
warn(53, error);
|
|
143
147
|
}
|
|
148
|
+
super.postHarvestCleanup({
|
|
149
|
+
sent,
|
|
150
|
+
retry
|
|
151
|
+
}); // this will set isRetrying & re-buffer the body if request is to be retried
|
|
152
|
+
if (this.isRetrying && this.retries++ < 1) {
|
|
153
|
+
// Only retry once
|
|
154
|
+
setTimeout(() => this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
155
|
+
sendEmptyBody: true
|
|
156
|
+
}), 5000); // Retry sending the RUM event after 5 seconds
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
144
159
|
if (status >= 400 || status === 0) {
|
|
145
160
|
warn(18, status);
|
|
161
|
+
this.blocked = true;
|
|
162
|
+
|
|
163
|
+
// Get estimated payload size of our backlog
|
|
164
|
+
const textEncoder = new TextEncoder();
|
|
165
|
+
const payloadSize = Object.values(newrelic.ee.backlog).reduce((acc, value) => {
|
|
166
|
+
if (!value) return acc;
|
|
167
|
+
const encoded = textEncoder.encode(value);
|
|
168
|
+
return acc + encoded.byteLength;
|
|
169
|
+
}, 0);
|
|
170
|
+
|
|
171
|
+
// Send SMs about failed RUM request
|
|
172
|
+
const body = {
|
|
173
|
+
sm: [{
|
|
174
|
+
params: {
|
|
175
|
+
name: "Browser/Supportability/BCS/Error/".concat(status)
|
|
176
|
+
},
|
|
177
|
+
stats: {
|
|
178
|
+
c: 1
|
|
179
|
+
}
|
|
180
|
+
}, {
|
|
181
|
+
params: {
|
|
182
|
+
name: 'Browser/Supportability/BCS/Error/Dropped/Bytes'
|
|
183
|
+
},
|
|
184
|
+
stats: {
|
|
185
|
+
c: 1,
|
|
186
|
+
t: payloadSize
|
|
187
|
+
}
|
|
188
|
+
}, {
|
|
189
|
+
params: {
|
|
190
|
+
name: 'Browser/Supportability/BCS/Error/Duration/Ms'
|
|
191
|
+
},
|
|
192
|
+
stats: {
|
|
193
|
+
c: 1,
|
|
194
|
+
t: rumEndTime - this.rumStartTime
|
|
195
|
+
}
|
|
196
|
+
}]
|
|
197
|
+
};
|
|
198
|
+
send(this.agentRef, {
|
|
199
|
+
endpoint: FEATURE_TO_ENDPOINT[FEATURE_NAMES.metrics],
|
|
200
|
+
payload: {
|
|
201
|
+
body
|
|
202
|
+
},
|
|
203
|
+
submitMethod: getSubmitMethod(),
|
|
204
|
+
featureName: FEATURE_NAMES.metrics
|
|
205
|
+
});
|
|
206
|
+
|
|
146
207
|
// Adding retry logic for the rum call will be a separate change; this.blocked will need to be changed since that prevents another triggerHarvestFor()
|
|
147
208
|
this.ee.abort();
|
|
148
209
|
return;
|
|
@@ -161,6 +222,7 @@ export class Aggregate extends AggregateBase {
|
|
|
161
222
|
}
|
|
162
223
|
} catch (error) {
|
|
163
224
|
this.ee.abort();
|
|
225
|
+
this.blocked = true;
|
|
164
226
|
warn(17, error);
|
|
165
227
|
return;
|
|
166
228
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import { handle } from '../../../common/event-emitter/handle';
|
|
6
5
|
import { setupSetPageViewNameAPI } from '../../../loaders/api/setPageViewName';
|
|
7
6
|
import { InstrumentBase } from '../../utils/instrument-base';
|
|
8
7
|
import * as CONSTANTS from '../constants';
|
|
@@ -19,9 +18,6 @@ export class Instrument extends InstrumentBase {
|
|
|
19
18
|
|
|
20
19
|
/** feature specific APIs */
|
|
21
20
|
setupSetPageViewNameAPI(agentRef);
|
|
22
|
-
|
|
23
|
-
/** messages from the register API that can trigger a new RUM call */
|
|
24
|
-
this.ee.on('api-send-rum', (attrs, target) => handle('send-rum', [attrs, target], undefined, this.featureName, this.ee));
|
|
25
21
|
this.importAggregator(agentRef, () => import(/* webpackChunkName: "page_view_event-aggregate" */'../aggregate'));
|
|
26
22
|
}
|
|
27
23
|
setupInspectionEvents(agentIdentifier) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { registerHandler } from '../../../common/event-emitter/register-handler';
|
|
10
|
-
import { ABORT_REASONS, FEATURE_NAME, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES,
|
|
10
|
+
import { ABORT_REASONS, ERROR_DURING_REPLAY, FEATURE_NAME, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES, TRIGGERS } from '../constants';
|
|
11
11
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
12
12
|
import { sharedChannel } from '../../../common/constants/shared-channel';
|
|
13
13
|
import { obj as encodeObj } from '../../../common/url/encode';
|
|
@@ -21,6 +21,7 @@ import { now } from '../../../common/timing/now';
|
|
|
21
21
|
import { MAX_PAYLOAD_SIZE } from '../../../common/constants/agent-constants';
|
|
22
22
|
import { cleanURL } from '../../../common/url/clean-url';
|
|
23
23
|
import { canEnableSessionTracking } from '../../utils/feature-gates';
|
|
24
|
+
import { PAUSE_REPLAY } from '../../../loaders/api/constants';
|
|
24
25
|
export class Aggregate extends AggregateBase {
|
|
25
26
|
static featureName = FEATURE_NAME;
|
|
26
27
|
mode = MODE.OFF;
|
|
@@ -72,10 +73,10 @@ export class Aggregate extends AggregateBase {
|
|
|
72
73
|
if (this.mode !== MODE.OFF && data.sessionReplayMode === MODE.OFF) this.abort(ABORT_REASONS.CROSS_TAB);
|
|
73
74
|
this.mode = data.sessionReplayMode;
|
|
74
75
|
});
|
|
75
|
-
registerHandler(
|
|
76
|
+
registerHandler(PAUSE_REPLAY, () => {
|
|
76
77
|
this.forceStop(this.mode === MODE.FULL);
|
|
77
78
|
}, this.featureName, this.ee);
|
|
78
|
-
registerHandler(
|
|
79
|
+
registerHandler(ERROR_DURING_REPLAY, e => {
|
|
79
80
|
this.handleError(e);
|
|
80
81
|
}, this.featureName, this.ee);
|
|
81
82
|
const {
|