@newrelic/browser-agent 1.239.1 → 1.241.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/README.md +4 -0
- package/dist/cjs/cdn/pro.js +3 -2
- package/dist/cjs/cdn/spa.js +4 -3
- package/dist/cjs/common/config/state/init.js +25 -17
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/constants/runtime.js +9 -5
- package/dist/cjs/common/harvest/harvest.js +5 -3
- package/dist/cjs/common/vitals/constants.js +17 -0
- package/dist/cjs/common/vitals/cumulative-layout-shift.js +27 -0
- package/dist/cjs/common/vitals/first-contentful-paint.js +49 -0
- package/dist/cjs/common/vitals/first-input-delay.js +32 -0
- package/dist/{esm/features/page_view_timing → cjs/common/vitals}/first-paint.js +19 -17
- package/dist/cjs/common/vitals/interaction-to-next-paint.js +29 -0
- package/dist/cjs/common/vitals/largest-contentful-paint.js +41 -0
- package/dist/cjs/common/vitals/long-task.js +64 -0
- package/dist/cjs/common/vitals/time-to-first-byte.js +36 -0
- package/dist/cjs/common/vitals/vital-metric.js +71 -0
- package/dist/cjs/features/ajax/aggregate/index.js +4 -1
- package/dist/cjs/features/metrics/aggregate/index.js +17 -7
- package/dist/cjs/features/page_view_event/aggregate/index.js +18 -40
- package/dist/cjs/features/page_view_event/constants.js +2 -8
- package/dist/cjs/features/page_view_event/instrument/index.js +0 -22
- package/dist/cjs/features/page_view_timing/aggregate/index.js +36 -147
- package/dist/cjs/features/page_view_timing/instrument/index.js +0 -3
- package/dist/cjs/features/session_replay/aggregate/index.js +81 -35
- package/dist/cjs/features/session_trace/aggregate/index.js +13 -1
- package/dist/cjs/features/spa/aggregate/index.js +4 -3
- package/dist/cjs/loaders/agent.js +3 -0
- package/dist/cjs/loaders/api/api.js +2 -0
- package/dist/cjs/loaders/api/apiAsync.js +4 -2
- package/dist/cjs/loaders/browser-agent.js +2 -1
- package/dist/cjs/loaders/configure/configure.js +13 -1
- package/dist/cjs/loaders/configure/public-path.js +13 -0
- package/dist/cjs/loaders/configure/public-path.npm.js +10 -0
- package/dist/esm/cdn/pro.js +2 -1
- package/dist/esm/cdn/spa.js +2 -1
- package/dist/esm/common/config/state/init.js +25 -17
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/constants/runtime.js +5 -3
- package/dist/esm/common/harvest/harvest.js +6 -4
- package/dist/esm/common/vitals/constants.js +10 -0
- package/dist/esm/common/vitals/cumulative-layout-shift.js +20 -0
- package/dist/esm/common/vitals/first-contentful-paint.js +41 -0
- package/dist/esm/common/vitals/first-input-delay.js +25 -0
- package/dist/{cjs/features/page_view_timing → esm/common/vitals}/first-paint.js +12 -24
- package/dist/esm/common/vitals/interaction-to-next-paint.js +22 -0
- package/dist/esm/common/vitals/largest-contentful-paint.js +34 -0
- package/dist/esm/common/vitals/long-task.js +57 -0
- package/dist/esm/common/vitals/time-to-first-byte.js +29 -0
- package/dist/esm/common/vitals/vital-metric.js +64 -0
- package/dist/esm/features/ajax/aggregate/index.js +4 -1
- package/dist/esm/features/metrics/aggregate/index.js +18 -8
- package/dist/esm/features/page_view_event/aggregate/index.js +20 -42
- package/dist/esm/features/page_view_event/constants.js +1 -4
- package/dist/esm/features/page_view_event/instrument/index.js +0 -22
- package/dist/esm/features/page_view_timing/aggregate/index.js +37 -148
- package/dist/esm/features/page_view_timing/instrument/index.js +0 -3
- package/dist/esm/features/session_replay/aggregate/index.js +81 -35
- package/dist/esm/features/session_trace/aggregate/index.js +13 -1
- package/dist/esm/features/spa/aggregate/index.js +4 -3
- package/dist/esm/loaders/agent.js +2 -0
- package/dist/esm/loaders/api/api.js +2 -0
- package/dist/esm/loaders/api/apiAsync.js +5 -3
- package/dist/esm/loaders/browser-agent.js +2 -1
- package/dist/esm/loaders/configure/configure.js +13 -1
- package/dist/esm/loaders/configure/public-path.js +6 -0
- package/dist/esm/loaders/configure/public-path.npm.js +3 -0
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/constants/runtime.d.ts +3 -1
- package/dist/types/common/constants/runtime.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.d.ts +0 -1
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/vitals/constants.d.ts +11 -0
- package/dist/types/common/vitals/constants.d.ts.map +1 -0
- package/dist/types/common/vitals/cumulative-layout-shift.d.ts +3 -0
- package/dist/types/common/vitals/cumulative-layout-shift.d.ts.map +1 -0
- package/dist/types/common/vitals/first-contentful-paint.d.ts +3 -0
- package/dist/types/common/vitals/first-contentful-paint.d.ts.map +1 -0
- package/dist/types/common/vitals/first-input-delay.d.ts +3 -0
- package/dist/types/common/vitals/first-input-delay.d.ts.map +1 -0
- package/dist/types/common/vitals/first-paint.d.ts +3 -0
- package/dist/types/common/vitals/first-paint.d.ts.map +1 -0
- package/dist/types/common/vitals/interaction-to-next-paint.d.ts +3 -0
- package/dist/types/common/vitals/interaction-to-next-paint.d.ts.map +1 -0
- package/dist/types/common/vitals/largest-contentful-paint.d.ts +3 -0
- package/dist/types/common/vitals/largest-contentful-paint.d.ts.map +1 -0
- package/dist/types/common/vitals/long-task.d.ts +3 -0
- package/dist/types/common/vitals/long-task.d.ts.map +1 -0
- package/dist/types/common/vitals/time-to-first-byte.d.ts +3 -0
- package/dist/types/common/vitals/time-to-first-byte.d.ts.map +1 -0
- package/dist/types/common/vitals/vital-metric.d.ts +18 -0
- package/dist/types/common/vitals/vital-metric.d.ts.map +1 -0
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +3 -2
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/constants.d.ts +0 -3
- package/dist/types/features/page_view_event/constants.d.ts.map +1 -1
- package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +1 -3
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +16 -4
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +9 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/dist/types/loaders/api/apiAsync.d.ts.map +1 -1
- package/dist/types/loaders/browser-agent.d.ts.map +1 -1
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/dist/types/loaders/configure/public-path.d.ts +2 -0
- package/dist/types/loaders/configure/public-path.d.ts.map +1 -0
- package/dist/types/loaders/configure/public-path.npm.d.ts +2 -0
- package/dist/types/loaders/configure/public-path.npm.d.ts.map +1 -0
- package/package.json +2 -3
- package/src/cdn/pro.js +2 -0
- package/src/cdn/spa.js +2 -0
- package/src/common/config/state/init.js +21 -17
- package/src/common/constants/runtime.js +7 -3
- package/src/common/constants/runtime.test.js +8 -0
- package/src/common/harvest/harvest-scheduler.test.js +2 -2
- package/src/common/harvest/harvest.js +6 -4
- package/src/common/harvest/harvest.test.js +17 -0
- package/src/common/vitals/__mocks__/web-vitals.js +19 -0
- package/src/common/vitals/constants.js +10 -0
- package/src/common/vitals/cumulative-layout-shift.js +13 -0
- package/src/common/vitals/cumulative-layout-shift.test.js +71 -0
- package/src/common/vitals/first-contentful-paint.js +31 -0
- package/src/common/vitals/first-contentful-paint.test.js +124 -0
- package/src/common/vitals/first-input-delay.js +20 -0
- package/src/common/vitals/first-input-delay.test.js +88 -0
- package/src/{features/page_view_timing → common/vitals}/first-paint.js +11 -17
- package/src/common/vitals/first-paint.test.js +127 -0
- package/src/common/vitals/interaction-to-next-paint.js +13 -0
- package/src/common/vitals/interaction-to-next-paint.test.js +74 -0
- package/src/common/vitals/largest-contentful-paint.js +29 -0
- package/src/common/vitals/largest-contentful-paint.test.js +94 -0
- package/src/common/vitals/long-task.js +52 -0
- package/src/common/vitals/long-task.test.js +122 -0
- package/src/common/vitals/time-to-first-byte.js +21 -0
- package/src/common/vitals/time-to-first-byte.test.js +147 -0
- package/src/common/vitals/vital-metric.js +60 -0
- package/src/common/vitals/vital-metric.test.js +171 -0
- package/src/features/ajax/aggregate/index.js +5 -1
- package/src/features/metrics/aggregate/index.js +11 -4
- package/src/features/page_view_event/aggregate/index.js +20 -43
- package/src/features/page_view_event/constants.js +0 -3
- package/src/features/page_view_event/instrument/index.js +0 -21
- package/src/features/page_view_timing/aggregate/index.component-test.js +86 -0
- package/src/features/page_view_timing/aggregate/index.js +31 -108
- package/src/features/page_view_timing/instrument/index.js +0 -3
- package/src/features/session_replay/aggregate/index.component-test.js +10 -10
- package/src/features/session_replay/aggregate/index.js +62 -29
- package/src/features/session_trace/aggregate/index.js +15 -1
- package/src/features/spa/aggregate/index.js +4 -3
- package/src/loaders/agent.js +2 -0
- package/src/loaders/api/api.js +2 -0
- package/src/loaders/api/apiAsync.js +5 -4
- package/src/loaders/browser-agent.js +3 -1
- package/src/loaders/configure/configure.js +15 -7
- package/src/loaders/configure/public-path.js +6 -0
- package/src/loaders/configure/public-path.npm.js +4 -0
- package/dist/cjs/common/metrics/paint-metrics.js +0 -13
- package/dist/cjs/features/page_view_timing/long-tasks.js +0 -75
- package/dist/esm/common/metrics/paint-metrics.js +0 -6
- package/dist/esm/features/page_view_timing/long-tasks.js +0 -69
- package/dist/types/common/metrics/paint-metrics.d.ts +0 -2
- package/dist/types/common/metrics/paint-metrics.d.ts.map +0 -1
- package/dist/types/features/page_view_timing/first-paint.d.ts +0 -2
- package/dist/types/features/page_view_timing/first-paint.d.ts.map +0 -1
- package/dist/types/features/page_view_timing/long-tasks.d.ts +0 -2
- package/dist/types/features/page_view_timing/long-tasks.d.ts.map +0 -1
- package/src/common/metrics/paint-metrics.js +0 -6
- package/src/features/page_view_timing/long-tasks.js +0 -60
|
@@ -3,22 +3,33 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { onFCP, onFID, onLCP, onCLS, onINP } from 'web-vitals';
|
|
7
|
-
import { onFirstPaint } from '../first-paint';
|
|
8
|
-
import { onLongTask } from '../long-tasks';
|
|
9
|
-
import { iOSBelow16 } from '../../../common/constants/runtime';
|
|
10
6
|
import { nullable, numeric, getAddStringContext, addCustomAttributes } from '../../../common/serialize/bel-serializer';
|
|
11
7
|
import { mapOwn } from '../../../common/util/map-own';
|
|
12
8
|
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
13
9
|
import { registerHandler } from '../../../common/event-emitter/register-handler';
|
|
14
|
-
import { cleanURL } from '../../../common/url/clean-url';
|
|
15
10
|
import { handle } from '../../../common/event-emitter/handle';
|
|
16
|
-
import { getInfo, getConfigurationValue
|
|
11
|
+
import { getInfo, getConfigurationValue } from '../../../common/config/config';
|
|
17
12
|
import { FEATURE_NAME } from '../constants';
|
|
18
13
|
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
19
14
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
15
|
+
import { cumulativeLayoutShift } from '../../../common/vitals/cumulative-layout-shift';
|
|
16
|
+
import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint';
|
|
17
|
+
import { firstInputDelay } from '../../../common/vitals/first-input-delay';
|
|
18
|
+
import { firstPaint } from '../../../common/vitals/first-paint';
|
|
19
|
+
import { interactionToNextPaint } from '../../../common/vitals/interaction-to-next-paint';
|
|
20
|
+
import { largestContentfulPaint } from '../../../common/vitals/largest-contentful-paint';
|
|
21
|
+
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte';
|
|
22
|
+
import { longTask } from '../../../common/vitals/long-task';
|
|
20
23
|
export class Aggregate extends AggregateBase {
|
|
21
24
|
static featureName = FEATURE_NAME;
|
|
25
|
+
#handleVitalMetric = _ref => {
|
|
26
|
+
let {
|
|
27
|
+
name,
|
|
28
|
+
value,
|
|
29
|
+
attrs
|
|
30
|
+
} = _ref;
|
|
31
|
+
this.addTiming(name, value, attrs);
|
|
32
|
+
};
|
|
22
33
|
constructor(agentIdentifier, aggregator) {
|
|
23
34
|
var _this;
|
|
24
35
|
super(agentIdentifier, aggregator, FEATURE_NAME);
|
|
@@ -26,163 +37,41 @@ export class Aggregate extends AggregateBase {
|
|
|
26
37
|
this.timings = [];
|
|
27
38
|
this.timingsSent = [];
|
|
28
39
|
this.curSessEndRecorded = false;
|
|
29
|
-
this
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
/* PerformancePaintTiming API - BFC is not yet supported. */
|
|
37
|
-
onFirstPaint(_ref => {
|
|
38
|
-
let {
|
|
39
|
-
name,
|
|
40
|
-
value
|
|
41
|
-
} = _ref;
|
|
42
|
-
if (pageStartedHidden) return;
|
|
43
|
-
this.addTiming(name.toLowerCase(), Math.floor(value));
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
/* First Contentful Paint - As of WV v3, it still imperfectly tries to detect document vis state asap and isn't supposed to report if page starts hidden. */
|
|
47
|
-
if (iOSBelow16) {
|
|
48
|
-
try {
|
|
49
|
-
if (!pageStartedHidden) {
|
|
50
|
-
// see ios-version.js for detail on this following bug case; tldr: buffered flag doesn't work but getEntriesByType does
|
|
51
|
-
const paintEntries = performance.getEntriesByType('paint');
|
|
52
|
-
paintEntries.forEach(entry => {
|
|
53
|
-
if (entry.name === 'first-contentful-paint') {
|
|
54
|
-
this.addTiming('fcp', Math.floor(entry.startTime));
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
} catch (e) {}
|
|
59
|
-
} else {
|
|
60
|
-
onFCP(_ref2 => {
|
|
61
|
-
let {
|
|
62
|
-
name,
|
|
63
|
-
value
|
|
64
|
-
} = _ref2;
|
|
65
|
-
if (pageStartedHidden || this.alreadySent.has(name)) return;
|
|
66
|
-
this.alreadySent.add(name);
|
|
67
|
-
this.addTiming(name.toLowerCase(), value);
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/* First Input Delay (+"First Interaction") - As of WV v3, it still imperfectly tries to detect document vis state asap and isn't supposed to report if page starts hidden. */
|
|
72
|
-
onFID(_ref3 => {
|
|
73
|
-
let {
|
|
74
|
-
name,
|
|
75
|
-
value,
|
|
76
|
-
entries
|
|
77
|
-
} = _ref3;
|
|
78
|
-
if (pageStartedHidden || this.alreadySent.has(name) || entries.length === 0) return;
|
|
79
|
-
this.alreadySent.add(name);
|
|
80
|
-
|
|
81
|
-
// CWV will only report one (THE) first-input entry to us; fid isn't reported if there are no user interactions occurs before the *first* page hiding.
|
|
82
|
-
const fiEntry = entries[0];
|
|
83
|
-
const attributes = {
|
|
84
|
-
type: fiEntry.name,
|
|
85
|
-
fid: Math.round(value)
|
|
86
|
-
};
|
|
87
|
-
this.addConnectionAttributes(attributes);
|
|
88
|
-
this.addTiming('fi', Math.round(fiEntry.startTime), attributes);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
/* Largest Contentful Paint - As of WV v3, it still imperfectly tries to detect document vis state asap and isn't supposed to report if page starts hidden. */
|
|
92
|
-
onLCP(_ref4 => {
|
|
40
|
+
firstPaint.subscribe(this.#handleVitalMetric);
|
|
41
|
+
firstContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
42
|
+
firstInputDelay.subscribe(this.#handleVitalMetric);
|
|
43
|
+
largestContentfulPaint.subscribe(this.#handleVitalMetric);
|
|
44
|
+
interactionToNextPaint.subscribe(this.#handleVitalMetric);
|
|
45
|
+
timeToFirstByte.subscribe(_ref2 => {
|
|
93
46
|
let {
|
|
94
|
-
name,
|
|
95
|
-
value,
|
|
96
47
|
entries
|
|
97
|
-
} =
|
|
98
|
-
|
|
99
|
-
this.alreadySent.add(name);
|
|
100
|
-
const attributes = {};
|
|
101
|
-
if (entries.length > 0) {
|
|
102
|
-
// CWV will only ever report one (THE) lcp entry to us; lcp is also only reported *once* on earlier(user interaction, page hidden).
|
|
103
|
-
const lcpEntry = entries[entries.length - 1]; // this looks weird if we only expect one, but this is how cwv-attribution gets it so to be sure...
|
|
104
|
-
attributes.size = lcpEntry.size;
|
|
105
|
-
attributes.eid = lcpEntry.id;
|
|
106
|
-
if (lcpEntry.url) {
|
|
107
|
-
attributes.elUrl = cleanURL(lcpEntry.url);
|
|
108
|
-
}
|
|
109
|
-
if (lcpEntry.element?.tagName) {
|
|
110
|
-
attributes.elTag = lcpEntry.element.tagName;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
this.addConnectionAttributes(attributes);
|
|
114
|
-
this.addTiming(name.toLowerCase(), value, attributes);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
/* Cumulative Layout Shift - We don't have to limit this callback since cls is stored as a state and only sent as attribute on other timings.
|
|
118
|
-
reportAllChanges ensures our tracked cls has the most recent rolling value to attach to 'unload' and 'pagehide'. */
|
|
119
|
-
onCLS(_ref5 => {
|
|
120
|
-
let {
|
|
121
|
-
value
|
|
122
|
-
} = _ref5;
|
|
123
|
-
this.cls = value;
|
|
124
|
-
}, {
|
|
125
|
-
reportAllChanges: true
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
/* Interaction-to-Next-Paint */
|
|
129
|
-
onINP(_ref6 => {
|
|
130
|
-
let {
|
|
131
|
-
name,
|
|
132
|
-
value,
|
|
133
|
-
id
|
|
134
|
-
} = _ref6;
|
|
135
|
-
return this.addTiming(name.toLowerCase(), value, {
|
|
136
|
-
metricId: id
|
|
137
|
-
});
|
|
48
|
+
} = _ref2;
|
|
49
|
+
this.addTiming('load', Math.round(entries[0].loadEventEnd));
|
|
138
50
|
});
|
|
139
|
-
|
|
140
|
-
/* PerformanceLongTaskTiming API */
|
|
141
|
-
if (getConfigurationValue(this.agentIdentifier, 'page_view_timing.long_task') === true) {
|
|
142
|
-
onLongTask(_ref7 => {
|
|
143
|
-
let {
|
|
144
|
-
name,
|
|
145
|
-
value,
|
|
146
|
-
info
|
|
147
|
-
} = _ref7;
|
|
148
|
-
return this.addTiming(name.toLowerCase(), value, info);
|
|
149
|
-
}); // lt context is passed as 'info'=attrs in the timing node
|
|
150
|
-
}
|
|
151
|
-
/* ------------------------------------End of ex-loader section */
|
|
51
|
+
if (getConfigurationValue(this.agentIdentifier, 'page_view_timing.long_task') === true) longTask.subscribe(this.#handleVitalMetric);
|
|
152
52
|
|
|
153
53
|
/* It's important that CWV api, like "onLCP", is called before this scheduler is initialized. The reason is because they listen to the same
|
|
154
54
|
on vis change or pagehide events, and we'd want ex. onLCP to record the timing (win the race) before we try to send "final harvest". */
|
|
155
|
-
|
|
156
|
-
onFinished: function () {
|
|
157
|
-
return _this.onHarvestFinished(...arguments);
|
|
158
|
-
},
|
|
159
|
-
getPayload: function () {
|
|
160
|
-
return _this.prepareHarvest(...arguments);
|
|
161
|
-
}
|
|
162
|
-
}, this);
|
|
163
|
-
registerHandler('timing', (name, value, attrs) => this.addTiming(name, value, attrs), this.featureName, this.ee); // notice CLS is added to all timings via 4th param
|
|
55
|
+
|
|
164
56
|
registerHandler('docHidden', msTimestamp => this.endCurrentSession(msTimestamp), this.featureName, this.ee);
|
|
165
57
|
registerHandler('winPagehide', msTimestamp => this.recordPageUnload(msTimestamp), this.featureName, this.ee);
|
|
166
58
|
const initialHarvestSeconds = getConfigurationValue(this.agentIdentifier, 'page_view_timing.initialHarvestSeconds') || 10;
|
|
167
59
|
const harvestTimeSeconds = getConfigurationValue(this.agentIdentifier, 'page_view_timing.harvestTimeSeconds') || 30;
|
|
168
60
|
// send initial data sooner, then start regular
|
|
169
61
|
this.ee.on("drain-".concat(this.featureName), () => {
|
|
62
|
+
this.scheduler = new HarvestScheduler('events', {
|
|
63
|
+
onFinished: function () {
|
|
64
|
+
return _this.onHarvestFinished(...arguments);
|
|
65
|
+
},
|
|
66
|
+
getPayload: function () {
|
|
67
|
+
return _this.prepareHarvest(...arguments);
|
|
68
|
+
}
|
|
69
|
+
}, this);
|
|
170
70
|
this.scheduler.startTimer(harvestTimeSeconds, initialHarvestSeconds);
|
|
171
71
|
});
|
|
172
72
|
this.drain();
|
|
173
73
|
}
|
|
174
74
|
|
|
175
|
-
// takes an attributes object and appends connection attributes if available
|
|
176
|
-
addConnectionAttributes(attributes) {
|
|
177
|
-
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; // to date, both window & worker shares the same support for connection
|
|
178
|
-
if (!connection) return;
|
|
179
|
-
if (connection.type) attributes['net-type'] = connection.type;
|
|
180
|
-
if (connection.effectiveType) attributes['net-etype'] = connection.effectiveType;
|
|
181
|
-
if (connection.rtt) attributes['net-rtt'] = connection.rtt;
|
|
182
|
-
if (connection.downlink) attributes['net-dlink'] = connection.downlink;
|
|
183
|
-
return attributes;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
75
|
/**
|
|
187
76
|
* Add the time of _document visibilitychange to hidden_ to the next PVT harvest == NRDB pageHide attr.
|
|
188
77
|
* @param {number} timestamp
|
|
@@ -219,8 +108,8 @@ export class Aggregate extends AggregateBase {
|
|
|
219
108
|
Mitigation: We've set initial CLS to null so that it's omitted from timings like 'pageHide' in that edge case. It should only be included if onCLS callback was executed at least once.
|
|
220
109
|
Future: onCLS value changes should be reported directly & CLS separated into its own timing node so it's not beholden to 'pageHide' firing. It'd also be possible to report the real final CLS.
|
|
221
110
|
*/
|
|
222
|
-
if (
|
|
223
|
-
attrs.cls =
|
|
111
|
+
if (cumulativeLayoutShift.current.value >= 0) {
|
|
112
|
+
attrs.cls = cumulativeLayoutShift.current.value;
|
|
224
113
|
}
|
|
225
114
|
this.timings.push({
|
|
226
115
|
name,
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { handle } from '../../../common/event-emitter/handle';
|
|
6
|
-
import { getRuntime } from '../../../common/config/config';
|
|
7
6
|
import { subscribeToVisibilityChange } from '../../../common/window/page-visibility';
|
|
8
7
|
import { windowAddEventListener } from '../../../common/event-listener/event-listener-opts';
|
|
9
8
|
import { now } from '../../../common/timing/now';
|
|
@@ -17,9 +16,7 @@ export class Instrument extends InstrumentBase {
|
|
|
17
16
|
super(agentIdentifier, aggregator, FEATURE_NAME, auto);
|
|
18
17
|
if (!isBrowserScope) return; // CWV is irrelevant outside web context
|
|
19
18
|
|
|
20
|
-
// Document visibility state becomes hidden; this should run as soon as possible in page life.
|
|
21
19
|
// While we try to replicate web-vital's visibilitywatcher logic in an effort to defer that library to post-pageload, this isn't perfect and doesn't consider prerendering.
|
|
22
|
-
getRuntime(agentIdentifier).initHidden = Boolean(document.visibilityState === 'hidden');
|
|
23
20
|
subscribeToVisibilityChange(() => handle('docHidden', [now()], undefined, FEATURE_NAME, this.ee), true);
|
|
24
21
|
|
|
25
22
|
// Window fires its pagehide event (typically on navigation--this occurrence is a *subset* of vis change); don't defer this unless it's guarantee it cannot happen before load(?)
|
|
@@ -20,6 +20,7 @@ import { AggregateBase } from '../../utils/aggregate-base';
|
|
|
20
20
|
import { sharedChannel } from '../../../common/constants/shared-channel';
|
|
21
21
|
import { obj as encodeObj } from '../../../common/url/encode';
|
|
22
22
|
import { warn } from '../../../common/util/console';
|
|
23
|
+
import { globalScope } from '../../../common/constants/runtime';
|
|
23
24
|
|
|
24
25
|
// would be better to get this dynamically in some way
|
|
25
26
|
export const RRWEB_VERSION = '2.0.0-alpha.8';
|
|
@@ -64,17 +65,30 @@ export class Aggregate extends AggregateBase {
|
|
|
64
65
|
* -- When visibility changes from "hidden" -> "visible", it must capture a full snapshot for the replay to work correctly across tabs
|
|
65
66
|
*/
|
|
66
67
|
this.hasSnapshot = false;
|
|
68
|
+
/** Payload metadata -- Should indicate that the payload being sent has a meta node. The meta node should always precede a snapshot node. */
|
|
69
|
+
this.hasMeta = false;
|
|
67
70
|
/** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
|
|
68
71
|
this.hasError = false;
|
|
69
72
|
|
|
70
|
-
/** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs.
|
|
73
|
+
/** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs.
|
|
74
|
+
* cycle timestamps are used as fallbacks if event timestamps cannot be used
|
|
75
|
+
*/
|
|
71
76
|
this.timestamp = {
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
event: {
|
|
78
|
+
first: undefined,
|
|
79
|
+
last: undefined
|
|
80
|
+
},
|
|
81
|
+
cycle: {
|
|
82
|
+
first: undefined,
|
|
83
|
+
last: undefined
|
|
84
|
+
}
|
|
74
85
|
};
|
|
75
86
|
|
|
76
87
|
/** A value which increments with every new mutation node reported. Resets after a harvest is sent */
|
|
77
88
|
this.payloadBytesEstimation = 0;
|
|
89
|
+
|
|
90
|
+
/** Hold on to the last meta node, so that it can be re-inserted if the meta and snapshot nodes are broken up due to harvesting */
|
|
91
|
+
this.lastMeta = undefined;
|
|
78
92
|
const shouldSetup = getConfigurationValue(agentIdentifier, 'privacy.cookies_enabled') === true && getConfigurationValue(agentIdentifier, 'session_trace.enabled') === true;
|
|
79
93
|
|
|
80
94
|
/** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
|
|
@@ -124,7 +138,7 @@ export class Aggregate extends AggregateBase {
|
|
|
124
138
|
}, this.featureName, this.ee);
|
|
125
139
|
this.waitForFlags(['sr']).then(_ref => {
|
|
126
140
|
let [flagOn] = _ref;
|
|
127
|
-
return this.initializeRecording(flagOn, Math.random() < getConfigurationValue(this.agentIdentifier, 'session_replay.
|
|
141
|
+
return this.initializeRecording(flagOn, Math.random() * 100 < getConfigurationValue(this.agentIdentifier, 'session_replay.error_sampling_rate'), Math.random() * 100 < getConfigurationValue(this.agentIdentifier, 'session_replay.sampling_rate'));
|
|
128
142
|
}).then(() => sharedChannel.onReplayReady(this.mode)); // notify watchers that replay started with the mode
|
|
129
143
|
|
|
130
144
|
this.drain();
|
|
@@ -165,6 +179,12 @@ export class Aggregate extends AggregateBase {
|
|
|
165
179
|
if (this.mode === MODE.ERROR && this.errorNoticed) {
|
|
166
180
|
this.mode = MODE.FULL;
|
|
167
181
|
}
|
|
182
|
+
try {
|
|
183
|
+
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
184
|
+
recorder = (await import( /* webpackChunkName: "recorder" */'rrweb')).record;
|
|
185
|
+
} catch (err) {
|
|
186
|
+
return this.abort();
|
|
187
|
+
}
|
|
168
188
|
|
|
169
189
|
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
170
190
|
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
@@ -173,12 +193,6 @@ export class Aggregate extends AggregateBase {
|
|
|
173
193
|
// We only report (harvest) in FULL mode
|
|
174
194
|
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
175
195
|
}
|
|
176
|
-
try {
|
|
177
|
-
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
178
|
-
recorder = (await import( /* webpackChunkName: "recorder" */'rrweb')).record;
|
|
179
|
-
} catch (err) {
|
|
180
|
-
return this.abort();
|
|
181
|
-
}
|
|
182
196
|
try {
|
|
183
197
|
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
184
198
|
const {
|
|
@@ -213,6 +227,8 @@ export class Aggregate extends AggregateBase {
|
|
|
213
227
|
getHarvestContents() {
|
|
214
228
|
const agentRuntime = getRuntime(this.agentIdentifier);
|
|
215
229
|
const info = getInfo(this.agentIdentifier);
|
|
230
|
+
const firstTimestamp = this.timestamp.event.first || this.timestamp.cycle.first;
|
|
231
|
+
const lastTimestamp = this.timestamp.event.last || this.timestamp.cycle.last;
|
|
216
232
|
return {
|
|
217
233
|
qs: {
|
|
218
234
|
browser_monitoring_key: info.licenseKey,
|
|
@@ -223,11 +239,12 @@ export class Aggregate extends AggregateBase {
|
|
|
223
239
|
...(this.shouldCompress && {
|
|
224
240
|
content_encoding: 'gzip'
|
|
225
241
|
}),
|
|
226
|
-
'replay.firstTimestamp':
|
|
227
|
-
'replay.lastTimestamp':
|
|
228
|
-
'replay.durationMs':
|
|
242
|
+
'replay.firstTimestamp': firstTimestamp,
|
|
243
|
+
'replay.lastTimestamp': lastTimestamp,
|
|
244
|
+
'replay.durationMs': lastTimestamp - firstTimestamp,
|
|
229
245
|
agentVersion: agentRuntime.version,
|
|
230
246
|
session: agentRuntime.session.state.value,
|
|
247
|
+
hasMeta: this.hasMeta,
|
|
231
248
|
hasSnapshot: this.hasSnapshot,
|
|
232
249
|
hasError: this.hasError,
|
|
233
250
|
isFirstChunk: this.isFirstChunk,
|
|
@@ -252,6 +269,7 @@ export class Aggregate extends AggregateBase {
|
|
|
252
269
|
this.events = [];
|
|
253
270
|
this.isFirstChunk = false;
|
|
254
271
|
this.hasSnapshot = false;
|
|
272
|
+
this.hasMeta = false;
|
|
255
273
|
this.hasError = false;
|
|
256
274
|
this.payloadBytesEstimation = 0;
|
|
257
275
|
this.clearTimestamps();
|
|
@@ -263,27 +281,30 @@ export class Aggregate extends AggregateBase {
|
|
|
263
281
|
warn('Recording library was never imported');
|
|
264
282
|
return this.abort();
|
|
265
283
|
}
|
|
284
|
+
this.clearTimestamps();
|
|
285
|
+
// set the fallbacks as early as possible
|
|
286
|
+
this.setTimestamps();
|
|
266
287
|
this.recording = true;
|
|
267
288
|
const {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
289
|
+
block_class,
|
|
290
|
+
ignore_class,
|
|
291
|
+
mask_text_class,
|
|
292
|
+
block_selector,
|
|
293
|
+
mask_input_options,
|
|
294
|
+
mask_text_selector,
|
|
295
|
+
mask_all_inputs
|
|
275
296
|
} = getConfigurationValue(this.agentIdentifier, 'session_replay');
|
|
276
297
|
// set up rrweb configurations for maximum privacy --
|
|
277
298
|
// https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
|
|
278
299
|
const stop = recorder({
|
|
279
300
|
emit: this.store.bind(this),
|
|
280
|
-
blockClass,
|
|
281
|
-
ignoreClass,
|
|
282
|
-
maskTextClass,
|
|
283
|
-
blockSelector,
|
|
284
|
-
maskInputOptions,
|
|
285
|
-
maskTextSelector,
|
|
286
|
-
maskAllInputs,
|
|
301
|
+
blockClass: block_class,
|
|
302
|
+
ignoreClass: ignore_class,
|
|
303
|
+
maskTextClass: mask_text_class,
|
|
304
|
+
blockSelector: block_selector,
|
|
305
|
+
maskInputOptions: mask_input_options,
|
|
306
|
+
maskTextSelector: mask_text_selector,
|
|
307
|
+
maskAllInputs: mask_all_inputs,
|
|
287
308
|
checkoutEveryNms: CHECKOUT_MS[this.mode]
|
|
288
309
|
});
|
|
289
310
|
this.stopRecording = () => {
|
|
@@ -294,6 +315,7 @@ export class Aggregate extends AggregateBase {
|
|
|
294
315
|
|
|
295
316
|
/** Store a payload in the buffer (this.events). This should be the callback to the recording lib noticing a mutation */
|
|
296
317
|
store(event, isCheckout) {
|
|
318
|
+
this.setTimestamps(event);
|
|
297
319
|
if (this.blocked) return;
|
|
298
320
|
const eventBytes = stringify(event).length;
|
|
299
321
|
/** The estimated size of the payload after compression */
|
|
@@ -310,8 +332,22 @@ export class Aggregate extends AggregateBase {
|
|
|
310
332
|
// we are still waiting for an error to throw, so keep wiping the buffer over time
|
|
311
333
|
this.clearBuffer();
|
|
312
334
|
}
|
|
313
|
-
|
|
314
|
-
|
|
335
|
+
|
|
336
|
+
// meta event
|
|
337
|
+
if (event.type === 4) {
|
|
338
|
+
this.hasMeta = true;
|
|
339
|
+
this.lastMeta = event;
|
|
340
|
+
}
|
|
341
|
+
// snapshot event
|
|
342
|
+
if (event.type === 2) {
|
|
343
|
+
this.hasSnapshot = true;
|
|
344
|
+
// small chance that the meta event got separated from its matching snapshot across payload harvests
|
|
345
|
+
// it needs to precede the snapshot, so shove it in first.
|
|
346
|
+
if (!this.hasMeta) {
|
|
347
|
+
this.events.push(this.lastMeta);
|
|
348
|
+
this.hasMeta = true;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
315
351
|
this.events.push(event);
|
|
316
352
|
this.payloadBytesEstimation += eventBytes;
|
|
317
353
|
|
|
@@ -328,15 +364,25 @@ export class Aggregate extends AggregateBase {
|
|
|
328
364
|
if (!recorder) return;
|
|
329
365
|
recorder.takeFullSnapshot();
|
|
330
366
|
}
|
|
331
|
-
setTimestamps(
|
|
332
|
-
if
|
|
333
|
-
|
|
334
|
-
this.timestamp.
|
|
367
|
+
setTimestamps(event) {
|
|
368
|
+
// fallbacks if timestamps cannot be derived from rrweb events
|
|
369
|
+
this.timestamp.cycle.last = getRuntime(this.agentIdentifier).offset + globalScope.performance.now();
|
|
370
|
+
if (!this.timestamp.cycle.first) this.timestamp.cycle.first = this.timestamp.cycle.last;
|
|
371
|
+
// timestamps based on rrweb events
|
|
372
|
+
if (!event || !event.timestamp) return;
|
|
373
|
+
if (!this.timestamp.event.first) this.timestamp.event.first = event.timestamp;
|
|
374
|
+
this.timestamp.event.last = event.timestamp;
|
|
335
375
|
}
|
|
336
376
|
clearTimestamps() {
|
|
337
377
|
this.timestamp = {
|
|
338
|
-
|
|
339
|
-
|
|
378
|
+
event: {
|
|
379
|
+
first: undefined,
|
|
380
|
+
last: undefined
|
|
381
|
+
},
|
|
382
|
+
cycle: {
|
|
383
|
+
first: undefined,
|
|
384
|
+
last: undefined
|
|
385
|
+
}
|
|
340
386
|
};
|
|
341
387
|
}
|
|
342
388
|
|
|
@@ -485,9 +485,12 @@ export class Aggregate extends AggregateBase {
|
|
|
485
485
|
// if PO isn't supported, this checks resourcetiming buffer every harvest.
|
|
486
486
|
this.storeResources(window.performance.getEntriesByType('resource'));
|
|
487
487
|
}
|
|
488
|
+
let earliestTimeStamp = Infinity;
|
|
488
489
|
const stns = Object.entries(this.trace).flatMap(_ref3 => {
|
|
489
490
|
let [name, listOfSTNodes] = _ref3;
|
|
490
491
|
// basically take the "this.trace" map-obj and concat all the list-type values
|
|
492
|
+
const oldestNodeTS = listOfSTNodes.reduce((acc, next) => !acc || next.s < acc ? next.s : acc, undefined);
|
|
493
|
+
if (oldestNodeTS < earliestTimeStamp) earliestTimeStamp = oldestNodeTS;
|
|
491
494
|
if (!(name in toAggregate)) return listOfSTNodes;
|
|
492
495
|
// Special processing for event nodes dealing with user inputs:
|
|
493
496
|
const reindexByOriginFn = this.smearEvtsByOrigin(name);
|
|
@@ -502,8 +505,17 @@ export class Aggregate extends AggregateBase {
|
|
|
502
505
|
this.nodeCount = 0;
|
|
503
506
|
return {
|
|
504
507
|
qs: {
|
|
505
|
-
st:
|
|
508
|
+
st: this.agentRuntime.offset,
|
|
509
|
+
/** hr === "hasReplay" in NR1, standalone is always checked and processed before harvesting
|
|
510
|
+
* so a race condition between ST and SR states should not be a concern if implemented here */
|
|
511
|
+
hr: Number(!this.isStandalone),
|
|
512
|
+
/** fts === "firstTimestamp" in NR1, indicates what the earliest NODE timestamp was
|
|
513
|
+
* so that blob parsing doesn't need to happen to support UI/API functions */
|
|
514
|
+
fts: this.agentRuntime.offset + earliestTimeStamp,
|
|
515
|
+
/** n === "nodeCount" in NR1, a count of nodes in the ST payload, so that blob parsing doesn't need to happen to support UI/API functions */
|
|
516
|
+
n: stns.length // node count
|
|
506
517
|
},
|
|
518
|
+
|
|
507
519
|
body: {
|
|
508
520
|
res: stns
|
|
509
521
|
}
|
|
@@ -9,7 +9,6 @@ import { shouldCollectEvent } from '../../../common/deny-list/deny-list';
|
|
|
9
9
|
import { mapOwn } from '../../../common/util/map-own';
|
|
10
10
|
import { navTimingValues as navTiming } from '../../../common/timing/nav-timing';
|
|
11
11
|
import { generateUuid } from '../../../common/ids/unique-id';
|
|
12
|
-
import { paintMetrics } from '../../../common/metrics/paint-metrics';
|
|
13
12
|
import { Interaction } from './interaction';
|
|
14
13
|
import { getConfigurationValue, getRuntime } from '../../../common/config/config';
|
|
15
14
|
import { eventListenerOpts } from '../../../common/event-listener/event-listener-opts';
|
|
@@ -19,6 +18,8 @@ import { ee } from '../../../common/event-emitter/contextual-ee';
|
|
|
19
18
|
import * as CONSTANTS from '../constants';
|
|
20
19
|
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
21
20
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
21
|
+
import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint';
|
|
22
|
+
import { firstPaint } from '../../../common/vitals/first-paint';
|
|
22
23
|
const {
|
|
23
24
|
FEATURE_NAME,
|
|
24
25
|
INTERACTION_EVENTS,
|
|
@@ -653,8 +654,8 @@ export class Aggregate extends AggregateBase {
|
|
|
653
654
|
// assign unique id, this is serialized and used to link interactions with errors
|
|
654
655
|
interaction.root.attrs.id = generateUuid();
|
|
655
656
|
if (interaction.root.attrs.trigger === 'initialPageLoad') {
|
|
656
|
-
interaction.root.attrs.firstPaint =
|
|
657
|
-
interaction.root.attrs.firstContentfulPaint =
|
|
657
|
+
interaction.root.attrs.firstPaint = firstPaint.current.value;
|
|
658
|
+
interaction.root.attrs.firstContentfulPaint = firstContentfulPaint.current.value;
|
|
658
659
|
}
|
|
659
660
|
baseEE.emit('interactionSaved', [interaction]);
|
|
660
661
|
state.interactionsToHarvest.push(interaction);
|
|
@@ -123,6 +123,8 @@ export function setAPI(agentIdentifier, forceDrain) {
|
|
|
123
123
|
};
|
|
124
124
|
apiInterface.start = features => {
|
|
125
125
|
try {
|
|
126
|
+
const smTag = !features ? 'undefined' : 'defined';
|
|
127
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ["API/start/".concat(smTag, "/called")], undefined, FEATURE_NAMES.metrics, instanceEE);
|
|
126
128
|
const featNames = Object.values(FEATURE_NAMES);
|
|
127
129
|
if (features === undefined) features = featNames;else {
|
|
128
130
|
features = Array.isArray(features) && features.length ? features : [features];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FEATURE_NAMES } from '../features/features';
|
|
2
|
-
import {
|
|
2
|
+
import { getConfiguration, getInfo, getRuntime } from '../../common/config/config';
|
|
3
3
|
import { ee } from '../../common/event-emitter/contextual-ee';
|
|
4
4
|
import { handle } from '../../common/event-emitter/handle';
|
|
5
5
|
import { registerHandler } from '../../common/event-emitter/register-handler';
|
|
@@ -10,7 +10,6 @@ import { CUSTOM_METRIC_CHANNEL } from '../../features/metrics/constants';
|
|
|
10
10
|
export function setAPI(agentIdentifier) {
|
|
11
11
|
var instanceEE = ee.get(agentIdentifier);
|
|
12
12
|
var cycle = 0;
|
|
13
|
-
var scheme = getConfigurationValue(agentIdentifier, 'ssl') === false ? 'http' : 'https';
|
|
14
13
|
var api = {
|
|
15
14
|
finished: single(finished),
|
|
16
15
|
setErrorHandler,
|
|
@@ -66,7 +65,10 @@ export function setAPI(agentIdentifier) {
|
|
|
66
65
|
cycle += 1;
|
|
67
66
|
const agentInfo = getInfo(agentIdentifier);
|
|
68
67
|
if (!agentInfo.beacon) return;
|
|
69
|
-
|
|
68
|
+
const agentInit = getConfiguration(agentIdentifier);
|
|
69
|
+
const scheme = agentInit.ssl === false ? 'http' : 'https';
|
|
70
|
+
const beacon = agentInit.proxy.beacon || agentInfo.beacon;
|
|
71
|
+
let url = "".concat(scheme, "://").concat(beacon, "/1/").concat(agentInfo.licenseKey);
|
|
70
72
|
url += '?a=' + agentInfo.applicationID + '&';
|
|
71
73
|
url += 't=' + requestName + '&';
|
|
72
74
|
url += 'qt=' + ~~queueTime + '&';
|
|
@@ -7,6 +7,7 @@ import { Instrument as InstrumentXhr } from '../features/ajax/instrument';
|
|
|
7
7
|
import { Instrument as InstrumentSessionTrace } from '../features/session_trace/instrument';
|
|
8
8
|
import { Instrument as InstrumentSpa } from '../features/spa/instrument';
|
|
9
9
|
import { Instrument as InstrumentPageAction } from '../features/page_action/instrument';
|
|
10
|
+
import { Instrument as InstrumentSessionReplay } from '../features/session_replay/instrument';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* An agent class with all feature modules available. Features may be disabled and enabled via runtime configuration.
|
|
@@ -16,7 +17,7 @@ export class BrowserAgent extends Agent {
|
|
|
16
17
|
constructor(args) {
|
|
17
18
|
super({
|
|
18
19
|
...args,
|
|
19
|
-
features: [InstrumentXhr, InstrumentPageViewEvent, InstrumentPageViewTiming, InstrumentSessionTrace, InstrumentMetrics, InstrumentPageAction, InstrumentErrors, InstrumentSpa],
|
|
20
|
+
features: [InstrumentXhr, InstrumentPageViewEvent, InstrumentPageViewTiming, InstrumentSessionTrace, InstrumentMetrics, InstrumentPageAction, InstrumentErrors, InstrumentSpa, InstrumentSessionReplay],
|
|
20
21
|
loaderType: 'browser-agent'
|
|
21
22
|
});
|
|
22
23
|
}
|
|
@@ -3,6 +3,9 @@ import { addToNREUM, gosCDN, gosNREUMInitializedAgents } from '../../common/wind
|
|
|
3
3
|
import { getConfiguration, setConfiguration, setInfo, setLoaderConfig, setRuntime } from '../../common/config/config';
|
|
4
4
|
import { activatedFeatures } from '../../common/util/feature-flags';
|
|
5
5
|
import { isWorkerScope } from '../../common/constants/runtime';
|
|
6
|
+
import { redefinePublicPath } from './public-path';
|
|
7
|
+
let alreadySetOnce = false; // the configure() function can run multiple times in agent lifecycle
|
|
8
|
+
|
|
6
9
|
export function configure(agentIdentifier) {
|
|
7
10
|
let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
8
11
|
let loaderType = arguments.length > 2 ? arguments[2] : undefined;
|
|
@@ -34,7 +37,16 @@ export function configure(agentIdentifier) {
|
|
|
34
37
|
}
|
|
35
38
|
setInfo(agentIdentifier, info);
|
|
36
39
|
const updatedInit = getConfiguration(agentIdentifier);
|
|
37
|
-
|
|
40
|
+
const internalTrafficList = [info.beacon, info.errorBeacon];
|
|
41
|
+
if (!alreadySetOnce) {
|
|
42
|
+
alreadySetOnce = true;
|
|
43
|
+
if (updatedInit.proxy.assets) {
|
|
44
|
+
redefinePublicPath(updatedInit.proxy.assets + '/'); // much like the info.beacon & init.proxy.beacon, this input should not end in a slash, but one is needed for webpack concat
|
|
45
|
+
internalTrafficList.push(updatedInit.proxy.assets);
|
|
46
|
+
}
|
|
47
|
+
if (updatedInit.proxy.beacon) internalTrafficList.push(updatedInit.proxy.beacon);
|
|
48
|
+
}
|
|
49
|
+
runtime.denyList = [...(updatedInit.ajax.deny_list || []), ...(updatedInit.ajax.block_internal ? internalTrafficList : [])];
|
|
38
50
|
setRuntime(agentIdentifier, runtime);
|
|
39
51
|
setTopLevelCallers();
|
|
40
52
|
const api = setAPI(agentIdentifier, forceDrain);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Set the default CDN or remote for fetching the assets; NPM shouldn't change this var.
|
|
2
|
+
|
|
3
|
+
export const redefinePublicPath = url => {
|
|
4
|
+
// There's no URL validation here, so caller should check arg if need be.
|
|
5
|
+
__webpack_public_path__ = url; // eslint-disable-line
|
|
6
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../src/common/config/state/init.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../src/common/config/state/init.js"],"names":[],"mappings":"AA0EA,+CAIC;AAED,0DAIC;AAED,+DAYC"}
|
|
@@ -13,6 +13,7 @@ export const isBrowserScope: boolean;
|
|
|
13
13
|
*/
|
|
14
14
|
export const isWorkerScope: boolean;
|
|
15
15
|
export const globalScope: false | typeof globalThis;
|
|
16
|
+
export const initiallyHidden: boolean;
|
|
16
17
|
export const initialLocation: string;
|
|
17
18
|
export const isiOS: boolean;
|
|
18
19
|
/**
|
|
@@ -25,5 +26,6 @@ export const isiOS: boolean;
|
|
|
25
26
|
export const iOSBelow16: boolean;
|
|
26
27
|
export const ffVersion: number;
|
|
27
28
|
export const isIE: boolean;
|
|
28
|
-
export const supportsSendBeacon:
|
|
29
|
+
export const supportsSendBeacon: boolean;
|
|
30
|
+
export const offset: number;
|
|
29
31
|
//# sourceMappingURL=runtime.d.ts.map
|