@newrelic/browser-agent 1.253.0 → 1.254.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 +15 -0
- package/README.md +1 -1
- package/dist/cjs/cdn/polyfills.js +2 -1
- package/dist/cjs/common/config/state/runtime.js +4 -1
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/drain/drain.js +41 -27
- package/dist/cjs/common/event-emitter/contextual-ee.js +24 -22
- package/dist/cjs/common/harvest/harvest.js +5 -1
- package/dist/cjs/common/timing/time-keeper.js +94 -0
- package/dist/cjs/common/util/feature-flags.js +14 -31
- package/dist/cjs/common/wrap/wrap-events.js +2 -2
- package/dist/cjs/common/wrap/wrap-fetch.js +1 -2
- package/dist/cjs/common/wrap/wrap-function.js +7 -5
- package/dist/cjs/common/wrap/wrap-promise.js +1 -2
- package/dist/cjs/features/ajax/aggregate/index.js +7 -13
- package/dist/cjs/features/jserrors/aggregate/index.js +25 -24
- package/dist/cjs/features/metrics/aggregate/index.js +25 -24
- package/dist/cjs/features/page_action/aggregate/index.js +6 -4
- package/dist/cjs/features/page_view_event/aggregate/index.js +22 -2
- package/dist/cjs/features/page_view_timing/aggregate/index.js +15 -16
- package/dist/cjs/features/session_replay/aggregate/index.js +12 -4
- package/dist/cjs/features/session_trace/aggregate/index.js +11 -8
- package/dist/cjs/features/soft_navigations/aggregate/index.js +17 -12
- package/dist/cjs/features/spa/aggregate/index.js +19 -14
- package/dist/cjs/features/utils/aggregate-base.js +18 -5
- package/dist/cjs/features/utils/feature-base.js +2 -0
- package/dist/cjs/features/utils/instrument-base.js +1 -0
- package/dist/cjs/loaders/agent-base.js +2 -7
- package/dist/cjs/loaders/agent.js +4 -4
- package/dist/cjs/loaders/api/api.js +1 -1
- package/dist/cjs/loaders/configure/configure.js +1 -1
- package/dist/cjs/loaders/configure/nonce.cdn.js +13 -0
- package/dist/cjs/loaders/configure/nonce.js +2 -13
- package/dist/cjs/loaders/configure/public-path.cdn.js +16 -0
- package/dist/cjs/loaders/configure/public-path.js +2 -8
- package/dist/esm/cdn/polyfills.js +2 -1
- package/dist/esm/common/config/state/runtime.js +4 -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/drain/drain.js +40 -27
- package/dist/esm/common/event-emitter/contextual-ee.js +24 -22
- package/dist/esm/common/harvest/harvest.js +5 -1
- package/dist/esm/common/timing/time-keeper.js +88 -0
- package/dist/esm/common/util/feature-flags.js +14 -31
- package/dist/esm/common/wrap/wrap-events.js +3 -3
- package/dist/esm/common/wrap/wrap-fetch.js +2 -3
- package/dist/esm/common/wrap/wrap-function.js +5 -4
- package/dist/esm/common/wrap/wrap-promise.js +2 -3
- package/dist/esm/features/ajax/aggregate/index.js +7 -13
- package/dist/esm/features/jserrors/aggregate/index.js +25 -24
- package/dist/esm/features/metrics/aggregate/index.js +25 -24
- package/dist/esm/features/page_action/aggregate/index.js +6 -4
- package/dist/esm/features/page_view_event/aggregate/index.js +22 -2
- package/dist/esm/features/page_view_timing/aggregate/index.js +15 -16
- package/dist/esm/features/session_replay/aggregate/index.js +12 -4
- package/dist/esm/features/session_trace/aggregate/index.js +11 -8
- package/dist/esm/features/soft_navigations/aggregate/index.js +17 -12
- package/dist/esm/features/spa/aggregate/index.js +19 -14
- package/dist/esm/features/utils/aggregate-base.js +18 -5
- package/dist/esm/features/utils/feature-base.js +2 -0
- package/dist/esm/features/utils/instrument-base.js +1 -0
- package/dist/esm/loaders/agent-base.js +2 -7
- package/dist/esm/loaders/agent.js +4 -4
- package/dist/esm/loaders/api/api.js +1 -1
- package/dist/esm/loaders/configure/configure.js +1 -1
- package/dist/esm/loaders/configure/nonce.cdn.js +11 -0
- package/dist/esm/loaders/configure/nonce.js +1 -11
- package/dist/esm/loaders/configure/public-path.cdn.js +9 -0
- package/dist/esm/loaders/configure/public-path.js +2 -8
- package/dist/types/common/config/state/runtime.d.ts.map +1 -1
- package/dist/types/common/drain/drain.d.ts +6 -0
- package/dist/types/common/drain/drain.d.ts.map +1 -1
- package/dist/types/common/event-emitter/contextual-ee.d.ts +4 -3
- package/dist/types/common/event-emitter/contextual-ee.d.ts.map +1 -1
- package/dist/types/common/event-emitter/event-context.d.ts.map +1 -0
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/timing/time-keeper.d.ts +31 -0
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -0
- package/dist/types/common/util/feature-flags.d.ts +11 -2
- package/dist/types/common/util/feature-flags.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-function.d.ts +1 -0
- package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts +5 -5
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +0 -2
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts +0 -2
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts +2 -0
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +2 -2
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/feature-base.d.ts +1 -0
- package/dist/types/features/utils/feature-base.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/agent-base.d.ts +2 -2
- package/dist/types/loaders/agent-base.d.ts.map +1 -1
- package/dist/types/loaders/configure/public-path.d.ts +1 -1
- package/dist/types/loaders/configure/public-path.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cdn/polyfills.js +1 -0
- package/src/common/config/state/runtime.js +4 -1
- package/src/common/drain/drain.js +41 -28
- package/src/common/event-emitter/contextual-ee.js +29 -31
- package/src/common/harvest/harvest.js +4 -1
- package/src/common/timing/time-keeper.js +96 -0
- package/src/common/util/feature-flags.js +13 -31
- package/src/common/wrap/wrap-events.js +3 -3
- package/src/common/wrap/wrap-fetch.js +2 -3
- package/src/common/wrap/wrap-function.js +6 -4
- package/src/common/wrap/wrap-promise.js +2 -3
- package/src/features/ajax/aggregate/index.js +8 -16
- package/src/features/jserrors/aggregate/index.js +12 -14
- package/src/features/metrics/aggregate/index.js +18 -17
- package/src/features/page_action/aggregate/index.js +6 -5
- package/src/features/page_view_event/aggregate/index.js +18 -2
- package/src/features/page_view_timing/aggregate/index.js +15 -15
- package/src/features/session_replay/aggregate/index.js +10 -4
- package/src/features/session_trace/aggregate/index.js +2 -2
- package/src/features/soft_navigations/aggregate/index.js +14 -12
- package/src/features/spa/aggregate/index.js +15 -13
- package/src/features/utils/aggregate-base.js +16 -8
- package/src/features/utils/feature-base.js +3 -0
- package/src/features/utils/instrument-base.js +1 -0
- package/src/loaders/agent-base.js +2 -7
- package/src/loaders/agent.js +2 -2
- package/src/loaders/api/api.js +1 -1
- package/src/loaders/configure/nonce.cdn.js +12 -0
- package/src/loaders/configure/nonce.js +1 -12
- package/src/loaders/configure/public-path.cdn.js +9 -0
- package/src/loaders/configure/public-path.js +2 -8
- package/dist/cjs/common/context/observation-context-manager.js +0 -56
- package/dist/cjs/loaders/configure/nonce.npm.js +0 -2
- package/dist/cjs/loaders/configure/public-path.npm.js +0 -10
- package/dist/esm/common/context/observation-context-manager.js +0 -49
- package/dist/esm/loaders/configure/nonce.npm.js +0 -1
- package/dist/esm/loaders/configure/public-path.npm.js +0 -3
- package/dist/types/common/context/event-context.d.ts.map +0 -1
- package/dist/types/common/context/observation-context-manager.d.ts +0 -28
- package/dist/types/common/context/observation-context-manager.d.ts.map +0 -1
- package/dist/types/loaders/configure/nonce.npm.d.ts +0 -1
- package/dist/types/loaders/configure/nonce.npm.d.ts.map +0 -1
- package/dist/types/loaders/configure/public-path.npm.d.ts +0 -2
- package/dist/types/loaders/configure/public-path.npm.d.ts.map +0 -1
- package/src/common/context/observation-context-manager.js +0 -55
- package/src/loaders/configure/nonce.npm.js +0 -1
- package/src/loaders/configure/public-path.npm.js +0 -3
- /package/dist/cjs/common/{context → event-emitter}/event-context.js +0 -0
- /package/dist/esm/common/{context → event-emitter}/event-context.js +0 -0
- /package/dist/types/common/{context → event-emitter}/event-context.d.ts +0 -0
- /package/src/common/{context → event-emitter}/event-context.js +0 -0
|
@@ -4,8 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.Agent = void 0;
|
|
7
|
-
require("./configure/public-path
|
|
8
|
-
require("./configure/nonce
|
|
7
|
+
require("./configure/public-path");
|
|
8
|
+
require("./configure/nonce");
|
|
9
9
|
var _agentBase = require("./agent-base");
|
|
10
10
|
var _enabledFeatures = require("./features/enabled-features");
|
|
11
11
|
var _configure = require("./configure/configure");
|
|
@@ -88,8 +88,8 @@ class Agent extends _agentBase.AgentBase {
|
|
|
88
88
|
delete newrelic.initializedAgents[this.agentIdentifier]?.features; // GC mem used internally by features
|
|
89
89
|
delete this.sharedAggregator;
|
|
90
90
|
// Keep the initialized agent object with its configs for troubleshooting purposes.
|
|
91
|
-
newrelic.ee
|
|
92
|
-
|
|
91
|
+
const thisEE = newrelic.ee.get(this.agentIdentifier);
|
|
92
|
+
thisEE.abort(); // set flag and clear backlog
|
|
93
93
|
return false;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -210,7 +210,7 @@ function setAPI(agentIdentifier, forceDrain) {
|
|
|
210
210
|
(0, _drain.drain)(agentIdentifier, 'api');
|
|
211
211
|
}).catch(() => {
|
|
212
212
|
(0, _console.warn)('Downloading runtime APIs failed...');
|
|
213
|
-
|
|
213
|
+
instanceEE.abort();
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
return apiInterface;
|
|
@@ -9,7 +9,7 @@ var _nreum = require("../../common/window/nreum");
|
|
|
9
9
|
var _config = require("../../common/config/config");
|
|
10
10
|
var _featureFlags = require("../../common/util/feature-flags");
|
|
11
11
|
var _runtime = require("../../common/constants/runtime");
|
|
12
|
-
var _publicPath = require("./public-path
|
|
12
|
+
var _publicPath = require("./public-path");
|
|
13
13
|
let alreadySetOnce = false; // the configure() function can run multiple times in agent lifecycle
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/* global __webpack_require__ */
|
|
4
|
+
|
|
5
|
+
__webpack_require__.nc = (() => {
|
|
6
|
+
try {
|
|
7
|
+
return document?.currentScript?.nonce;
|
|
8
|
+
} catch (ex) {
|
|
9
|
+
// Swallow error and proceed like nonce is not defined
|
|
10
|
+
// This will happen when the agent is loaded in a worker scope
|
|
11
|
+
}
|
|
12
|
+
return '';
|
|
13
|
+
})();
|
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/* global __webpack_require__ */
|
|
4
|
-
|
|
5
|
-
__webpack_require__.nc = (() => {
|
|
6
|
-
try {
|
|
7
|
-
return document?.currentScript?.nonce;
|
|
8
|
-
} catch (ex) {
|
|
9
|
-
// Swallow error and proceed like nonce is not defined
|
|
10
|
-
// This will happen when the agent is loaded in a worker scope
|
|
11
|
-
}
|
|
12
|
-
return '';
|
|
13
|
-
})();
|
|
1
|
+
// We don't support setting automating the nonce attribute in the npm package
|
|
2
|
+
"use strict";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.redefinePublicPath = void 0;
|
|
7
|
+
// Set the default CDN or remote for fetching the assets; NPM shouldn't change this var.
|
|
8
|
+
|
|
9
|
+
const redefinePublicPath = urlString => {
|
|
10
|
+
const isOrigin = urlString.startsWith('http');
|
|
11
|
+
// Input is not expected to end in a slash, but webpack concats as-is, so one is inserted.
|
|
12
|
+
urlString += '/';
|
|
13
|
+
// If there's no existing HTTP scheme, the secure protocol is prepended by default.
|
|
14
|
+
__webpack_public_path__ = isOrigin ? urlString : 'https://' + urlString; // eslint-disable-line
|
|
15
|
+
};
|
|
16
|
+
exports.redefinePublicPath = redefinePublicPath;
|
|
@@ -4,13 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.redefinePublicPath = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const redefinePublicPath = urlString => {
|
|
10
|
-
const isOrigin = urlString.startsWith('http');
|
|
11
|
-
// Input is not expected to end in a slash, but webpack concats as-is, so one is inserted.
|
|
12
|
-
urlString += '/';
|
|
13
|
-
// If there's no existing HTTP scheme, the secure protocol is prepended by default.
|
|
14
|
-
__webpack_public_path__ = isOrigin ? urlString : 'https://' + urlString; // eslint-disable-line
|
|
7
|
+
const redefinePublicPath = () => {
|
|
8
|
+
// We don't support setting public path in webpack via NPM build.
|
|
15
9
|
};
|
|
16
10
|
exports.redefinePublicPath = redefinePublicPath;
|
|
@@ -21,4 +21,5 @@ import 'core-js/stable/weak-set';
|
|
|
21
21
|
import 'core-js/stable/object/get-own-property-descriptors';
|
|
22
22
|
import 'core-js/stable/url';
|
|
23
23
|
import 'core-js/stable/url-search-params';
|
|
24
|
-
import 'core-js/stable/string/starts-with';
|
|
24
|
+
import 'core-js/stable/string/starts-with';
|
|
25
|
+
import 'core-js/stable/number/is-nan';
|
|
@@ -17,10 +17,13 @@ const model = {
|
|
|
17
17
|
origin: '' + globalScope.location,
|
|
18
18
|
ptid: undefined,
|
|
19
19
|
releaseIds: {},
|
|
20
|
+
/** Agent-specific metadata found in the RUM call response. ex. entityGuid */
|
|
21
|
+
appMetadata: {},
|
|
20
22
|
session: undefined,
|
|
21
23
|
xhrWrappable: typeof globalScope.XMLHttpRequest?.prototype?.addEventListener === 'function',
|
|
22
24
|
version: VERSION,
|
|
23
|
-
denyList: undefined
|
|
25
|
+
denyList: undefined,
|
|
26
|
+
harvestCount: 0
|
|
24
27
|
};
|
|
25
28
|
const _cache = {};
|
|
26
29
|
export function getRuntime(id) {
|
|
@@ -28,13 +28,24 @@ export function registerDrain(agentIdentifier, group) {
|
|
|
28
28
|
if (!registry[agentIdentifier].get(group)) registry[agentIdentifier].set(group, item);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Removes an item from the registry and immediately re-checks if the registry is ready to "drain all"
|
|
33
|
+
* @param {*} agentIdentifier - A 16 character string uniquely identifying the agent.
|
|
34
|
+
* @param {*} group - The named "bucket" to be removed from the registry
|
|
35
|
+
*/
|
|
36
|
+
export function deregisterDrain(agentIdentifier, group) {
|
|
37
|
+
curateRegistry(agentIdentifier);
|
|
38
|
+
if (registry[agentIdentifier].get(group)) registry[agentIdentifier].delete(group);
|
|
39
|
+
if (registry[agentIdentifier].size) checkCanDrainAll(agentIdentifier);
|
|
40
|
+
}
|
|
41
|
+
|
|
31
42
|
/**
|
|
32
43
|
* Registers the specified agent with the centralized event buffer registry if it is not already registered.
|
|
33
44
|
* Agents without an identifier (as in the case of some tests) will be excluded from the registry.
|
|
34
45
|
* @param {string} agentIdentifier - A 16 character string uniquely identifying an agent.
|
|
35
46
|
*/
|
|
36
47
|
function curateRegistry(agentIdentifier) {
|
|
37
|
-
if (!agentIdentifier)
|
|
48
|
+
if (!agentIdentifier) throw new Error('agentIdentifier required');
|
|
38
49
|
if (!registry[agentIdentifier]) registry[agentIdentifier] = new Map();
|
|
39
50
|
}
|
|
40
51
|
|
|
@@ -53,11 +64,15 @@ export function drain() {
|
|
|
53
64
|
// If the feature for the specified agent is not in the registry, that means the instrument file was bypassed.
|
|
54
65
|
// This could happen in tests, or loaders that directly import the aggregator. In these cases it is safe to
|
|
55
66
|
// drain the feature group immediately rather than waiting to drain all at once.
|
|
56
|
-
if (!agentIdentifier || !registry[agentIdentifier].get(featureName) || force) return drainGroup(featureName);
|
|
67
|
+
if (!agentIdentifier || !registry[agentIdentifier].get(featureName) || force) return drainGroup(agentIdentifier, featureName);
|
|
57
68
|
|
|
58
69
|
// When `drain` is called, this feature is ready to drain (staged).
|
|
59
70
|
registry[agentIdentifier].get(featureName).staged = true;
|
|
71
|
+
checkCanDrainAll(agentIdentifier);
|
|
72
|
+
}
|
|
60
73
|
|
|
74
|
+
/** Checks all items in the registry to see if they have been "staged". If ALL items are staged, it will drain all registry items (drainGroup). It not, nothing will happen */
|
|
75
|
+
function checkCanDrainAll(agentIdentifier) {
|
|
61
76
|
// Only when the event-groups for all features are ready to drain (staged) do we execute the drain. This has the effect
|
|
62
77
|
// that the last feature to call drain triggers drain for all features.
|
|
63
78
|
const items = [...registry[agentIdentifier]];
|
|
@@ -69,40 +84,38 @@ export function drain() {
|
|
|
69
84
|
items.forEach(_ref2 => {
|
|
70
85
|
let [group] = _ref2;
|
|
71
86
|
registry[agentIdentifier].delete(group);
|
|
72
|
-
drainGroup(group);
|
|
87
|
+
drainGroup(agentIdentifier, group);
|
|
73
88
|
});
|
|
74
89
|
}
|
|
90
|
+
}
|
|
75
91
|
|
|
76
|
-
|
|
92
|
+
/**
|
|
77
93
|
* Drains all the buffered (backlog) events for a particular feature's event-group by emitting each event to each of
|
|
78
94
|
* the subscribed handlers for the group.
|
|
79
95
|
* @param {*} group - The name of a particular feature's event "bucket".
|
|
80
96
|
*/
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
mapOwn(groupHandlers, function (eventType, handlerRegistrationList) {
|
|
94
|
-
mapOwn(handlerRegistrationList, function (i, registration) {
|
|
95
|
-
// registration is an array of: [targetEE, eventHandler]
|
|
96
|
-
registration[0].on(eventType, registration[1]);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
97
|
+
function drainGroup(agentIdentifier, group) {
|
|
98
|
+
const baseEE = agentIdentifier ? ee.get(agentIdentifier) : ee;
|
|
99
|
+
const handlers = defaultRegister.handlers; // other storage in registerHandler
|
|
100
|
+
if (!baseEE.backlog || !handlers) return;
|
|
101
|
+
var bufferedEventsInGroup = baseEE.backlog[group];
|
|
102
|
+
var groupHandlers = handlers[group]; // each group in the registerHandler storage
|
|
103
|
+
if (groupHandlers) {
|
|
104
|
+
// We don't cache the length of the buffer while looping because events might still be added while processing.
|
|
105
|
+
for (var i = 0; bufferedEventsInGroup && i < bufferedEventsInGroup.length; ++i) {
|
|
106
|
+
// eslint-disable-line no-unmodified-loop-condition
|
|
107
|
+
emitEvent(bufferedEventsInGroup[i], groupHandlers);
|
|
99
108
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
mapOwn(groupHandlers, function (eventType, handlerRegistrationList) {
|
|
110
|
+
mapOwn(handlerRegistrationList, function (i, registration) {
|
|
111
|
+
// registration is an array of: [targetEE, eventHandler]
|
|
112
|
+
registration[0].on(eventType, registration[1]);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
105
115
|
}
|
|
116
|
+
if (!baseEE.isolatedBacklog) delete handlers[group];
|
|
117
|
+
baseEE.backlog[group] = null;
|
|
118
|
+
baseEE.emit('drain-' + group, []);
|
|
106
119
|
}
|
|
107
120
|
|
|
108
121
|
/**
|
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
import { gosNREUM } from '../window/nreum';
|
|
7
7
|
import { getOrSet } from '../util/get-or-set';
|
|
8
8
|
import { getRuntime } from '../config/config';
|
|
9
|
-
import { EventContext } from '
|
|
10
|
-
import {
|
|
9
|
+
import { EventContext } from './event-context';
|
|
10
|
+
import { bundleId } from '../ids/bundle-id';
|
|
11
11
|
|
|
12
|
+
// create a unique id to store event context data for the current agent bundle
|
|
13
|
+
const contextId = "nr@context:".concat(bundleId);
|
|
12
14
|
// create global emitter instance that can be shared among bundles
|
|
13
15
|
const globalInstance = ee(undefined, 'globalEE');
|
|
14
16
|
|
|
@@ -17,7 +19,7 @@ const nr = gosNREUM();
|
|
|
17
19
|
if (!nr.ee) {
|
|
18
20
|
nr.ee = globalInstance;
|
|
19
21
|
}
|
|
20
|
-
export { globalInstance as ee };
|
|
22
|
+
export { globalInstance as ee, contextId };
|
|
21
23
|
function ee(old, debugId) {
|
|
22
24
|
var handlers = {};
|
|
23
25
|
var bufferGroupMap = {};
|
|
@@ -44,20 +46,34 @@ function ee(old, debugId) {
|
|
|
44
46
|
context,
|
|
45
47
|
buffer: bufferEventsByGroup,
|
|
46
48
|
abort,
|
|
47
|
-
aborted: false,
|
|
48
49
|
isBuffering,
|
|
49
50
|
debugId,
|
|
50
51
|
backlog: isolatedBacklog ? {} : old && typeof old.backlog === 'object' ? old.backlog : {},
|
|
51
|
-
|
|
52
|
+
isolatedBacklog
|
|
52
53
|
};
|
|
54
|
+
function abort() {
|
|
55
|
+
emitter._aborted = true;
|
|
56
|
+
Object.keys(emitter.backlog).forEach(key => {
|
|
57
|
+
delete emitter.backlog[key];
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
Object.defineProperty(emitter, 'aborted', {
|
|
61
|
+
get: () => {
|
|
62
|
+
let aborted = emitter._aborted || false;
|
|
63
|
+
if (aborted) return aborted;else if (old) {
|
|
64
|
+
aborted = old.aborted;
|
|
65
|
+
}
|
|
66
|
+
return aborted;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
53
69
|
return emitter;
|
|
54
70
|
function context(contextOrStore) {
|
|
55
71
|
if (contextOrStore && contextOrStore instanceof EventContext) {
|
|
56
72
|
return contextOrStore;
|
|
57
73
|
} else if (contextOrStore) {
|
|
58
|
-
return getOrSet(contextOrStore,
|
|
74
|
+
return getOrSet(contextOrStore, contextId, () => new EventContext(contextId));
|
|
59
75
|
} else {
|
|
60
|
-
return
|
|
76
|
+
return new EventContext(contextId);
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
function emit(type, args, contextOrStore, force, bubble) {
|
|
@@ -101,11 +117,7 @@ function ee(old, debugId) {
|
|
|
101
117
|
return handlers[type] || [];
|
|
102
118
|
}
|
|
103
119
|
function getOrCreate(name) {
|
|
104
|
-
|
|
105
|
-
if (!newEventEmitter.observationContextManager && emitter.observationContextManager) {
|
|
106
|
-
newEventEmitter.observationContextManager = emitter.observationContextManager;
|
|
107
|
-
}
|
|
108
|
-
return newEventEmitter;
|
|
120
|
+
return emitters[name] = emitters[name] || ee(emitter, name);
|
|
109
121
|
}
|
|
110
122
|
function bufferEventsByGroup(types, group) {
|
|
111
123
|
const eventBuffer = getBuffer();
|
|
@@ -131,14 +143,4 @@ function ee(old, debugId) {
|
|
|
131
143
|
function getBuffer() {
|
|
132
144
|
return emitter.backlog;
|
|
133
145
|
}
|
|
134
|
-
}
|
|
135
|
-
function abort() {
|
|
136
|
-
globalInstance.aborted = true;
|
|
137
|
-
// The global backlog can be referenced directly by other emitters,
|
|
138
|
-
// so we need to delete its contents as opposed to replacing it.
|
|
139
|
-
// Otherwise, these references to the old backlog would still exist
|
|
140
|
-
// and the keys will not be garbage collected.
|
|
141
|
-
Object.keys(globalInstance.backlog).forEach(key => {
|
|
142
|
-
delete globalInstance.backlog[key];
|
|
143
|
-
});
|
|
144
146
|
}
|
|
@@ -177,7 +177,9 @@ export class Harvest extends SharedContext {
|
|
|
177
177
|
// status 0 refers to a local error, such as CORS or network failure, or a blocked request by the browser (e.g. adblocker)
|
|
178
178
|
const cbResult = {
|
|
179
179
|
sent: this.status !== 0,
|
|
180
|
-
status: this.status
|
|
180
|
+
status: this.status,
|
|
181
|
+
xhr: this,
|
|
182
|
+
fullUrl
|
|
181
183
|
};
|
|
182
184
|
if (this.status === 429) {
|
|
183
185
|
cbResult.retry = true;
|
|
@@ -191,6 +193,8 @@ export class Harvest extends SharedContext {
|
|
|
191
193
|
cbFinished(cbResult);
|
|
192
194
|
}, eventListenerOpts(false));
|
|
193
195
|
}
|
|
196
|
+
const runtime = getRuntime(this.sharedContext.agentIdentifier);
|
|
197
|
+
runtime.harvestCount++;
|
|
194
198
|
return result;
|
|
195
199
|
}
|
|
196
200
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { gosNREUM } from '../window/nreum';
|
|
2
|
+
import { globalScope } from '../constants/runtime';
|
|
3
|
+
import { getRuntime } from '../config/config';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Class used to adjust the timestamp of harvested data to New Relic server time. This
|
|
7
|
+
* is done by tracking the performance timings of the RUM call and applying a calculation
|
|
8
|
+
* to the harvested data event offset time.
|
|
9
|
+
*/
|
|
10
|
+
export class TimeKeeper {
|
|
11
|
+
#agent;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Represents the browser origin time corrected to NR server time.
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
#correctedOriginTime;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents the difference in milliseconds between the calculated NR server time and
|
|
21
|
+
* the local time.
|
|
22
|
+
* @type {number}
|
|
23
|
+
*/
|
|
24
|
+
#localTimeDiff;
|
|
25
|
+
constructor(agent) {
|
|
26
|
+
this.#agent = agent;
|
|
27
|
+
}
|
|
28
|
+
static getTimeKeeperByAgentIdentifier(agentIdentifier) {
|
|
29
|
+
const nr = gosNREUM();
|
|
30
|
+
return Object.keys(nr?.initializedAgents || {}).indexOf(agentIdentifier) > -1 ? nr.initializedAgents[agentIdentifier].timeKeeper : undefined;
|
|
31
|
+
}
|
|
32
|
+
get correctedPageOriginTime() {
|
|
33
|
+
return this.#correctedOriginTime;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Process a rum request to calculate NR server time.
|
|
38
|
+
* @param rumRequest {XMLHttpRequest} The xhr for the rum request
|
|
39
|
+
* @param rumRequestUrl {string} The full url of the rum request
|
|
40
|
+
*/
|
|
41
|
+
processRumRequest(rumRequest, rumRequestUrl) {
|
|
42
|
+
const responseDateHeader = rumRequest.getResponseHeader('Date');
|
|
43
|
+
if (!responseDateHeader) {
|
|
44
|
+
throw new Error('Missing date header on rum response.');
|
|
45
|
+
}
|
|
46
|
+
const resourceEntries = globalScope.performance.getEntriesByName(rumRequestUrl, 'resource');
|
|
47
|
+
if (!Array.isArray(resourceEntries) || resourceEntries.length === 0) {
|
|
48
|
+
throw new Error('Missing rum request performance entry.');
|
|
49
|
+
}
|
|
50
|
+
let medianRumOffset = 0;
|
|
51
|
+
let serverOffset = 0;
|
|
52
|
+
if (typeof resourceEntries[0].responseStart === 'number' && resourceEntries[0].responseStart !== 0) {
|
|
53
|
+
// Cors is enabled and we can make a more accurate calculation of NR server time
|
|
54
|
+
medianRumOffset = (resourceEntries[0].responseStart - resourceEntries[0].requestStart) / 2;
|
|
55
|
+
serverOffset = Math.floor(resourceEntries[0].requestStart + medianRumOffset);
|
|
56
|
+
} else {
|
|
57
|
+
// Cors is disabled or erred, we need to use a less accurate calculation
|
|
58
|
+
medianRumOffset = (resourceEntries[0].responseEnd - resourceEntries[0].fetchStart) / 2;
|
|
59
|
+
serverOffset = Math.floor(resourceEntries[0].fetchStart + medianRumOffset);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Corrected page origin time
|
|
63
|
+
this.#correctedOriginTime = Math.floor(Date.parse(responseDateHeader) - serverOffset);
|
|
64
|
+
this.#localTimeDiff = getRuntime(this.#agent.agentIdentifier).offset - this.#correctedOriginTime;
|
|
65
|
+
if (Number.isNaN(this.#correctedOriginTime)) {
|
|
66
|
+
throw new Error('Date header invalid format.');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Converts a page origin relative time to an absolute timestamp
|
|
72
|
+
* corrected to NR server time.
|
|
73
|
+
* @param relativeTime {number} The relative time of the event in milliseconds
|
|
74
|
+
* @returns {number} The correct timestamp as a unix/epoch timestamp value
|
|
75
|
+
*/
|
|
76
|
+
convertRelativeTimestamp(relativeTime) {
|
|
77
|
+
return this.#correctedOriginTime + relativeTime;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Corrects an event timestamp to NR server time.
|
|
82
|
+
* @param timestamp {number} The unix/epoch timestamp of the event with milliseconds
|
|
83
|
+
* @return {number} Corrected unix/epoch timestamp
|
|
84
|
+
*/
|
|
85
|
+
correctAbsoluteTimestamp(timestamp) {
|
|
86
|
+
return Math.floor(timestamp - this.#localTimeDiff);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -3,47 +3,30 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { ee } from '../event-emitter/contextual-ee';
|
|
6
|
-
import { handle } from '../event-emitter/handle';
|
|
7
|
-
import { FEATURE_NAMES } from '../../loaders/features/features';
|
|
8
6
|
import { dispatchGlobalEvent } from '../dispatch/global-event';
|
|
9
|
-
const bucketMap = {
|
|
10
|
-
stn: [FEATURE_NAMES.sessionTrace],
|
|
11
|
-
err: [FEATURE_NAMES.jserrors, FEATURE_NAMES.metrics],
|
|
12
|
-
ins: [FEATURE_NAMES.pageAction],
|
|
13
|
-
spa: [FEATURE_NAMES.spa, FEATURE_NAMES.softNav],
|
|
14
|
-
sr: [FEATURE_NAMES.sessionReplay, FEATURE_NAMES.sessionTrace]
|
|
15
|
-
};
|
|
16
7
|
const sentIds = new Set();
|
|
17
8
|
|
|
18
|
-
/**
|
|
9
|
+
/** A map of feature flags and their values as provided by the rum call -- scoped by agent ID */
|
|
10
|
+
export const activatedFeatures = {};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Sets the activatedFeatures object, dispatches the global loaded event,
|
|
14
|
+
* and emits the rumresp flag to features
|
|
15
|
+
* @param {{[key:string]:number}} flags key-val pair of flag names and numeric
|
|
16
|
+
* @param {string} agentIdentifier agent instance identifier
|
|
17
|
+
* @returns {void}
|
|
18
|
+
*/
|
|
19
19
|
export function activateFeatures(flags, agentIdentifier) {
|
|
20
20
|
const sharedEE = ee.get(agentIdentifier);
|
|
21
|
+
activatedFeatures[agentIdentifier] ??= {};
|
|
21
22
|
if (!(flags && typeof flags === 'object')) return;
|
|
22
23
|
if (sentIds.has(agentIdentifier)) return;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (bucketMap[flag]) {
|
|
26
|
-
bucketMap[flag].forEach(feat => {
|
|
27
|
-
if (!num) handle('block-' + flag, [], undefined, feat, sharedEE);else handle('feat-' + flag, [], undefined, feat, sharedEE);
|
|
28
|
-
handle('rumresp-' + flag, [Boolean(num)], undefined, feat, sharedEE); // this is a duplicate of feat-/block- but makes awaiting for 1 event easier than 2
|
|
29
|
-
});
|
|
30
|
-
} else if (num) handle('feat-' + flag, [], undefined, undefined, sharedEE); // not sure what other flags are overlooked, but there's a test for ones not in the map --
|
|
31
|
-
activatedFeatures[flag] = Boolean(num);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Let the features waiting on their respective flags know that RUM response was received and that any missing flags are interpreted as bad entitlement / "off".
|
|
35
|
-
// Hence, those features will not be hanging forever if their flags aren't included in the response.
|
|
36
|
-
Object.keys(bucketMap).forEach(flag => {
|
|
37
|
-
if (activatedFeatures[flag] === undefined) {
|
|
38
|
-
bucketMap[flag]?.forEach(feat => handle('rumresp-' + flag, [false], undefined, feat, sharedEE));
|
|
39
|
-
activatedFeatures[flag] = false;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
24
|
+
sharedEE.emit('rumresp', [flags]);
|
|
25
|
+
activatedFeatures[agentIdentifier] = flags;
|
|
42
26
|
sentIds.add(agentIdentifier);
|
|
43
27
|
|
|
44
28
|
// let any window level subscribers know that the agent is running
|
|
45
29
|
dispatchGlobalEvent({
|
|
46
30
|
loaded: true
|
|
47
31
|
});
|
|
48
|
-
}
|
|
49
|
-
export const activatedFeatures = {};
|
|
32
|
+
}
|
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
* This module is used directly by: session_trace.
|
|
8
8
|
* It is also called by -> wrapXhr <-, so see "wrap-xhr.js" for features that use this indirectly.
|
|
9
9
|
*/
|
|
10
|
-
import { ee as baseEE } from '../event-emitter/contextual-ee';
|
|
10
|
+
import { ee as baseEE, contextId } from '../event-emitter/contextual-ee';
|
|
11
11
|
import { createWrapperWithEmitter as wfn } from './wrap-function';
|
|
12
12
|
import { getOrSet } from '../util/get-or-set';
|
|
13
13
|
import { globalScope, isBrowserScope } from '../constants/runtime';
|
|
14
|
-
import { ObservationContextManager } from '../context/observation-context-manager';
|
|
15
14
|
const wrapped = {};
|
|
16
15
|
const XHR = globalScope.XMLHttpRequest;
|
|
17
16
|
const ADD_EVENT_LISTENER = 'addEventListener';
|
|
18
17
|
const REMOVE_EVENT_LISTENER = 'removeEventListener';
|
|
18
|
+
const flag = "nr@wrapped:".concat(contextId);
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Wraps `addEventListener` and `removeEventListener` on: global scope; the prototype of `XMLHttpRequest`, and
|
|
@@ -44,7 +44,7 @@ export function wrapEvents(sharedEE) {
|
|
|
44
44
|
if (originalListener === null || typeof originalListener !== 'function' && typeof originalListener !== 'object') {
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
var wrapped = getOrSet(originalListener,
|
|
47
|
+
var wrapped = getOrSet(originalListener, flag, function () {
|
|
48
48
|
var listener = {
|
|
49
49
|
object: wrapHandleEvent,
|
|
50
50
|
function: originalListener
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
* @file Wraps `fetch` and related methods for instrumentation.
|
|
7
7
|
* This module is used by: ajax, spa.
|
|
8
8
|
*/
|
|
9
|
-
import { ee as baseEE } from '../event-emitter/contextual-ee';
|
|
9
|
+
import { ee as baseEE, contextId } from '../event-emitter/contextual-ee';
|
|
10
10
|
import { globalScope } from '../constants/runtime';
|
|
11
|
-
import { ObservationContextManager } from '../context/observation-context-manager';
|
|
12
11
|
var prefix = 'fetch-';
|
|
13
12
|
var bodyPrefix = prefix + 'body-';
|
|
14
13
|
var bodyMethods = ['arrayBuffer', 'blob', 'json', 'text', 'formData'];
|
|
@@ -71,7 +70,7 @@ export function wrapFetch(sharedEE) {
|
|
|
71
70
|
// we are wrapping args in an array so we can preserve the reference
|
|
72
71
|
ee.emit(prefix + 'before-start', [args], ctx);
|
|
73
72
|
var dtPayload;
|
|
74
|
-
if (ctx[
|
|
73
|
+
if (ctx[contextId] && ctx[contextId].dt) dtPayload = ctx[contextId].dt;
|
|
75
74
|
var origPromiseFromFetch = fn.apply(this, args);
|
|
76
75
|
ee.emit(prefix + 'start', [args, dtPayload], origPromiseFromFetch);
|
|
77
76
|
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { ee } from '../event-emitter/contextual-ee';
|
|
10
|
-
import {
|
|
10
|
+
import { bundleId } from '../ids/bundle-id';
|
|
11
|
+
export const flag = "nr@original:".concat(bundleId);
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* A convenience alias of `hasOwnProperty`.
|
|
@@ -39,7 +40,7 @@ export function createWrapperWithEmitter(emitter, always) {
|
|
|
39
40
|
* As a property on a wrapped function, contains the original function.
|
|
40
41
|
* @type {string}
|
|
41
42
|
*/
|
|
42
|
-
wrapFn.flag =
|
|
43
|
+
wrapFn.flag = flag;
|
|
43
44
|
return wrapFn;
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -55,7 +56,7 @@ export function createWrapperWithEmitter(emitter, always) {
|
|
|
55
56
|
// Unless fn is both wrappable and unwrapped, return it unchanged.
|
|
56
57
|
if (notWrappable(fn)) return fn;
|
|
57
58
|
if (!prefix) prefix = '';
|
|
58
|
-
nrWrapper[
|
|
59
|
+
nrWrapper[flag] = fn;
|
|
59
60
|
copy(fn, nrWrapper, emitter);
|
|
60
61
|
return nrWrapper;
|
|
61
62
|
|
|
@@ -209,5 +210,5 @@ function copy(from, to, emitter) {
|
|
|
209
210
|
* @returns {boolean} Whether the passed function is ineligible to be wrapped.
|
|
210
211
|
*/
|
|
211
212
|
function notWrappable(fn) {
|
|
212
|
-
return !(fn && typeof fn === 'function' && fn.apply && !fn[
|
|
213
|
+
return !(fn && typeof fn === 'function' && fn.apply && !fn[flag]);
|
|
213
214
|
}
|
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
* This module is used by: spa.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { createWrapperWithEmitter as wrapFn } from './wrap-function';
|
|
10
|
+
import { createWrapperWithEmitter as wrapFn, flag } from './wrap-function';
|
|
11
11
|
import { ee as baseEE } from '../event-emitter/contextual-ee';
|
|
12
12
|
import { globalScope } from '../constants/runtime';
|
|
13
|
-
import { ObservationContextManager } from '../context/observation-context-manager';
|
|
14
13
|
const wrapped = {};
|
|
15
14
|
|
|
16
15
|
/**
|
|
@@ -119,7 +118,7 @@ export function wrapPromise(sharedEE) {
|
|
|
119
118
|
promiseEE.emit('propagate', [originalThis, true], origFnCallWithThis, false, false);
|
|
120
119
|
return origFnCallWithThis;
|
|
121
120
|
};
|
|
122
|
-
prevPromiseObj.prototype.then[
|
|
121
|
+
prevPromiseObj.prototype.then[flag] = prevPromiseOrigThen;
|
|
123
122
|
promiseEE.on('executor-start', function (args) {
|
|
124
123
|
args[0] = promiseWrapper(args[0], 'resolve-', this, null, false);
|
|
125
124
|
args[1] = promiseWrapper(args[1], 'resolve-', this, null, false);
|