@newrelic/browser-agent 1.302.0-rc.7 → 1.302.0-rc.9
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 +1 -0
- package/dist/cjs/common/session/session-entity.js +4 -2
- package/dist/cjs/features/generic_events/aggregate/index.js +2 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +4 -2
- package/dist/cjs/features/page_view_event/instrument/index.js +0 -4
- 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 +11 -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/register-api-types.js +1 -0
- package/dist/cjs/loaders/api/register.js +8 -0
- package/dist/cjs/loaders/api-base.js +11 -1
- 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 +1 -0
- package/dist/esm/common/session/session-entity.js +4 -2
- package/dist/esm/features/generic_events/aggregate/index.js +2 -2
- package/dist/esm/features/page_view_event/aggregate/index.js +4 -2
- package/dist/esm/features/page_view_event/instrument/index.js +0 -4
- 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 +11 -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/register-api-types.js +1 -0
- package/dist/esm/loaders/api/register.js +8 -0
- package/dist/esm/loaders/api-base.js +12 -2
- 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/session/session-entity.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +1 -0
- 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/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 +18 -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/register-api-types.d.ts +9 -0
- 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 +14 -2
- package/dist/types/loaders/api-base.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/config/init-types.js +2 -0
- package/src/common/config/init.js +1 -0
- package/src/common/harvest/harvester.js +1 -0
- package/src/common/session/session-entity.js +6 -2
- package/src/features/generic_events/aggregate/index.js +2 -2
- package/src/features/page_view_event/aggregate/index.js +5 -2
- package/src/features/page_view_event/instrument/index.js +0 -4
- package/src/features/utils/agent-session.js +12 -0
- package/src/features/utils/instrument-base.js +7 -9
- package/src/interfaces/registered-entity.js +11 -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/register-api-types.js +1 -0
- package/src/loaders/api/register.js +2 -0
- package/src/loaders/api-base.js +12 -2
|
@@ -89,6 +89,8 @@ exports.default = void 0;
|
|
|
89
89
|
* @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.
|
|
90
90
|
* @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.
|
|
91
91
|
* @property {boolean} [ssl] - If explicitly false, the agent will use HTTP instead of HTTPS. This setting should NOT be used.
|
|
92
|
+
* @property {Object} [browser_consent_mode]
|
|
93
|
+
* @property {boolean} [browser_consent_mode.enabled] - If true, the agent will use consent mode for whether to allow or disallow data harvest.
|
|
92
94
|
* @property {Object} [user_actions]
|
|
93
95
|
* @property {boolean} [user_actions.enabled] - Must be true to allow UserAction events to be captured.
|
|
94
96
|
* @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,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.302.0-rc.
|
|
20
|
+
const VERSION = exports.VERSION = "1.302.0-rc.9";
|
|
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.302.0-rc.
|
|
20
|
+
const VERSION = exports.VERSION = "1.302.0-rc.9";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -69,6 +69,7 @@ class Harvester {
|
|
|
69
69
|
endpointVersion: aggregateInst.harvestEndpointVersion || 1
|
|
70
70
|
};
|
|
71
71
|
if (aggregateInst.blocked) return output;
|
|
72
|
+
if (this.agentRef.init?.browser_consent_mode?.enabled && !this.agentRef.runtime?.session?.state?.consent) return output;
|
|
72
73
|
const submitMethod = (0, _submitData.getSubmitMethod)(localOpts);
|
|
73
74
|
if (!submitMethod) return output;
|
|
74
75
|
const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === _submitData.xhr; // always retry all features harvests except for final
|
|
@@ -39,7 +39,8 @@ const model = {
|
|
|
39
39
|
serverTimeDiff: null,
|
|
40
40
|
// set by TimeKeeper; "undefined" value will not be stringified and stored but "null" will
|
|
41
41
|
custom: {},
|
|
42
|
-
numOfResets: 0
|
|
42
|
+
numOfResets: 0,
|
|
43
|
+
consent: false // set by consent() API call
|
|
43
44
|
};
|
|
44
45
|
class SessionEntity {
|
|
45
46
|
/**
|
|
@@ -90,7 +91,8 @@ class SessionEntity {
|
|
|
90
91
|
}) {
|
|
91
92
|
/** Ensure that certain properties are preserved across a reset if already set */
|
|
92
93
|
const persistentAttributes = {
|
|
93
|
-
serverTimeDiff: this.state.serverTimeDiff || model.serverTimeDiff
|
|
94
|
+
serverTimeDiff: this.state.serverTimeDiff || model.serverTimeDiff,
|
|
95
|
+
consent: this.state.consent || model.consent
|
|
94
96
|
};
|
|
95
97
|
this.state = {};
|
|
96
98
|
this.sync({
|
|
@@ -238,7 +238,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
238
238
|
}
|
|
239
239
|
}, this.featureName, this.ee);
|
|
240
240
|
}
|
|
241
|
-
(0, _registerHandler.registerHandler)('api-measure', (args, n) => {
|
|
241
|
+
(0, _registerHandler.registerHandler)('api-measure', (args, n, target) => {
|
|
242
242
|
const {
|
|
243
243
|
start,
|
|
244
244
|
duration,
|
|
@@ -252,7 +252,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
252
252
|
entryDuration: duration,
|
|
253
253
|
entryType: 'measure'
|
|
254
254
|
};
|
|
255
|
-
this.addEvent(event);
|
|
255
|
+
this.addEvent(event, target);
|
|
256
256
|
}, this.featureName, this.ee);
|
|
257
257
|
this.drain();
|
|
258
258
|
});
|
|
@@ -32,6 +32,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
32
32
|
static featureName = CONSTANTS.FEATURE_NAME;
|
|
33
33
|
constructor(agentRef) {
|
|
34
34
|
super(agentRef, CONSTANTS.FEATURE_NAME);
|
|
35
|
+
this.sentRum = false; // flag to facilitate calling sendRum() once externally (by the consent API in agent-session.js)
|
|
36
|
+
|
|
35
37
|
this.timeToFirstByte = 0;
|
|
36
38
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
37
39
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
@@ -125,9 +127,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
125
127
|
return queryParameters;
|
|
126
128
|
};
|
|
127
129
|
this.events.add(body);
|
|
128
|
-
this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
130
|
+
if (this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
129
131
|
sendEmptyBody: true
|
|
130
|
-
});
|
|
132
|
+
}).ranSend) this.sentRum = true;
|
|
131
133
|
}
|
|
132
134
|
serializer(eventBuffer) {
|
|
133
135
|
// this is necessary because PVE sends a single item rather than an array; in the case of undefined, this prevents sending [null] as body
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.PageViewEvent = exports.Instrument = void 0;
|
|
7
|
-
var _handle = require("../../../common/event-emitter/handle");
|
|
8
7
|
var _setPageViewName = require("../../../loaders/api/setPageViewName");
|
|
9
8
|
var _instrumentBase = require("../../utils/instrument-base");
|
|
10
9
|
var CONSTANTS = _interopRequireWildcard(require("../constants"));
|
|
@@ -25,9 +24,6 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
25
24
|
|
|
26
25
|
/** feature specific APIs */
|
|
27
26
|
(0, _setPageViewName.setupSetPageViewNameAPI)(agentRef);
|
|
28
|
-
|
|
29
|
-
/** messages from the register API that can trigger a new RUM call */
|
|
30
|
-
this.ee.on('api-send-rum', (attrs, target) => (0, _handle.handle)('send-rum', [attrs, target], undefined, this.featureName, this.ee));
|
|
31
27
|
this.importAggregator(agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "page_view_event-aggregate" */'../aggregate'))));
|
|
32
28
|
}
|
|
33
29
|
setupInspectionEvents(agentIdentifier) {
|
|
@@ -59,6 +59,19 @@ function setupAgentSession(agentRef) {
|
|
|
59
59
|
(0, _registerHandler.registerHandler)('api-setUserId', (time, key, value) => {
|
|
60
60
|
agentRef.runtime.session.syncCustomAttribute(key, value);
|
|
61
61
|
}, 'session', sharedEE);
|
|
62
|
+
(0, _registerHandler.registerHandler)('api-consent', accept => {
|
|
63
|
+
agentRef.runtime.session.write({
|
|
64
|
+
consent: accept === undefined ? true : accept
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// call sendRum if it wasn't called yet
|
|
68
|
+
agentRef.features.page_view_event.onAggregateImported.then(loaded => {
|
|
69
|
+
const pveAgg = agentRef.features.page_view_event.featAggregate;
|
|
70
|
+
if (loaded && !pveAgg.sentRum) {
|
|
71
|
+
pveAgg.sendRum();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}, 'session', sharedEE);
|
|
62
75
|
(0, _drain.drain)(agentRef.agentIdentifier, 'session');
|
|
63
76
|
return agentRef.runtime.session;
|
|
64
77
|
}
|
|
@@ -50,7 +50,10 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
50
50
|
* @type {Promise} Assigned immediately after @see importAggregator runs. Serves as a signal for when the inner async fn finishes execution. Useful for features to await
|
|
51
51
|
* one another if there are inter-features dependencies.
|
|
52
52
|
*/
|
|
53
|
-
this.
|
|
53
|
+
this.loadedSuccessfully = undefined;
|
|
54
|
+
this.onAggregateImported = new Promise(resolve => {
|
|
55
|
+
this.loadedSuccessfully = resolve;
|
|
56
|
+
});
|
|
54
57
|
|
|
55
58
|
/**
|
|
56
59
|
* used in conjunction with newrelic.start() to defer harvesting in features
|
|
@@ -82,10 +85,6 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
82
85
|
*/
|
|
83
86
|
importAggregator(agentRef, fetchAggregator, argsObjFromInstrument = {}) {
|
|
84
87
|
if (this.featAggregate) return;
|
|
85
|
-
let loadedSuccessfully;
|
|
86
|
-
this.onAggregateImported = new Promise(resolve => {
|
|
87
|
-
loadedSuccessfully = resolve;
|
|
88
|
-
});
|
|
89
88
|
const importLater = async () => {
|
|
90
89
|
// wait for the deferred promise to resolve before proceeding
|
|
91
90
|
// this will resolve immediately if the feature is auto-started,
|
|
@@ -113,7 +112,7 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
113
112
|
try {
|
|
114
113
|
if (!this.#shouldImportAgg(this.featureName, session, agentRef.init)) {
|
|
115
114
|
(0, _drain.drain)(this.agentIdentifier, this.featureName);
|
|
116
|
-
loadedSuccessfully(false); // aggregate module isn't loaded at all
|
|
115
|
+
this.loadedSuccessfully(false); // aggregate module isn't loaded at all
|
|
117
116
|
return;
|
|
118
117
|
}
|
|
119
118
|
const {
|
|
@@ -121,13 +120,13 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
121
120
|
} = await fetchAggregator();
|
|
122
121
|
this.featAggregate = new Aggregate(agentRef, argsObjFromInstrument);
|
|
123
122
|
agentRef.runtime.harvester.initializedAggregates.push(this.featAggregate); // "subscribe" the feature to future harvest intervals (PVE will start the timer)
|
|
124
|
-
loadedSuccessfully(true);
|
|
123
|
+
this.loadedSuccessfully(true);
|
|
125
124
|
} catch (e) {
|
|
126
125
|
(0, _console.warn)(34, e);
|
|
127
126
|
this.abortHandler?.(); // undo any important alterations made to the page
|
|
128
127
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
129
128
|
(0, _drain.drain)(this.agentIdentifier, this.featureName, true);
|
|
130
|
-
loadedSuccessfully(false);
|
|
129
|
+
this.loadedSuccessfully(false);
|
|
131
130
|
if (this.ee) this.ee.abort();
|
|
132
131
|
}
|
|
133
132
|
};
|
|
@@ -64,6 +64,17 @@ class RegisteredEntity {
|
|
|
64
64
|
(0, _console.warn)(35, 'recordCustomEvent');
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Measures a task that is recorded as a BrowserPerformance event.
|
|
69
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/measure/}
|
|
70
|
+
* @param {string} name The name of the task
|
|
71
|
+
* @param {{start: number, end: number, duration: number, customAttributes: object}} [options] An object used to control the way the measure API operates
|
|
72
|
+
* @returns {{start: number, end: number, duration: number, customAttributes: object}} Measurement details
|
|
73
|
+
*/
|
|
74
|
+
measure(name, options) {
|
|
75
|
+
(0, _console.warn)(35, 'measure');
|
|
76
|
+
}
|
|
77
|
+
|
|
67
78
|
/**
|
|
68
79
|
* Adds a user-defined attribute name and value to subsequent events on the page for the registered target. Note -- the persist flag does not work with the register API.
|
|
69
80
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcustomattribute/}
|
|
@@ -19,6 +19,7 @@ var _setCustomAttribute = require("./api/setCustomAttribute");
|
|
|
19
19
|
var _setUserId = require("./api/setUserId");
|
|
20
20
|
var _setApplicationVersion = require("./api/setApplicationVersion");
|
|
21
21
|
var _start = require("./api/start");
|
|
22
|
+
var _consent = require("./api/consent");
|
|
22
23
|
/**
|
|
23
24
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
24
25
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -77,6 +78,7 @@ class Agent extends _agentBase.AgentBase {
|
|
|
77
78
|
(0, _setUserId.setupSetUserIdAPI)(this);
|
|
78
79
|
(0, _setApplicationVersion.setupSetApplicationVersionAPI)(this);
|
|
79
80
|
(0, _start.setupStartAPI)(this);
|
|
81
|
+
(0, _consent.setupConsentAPI)(this);
|
|
80
82
|
this.run();
|
|
81
83
|
}
|
|
82
84
|
get config() {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.setupConsentAPI = setupConsentAPI;
|
|
7
|
+
var _constants = require("./constants");
|
|
8
|
+
var _sharedHandlers = require("./sharedHandlers");
|
|
9
|
+
var _handle = require("../../common/event-emitter/handle");
|
|
10
|
+
var _console = require("../../common/util/console");
|
|
11
|
+
/**
|
|
12
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
13
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
function setupConsentAPI(agent) {
|
|
17
|
+
(0, _sharedHandlers.setupAPI)(_constants.CONSENT, function (accept) {
|
|
18
|
+
if (accept !== undefined && typeof accept !== 'boolean') {
|
|
19
|
+
(0, _console.warn)(65, typeof accept);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
(0, _handle.handle)(_constants.prefix + _constants.CONSENT, [accept], undefined, 'session', agent.ee);
|
|
23
|
+
}, agent);
|
|
24
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.spaPrefix = exports.prefix = exports.WRAP_LOGGER = exports.START = exports.SET_USER_ID = exports.SET_PAGE_VIEW_NAME = exports.SET_ERROR_HANDLER = exports.SET_CUSTOM_ATTRIBUTE = exports.SET_CURRENT_ROUTE_NAME = exports.SET_APPLICATION_VERSION = exports.REGISTER = exports.RECORD_REPLAY = exports.RECORD_CUSTOM_EVENT = exports.PAUSE_REPLAY = exports.NOTICE_ERROR = exports.MEASURE = exports.LOG = exports.INTERACTION = exports.FINISHED = exports.ADD_TO_TRACE = exports.ADD_RELEASE = exports.ADD_PAGE_ACTION = void 0;
|
|
6
|
+
exports.spaPrefix = exports.prefix = exports.WRAP_LOGGER = exports.START = exports.SET_USER_ID = exports.SET_PAGE_VIEW_NAME = exports.SET_ERROR_HANDLER = exports.SET_CUSTOM_ATTRIBUTE = exports.SET_CURRENT_ROUTE_NAME = exports.SET_APPLICATION_VERSION = exports.REGISTER = exports.RECORD_REPLAY = exports.RECORD_CUSTOM_EVENT = exports.PAUSE_REPLAY = exports.NOTICE_ERROR = exports.MEASURE = exports.LOG = exports.INTERACTION = exports.FINISHED = exports.CONSENT = exports.ADD_TO_TRACE = exports.ADD_RELEASE = exports.ADD_PAGE_ACTION = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
9
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -29,4 +29,5 @@ const SET_PAGE_VIEW_NAME = exports.SET_PAGE_VIEW_NAME = 'setPageViewName';
|
|
|
29
29
|
const SET_USER_ID = exports.SET_USER_ID = 'setUserId';
|
|
30
30
|
const START = exports.START = 'start';
|
|
31
31
|
const WRAP_LOGGER = exports.WRAP_LOGGER = 'wrapLogger';
|
|
32
|
-
const MEASURE = exports.MEASURE = 'measure';
|
|
32
|
+
const MEASURE = exports.MEASURE = 'measure';
|
|
33
|
+
const CONSENT = exports.CONSENT = 'consent';
|
|
@@ -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
|
}
|
|
@@ -14,6 +14,7 @@ exports.default = void 0;
|
|
|
14
14
|
* @property {(message: string, options?: { customAttributes?: object, level?: 'ERROR' | 'TRACE' | 'DEBUG' | 'INFO' | 'WARN'}) => void} log - Capture a log for the registered entity.
|
|
15
15
|
* @property {(error: Error | string, customAttributes?: object) => void} noticeError - Notice an error for the registered entity.
|
|
16
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.
|
|
17
18
|
* @property {(value: string | null) => void} setApplicationVersion - Add an application.version attribute to all outgoing data for the registered entity.
|
|
18
19
|
* @property {(name: string, value: string | number | boolean | null, persist?: boolean) => void} setCustomAttribute - Add a custom attribute to outgoing data for the registered entity.
|
|
19
20
|
* @property {(value: string | null) => void} setUserId - Add an enduser.id attribute to all outgoing API data for the registered entity.
|
|
@@ -17,6 +17,7 @@ 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");
|
|
20
21
|
var _recordCustomEvent = require("./recordCustomEvent");
|
|
21
22
|
/**
|
|
22
23
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
@@ -101,6 +102,13 @@ function buildRegisterApi(agentRef, target) {
|
|
|
101
102
|
...(options.customAttributes || {})
|
|
102
103
|
}
|
|
103
104
|
}, agentRef], target),
|
|
105
|
+
measure: (name, options = {}) => report(_measure.measure, [name, {
|
|
106
|
+
...options,
|
|
107
|
+
customAttributes: {
|
|
108
|
+
...attrs,
|
|
109
|
+
...(options.customAttributes || {})
|
|
110
|
+
}
|
|
111
|
+
}, agentRef], target),
|
|
104
112
|
noticeError: (error, attributes = {}) => report(_noticeError.noticeError, [error, {
|
|
105
113
|
...attrs,
|
|
106
114
|
...attributes
|
|
@@ -224,11 +224,21 @@ class ApiBase {
|
|
|
224
224
|
* Measures a task that is recorded as a BrowserPerformance event.
|
|
225
225
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/measure/}
|
|
226
226
|
* @param {string} name The name of the task
|
|
227
|
-
* @param {object
|
|
227
|
+
* @param {{start: number, end: number, duration: number, customAttributes: object}} [options] An object used to control the way the measure API operates
|
|
228
228
|
* @returns {{start: number, end: number, duration: number, customAttributes: object}} Measurement details
|
|
229
229
|
*/
|
|
230
230
|
measure(name, options) {
|
|
231
231
|
return this.#callMethod(_constants.MEASURE, name, options);
|
|
232
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
|
+
}
|
|
233
243
|
}
|
|
234
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.
|
|
@@ -61,6 +61,7 @@ export class Harvester {
|
|
|
61
61
|
endpointVersion: aggregateInst.harvestEndpointVersion || 1
|
|
62
62
|
};
|
|
63
63
|
if (aggregateInst.blocked) return output;
|
|
64
|
+
if (this.agentRef.init?.browser_consent_mode?.enabled && !this.agentRef.runtime?.session?.state?.consent) return output;
|
|
64
65
|
const submitMethod = getSubmitMethod(localOpts);
|
|
65
66
|
if (!submitMethod) return output;
|
|
66
67
|
const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === xhrMethod; // always retry all features harvests except for final
|
|
@@ -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({
|
|
@@ -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
|
});
|
|
@@ -24,6 +24,8 @@ export class Aggregate extends AggregateBase {
|
|
|
24
24
|
static featureName = CONSTANTS.FEATURE_NAME;
|
|
25
25
|
constructor(agentRef) {
|
|
26
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
|
+
|
|
27
29
|
this.timeToFirstByte = 0;
|
|
28
30
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
29
31
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
@@ -117,9 +119,9 @@ export class Aggregate extends AggregateBase {
|
|
|
117
119
|
return queryParameters;
|
|
118
120
|
};
|
|
119
121
|
this.events.add(body);
|
|
120
|
-
this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
122
|
+
if (this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
121
123
|
sendEmptyBody: true
|
|
122
|
-
});
|
|
124
|
+
}).ranSend) this.sentRum = true;
|
|
123
125
|
}
|
|
124
126
|
serializer(eventBuffer) {
|
|
125
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
|
|
@@ -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) {
|
|
@@ -52,6 +52,19 @@ export function setupAgentSession(agentRef) {
|
|
|
52
52
|
registerHandler('api-setUserId', (time, key, value) => {
|
|
53
53
|
agentRef.runtime.session.syncCustomAttribute(key, value);
|
|
54
54
|
}, 'session', sharedEE);
|
|
55
|
+
registerHandler('api-consent', accept => {
|
|
56
|
+
agentRef.runtime.session.write({
|
|
57
|
+
consent: accept === undefined ? true : accept
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// call sendRum if it wasn't called yet
|
|
61
|
+
agentRef.features.page_view_event.onAggregateImported.then(loaded => {
|
|
62
|
+
const pveAgg = agentRef.features.page_view_event.featAggregate;
|
|
63
|
+
if (loaded && !pveAgg.sentRum) {
|
|
64
|
+
pveAgg.sendRum();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}, 'session', sharedEE);
|
|
55
68
|
drain(agentRef.agentIdentifier, 'session');
|
|
56
69
|
return agentRef.runtime.session;
|
|
57
70
|
}
|
|
@@ -48,7 +48,10 @@ export class InstrumentBase extends FeatureBase {
|
|
|
48
48
|
* @type {Promise} Assigned immediately after @see importAggregator runs. Serves as a signal for when the inner async fn finishes execution. Useful for features to await
|
|
49
49
|
* one another if there are inter-features dependencies.
|
|
50
50
|
*/
|
|
51
|
-
this.
|
|
51
|
+
this.loadedSuccessfully = undefined;
|
|
52
|
+
this.onAggregateImported = new Promise(resolve => {
|
|
53
|
+
this.loadedSuccessfully = resolve;
|
|
54
|
+
});
|
|
52
55
|
|
|
53
56
|
/**
|
|
54
57
|
* used in conjunction with newrelic.start() to defer harvesting in features
|
|
@@ -80,10 +83,6 @@ export class InstrumentBase extends FeatureBase {
|
|
|
80
83
|
*/
|
|
81
84
|
importAggregator(agentRef, fetchAggregator, argsObjFromInstrument = {}) {
|
|
82
85
|
if (this.featAggregate) return;
|
|
83
|
-
let loadedSuccessfully;
|
|
84
|
-
this.onAggregateImported = new Promise(resolve => {
|
|
85
|
-
loadedSuccessfully = resolve;
|
|
86
|
-
});
|
|
87
86
|
const importLater = async () => {
|
|
88
87
|
// wait for the deferred promise to resolve before proceeding
|
|
89
88
|
// this will resolve immediately if the feature is auto-started,
|
|
@@ -111,7 +110,7 @@ export class InstrumentBase extends FeatureBase {
|
|
|
111
110
|
try {
|
|
112
111
|
if (!this.#shouldImportAgg(this.featureName, session, agentRef.init)) {
|
|
113
112
|
drain(this.agentIdentifier, this.featureName);
|
|
114
|
-
loadedSuccessfully(false); // aggregate module isn't loaded at all
|
|
113
|
+
this.loadedSuccessfully(false); // aggregate module isn't loaded at all
|
|
115
114
|
return;
|
|
116
115
|
}
|
|
117
116
|
const {
|
|
@@ -119,13 +118,13 @@ export class InstrumentBase extends FeatureBase {
|
|
|
119
118
|
} = await fetchAggregator();
|
|
120
119
|
this.featAggregate = new Aggregate(agentRef, argsObjFromInstrument);
|
|
121
120
|
agentRef.runtime.harvester.initializedAggregates.push(this.featAggregate); // "subscribe" the feature to future harvest intervals (PVE will start the timer)
|
|
122
|
-
loadedSuccessfully(true);
|
|
121
|
+
this.loadedSuccessfully(true);
|
|
123
122
|
} catch (e) {
|
|
124
123
|
warn(34, e);
|
|
125
124
|
this.abortHandler?.(); // undo any important alterations made to the page
|
|
126
125
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
127
126
|
drain(this.agentIdentifier, this.featureName, true);
|
|
128
|
-
loadedSuccessfully(false);
|
|
127
|
+
this.loadedSuccessfully(false);
|
|
129
128
|
if (this.ee) this.ee.abort();
|
|
130
129
|
}
|
|
131
130
|
};
|
|
@@ -58,6 +58,17 @@ export class RegisteredEntity {
|
|
|
58
58
|
warn(35, 'recordCustomEvent');
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Measures a task that is recorded as a BrowserPerformance event.
|
|
63
|
+
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/measure/}
|
|
64
|
+
* @param {string} name The name of the task
|
|
65
|
+
* @param {{start: number, end: number, duration: number, customAttributes: object}} [options] An object used to control the way the measure API operates
|
|
66
|
+
* @returns {{start: number, end: number, duration: number, customAttributes: object}} Measurement details
|
|
67
|
+
*/
|
|
68
|
+
measure(name, options) {
|
|
69
|
+
warn(35, 'measure');
|
|
70
|
+
}
|
|
71
|
+
|
|
61
72
|
/**
|
|
62
73
|
* Adds a user-defined attribute name and value to subsequent events on the page for the registered target. Note -- the persist flag does not work with the register API.
|
|
63
74
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcustomattribute/}
|