@newrelic/browser-agent 1.315.0 → 1.316.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -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/session/constants.js +3 -4
- package/dist/cjs/common/session/session-entity.js +2 -2
- package/dist/cjs/common/session/session-key.js +22 -0
- package/dist/cjs/features/page_view_event/aggregate/index.js +0 -5
- package/dist/cjs/features/session_replay/instrument/index.js +4 -2
- package/dist/cjs/features/utils/agent-session.js +7 -6
- package/dist/cjs/features/utils/aggregate-base.js +0 -34
- package/dist/cjs/features/utils/instrument-base.js +47 -2
- package/dist/cjs/loaders/api-base.js +1 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/session/constants.js +2 -3
- package/dist/esm/common/session/session-entity.js +3 -3
- package/dist/esm/common/session/session-key.js +16 -0
- package/dist/esm/features/page_view_event/aggregate/index.js +0 -5
- package/dist/esm/features/session_replay/instrument/index.js +5 -3
- package/dist/esm/features/utils/agent-session.js +3 -2
- package/dist/esm/features/utils/aggregate-base.js +0 -34
- package/dist/esm/features/utils/instrument-base.js +46 -2
- package/dist/esm/loaders/api-base.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/session/constants.d.ts +2 -3
- package/dist/types/common/session/constants.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.d.ts +1 -1
- package/dist/types/common/session/session-key.d.ts +2 -0
- package/dist/types/common/session/session-key.d.ts.map +1 -0
- package/dist/types/features/page_view_event/aggregate/index.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/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/api-base.d.ts +1 -1
- package/package.json +1 -1
- package/src/common/session/constants.js +2 -3
- package/src/common/session/session-entity.js +3 -3
- package/src/common/session/session-key.js +17 -0
- package/src/features/page_view_event/aggregate/index.js +0 -5
- package/src/features/session_replay/instrument/index.js +5 -3
- package/src/features/utils/agent-session.js +3 -2
- package/src/features/utils/aggregate-base.js +0 -32
- package/src/features/utils/instrument-base.js +45 -2
- package/src/loaders/api-base.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.316.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.315.0...v1.316.0) (2026-06-01)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Use app-namespaced keys for session ([#1776](https://github.com/newrelic/newrelic-browser-agent/issues/1776)) ([60ec5bf](https://github.com/newrelic/newrelic-browser-agent/commit/60ec5bf566d27d68e59c827f08dcd8dd73d8cd2c))
|
|
12
|
+
|
|
6
13
|
## [1.315.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.314.0...v1.315.0) (2026-05-26)
|
|
7
14
|
|
|
8
15
|
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.
|
|
20
|
+
const VERSION = exports.VERSION = "1.316.0";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.
|
|
20
|
+
const VERSION = exports.VERSION = "1.316.0";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.SESSION_STORAGE_KEY_PREFIX = exports.SESSION_EVENT_TYPES = exports.SESSION_EVENTS = exports.MODE = exports.DEFAULT_INACTIVE_MS = exports.DEFAULT_EXPIRES_MS = void 0;
|
|
7
7
|
/**
|
|
8
|
-
* Copyright 2020-
|
|
8
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
9
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
10
10
|
*/
|
|
11
|
-
const
|
|
12
|
-
const DEFAULT_KEY = exports.DEFAULT_KEY = 'SESSION';
|
|
11
|
+
const SESSION_STORAGE_KEY_PREFIX = exports.SESSION_STORAGE_KEY_PREFIX = 'NRBA_SESSION::';
|
|
13
12
|
const DEFAULT_EXPIRES_MS = exports.DEFAULT_EXPIRES_MS = 14400000;
|
|
14
13
|
const DEFAULT_INACTIVE_MS = exports.DEFAULT_INACTIVE_MS = 1800000;
|
|
15
14
|
const SESSION_EVENTS = exports.SESSION_EVENTS = {
|
|
@@ -45,7 +45,7 @@ const model = {
|
|
|
45
45
|
class SessionEntity {
|
|
46
46
|
/**
|
|
47
47
|
* Create a self-managing Session Entity. This entity is scoped to the agent which triggered it, allowing for multiple simultaneous session objects to exist.
|
|
48
|
-
|
|
48
|
+
* Session data is stored at NRBA_SESSION::{key}, where key can be app-scoped by the caller to avoid collisions across multiple agents on the same origin.
|
|
49
49
|
* The value can be overridden in the constructor, but will default to a unique 16 character hex string
|
|
50
50
|
* expiresMs and inactiveMs are used to "expire" the session, but can be overridden in the constructor. Pass 0 to disable expiration timers.
|
|
51
51
|
*/
|
|
@@ -174,7 +174,7 @@ class SessionEntity {
|
|
|
174
174
|
|
|
175
175
|
// This is the actual key appended to the storage API
|
|
176
176
|
get lookupKey() {
|
|
177
|
-
return "".concat(_constants.
|
|
177
|
+
return "".concat(_constants.SESSION_STORAGE_KEY_PREFIX).concat(this.key);
|
|
178
178
|
}
|
|
179
179
|
sync(data) {
|
|
180
180
|
Object.assign(this.state, data);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getAppSessionHash = getAppSessionHash;
|
|
7
|
+
/**
|
|
8
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
9
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
10
|
+
*/
|
|
11
|
+
// Deterministic 32-bit FNV-1a hash, rendered as a fixed 8-char hex string.
|
|
12
|
+
function hashTo8Hex(value) {
|
|
13
|
+
let hash = 0x811c9dc5;
|
|
14
|
+
for (let i = 0; i < value.length; i++) {
|
|
15
|
+
hash ^= value.charCodeAt(i);
|
|
16
|
+
hash = Math.imul(hash, 0x01000193);
|
|
17
|
+
}
|
|
18
|
+
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
19
|
+
}
|
|
20
|
+
function getAppSessionHash(licenseKey, applicationID) {
|
|
21
|
+
return hashTo8Hex("".concat(String(licenseKey), ":").concat(String(applicationID)));
|
|
22
|
+
}
|
|
@@ -7,7 +7,6 @@ exports.Aggregate = void 0;
|
|
|
7
7
|
var _runtime = require("../../../common/constants/runtime");
|
|
8
8
|
var _navTiming = require("../../../common/timing/nav-timing");
|
|
9
9
|
var _stringify = require("../../../common/util/stringify");
|
|
10
|
-
var _info = require("../../../common/config/info");
|
|
11
10
|
var CONSTANTS = _interopRequireWildcard(require("../constants"));
|
|
12
11
|
var _initializedFeatures = require("./initialized-features");
|
|
13
12
|
var _featureFlags = require("../../../common/util/feature-flags");
|
|
@@ -39,10 +38,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
39
38
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
40
39
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
41
40
|
this.retries = 0;
|
|
42
|
-
if (!(0, _info.isValid)(agentRef.info)) {
|
|
43
|
-
this.ee.abort();
|
|
44
|
-
return (0, _console.warn)(43);
|
|
45
|
-
}
|
|
46
41
|
agentRef.runtime.timeKeeper = new _timeKeeper.TimeKeeper(agentRef.runtime.session);
|
|
47
42
|
if (_runtime.isBrowserScope) {
|
|
48
43
|
_timeToFirstByte.timeToFirstByte.subscribe(({
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.SessionReplay = exports.Instrument = void 0;
|
|
7
7
|
var _handle = require("../../../common/event-emitter/handle");
|
|
8
8
|
var _constants = require("../../../common/session/constants");
|
|
9
|
+
var _sessionKey = require("../../../common/session/session-key");
|
|
9
10
|
var _instrumentBase = require("../../utils/instrument-base");
|
|
10
11
|
var _utils = require("../shared/utils");
|
|
11
12
|
var _constants2 = require("../constants");
|
|
@@ -13,7 +14,7 @@ var _recordReplay = require("../../../loaders/api/recordReplay");
|
|
|
13
14
|
var _pauseReplay = require("../../../loaders/api/pauseReplay");
|
|
14
15
|
var _constants3 = require("../../../loaders/api/constants");
|
|
15
16
|
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); } /**
|
|
16
|
-
* Copyright 2020-
|
|
17
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
17
18
|
* SPDX-License-Identifier: Apache-2.0
|
|
18
19
|
*/ /**
|
|
19
20
|
* @file Primes the Session Replay feature for lazy loading.
|
|
@@ -31,8 +32,9 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
31
32
|
(0, _recordReplay.setupRecordReplayAPI)(agentRef);
|
|
32
33
|
(0, _pauseReplay.setupPauseReplayAPI)(agentRef);
|
|
33
34
|
let session;
|
|
35
|
+
const fullNamespacedKey = "".concat(_constants.SESSION_STORAGE_KEY_PREFIX).concat((0, _sessionKey.getAppSessionHash)(agentRef.info.licenseKey, agentRef.info.applicationID));
|
|
34
36
|
try {
|
|
35
|
-
session = JSON.parse(localStorage.getItem(
|
|
37
|
+
session = JSON.parse(localStorage.getItem(fullNamespacedKey));
|
|
36
38
|
} catch (err) {}
|
|
37
39
|
if ((0, _utils.hasReplayPrerequisite)(agentRef.init)) {
|
|
38
40
|
this.ee.on(_constants3.RECORD_REPLAY, () => this.#apiStartOrRestartReplay());
|
|
@@ -8,12 +8,12 @@ var _drain = require("../../common/drain/drain");
|
|
|
8
8
|
var _registerHandler = require("../../common/event-emitter/register-handler");
|
|
9
9
|
var _sessionEntity = require("../../common/session/session-entity");
|
|
10
10
|
var _localStorage = require("../../common/storage/local-storage.js");
|
|
11
|
-
var
|
|
11
|
+
var _sessionKey = require("../../common/session/session-key");
|
|
12
12
|
var _info = require("../../common/config/info");
|
|
13
13
|
var _attributeSize = require("../../common/util/attribute-size");
|
|
14
14
|
var _handle = require("../../common/event-emitter/handle");
|
|
15
|
-
var
|
|
16
|
-
var
|
|
15
|
+
var _constants = require("../../loaders/api/constants");
|
|
16
|
+
var _constants2 = require("../metrics/constants");
|
|
17
17
|
var _features = require("../../loaders/features/features");
|
|
18
18
|
var _sharedHandlers = require("../../loaders/api/sharedHandlers");
|
|
19
19
|
/**
|
|
@@ -25,9 +25,10 @@ function setupAgentSession(agentRef) {
|
|
|
25
25
|
if (agentRef.runtime.session) return agentRef.runtime.session; // already setup
|
|
26
26
|
|
|
27
27
|
const sessionInit = agentRef.init.session;
|
|
28
|
+
const namespacedKey = (0, _sessionKey.getAppSessionHash)(agentRef.info.licenseKey, agentRef.info.applicationID);
|
|
28
29
|
agentRef.runtime.session = new _sessionEntity.SessionEntity({
|
|
29
30
|
agentRef,
|
|
30
|
-
key:
|
|
31
|
+
key: namespacedKey,
|
|
31
32
|
storage: new _localStorage.LocalStorage(),
|
|
32
33
|
expiresMs: sessionInit?.expiresMs,
|
|
33
34
|
inactiveMs: sessionInit?.inactiveMs
|
|
@@ -65,8 +66,8 @@ function setupAgentSession(agentRef) {
|
|
|
65
66
|
}, 'session', sharedEE);
|
|
66
67
|
(0, _registerHandler.registerHandler)('api-setUserIdAndResetSession', value => {
|
|
67
68
|
agentRef.runtime.session.reset();
|
|
68
|
-
(0, _handle.handle)(
|
|
69
|
-
(0, _sharedHandlers.appendJsAttribute)(agentRef, 'enduser.id', value,
|
|
69
|
+
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['API/' + _constants.SET_USER_ID + '/resetSession/called'], undefined, _features.FEATURE_NAMES.metrics, sharedEE);
|
|
70
|
+
(0, _sharedHandlers.appendJsAttribute)(agentRef, 'enduser.id', value, _constants.SET_USER_ID, true);
|
|
70
71
|
}, 'session', sharedEE);
|
|
71
72
|
(0, _registerHandler.registerHandler)('api-consent', accept => {
|
|
72
73
|
agentRef.runtime.session.write({
|
|
@@ -5,9 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.AggregateBase = void 0;
|
|
7
7
|
var _featureBase = require("./feature-base");
|
|
8
|
-
var _info = require("../../common/config/info");
|
|
9
|
-
var _configure = require("../../loaders/configure/configure");
|
|
10
|
-
var _nreum = require("../../common/window/nreum");
|
|
11
8
|
var _drain = require("../../common/drain/drain");
|
|
12
9
|
var _obfuscate = require("../../common/util/obfuscate");
|
|
13
10
|
var _features = require("../../loaders/features/features");
|
|
@@ -30,7 +27,6 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
30
27
|
*/
|
|
31
28
|
constructor(agentRef, featureName) {
|
|
32
29
|
super(agentRef, featureName);
|
|
33
|
-
this.checkConfiguration(agentRef);
|
|
34
30
|
this.doOnceForAllAggregate(agentRef);
|
|
35
31
|
|
|
36
32
|
/** @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 */
|
|
@@ -182,36 +178,6 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
182
178
|
this.events.clearSave(this.harvestOpts);
|
|
183
179
|
}
|
|
184
180
|
|
|
185
|
-
/**
|
|
186
|
-
* Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
|
|
187
|
-
* loader configurations may appear after the loader code is executed.
|
|
188
|
-
*/
|
|
189
|
-
checkConfiguration(existingAgent) {
|
|
190
|
-
// NOTE: This check has to happen at aggregator load time
|
|
191
|
-
if (!(0, _info.isValid)(existingAgent.info)) {
|
|
192
|
-
const cdn = (0, _nreum.gosCDN)();
|
|
193
|
-
let jsAttributes = {
|
|
194
|
-
...cdn.info?.jsAttributes
|
|
195
|
-
};
|
|
196
|
-
try {
|
|
197
|
-
jsAttributes = {
|
|
198
|
-
...jsAttributes,
|
|
199
|
-
...existingAgent.info?.jsAttributes
|
|
200
|
-
};
|
|
201
|
-
} catch (err) {
|
|
202
|
-
// do nothing
|
|
203
|
-
}
|
|
204
|
-
(0, _configure.configure)(existingAgent, {
|
|
205
|
-
...cdn,
|
|
206
|
-
info: {
|
|
207
|
-
...cdn.info,
|
|
208
|
-
jsAttributes
|
|
209
|
-
},
|
|
210
|
-
runtime: existingAgent.runtime
|
|
211
|
-
}, existingAgent.runtime.loaderType);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
181
|
/**
|
|
216
182
|
* These are actions related to shared resources that should be initialized once by whichever feature Aggregate subclass loads first.
|
|
217
183
|
* This method should run after checkConfiguration, which may reset the agent's info/runtime object that is used here.
|
|
@@ -9,6 +9,9 @@ var _featureBase = require("./feature-base");
|
|
|
9
9
|
var _load = require("../../common/window/load");
|
|
10
10
|
var _runtime = require("../../common/constants/runtime");
|
|
11
11
|
var _console = require("../../common/util/console");
|
|
12
|
+
var _info = require("../../common/config/info");
|
|
13
|
+
var _configure = require("../../loaders/configure/configure");
|
|
14
|
+
var _nreum = require("../../common/window/nreum");
|
|
12
15
|
var _features = require("../../loaders/features/features");
|
|
13
16
|
var _utils = require("../session_replay/shared/utils");
|
|
14
17
|
var _featureGates = require("./feature-gates");
|
|
@@ -20,9 +23,11 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
20
23
|
* SPDX-License-Identifier: Apache-2.0
|
|
21
24
|
*/ /**
|
|
22
25
|
* @file Defines `InstrumentBase` to be used as the super of the Instrument classes implemented by each feature.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
26
|
+
* Validates and loads feature aggregates, including a one-time late configuration check before import.
|
|
27
|
+
* Inherits `blocked` behavior from [FeatureBase]{@link ./feature-base}.
|
|
25
28
|
*/
|
|
29
|
+
const checkedAgents = new WeakSet();
|
|
30
|
+
|
|
26
31
|
/**
|
|
27
32
|
* Base class for instrumenting a feature.
|
|
28
33
|
* @extends FeatureBase
|
|
@@ -89,6 +94,14 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
89
94
|
// this will resolve immediately if the feature is auto-started,
|
|
90
95
|
// or otherwise when the manual-start-all event is emitted by the start API
|
|
91
96
|
await this.deferred;
|
|
97
|
+
this.#checkConfiguration(agentRef); // check for late-appearing 'info' config on the page
|
|
98
|
+
if (!(0, _info.isValid)(agentRef.info)) {
|
|
99
|
+
// if there still isn't valid info, then we can't proceed with session setup or importing the aggregates
|
|
100
|
+
(0, _console.warn)(43);
|
|
101
|
+
agentRef.ee.abort();
|
|
102
|
+
this.loadedSuccessfully(false);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
92
105
|
let session;
|
|
93
106
|
try {
|
|
94
107
|
if ((0, _featureGates.canEnableSessionTracking)(agentRef.init)) {
|
|
@@ -153,5 +166,37 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
153
166
|
return true;
|
|
154
167
|
}
|
|
155
168
|
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
|
|
172
|
+
* loader configurations may appear after the loader code is executed.
|
|
173
|
+
*/
|
|
174
|
+
#checkConfiguration(existingAgent) {
|
|
175
|
+
if (checkedAgents.has(existingAgent)) return;
|
|
176
|
+
checkedAgents.add(existingAgent);
|
|
177
|
+
// NOTE: This check has to happen at load time
|
|
178
|
+
if (!(0, _info.isValid)(existingAgent.info)) {
|
|
179
|
+
const cdn = (0, _nreum.gosCDN)();
|
|
180
|
+
let jsAttributes = {
|
|
181
|
+
...cdn.info?.jsAttributes
|
|
182
|
+
};
|
|
183
|
+
try {
|
|
184
|
+
jsAttributes = {
|
|
185
|
+
...jsAttributes,
|
|
186
|
+
...existingAgent.info?.jsAttributes
|
|
187
|
+
};
|
|
188
|
+
} catch (err) {
|
|
189
|
+
// do nothing
|
|
190
|
+
}
|
|
191
|
+
(0, _configure.configure)(existingAgent, {
|
|
192
|
+
...cdn,
|
|
193
|
+
info: {
|
|
194
|
+
...cdn.info,
|
|
195
|
+
jsAttributes
|
|
196
|
+
},
|
|
197
|
+
runtime: existingAgent.runtime
|
|
198
|
+
}, existingAgent.runtime.loaderType);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
156
201
|
}
|
|
157
202
|
exports.InstrumentBase = InstrumentBase;
|
|
@@ -235,7 +235,7 @@ class ApiBase {
|
|
|
235
235
|
|
|
236
236
|
/**
|
|
237
237
|
* Accepts or rejects consent when the agent is configured to require consent before harvesting.
|
|
238
|
-
|
|
238
|
+
* The consent state is stored in the agent session object in browser storage.
|
|
239
239
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/consent/}
|
|
240
240
|
* @param {boolean?} accept Whether to accept or reject consent. Defaults to true (accept) if left undefined.
|
|
241
241
|
*/
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
export const
|
|
6
|
-
export const DEFAULT_KEY = 'SESSION';
|
|
5
|
+
export const SESSION_STORAGE_KEY_PREFIX = 'NRBA_SESSION::';
|
|
7
6
|
export const DEFAULT_EXPIRES_MS = 14400000;
|
|
8
7
|
export const DEFAULT_INACTIVE_MS = 1800000;
|
|
9
8
|
export const SESSION_EVENTS = {
|
|
@@ -7,7 +7,7 @@ import { warn } from '../util/console';
|
|
|
7
7
|
import { stringify } from '../util/stringify';
|
|
8
8
|
import { Timer } from '../timer/timer';
|
|
9
9
|
import { isBrowserScope } from '../constants/runtime';
|
|
10
|
-
import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, MODE,
|
|
10
|
+
import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, MODE, SESSION_EVENTS, SESSION_EVENT_TYPES, SESSION_STORAGE_KEY_PREFIX } from './constants';
|
|
11
11
|
import { InteractionTimer } from '../timer/interaction-timer';
|
|
12
12
|
import { wrapEvents } from '../wrap/wrap-events';
|
|
13
13
|
import { getModeledObject } from '../config/configurable';
|
|
@@ -39,7 +39,7 @@ const model = {
|
|
|
39
39
|
export class SessionEntity {
|
|
40
40
|
/**
|
|
41
41
|
* Create a self-managing Session Entity. This entity is scoped to the agent which triggered it, allowing for multiple simultaneous session objects to exist.
|
|
42
|
-
|
|
42
|
+
* Session data is stored at NRBA_SESSION::{key}, where key can be app-scoped by the caller to avoid collisions across multiple agents on the same origin.
|
|
43
43
|
* The value can be overridden in the constructor, but will default to a unique 16 character hex string
|
|
44
44
|
* expiresMs and inactiveMs are used to "expire" the session, but can be overridden in the constructor. Pass 0 to disable expiration timers.
|
|
45
45
|
*/
|
|
@@ -168,7 +168,7 @@ export class SessionEntity {
|
|
|
168
168
|
|
|
169
169
|
// This is the actual key appended to the storage API
|
|
170
170
|
get lookupKey() {
|
|
171
|
-
return "".concat(
|
|
171
|
+
return "".concat(SESSION_STORAGE_KEY_PREFIX).concat(this.key);
|
|
172
172
|
}
|
|
173
173
|
sync(data) {
|
|
174
174
|
Object.assign(this.state, data);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
// Deterministic 32-bit FNV-1a hash, rendered as a fixed 8-char hex string.
|
|
6
|
+
function hashTo8Hex(value) {
|
|
7
|
+
let hash = 0x811c9dc5;
|
|
8
|
+
for (let i = 0; i < value.length; i++) {
|
|
9
|
+
hash ^= value.charCodeAt(i);
|
|
10
|
+
hash = Math.imul(hash, 0x01000193);
|
|
11
|
+
}
|
|
12
|
+
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
13
|
+
}
|
|
14
|
+
export function getAppSessionHash(licenseKey, applicationID) {
|
|
15
|
+
return hashTo8Hex("".concat(String(licenseKey), ":").concat(String(applicationID)));
|
|
16
|
+
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import { globalScope, isBrowserScope, originTime, getNavigationEntry } from '../../../common/constants/runtime';
|
|
6
6
|
import { addPT, addPN } from '../../../common/timing/nav-timing';
|
|
7
7
|
import { stringify } from '../../../common/util/stringify';
|
|
8
|
-
import { isValid } from '../../../common/config/info';
|
|
9
8
|
import * as CONSTANTS from '../constants';
|
|
10
9
|
import { getActivatedFeaturesFlags } from './initialized-features';
|
|
11
10
|
import { activateFeatures } from '../../../common/util/feature-flags';
|
|
@@ -31,10 +30,6 @@ export class Aggregate extends AggregateBase {
|
|
|
31
30
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
32
31
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
33
32
|
this.retries = 0;
|
|
34
|
-
if (!isValid(agentRef.info)) {
|
|
35
|
-
this.ee.abort();
|
|
36
|
-
return warn(43);
|
|
37
|
-
}
|
|
38
33
|
agentRef.runtime.timeKeeper = new TimeKeeper(agentRef.runtime.session);
|
|
39
34
|
if (isBrowserScope) {
|
|
40
35
|
timeToFirstByte.subscribe(({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { handle } from '../../../common/event-emitter/handle';
|
|
10
|
-
import {
|
|
10
|
+
import { MODE, SESSION_STORAGE_KEY_PREFIX } from '../../../common/session/constants';
|
|
11
|
+
import { getAppSessionHash } from '../../../common/session/session-key';
|
|
11
12
|
import { InstrumentBase } from '../../utils/instrument-base';
|
|
12
13
|
import { hasReplayPrerequisite, isPreloadAllowed } from '../shared/utils';
|
|
13
14
|
import { ERROR_DURING_REPLAY, FEATURE_NAME, TRIGGERS } from '../constants';
|
|
@@ -27,8 +28,9 @@ export class Instrument extends InstrumentBase {
|
|
|
27
28
|
setupRecordReplayAPI(agentRef);
|
|
28
29
|
setupPauseReplayAPI(agentRef);
|
|
29
30
|
let session;
|
|
31
|
+
const fullNamespacedKey = "".concat(SESSION_STORAGE_KEY_PREFIX).concat(getAppSessionHash(agentRef.info.licenseKey, agentRef.info.applicationID));
|
|
30
32
|
try {
|
|
31
|
-
session = JSON.parse(localStorage.getItem(
|
|
33
|
+
session = JSON.parse(localStorage.getItem(fullNamespacedKey));
|
|
32
34
|
} catch (err) {}
|
|
33
35
|
if (hasReplayPrerequisite(agentRef.init)) {
|
|
34
36
|
this.ee.on(RECORD_REPLAY, () => this.#apiStartOrRestartReplay());
|
|
@@ -6,7 +6,7 @@ import { drain } from '../../common/drain/drain';
|
|
|
6
6
|
import { registerHandler } from '../../common/event-emitter/register-handler';
|
|
7
7
|
import { SessionEntity } from '../../common/session/session-entity';
|
|
8
8
|
import { LocalStorage } from '../../common/storage/local-storage.js';
|
|
9
|
-
import {
|
|
9
|
+
import { getAppSessionHash } from '../../common/session/session-key';
|
|
10
10
|
import { mergeInfo } from '../../common/config/info';
|
|
11
11
|
import { trackObjectAttributeSize } from '../../common/util/attribute-size';
|
|
12
12
|
import { handle } from '../../common/event-emitter/handle';
|
|
@@ -18,9 +18,10 @@ export function setupAgentSession(agentRef) {
|
|
|
18
18
|
if (agentRef.runtime.session) return agentRef.runtime.session; // already setup
|
|
19
19
|
|
|
20
20
|
const sessionInit = agentRef.init.session;
|
|
21
|
+
const namespacedKey = getAppSessionHash(agentRef.info.licenseKey, agentRef.info.applicationID);
|
|
21
22
|
agentRef.runtime.session = new SessionEntity({
|
|
22
23
|
agentRef,
|
|
23
|
-
key:
|
|
24
|
+
key: namespacedKey,
|
|
24
25
|
storage: new LocalStorage(),
|
|
25
26
|
expiresMs: sessionInit?.expiresMs,
|
|
26
27
|
inactiveMs: sessionInit?.inactiveMs
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { FeatureBase } from './feature-base';
|
|
6
|
-
import { isValid } from '../../common/config/info';
|
|
7
|
-
import { configure } from '../../loaders/configure/configure';
|
|
8
|
-
import { gosCDN } from '../../common/window/nreum';
|
|
9
6
|
import { drain } from '../../common/drain/drain';
|
|
10
7
|
import { Obfuscator } from '../../common/util/obfuscate';
|
|
11
8
|
import { FEATURE_NAMES } from '../../loaders/features/features';
|
|
@@ -23,7 +20,6 @@ export class AggregateBase extends FeatureBase {
|
|
|
23
20
|
*/
|
|
24
21
|
constructor(agentRef, featureName) {
|
|
25
22
|
super(agentRef, featureName);
|
|
26
|
-
this.checkConfiguration(agentRef);
|
|
27
23
|
this.doOnceForAllAggregate(agentRef);
|
|
28
24
|
|
|
29
25
|
/** @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 */
|
|
@@ -175,36 +171,6 @@ export class AggregateBase extends FeatureBase {
|
|
|
175
171
|
this.events.clearSave(this.harvestOpts);
|
|
176
172
|
}
|
|
177
173
|
|
|
178
|
-
/**
|
|
179
|
-
* Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
|
|
180
|
-
* loader configurations may appear after the loader code is executed.
|
|
181
|
-
*/
|
|
182
|
-
checkConfiguration(existingAgent) {
|
|
183
|
-
// NOTE: This check has to happen at aggregator load time
|
|
184
|
-
if (!isValid(existingAgent.info)) {
|
|
185
|
-
const cdn = gosCDN();
|
|
186
|
-
let jsAttributes = {
|
|
187
|
-
...cdn.info?.jsAttributes
|
|
188
|
-
};
|
|
189
|
-
try {
|
|
190
|
-
jsAttributes = {
|
|
191
|
-
...jsAttributes,
|
|
192
|
-
...existingAgent.info?.jsAttributes
|
|
193
|
-
};
|
|
194
|
-
} catch (err) {
|
|
195
|
-
// do nothing
|
|
196
|
-
}
|
|
197
|
-
configure(existingAgent, {
|
|
198
|
-
...cdn,
|
|
199
|
-
info: {
|
|
200
|
-
...cdn.info,
|
|
201
|
-
jsAttributes
|
|
202
|
-
},
|
|
203
|
-
runtime: existingAgent.runtime
|
|
204
|
-
}, existingAgent.runtime.loaderType);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
174
|
/**
|
|
209
175
|
* These are actions related to shared resources that should be initialized once by whichever feature Aggregate subclass loads first.
|
|
210
176
|
* This method should run after checkConfiguration, which may reset the agent's info/runtime object that is used here.
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @file Defines `InstrumentBase` to be used as the super of the Instrument classes implemented by each feature.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Validates and loads feature aggregates, including a one-time late configuration check before import.
|
|
9
|
+
* Inherits `blocked` behavior from [FeatureBase]{@link ./feature-base}.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { drain, registerDrain } from '../../common/drain/drain';
|
|
@@ -14,12 +14,16 @@ import { FeatureBase } from './feature-base';
|
|
|
14
14
|
import { onWindowLoad } from '../../common/window/load';
|
|
15
15
|
import { isBrowserScope } from '../../common/constants/runtime';
|
|
16
16
|
import { warn } from '../../common/util/console';
|
|
17
|
+
import { isValid } from '../../common/config/info';
|
|
18
|
+
import { configure } from '../../loaders/configure/configure';
|
|
19
|
+
import { gosCDN } from '../../common/window/nreum';
|
|
17
20
|
import { FEATURE_NAMES } from '../../loaders/features/features';
|
|
18
21
|
import { hasReplayPrerequisite } from '../session_replay/shared/utils';
|
|
19
22
|
import { canEnableSessionTracking } from './feature-gates';
|
|
20
23
|
import { single } from '../../common/util/invoke';
|
|
21
24
|
import { SESSION_ERROR } from '../../common/constants/agent-constants';
|
|
22
25
|
import { handle } from '../../common/event-emitter/handle';
|
|
26
|
+
const checkedAgents = new WeakSet();
|
|
23
27
|
|
|
24
28
|
/**
|
|
25
29
|
* Base class for instrumenting a feature.
|
|
@@ -87,6 +91,14 @@ export class InstrumentBase extends FeatureBase {
|
|
|
87
91
|
// this will resolve immediately if the feature is auto-started,
|
|
88
92
|
// or otherwise when the manual-start-all event is emitted by the start API
|
|
89
93
|
await this.deferred;
|
|
94
|
+
this.#checkConfiguration(agentRef); // check for late-appearing 'info' config on the page
|
|
95
|
+
if (!isValid(agentRef.info)) {
|
|
96
|
+
// if there still isn't valid info, then we can't proceed with session setup or importing the aggregates
|
|
97
|
+
warn(43);
|
|
98
|
+
agentRef.ee.abort();
|
|
99
|
+
this.loadedSuccessfully(false);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
90
102
|
let session;
|
|
91
103
|
try {
|
|
92
104
|
if (canEnableSessionTracking(agentRef.init)) {
|
|
@@ -151,4 +163,36 @@ export class InstrumentBase extends FeatureBase {
|
|
|
151
163
|
return true;
|
|
152
164
|
}
|
|
153
165
|
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
|
|
169
|
+
* loader configurations may appear after the loader code is executed.
|
|
170
|
+
*/
|
|
171
|
+
#checkConfiguration(existingAgent) {
|
|
172
|
+
if (checkedAgents.has(existingAgent)) return;
|
|
173
|
+
checkedAgents.add(existingAgent);
|
|
174
|
+
// NOTE: This check has to happen at load time
|
|
175
|
+
if (!isValid(existingAgent.info)) {
|
|
176
|
+
const cdn = gosCDN();
|
|
177
|
+
let jsAttributes = {
|
|
178
|
+
...cdn.info?.jsAttributes
|
|
179
|
+
};
|
|
180
|
+
try {
|
|
181
|
+
jsAttributes = {
|
|
182
|
+
...jsAttributes,
|
|
183
|
+
...existingAgent.info?.jsAttributes
|
|
184
|
+
};
|
|
185
|
+
} catch (err) {
|
|
186
|
+
// do nothing
|
|
187
|
+
}
|
|
188
|
+
configure(existingAgent, {
|
|
189
|
+
...cdn,
|
|
190
|
+
info: {
|
|
191
|
+
...cdn.info,
|
|
192
|
+
jsAttributes
|
|
193
|
+
},
|
|
194
|
+
runtime: existingAgent.runtime
|
|
195
|
+
}, existingAgent.runtime.loaderType);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
154
198
|
}
|
|
@@ -229,7 +229,7 @@ export class ApiBase {
|
|
|
229
229
|
|
|
230
230
|
/**
|
|
231
231
|
* Accepts or rejects consent when the agent is configured to require consent before harvesting.
|
|
232
|
-
|
|
232
|
+
* The consent state is stored in the agent session object in browser storage.
|
|
233
233
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/consent/}
|
|
234
234
|
* @param {boolean?} accept Whether to accept or reject consent. Defaults to true (accept) if left undefined.
|
|
235
235
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init-types.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/extract-url.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/attribute-size.js","../src/common/util/browser-stack-matchers.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/monkey-patched.js","../src/common/util/obfuscate.js","../src/common/util/short-circuit.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/util/webdriver-detection.js","../src/common/v2/script-correlation.js","../src/common/v2/script-tracker.js","../src/common/v2/utils.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/load-time.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/cause-string.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/harvest-metadata.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/aggregate/trace/utils.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/event-buffer.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/interfaces/registered-entity.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/api-base.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/addPageAction.js","../src/loaders/api/addRelease.js","../src/loaders/api/addToTrace.js","../src/loaders/api/consent.js","../src/loaders/api/constants.js","../src/loaders/api/finished.js","../src/loaders/api/interaction-types.js","../src/loaders/api/interaction.js","../src/loaders/api/log.js","../src/loaders/api/measure.js","../src/loaders/api/noticeError.js","../src/loaders/api/pauseReplay.js","../src/loaders/api/recordCustomEvent.js","../src/loaders/api/recordReplay.js","../src/loaders/api/register-api-types.js","../src/loaders/api/register.js","../src/loaders/api/setApplicationVersion.js","../src/loaders/api/setCustomAttribute.js","../src/loaders/api/setErrorHandler.js","../src/loaders/api/setPageViewName.js","../src/loaders/api/setUserId.js","../src/loaders/api/sharedHandlers.js","../src/loaders/api/start.js","../src/loaders/api/topLevelCallers.js","../src/loaders/api/wrapLogger.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init-types.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/session/session-key.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/extract-url.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/attribute-size.js","../src/common/util/browser-stack-matchers.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/monkey-patched.js","../src/common/util/obfuscate.js","../src/common/util/short-circuit.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/util/webdriver-detection.js","../src/common/v2/script-correlation.js","../src/common/v2/script-tracker.js","../src/common/v2/utils.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/load-time.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/cause-string.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/harvest-metadata.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/aggregate/trace/utils.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/event-buffer.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/interfaces/registered-entity.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/api-base.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/addPageAction.js","../src/loaders/api/addRelease.js","../src/loaders/api/addToTrace.js","../src/loaders/api/consent.js","../src/loaders/api/constants.js","../src/loaders/api/finished.js","../src/loaders/api/interaction-types.js","../src/loaders/api/interaction.js","../src/loaders/api/log.js","../src/loaders/api/measure.js","../src/loaders/api/noticeError.js","../src/loaders/api/pauseReplay.js","../src/loaders/api/recordCustomEvent.js","../src/loaders/api/recordReplay.js","../src/loaders/api/register-api-types.js","../src/loaders/api/register.js","../src/loaders/api/setApplicationVersion.js","../src/loaders/api/setCustomAttribute.js","../src/loaders/api/setErrorHandler.js","../src/loaders/api/setPageViewName.js","../src/loaders/api/setUserId.js","../src/loaders/api/sharedHandlers.js","../src/loaders/api/start.js","../src/loaders/api/topLevelCallers.js","../src/loaders/api/wrapLogger.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.9.3"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
export const
|
|
6
|
-
export const DEFAULT_KEY: "SESSION";
|
|
5
|
+
export const SESSION_STORAGE_KEY_PREFIX: "NRBA_SESSION::";
|
|
7
6
|
export const DEFAULT_EXPIRES_MS: 14400000;
|
|
8
7
|
export const DEFAULT_INACTIVE_MS: 1800000;
|
|
9
8
|
export namespace SESSION_EVENTS {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/common/session/constants.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/common/session/constants.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH,yCAA0C,gBAAgB,CAAA;AAC1D,iCAAkC,QAAQ,CAAA;AAC1C,kCAAmC,OAAO,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export class SessionEntity {
|
|
2
2
|
/**
|
|
3
3
|
* Create a self-managing Session Entity. This entity is scoped to the agent which triggered it, allowing for multiple simultaneous session objects to exist.
|
|
4
|
-
|
|
4
|
+
* Session data is stored at NRBA_SESSION::{key}, where key can be app-scoped by the caller to avoid collisions across multiple agents on the same origin.
|
|
5
5
|
* The value can be overridden in the constructor, but will default to a unique 16 character hex string
|
|
6
6
|
* expiresMs and inactiveMs are used to "expire" the session, but can be overridden in the constructor. Pass 0 to disable expiration timers.
|
|
7
7
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-key.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-key.js"],"names":[],"mappings":"AAcA,+EAEC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_event/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_event/aggregate/index.js"],"names":[],"mappings":"AAuBA;IACE,2BAA2C;IAE3C,2BAwBC;IArBC,iBAAoB;IAEpB,wBAAwB;IACxB,8BAA8B;IAC9B,8BAA8B;IAC9B,gBAAgB;IAkBlB;;;;OAIG;IACH,2BAFW,GAAC,QAiEX;IAbC;;;;;;;;;;;;;;mBAOC;IANC,iCAAyB;IAc7B,kCAEC;IAED;;;;;;aAiGC;CACF;8BArN6B,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/instrument/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/instrument/index.js"],"names":[],"mappings":"AAkBA;IACE,2BAAiC;IAMjC,2BAiCC;IApCD,+CAA+C;IAC/C,cAAQ;IA+BF,sBAAwB;IAmB9B;;;OAGG;IACH,+BAkBC;;CAgBF;AAED,8CAAuC;+BAtGR,6BAA6B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-session.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/agent-session.js"],"names":[],"mappings":"AAiBA,
|
|
1
|
+
{"version":3,"file":"agent-session.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/agent-session.js"],"names":[],"mappings":"AAiBA,sDA2DC"}
|
|
@@ -58,11 +58,6 @@ export class AggregateBase extends FeatureBase {
|
|
|
58
58
|
sent?: boolean | undefined;
|
|
59
59
|
retry?: boolean | undefined;
|
|
60
60
|
}): void;
|
|
61
|
-
/**
|
|
62
|
-
* Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
|
|
63
|
-
* loader configurations may appear after the loader code is executed.
|
|
64
|
-
*/
|
|
65
|
-
checkConfiguration(existingAgent: any): void;
|
|
66
61
|
/**
|
|
67
62
|
* These are actions related to shared resources that should be initialized once by whichever feature Aggregate subclass loads first.
|
|
68
63
|
* This method should run after checkConfiguration, which may reset the agent's info/runtime object that is used here.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAeA;IACE;;;;OAIG;IACH,sBAHW,MAAM,eACN,MAAM,EAkBhB;IAZC,uOAAuO;IACvO,qCAAwC;IACxC,gLAAgL;IAChL,yBAA2B;IAC3B,sFAAsF;IACtF,oBAAuB;IAEvB,gBAAqB;IAqBjB,YAAsE;IAW5E,iNAAiN;IACjN,0CAEC;IAED;;;;OAIG;IACH,8BAHU,MAAM,CAKf;IAED,qBAOC;IAFG,6BAAmB;IAIvB;;;;OAIG;IACH,2BAOC;IAED;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAwBlB;IAED;;OAEG;IACH,cAEC;IAED,qCAEC;IAED;;;;;;OAMG;IACH,uDAJW,MAAM,GAAC,SAAS,SAsB1B;IAED;;;;;OAKG;IACH,4BAHG;QAAyB,IAAI,GAArB,OAAO,YAAC;QACS,KAAK,GAAtB,OAAO,YAAC;KAClB,QAKA;IAED;;;OAGG;IACH,2CAKC;IAHC,gBAA6C;IAK/C;;;;OAIG;IACH,uCAHW,GAAC,UACD,GAAC,QAIX;;CACF;4BAlM2B,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/instrument-base.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instrument-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/instrument-base.js"],"names":[],"mappings":"AA4BA;;;GAGG;AACH;IACE;;;;OAIG;IACH,sBAHW,MAAM,eACN,MAAM,EA0ChB;IArCC,8IAA8I;IAC9I,cADW,WAAW,SAAS,CACF;IAE7B;;;MAGE;IACF,eAHU,OAAO,kBAAkB,EAAE,aAAa,CAGpB;IAE9B;;;MAGE;IACF,iCAAmC;IACnC,kCAEE;IAEF;;;MAGE;IACF,uBAAiC;IAiBnC;;;;;;;OAOG;IACH,2BALW,MAAM,qDAEN,MAAM,QA6DhB;;CAiDF;4BAvL2B,gBAAgB"}
|
|
@@ -182,7 +182,7 @@ export class ApiBase {
|
|
|
182
182
|
};
|
|
183
183
|
/**
|
|
184
184
|
* Accepts or rejects consent when the agent is configured to require consent before harvesting.
|
|
185
|
-
|
|
185
|
+
* The consent state is stored in the agent session object in browser storage.
|
|
186
186
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/consent/}
|
|
187
187
|
* @param {boolean?} accept Whether to accept or reject consent. Defaults to true (accept) if left undefined.
|
|
188
188
|
*/
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
export const
|
|
6
|
-
export const DEFAULT_KEY = 'SESSION'
|
|
5
|
+
export const SESSION_STORAGE_KEY_PREFIX = 'NRBA_SESSION::'
|
|
7
6
|
export const DEFAULT_EXPIRES_MS = 14400000
|
|
8
7
|
export const DEFAULT_INACTIVE_MS = 1800000
|
|
9
8
|
|
|
@@ -7,7 +7,7 @@ import { warn } from '../util/console'
|
|
|
7
7
|
import { stringify } from '../util/stringify'
|
|
8
8
|
import { Timer } from '../timer/timer'
|
|
9
9
|
import { isBrowserScope } from '../constants/runtime'
|
|
10
|
-
import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, MODE,
|
|
10
|
+
import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, MODE, SESSION_EVENTS, SESSION_EVENT_TYPES, SESSION_STORAGE_KEY_PREFIX } from './constants'
|
|
11
11
|
import { InteractionTimer } from '../timer/interaction-timer'
|
|
12
12
|
import { wrapEvents } from '../wrap/wrap-events'
|
|
13
13
|
import { getModeledObject } from '../config/configurable'
|
|
@@ -39,7 +39,7 @@ const model = {
|
|
|
39
39
|
export class SessionEntity {
|
|
40
40
|
/**
|
|
41
41
|
* Create a self-managing Session Entity. This entity is scoped to the agent which triggered it, allowing for multiple simultaneous session objects to exist.
|
|
42
|
-
|
|
42
|
+
* Session data is stored at NRBA_SESSION::{key}, where key can be app-scoped by the caller to avoid collisions across multiple agents on the same origin.
|
|
43
43
|
* The value can be overridden in the constructor, but will default to a unique 16 character hex string
|
|
44
44
|
* expiresMs and inactiveMs are used to "expire" the session, but can be overridden in the constructor. Pass 0 to disable expiration timers.
|
|
45
45
|
*/
|
|
@@ -160,7 +160,7 @@ export class SessionEntity {
|
|
|
160
160
|
|
|
161
161
|
// This is the actual key appended to the storage API
|
|
162
162
|
get lookupKey () {
|
|
163
|
-
return `${
|
|
163
|
+
return `${SESSION_STORAGE_KEY_PREFIX}${this.key}`
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
sync (data) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
// Deterministic 32-bit FNV-1a hash, rendered as a fixed 8-char hex string.
|
|
6
|
+
function hashTo8Hex (value) {
|
|
7
|
+
let hash = 0x811c9dc5
|
|
8
|
+
for (let i = 0; i < value.length; i++) {
|
|
9
|
+
hash ^= value.charCodeAt(i)
|
|
10
|
+
hash = Math.imul(hash, 0x01000193)
|
|
11
|
+
}
|
|
12
|
+
return (hash >>> 0).toString(16).padStart(8, '0')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getAppSessionHash (licenseKey, applicationID) {
|
|
16
|
+
return hashTo8Hex(`${String(licenseKey)}:${String(applicationID)}`)
|
|
17
|
+
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import { globalScope, isBrowserScope, originTime, getNavigationEntry } from '../../../common/constants/runtime'
|
|
6
6
|
import { addPT, addPN } from '../../../common/timing/nav-timing'
|
|
7
7
|
import { stringify } from '../../../common/util/stringify'
|
|
8
|
-
import { isValid } from '../../../common/config/info'
|
|
9
8
|
import * as CONSTANTS from '../constants'
|
|
10
9
|
import { getActivatedFeaturesFlags } from './initialized-features'
|
|
11
10
|
import { activateFeatures } from '../../../common/util/feature-flags'
|
|
@@ -35,10 +34,6 @@ export class Aggregate extends AggregateBase {
|
|
|
35
34
|
this.firstByteToDomContent = 0 // our "dom processing" duration
|
|
36
35
|
this.retries = 0
|
|
37
36
|
|
|
38
|
-
if (!isValid(agentRef.info)) {
|
|
39
|
-
this.ee.abort()
|
|
40
|
-
return warn(43)
|
|
41
|
-
}
|
|
42
37
|
agentRef.runtime.timeKeeper = new TimeKeeper(agentRef.runtime.session)
|
|
43
38
|
|
|
44
39
|
if (isBrowserScope) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { handle } from '../../../common/event-emitter/handle'
|
|
10
|
-
import {
|
|
10
|
+
import { MODE, SESSION_STORAGE_KEY_PREFIX } from '../../../common/session/constants'
|
|
11
|
+
import { getAppSessionHash } from '../../../common/session/session-key'
|
|
11
12
|
import { InstrumentBase } from '../../utils/instrument-base'
|
|
12
13
|
import { hasReplayPrerequisite, isPreloadAllowed } from '../shared/utils'
|
|
13
14
|
import { ERROR_DURING_REPLAY, FEATURE_NAME, TRIGGERS } from '../constants'
|
|
@@ -30,8 +31,9 @@ export class Instrument extends InstrumentBase {
|
|
|
30
31
|
setupPauseReplayAPI(agentRef)
|
|
31
32
|
|
|
32
33
|
let session
|
|
34
|
+
const fullNamespacedKey = `${SESSION_STORAGE_KEY_PREFIX}${getAppSessionHash(agentRef.info.licenseKey, agentRef.info.applicationID)}`
|
|
33
35
|
try {
|
|
34
|
-
session = JSON.parse(localStorage.getItem(
|
|
36
|
+
session = JSON.parse(localStorage.getItem(fullNamespacedKey))
|
|
35
37
|
} catch (err) { }
|
|
36
38
|
|
|
37
39
|
if (hasReplayPrerequisite(agentRef.init)) {
|
|
@@ -6,7 +6,7 @@ import { drain } from '../../common/drain/drain'
|
|
|
6
6
|
import { registerHandler } from '../../common/event-emitter/register-handler'
|
|
7
7
|
import { SessionEntity } from '../../common/session/session-entity'
|
|
8
8
|
import { LocalStorage } from '../../common/storage/local-storage.js'
|
|
9
|
-
import {
|
|
9
|
+
import { getAppSessionHash } from '../../common/session/session-key'
|
|
10
10
|
import { mergeInfo } from '../../common/config/info'
|
|
11
11
|
import { trackObjectAttributeSize } from '../../common/util/attribute-size'
|
|
12
12
|
import { handle } from '../../common/event-emitter/handle'
|
|
@@ -19,10 +19,11 @@ export function setupAgentSession (agentRef) {
|
|
|
19
19
|
if (agentRef.runtime.session) return agentRef.runtime.session // already setup
|
|
20
20
|
|
|
21
21
|
const sessionInit = agentRef.init.session
|
|
22
|
+
const namespacedKey = getAppSessionHash(agentRef.info.licenseKey, agentRef.info.applicationID)
|
|
22
23
|
|
|
23
24
|
agentRef.runtime.session = new SessionEntity({
|
|
24
25
|
agentRef,
|
|
25
|
-
key:
|
|
26
|
+
key: namespacedKey,
|
|
26
27
|
storage: new LocalStorage(),
|
|
27
28
|
expiresMs: sessionInit?.expiresMs,
|
|
28
29
|
inactiveMs: sessionInit?.inactiveMs
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { FeatureBase } from './feature-base'
|
|
6
|
-
import { isValid } from '../../common/config/info'
|
|
7
|
-
import { configure } from '../../loaders/configure/configure'
|
|
8
|
-
import { gosCDN } from '../../common/window/nreum'
|
|
9
6
|
import { drain } from '../../common/drain/drain'
|
|
10
7
|
import { Obfuscator } from '../../common/util/obfuscate'
|
|
11
8
|
import { FEATURE_NAMES } from '../../loaders/features/features'
|
|
@@ -24,7 +21,6 @@ export class AggregateBase extends FeatureBase {
|
|
|
24
21
|
*/
|
|
25
22
|
constructor (agentRef, featureName) {
|
|
26
23
|
super(agentRef, featureName)
|
|
27
|
-
this.checkConfiguration(agentRef)
|
|
28
24
|
this.doOnceForAllAggregate(agentRef)
|
|
29
25
|
|
|
30
26
|
/** @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 */
|
|
@@ -181,34 +177,6 @@ export class AggregateBase extends FeatureBase {
|
|
|
181
177
|
this.events.clearSave(this.harvestOpts)
|
|
182
178
|
}
|
|
183
179
|
|
|
184
|
-
/**
|
|
185
|
-
* Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
|
|
186
|
-
* loader configurations may appear after the loader code is executed.
|
|
187
|
-
*/
|
|
188
|
-
checkConfiguration (existingAgent) {
|
|
189
|
-
// NOTE: This check has to happen at aggregator load time
|
|
190
|
-
if (!isValid(existingAgent.info)) {
|
|
191
|
-
const cdn = gosCDN()
|
|
192
|
-
let jsAttributes = { ...cdn.info?.jsAttributes }
|
|
193
|
-
try {
|
|
194
|
-
jsAttributes = {
|
|
195
|
-
...jsAttributes,
|
|
196
|
-
...existingAgent.info?.jsAttributes
|
|
197
|
-
}
|
|
198
|
-
} catch (err) {
|
|
199
|
-
// do nothing
|
|
200
|
-
}
|
|
201
|
-
configure(existingAgent, {
|
|
202
|
-
...cdn,
|
|
203
|
-
info: {
|
|
204
|
-
...cdn.info,
|
|
205
|
-
jsAttributes
|
|
206
|
-
},
|
|
207
|
-
runtime: existingAgent.runtime
|
|
208
|
-
}, existingAgent.runtime.loaderType)
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
180
|
/**
|
|
213
181
|
* These are actions related to shared resources that should be initialized once by whichever feature Aggregate subclass loads first.
|
|
214
182
|
* This method should run after checkConfiguration, which may reset the agent's info/runtime object that is used here.
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @file Defines `InstrumentBase` to be used as the super of the Instrument classes implemented by each feature.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Validates and loads feature aggregates, including a one-time late configuration check before import.
|
|
9
|
+
* Inherits `blocked` behavior from [FeatureBase]{@link ./feature-base}.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { drain, registerDrain } from '../../common/drain/drain'
|
|
@@ -14,6 +14,9 @@ import { FeatureBase } from './feature-base'
|
|
|
14
14
|
import { onWindowLoad } from '../../common/window/load'
|
|
15
15
|
import { isBrowserScope } from '../../common/constants/runtime'
|
|
16
16
|
import { warn } from '../../common/util/console'
|
|
17
|
+
import { isValid } from '../../common/config/info'
|
|
18
|
+
import { configure } from '../../loaders/configure/configure'
|
|
19
|
+
import { gosCDN } from '../../common/window/nreum'
|
|
17
20
|
import { FEATURE_NAMES } from '../../loaders/features/features'
|
|
18
21
|
import { hasReplayPrerequisite } from '../session_replay/shared/utils'
|
|
19
22
|
import { canEnableSessionTracking } from './feature-gates'
|
|
@@ -21,6 +24,8 @@ import { single } from '../../common/util/invoke'
|
|
|
21
24
|
import { SESSION_ERROR } from '../../common/constants/agent-constants'
|
|
22
25
|
import { handle } from '../../common/event-emitter/handle'
|
|
23
26
|
|
|
27
|
+
const checkedAgents = new WeakSet()
|
|
28
|
+
|
|
24
29
|
/**
|
|
25
30
|
* Base class for instrumenting a feature.
|
|
26
31
|
* @extends FeatureBase
|
|
@@ -90,6 +95,14 @@ export class InstrumentBase extends FeatureBase {
|
|
|
90
95
|
// or otherwise when the manual-start-all event is emitted by the start API
|
|
91
96
|
await this.deferred
|
|
92
97
|
|
|
98
|
+
this.#checkConfiguration(agentRef) // check for late-appearing 'info' config on the page
|
|
99
|
+
if (!isValid(agentRef.info)) { // if there still isn't valid info, then we can't proceed with session setup or importing the aggregates
|
|
100
|
+
warn(43)
|
|
101
|
+
agentRef.ee.abort()
|
|
102
|
+
this.loadedSuccessfully(false)
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
let session
|
|
94
107
|
try {
|
|
95
108
|
if (canEnableSessionTracking(agentRef.init)) { // would require some setup before certain features start
|
|
@@ -150,4 +163,34 @@ export class InstrumentBase extends FeatureBase {
|
|
|
150
163
|
return true
|
|
151
164
|
}
|
|
152
165
|
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
|
|
169
|
+
* loader configurations may appear after the loader code is executed.
|
|
170
|
+
*/
|
|
171
|
+
#checkConfiguration (existingAgent) {
|
|
172
|
+
if (checkedAgents.has(existingAgent)) return
|
|
173
|
+
checkedAgents.add(existingAgent)
|
|
174
|
+
// NOTE: This check has to happen at load time
|
|
175
|
+
if (!isValid(existingAgent.info)) {
|
|
176
|
+
const cdn = gosCDN()
|
|
177
|
+
let jsAttributes = { ...cdn.info?.jsAttributes }
|
|
178
|
+
try {
|
|
179
|
+
jsAttributes = {
|
|
180
|
+
...jsAttributes,
|
|
181
|
+
...existingAgent.info?.jsAttributes
|
|
182
|
+
}
|
|
183
|
+
} catch (err) {
|
|
184
|
+
// do nothing
|
|
185
|
+
}
|
|
186
|
+
configure(existingAgent, {
|
|
187
|
+
...cdn,
|
|
188
|
+
info: {
|
|
189
|
+
...cdn.info,
|
|
190
|
+
jsAttributes
|
|
191
|
+
},
|
|
192
|
+
runtime: existingAgent.runtime
|
|
193
|
+
}, existingAgent.runtime.loaderType)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
153
196
|
}
|
package/src/loaders/api-base.js
CHANGED
|
@@ -230,7 +230,7 @@ export class ApiBase {
|
|
|
230
230
|
|
|
231
231
|
/**
|
|
232
232
|
* Accepts or rejects consent when the agent is configured to require consent before harvesting.
|
|
233
|
-
|
|
233
|
+
* The consent state is stored in the agent session object in browser storage.
|
|
234
234
|
* {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/consent/}
|
|
235
235
|
* @param {boolean?} accept Whether to accept or reject consent. Defaults to true (accept) if left undefined.
|
|
236
236
|
*/
|