@newrelic/browser-agent 1.239.1 → 1.240.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 +6 -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/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 +7 -0
- 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 +27 -138
- package/dist/cjs/features/page_view_timing/instrument/index.js +0 -3
- 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/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 +6 -0
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/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 +8 -1
- 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 +28 -139
- package/dist/esm/features/page_view_timing/instrument/index.js +0 -3
- 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/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_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/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 +1 -1
- package/src/cdn/pro.js +2 -0
- package/src/cdn/spa.js +2 -0
- package/src/common/config/state/init.js +4 -0
- package/src/common/constants/runtime.js +7 -3
- package/src/common/constants/runtime.test.js +8 -0
- 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 +6 -1
- 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 +24 -102
- package/src/features/page_view_timing/instrument/index.js +0 -3
- 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/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
|
@@ -15,8 +15,9 @@ export const isBrowserScope = typeof window !== 'undefined' && !!window.document
|
|
|
15
15
|
*/
|
|
16
16
|
export const isWorkerScope = typeof WorkerGlobalScope !== 'undefined' && (typeof self !== 'undefined' && self instanceof WorkerGlobalScope && self.navigator instanceof WorkerNavigator || typeof globalThis !== 'undefined' && globalThis instanceof WorkerGlobalScope && globalThis.navigator instanceof WorkerNavigator);
|
|
17
17
|
export const globalScope = isBrowserScope ? window : typeof WorkerGlobalScope !== 'undefined' && (typeof self !== 'undefined' && self instanceof WorkerGlobalScope && self || typeof globalThis !== 'undefined' && globalThis instanceof WorkerGlobalScope && globalThis);
|
|
18
|
+
export const initiallyHidden = Boolean(globalScope?.document?.visibilityState === 'hidden');
|
|
18
19
|
export const initialLocation = '' + globalScope?.location;
|
|
19
|
-
export const isiOS = /iPad|iPhone|iPod/.test(navigator
|
|
20
|
+
export const isiOS = /iPad|iPhone|iPod/.test(globalScope.navigator?.userAgent);
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Shared Web Workers introduced in iOS 16.0+ and n/a in 15.6-
|
|
@@ -27,7 +28,7 @@ export const isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
|
27
28
|
*/
|
|
28
29
|
export const iOSBelow16 = isiOS && typeof SharedWorker === 'undefined';
|
|
29
30
|
export const ffVersion = (() => {
|
|
30
|
-
const match = navigator
|
|
31
|
+
const match = globalScope.navigator?.userAgent?.match(/Firefox[/\s](\d+\.\d+)/);
|
|
31
32
|
if (Array.isArray(match) && match.length >= 2) {
|
|
32
33
|
return +match[1];
|
|
33
34
|
}
|
|
@@ -35,4 +36,5 @@ export const ffVersion = (() => {
|
|
|
35
36
|
})();
|
|
36
37
|
export const isIE = Boolean(isBrowserScope && window.document.documentMode); // deprecated property that only works in IE
|
|
37
38
|
|
|
38
|
-
export const supportsSendBeacon = !!navigator
|
|
39
|
+
export const supportsSendBeacon = !!globalScope.navigator?.sendBeacon;
|
|
40
|
+
export const offset = Math.floor(globalScope?.performance?.timeOrigin || globalScope?.performance?.timing?.navigationStart || Date.now());
|
|
@@ -7,7 +7,7 @@ import { obj as encodeObj, param as encodeParam } from '../url/encode';
|
|
|
7
7
|
import { stringify } from '../util/stringify';
|
|
8
8
|
import * as submitData from '../util/submit-data';
|
|
9
9
|
import { getLocation } from '../url/location';
|
|
10
|
-
import { getInfo, getConfigurationValue, getRuntime } from '../config/config';
|
|
10
|
+
import { getInfo, getConfigurationValue, getRuntime, getConfiguration } from '../config/config';
|
|
11
11
|
import { cleanURL } from '../url/clean-url';
|
|
12
12
|
import { now } from '../timing/now';
|
|
13
13
|
import { eventListenerOpts } from '../event-listener/event-listener-opts';
|
|
@@ -32,7 +32,6 @@ export class Harvest extends SharedContext {
|
|
|
32
32
|
|
|
33
33
|
this.tooManyRequestsDelay = getConfigurationValue(this.sharedContext.agentIdentifier, 'harvest.tooManyRequestsDelay') || 60;
|
|
34
34
|
this.obfuscator = new Obfuscator(this.sharedContext);
|
|
35
|
-
this.getScheme = () => getConfigurationValue(this.sharedContext.agentIdentifier, 'ssl') === false ? 'http' : 'https';
|
|
36
35
|
this._events = {};
|
|
37
36
|
}
|
|
38
37
|
|
|
@@ -123,10 +122,13 @@ export class Harvest extends SharedContext {
|
|
|
123
122
|
}
|
|
124
123
|
return false;
|
|
125
124
|
}
|
|
125
|
+
const init = getConfiguration(this.sharedContext.agentIdentifier);
|
|
126
|
+
const protocol = init.ssl === false ? 'http' : 'https';
|
|
127
|
+
const perceviedBeacon = init.proxy.beacon || info.errorBeacon;
|
|
126
128
|
const endpointURLPart = endpoint !== 'rum' ? "/".concat(endpoint) : '';
|
|
127
|
-
let url = "".concat(
|
|
129
|
+
let url = "".concat(protocol, "://").concat(perceviedBeacon).concat(endpointURLPart, "/1/").concat(info.licenseKey);
|
|
128
130
|
if (customUrl) url = customUrl;
|
|
129
|
-
if (raw) url = "".concat(
|
|
131
|
+
if (raw) url = "".concat(protocol, "://").concat(perceviedBeacon, "/").concat(endpoint);
|
|
130
132
|
const baseParams = !raw && includeBaseParams ? this.baseQueryString() : '';
|
|
131
133
|
let payloadParams = encodeObj(qs, agentRuntime.maxBytes);
|
|
132
134
|
if (!submitMethod) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const VITAL_NAMES = {
|
|
2
|
+
FIRST_PAINT: 'fp',
|
|
3
|
+
FIRST_CONTENTFUL_PAINT: 'fcp',
|
|
4
|
+
FIRST_INPUT_DELAY: 'fi',
|
|
5
|
+
LARGEST_CONTENTFUL_PAINT: 'lcp',
|
|
6
|
+
CUMULATIVE_LAYOUT_SHIFT: 'cls',
|
|
7
|
+
INTERACTION_TO_NEXT_PAINT: 'inp',
|
|
8
|
+
LONG_TASK: 'lt',
|
|
9
|
+
TIME_TO_FIRST_BYTE: 'ttfb'
|
|
10
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { onCLS } from 'web-vitals';
|
|
2
|
+
import { VITAL_NAMES } from './constants';
|
|
3
|
+
import { VitalMetric } from './vital-metric';
|
|
4
|
+
import { isBrowserScope } from '../constants/runtime';
|
|
5
|
+
export const cumulativeLayoutShift = new VitalMetric(VITAL_NAMES.CUMULATIVE_LAYOUT_SHIFT, x => x);
|
|
6
|
+
if (isBrowserScope) {
|
|
7
|
+
onCLS(_ref => {
|
|
8
|
+
let {
|
|
9
|
+
value,
|
|
10
|
+
entries
|
|
11
|
+
} = _ref;
|
|
12
|
+
if (cumulativeLayoutShift.roundingMethod(value) === cumulativeLayoutShift.current.value) return;
|
|
13
|
+
cumulativeLayoutShift.update({
|
|
14
|
+
value,
|
|
15
|
+
entries
|
|
16
|
+
});
|
|
17
|
+
}, {
|
|
18
|
+
reportAllChanges: true
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { onFCP } from 'web-vitals';
|
|
2
|
+
// eslint-disable-next-line camelcase
|
|
3
|
+
import { iOSBelow16, initiallyHidden, isBrowserScope } from '../constants/runtime';
|
|
4
|
+
import { VITAL_NAMES } from './constants';
|
|
5
|
+
import { VitalMetric } from './vital-metric';
|
|
6
|
+
export const firstContentfulPaint = new VitalMetric(VITAL_NAMES.FIRST_CONTENTFUL_PAINT);
|
|
7
|
+
|
|
8
|
+
/* 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. */
|
|
9
|
+
if (isBrowserScope) {
|
|
10
|
+
// eslint-disable-next-line camelcase
|
|
11
|
+
if (iOSBelow16) {
|
|
12
|
+
try {
|
|
13
|
+
if (!initiallyHidden) {
|
|
14
|
+
// see ios-version.js for detail on this following bug case; tldr: buffered flag doesn't work but getEntriesByType does
|
|
15
|
+
const paintEntries = performance.getEntriesByType('paint');
|
|
16
|
+
paintEntries.forEach(entry => {
|
|
17
|
+
if (entry.name === 'first-contentful-paint') {
|
|
18
|
+
firstContentfulPaint.update({
|
|
19
|
+
value: Math.floor(entry.startTime),
|
|
20
|
+
entries: paintEntries
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
} catch (e) {
|
|
26
|
+
// ignore
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
onFCP(_ref => {
|
|
30
|
+
let {
|
|
31
|
+
value,
|
|
32
|
+
entries
|
|
33
|
+
} = _ref;
|
|
34
|
+
if (initiallyHidden || firstContentfulPaint.isValid) return;
|
|
35
|
+
firstContentfulPaint.update({
|
|
36
|
+
value,
|
|
37
|
+
entries
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { onFID } from 'web-vitals';
|
|
2
|
+
import { VitalMetric } from './vital-metric';
|
|
3
|
+
import { VITAL_NAMES } from './constants';
|
|
4
|
+
import { initiallyHidden, isBrowserScope } from '../constants/runtime';
|
|
5
|
+
export const firstInputDelay = new VitalMetric(VITAL_NAMES.FIRST_INPUT_DELAY);
|
|
6
|
+
if (isBrowserScope) {
|
|
7
|
+
onFID(_ref => {
|
|
8
|
+
let {
|
|
9
|
+
value,
|
|
10
|
+
entries
|
|
11
|
+
} = _ref;
|
|
12
|
+
if (initiallyHidden || firstInputDelay.isValid || entries.length === 0) return;
|
|
13
|
+
|
|
14
|
+
// 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.
|
|
15
|
+
firstInputDelay.update({
|
|
16
|
+
value: entries[0].startTime,
|
|
17
|
+
entries,
|
|
18
|
+
attrs: {
|
|
19
|
+
type: entries[0].name,
|
|
20
|
+
fid: Math.round(value)
|
|
21
|
+
},
|
|
22
|
+
shouldAddConnectionAttributes: true
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -1,33 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
exports.onFirstPaint = void 0;
|
|
7
|
-
/**
|
|
8
|
-
* Calls the `onReport` function when the 'first-paint' PerformancePaintTiming entry is observed.
|
|
9
|
-
* The argument supplied is an object similar to the Metric type used by web-vitals library.
|
|
10
|
-
*
|
|
11
|
-
* @param {Function} onReport - callback that accepts a `metric` object as the single parameter
|
|
12
|
-
*/
|
|
13
|
-
const onFirstPaint = onReport => {
|
|
1
|
+
import { initiallyHidden, isBrowserScope } from '../constants/runtime';
|
|
2
|
+
import { VITAL_NAMES } from './constants';
|
|
3
|
+
import { VitalMetric } from './vital-metric';
|
|
4
|
+
export const firstPaint = new VitalMetric(VITAL_NAMES.FIRST_PAINT);
|
|
5
|
+
if (isBrowserScope) {
|
|
14
6
|
const handleEntries = entries => {
|
|
15
7
|
entries.forEach(entry => {
|
|
16
|
-
if (entry.name === 'first-paint') {
|
|
8
|
+
if (entry.name === 'first-paint' && !firstPaint.isValid) {
|
|
17
9
|
observer.disconnect();
|
|
18
10
|
|
|
19
11
|
/* Initial hidden state and pre-rendering not yet considered for first paint. See web-vitals onFCP for example. */
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
onReport(metric);
|
|
12
|
+
firstPaint.update({
|
|
13
|
+
value: entry.startTime,
|
|
14
|
+
entries
|
|
15
|
+
});
|
|
25
16
|
}
|
|
26
17
|
});
|
|
27
18
|
};
|
|
28
19
|
let observer;
|
|
29
20
|
try {
|
|
30
|
-
if (PerformanceObserver.supportedEntryTypes.includes('paint')) {
|
|
21
|
+
if (PerformanceObserver.supportedEntryTypes.includes('paint') && !initiallyHidden) {
|
|
31
22
|
observer = new PerformanceObserver(list => {
|
|
32
23
|
// Delay by a microtask to workaround a bug in Safari where the
|
|
33
24
|
// callback is invoked immediately, rather than in a separate task.
|
|
@@ -44,7 +35,4 @@ const onFirstPaint = onReport => {
|
|
|
44
35
|
} catch (e) {
|
|
45
36
|
// Do nothing.
|
|
46
37
|
}
|
|
47
|
-
|
|
48
|
-
/* BFCache restore not yet considered for first paint. See web-vitals onFCP for example. */
|
|
49
|
-
};
|
|
50
|
-
exports.onFirstPaint = onFirstPaint;
|
|
38
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { onINP } from 'web-vitals';
|
|
2
|
+
import { VitalMetric } from './vital-metric';
|
|
3
|
+
import { VITAL_NAMES } from './constants';
|
|
4
|
+
import { isBrowserScope } from '../constants/runtime';
|
|
5
|
+
export const interactionToNextPaint = new VitalMetric(VITAL_NAMES.INTERACTION_TO_NEXT_PAINT);
|
|
6
|
+
if (isBrowserScope) {
|
|
7
|
+
/* Interaction-to-Next-Paint */
|
|
8
|
+
onINP(_ref => {
|
|
9
|
+
let {
|
|
10
|
+
value,
|
|
11
|
+
entries,
|
|
12
|
+
id
|
|
13
|
+
} = _ref;
|
|
14
|
+
interactionToNextPaint.update({
|
|
15
|
+
value,
|
|
16
|
+
entries,
|
|
17
|
+
attrs: {
|
|
18
|
+
metricId: id
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { onLCP } from 'web-vitals';
|
|
2
|
+
import { VitalMetric } from './vital-metric';
|
|
3
|
+
import { VITAL_NAMES } from './constants';
|
|
4
|
+
import { initiallyHidden, isBrowserScope } from '../constants/runtime';
|
|
5
|
+
import { cleanURL } from '../url/clean-url';
|
|
6
|
+
export const largestContentfulPaint = new VitalMetric(VITAL_NAMES.LARGEST_CONTENTFUL_PAINT);
|
|
7
|
+
if (isBrowserScope) {
|
|
8
|
+
onLCP(_ref => {
|
|
9
|
+
let {
|
|
10
|
+
value,
|
|
11
|
+
entries
|
|
12
|
+
} = _ref;
|
|
13
|
+
/* 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. */
|
|
14
|
+
if (initiallyHidden || largestContentfulPaint.isValid) return;
|
|
15
|
+
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...
|
|
16
|
+
largestContentfulPaint.update({
|
|
17
|
+
value,
|
|
18
|
+
entries,
|
|
19
|
+
...(entries.length > 0 && {
|
|
20
|
+
attrs: {
|
|
21
|
+
size: lcpEntry.size,
|
|
22
|
+
eid: lcpEntry.id,
|
|
23
|
+
...(!!lcpEntry.url && {
|
|
24
|
+
elUrl: cleanURL(lcpEntry.url)
|
|
25
|
+
}),
|
|
26
|
+
...(!!lcpEntry.element?.tagName && {
|
|
27
|
+
elTag: lcpEntry.element.tagName
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}),
|
|
31
|
+
shouldAddConnectionAttributes: true
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isBrowserScope } from '../constants/runtime';
|
|
2
|
+
import { subscribeToEOL } from '../unload/eol';
|
|
3
|
+
import { VITAL_NAMES } from './constants';
|
|
4
|
+
import { VitalMetric } from './vital-metric';
|
|
5
|
+
export const longTask = new VitalMetric(VITAL_NAMES.LONG_TASK);
|
|
6
|
+
if (isBrowserScope) {
|
|
7
|
+
const handleEntries = entries => {
|
|
8
|
+
entries.forEach(entry => {
|
|
9
|
+
longTask.update({
|
|
10
|
+
value: entry.duration,
|
|
11
|
+
entries: [entry],
|
|
12
|
+
attrs: {
|
|
13
|
+
ltFrame: entry.name,
|
|
14
|
+
// MDN: the browsing context or frame that can be attributed to the long task
|
|
15
|
+
ltStart: entry.startTime,
|
|
16
|
+
// MDN: a double representing the time (millisec) when the task started
|
|
17
|
+
ltCtr: entry.attribution[0].containerType,
|
|
18
|
+
// MDN: type of frame container: 'iframe', 'embed', or 'object' ... but this can also be 'window',
|
|
19
|
+
...(entry.attribution[0].containerType !== 'window' && {
|
|
20
|
+
ltCtrSrc: entry.attribution[0].containerSrc,
|
|
21
|
+
// MDN: container's 'src' attribute
|
|
22
|
+
ltCtrId: entry.attribution[0].containerId,
|
|
23
|
+
// MDN: container's 'id' attribute
|
|
24
|
+
ltCtrName: entry.attribution[0].containerName // MDN: container's 'name' attribute
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let observer;
|
|
32
|
+
try {
|
|
33
|
+
if (PerformanceObserver.supportedEntryTypes.includes('longtask')) {
|
|
34
|
+
observer = new PerformanceObserver(list => {
|
|
35
|
+
// Delay by a microtask to workaround a bug in Safari where the
|
|
36
|
+
// callback is invoked immediately, rather than in a separate task.
|
|
37
|
+
// See: https://github.com/GoogleChrome/web-vitals/issues/277
|
|
38
|
+
Promise.resolve().then(() => {
|
|
39
|
+
handleEntries(list.getEntries());
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
observer.observe({
|
|
43
|
+
type: 'longtask',
|
|
44
|
+
buffered: true
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
} catch (e) {
|
|
48
|
+
// Do nothing.
|
|
49
|
+
}
|
|
50
|
+
if (observer) {
|
|
51
|
+
subscribeToEOL(() => {
|
|
52
|
+
handleEntries(observer.takeRecords());
|
|
53
|
+
}, true); // this bool is a temp arg under staged BFCache work that runs the func under the new page session logic -- tb removed w/ the feature flag later
|
|
54
|
+
|
|
55
|
+
/* No work needed on BFCache restore for long task. */
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { globalScope, isBrowserScope, isiOS, offset } from '../constants/runtime';
|
|
2
|
+
import { VITAL_NAMES } from './constants';
|
|
3
|
+
import { VitalMetric } from './vital-metric';
|
|
4
|
+
import { onTTFB } from 'web-vitals';
|
|
5
|
+
export const timeToFirstByte = new VitalMetric(VITAL_NAMES.TIME_TO_FIRST_BYTE);
|
|
6
|
+
if (isBrowserScope && typeof PerformanceNavigationTiming !== 'undefined' && !isiOS) {
|
|
7
|
+
onTTFB(_ref => {
|
|
8
|
+
let {
|
|
9
|
+
value,
|
|
10
|
+
entries
|
|
11
|
+
} = _ref;
|
|
12
|
+
if (!timeToFirstByte.isValid) timeToFirstByte.update({
|
|
13
|
+
value,
|
|
14
|
+
entries
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
} else {
|
|
18
|
+
if (!timeToFirstByte.isValid) {
|
|
19
|
+
const entry = {};
|
|
20
|
+
// convert real timestamps to relative timestamps to match web-vitals behavior
|
|
21
|
+
for (let key in globalScope?.performance?.timing || {}) entry[key] = Math.max(globalScope?.performance?.timing[key] - offset, 0);
|
|
22
|
+
|
|
23
|
+
// ttfb is equiv to document's responseStart property in timing API --> https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming/responseStart
|
|
24
|
+
timeToFirstByte.update({
|
|
25
|
+
value: entry.responseStart,
|
|
26
|
+
entries: [entry]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export class VitalMetric {
|
|
2
|
+
#subscribers = new Set();
|
|
3
|
+
history = [];
|
|
4
|
+
constructor(name, roundingMethod) {
|
|
5
|
+
this.name = name;
|
|
6
|
+
this.attrs = {};
|
|
7
|
+
this.roundingMethod = typeof roundingMethod === 'function' ? roundingMethod : Math.floor;
|
|
8
|
+
}
|
|
9
|
+
update(_ref) {
|
|
10
|
+
let {
|
|
11
|
+
value,
|
|
12
|
+
entries = [],
|
|
13
|
+
attrs = {},
|
|
14
|
+
shouldAddConnectionAttributes = false
|
|
15
|
+
} = _ref;
|
|
16
|
+
if (value < 0) return;
|
|
17
|
+
const state = {
|
|
18
|
+
value: this.roundingMethod(value),
|
|
19
|
+
name: this.name,
|
|
20
|
+
entries,
|
|
21
|
+
attrs
|
|
22
|
+
};
|
|
23
|
+
if (shouldAddConnectionAttributes) addConnectionAttributes(state.attrs);
|
|
24
|
+
this.history.push(state);
|
|
25
|
+
this.#subscribers.forEach(cb => {
|
|
26
|
+
try {
|
|
27
|
+
cb(this.current);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
// ignore errors
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
get current() {
|
|
34
|
+
return this.history[this.history.length - 1] || {
|
|
35
|
+
value: undefined,
|
|
36
|
+
name: this.name,
|
|
37
|
+
entries: [],
|
|
38
|
+
attrs: {}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
get isValid() {
|
|
42
|
+
return this.current.value >= 0;
|
|
43
|
+
}
|
|
44
|
+
subscribe(callback) {
|
|
45
|
+
let buffered = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
46
|
+
if (typeof callback !== 'function') return;
|
|
47
|
+
this.#subscribers.add(callback);
|
|
48
|
+
// emit full history on subscription ("buffered" behavior)
|
|
49
|
+
if (this.isValid && !!buffered) this.history.forEach(state => {
|
|
50
|
+
callback(state);
|
|
51
|
+
});
|
|
52
|
+
return () => {
|
|
53
|
+
this.#subscribers.delete(callback);
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function addConnectionAttributes(obj) {
|
|
58
|
+
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; // to date, both window & worker shares the same support for connection
|
|
59
|
+
if (!connection) return;
|
|
60
|
+
if (connection.type) obj['net-type'] = connection.type;
|
|
61
|
+
if (connection.effectiveType) obj['net-etype'] = connection.effectiveType;
|
|
62
|
+
if (connection.rtt) obj['net-rtt'] = connection.rtt;
|
|
63
|
+
if (connection.downlink) obj['net-dlink'] = connection.downlink;
|
|
64
|
+
}
|
|
@@ -64,6 +64,8 @@ export class Aggregate extends AggregateBase {
|
|
|
64
64
|
scheduler.startTimer(harvestTimeSeconds);
|
|
65
65
|
});
|
|
66
66
|
this.drain();
|
|
67
|
+
const beacon = getInfo(agentIdentifier).errorBeacon;
|
|
68
|
+
const proxyBeacon = agentInit.proxy.beacon;
|
|
67
69
|
function storeXhr(params, metrics, startTime, endTime, type) {
|
|
68
70
|
metrics.time = startTime;
|
|
69
71
|
|
|
@@ -80,7 +82,8 @@ export class Aggregate extends AggregateBase {
|
|
|
80
82
|
aggregator.store('xhr', hash, params, metrics);
|
|
81
83
|
if (!allAjaxIsEnabled) return;
|
|
82
84
|
if (!shouldCollectEvent(params)) {
|
|
83
|
-
if (params.hostname ===
|
|
85
|
+
if (params.hostname === beacon || proxyBeacon && params.hostname === proxyBeacon) {
|
|
86
|
+
// This doesn't make a distinction if the same-domain request is going to a different port or path...
|
|
84
87
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Ajax/Events/Excluded/Agent'], undefined, FEATURE_NAMES.metrics, ee);
|
|
85
88
|
} else {
|
|
86
89
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Ajax/Events/Excluded/App'], undefined, FEATURE_NAMES.metrics, ee);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getRuntime } from '../../../common/config/config';
|
|
1
|
+
import { getRuntime, getConfiguration } from '../../../common/config/config';
|
|
2
2
|
import { registerHandler } from '../../../common/event-emitter/register-handler';
|
|
3
3
|
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
4
4
|
import { FEATURE_NAME, SUPPORTABILITY_METRIC, CUSTOM_METRIC, SUPPORTABILITY_METRIC_CHANNEL, CUSTOM_METRIC_CHANNEL } from '../constants';
|
|
@@ -87,6 +87,13 @@ export class Aggregate extends AggregateBase {
|
|
|
87
87
|
const rules = getRules(this.agentIdentifier);
|
|
88
88
|
if (rules.length > 0) this.storeSupportabilityMetrics('Generic/Obfuscate/Detected');
|
|
89
89
|
if (rules.length > 0 && !validateRules(rules)) this.storeSupportabilityMetrics('Generic/Obfuscate/Invalid');
|
|
90
|
+
|
|
91
|
+
// Check if proxy for either chunks or beacon is being used
|
|
92
|
+
const {
|
|
93
|
+
proxy
|
|
94
|
+
} = getConfiguration(this.agentIdentifier);
|
|
95
|
+
if (proxy.assets) this.storeSupportabilityMetrics('Config/AssetsUrl/Changed');
|
|
96
|
+
if (proxy.beacon) this.storeSupportabilityMetrics('Config/BeaconUrl/Changed');
|
|
90
97
|
}
|
|
91
98
|
eachSessionChecks() {
|
|
92
99
|
if (!isBrowserScope) return;
|
|
@@ -1,53 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
3
|
-
import { isiOS, globalScope, isBrowserScope } from '../../../common/constants/runtime';
|
|
4
|
-
import { onTTFB } from 'web-vitals';
|
|
1
|
+
import { globalScope, isBrowserScope } from '../../../common/constants/runtime';
|
|
5
2
|
import { addPT, addPN } from '../../../common/timing/nav-timing';
|
|
6
3
|
import { stringify } from '../../../common/util/stringify';
|
|
7
|
-
import {
|
|
8
|
-
import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
|
|
4
|
+
import { getInfo, getRuntime } from '../../../common/config/config';
|
|
9
5
|
import { Harvest } from '../../../common/harvest/harvest';
|
|
10
6
|
import * as CONSTANTS from '../constants';
|
|
11
7
|
import { getActivatedFeaturesFlags } from './initialized-features';
|
|
12
8
|
import { activateFeatures } from '../../../common/util/feature-flags';
|
|
13
9
|
import { warn } from '../../../common/util/console';
|
|
14
10
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
11
|
+
import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint';
|
|
12
|
+
import { firstPaint } from '../../../common/vitals/first-paint';
|
|
13
|
+
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte';
|
|
15
14
|
export class Aggregate extends AggregateBase {
|
|
16
15
|
static featureName = CONSTANTS.FEATURE_NAME;
|
|
17
16
|
constructor(agentIdentifier, aggregator) {
|
|
18
17
|
super(agentIdentifier, aggregator, CONSTANTS.FEATURE_NAME);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
this.timeToFirstByte = 0;
|
|
19
|
+
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
20
|
+
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
onTTFB(_ref => {
|
|
22
|
+
if (isBrowserScope) {
|
|
23
|
+
timeToFirstByte.subscribe(_ref => {
|
|
26
24
|
let {
|
|
27
25
|
value,
|
|
28
26
|
entries
|
|
29
27
|
} = _ref;
|
|
30
|
-
if (this.alreadySent) return;
|
|
31
|
-
this.alreadySent = true;
|
|
32
|
-
agentRuntime[CONSTANTS.TTFB] = Math.round(value); // this is our "backend" duration; web-vitals will ensure it's lower bounded at 0
|
|
33
|
-
|
|
34
|
-
// Similar to what vitals does for ttfb, we have to factor in activation-start when calculating relative timings:
|
|
35
28
|
const navEntry = entries[0];
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
agentRuntime[CONSTANTS.FBTDC] = Math.max(Math.round(navEntry.domContentLoadedEventEnd - respOrActivStart), 0); // our "dom processing" duration
|
|
29
|
+
this.timeToFirstByte = Math.max(value, this.timeToFirstByte);
|
|
30
|
+
this.firstByteToWindowLoad = Math.max(Math.round(navEntry.loadEventEnd - this.timeToFirstByte), this.firstByteToWindowLoad); // our "frontend" duration
|
|
31
|
+
this.firstByteToDomContent = Math.max(Math.round(navEntry.domContentLoadedEventEnd - this.timeToFirstByte), this.firstByteToDomContent); // our "dom processing" duration
|
|
40
32
|
|
|
41
33
|
this.sendRum();
|
|
42
34
|
});
|
|
43
35
|
} else {
|
|
44
|
-
|
|
36
|
+
// worker agent build does not get TTFB values, use default 0 values
|
|
37
|
+
this.sendRum();
|
|
45
38
|
}
|
|
46
39
|
}
|
|
47
|
-
|
|
48
|
-
getScheme() {
|
|
49
|
-
return getConfigurationValue(this.agentIdentifier, 'ssl') === false ? 'http' : 'https';
|
|
50
|
-
}
|
|
51
40
|
sendRum() {
|
|
52
41
|
const info = getInfo(this.agentIdentifier);
|
|
53
42
|
const agentRuntime = getRuntime(this.agentIdentifier);
|
|
@@ -64,13 +53,13 @@ export class Aggregate extends AggregateBase {
|
|
|
64
53
|
// Following PR #428, which demands that all agents send RUM call, these need to be sent even outside of the main window context where PerformanceTiming
|
|
65
54
|
// or PerformanceNavigationTiming do not exists. Hence, they'll be filled in by 0s instead in, for example, worker threads that still init the PVE module.
|
|
66
55
|
this.aggregator.store('measures', 'be', {
|
|
67
|
-
value:
|
|
56
|
+
value: this.timeToFirstByte
|
|
68
57
|
});
|
|
69
58
|
this.aggregator.store('measures', 'fe', {
|
|
70
|
-
value:
|
|
59
|
+
value: this.firstByteToWindowLoad
|
|
71
60
|
});
|
|
72
61
|
this.aggregator.store('measures', 'dc', {
|
|
73
|
-
value:
|
|
62
|
+
value: this.firstByteToDomContent
|
|
74
63
|
});
|
|
75
64
|
const queryParameters = {
|
|
76
65
|
tt: info.ttGuid,
|
|
@@ -111,19 +100,8 @@ export class Aggregate extends AggregateBase {
|
|
|
111
100
|
queryParameters.perf = stringify(perf);
|
|
112
101
|
}
|
|
113
102
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
var entries = globalScope.performance.getEntriesByType('paint');
|
|
117
|
-
entries.forEach(function (entry) {
|
|
118
|
-
if (!entry.startTime || entry.startTime <= 0) return;
|
|
119
|
-
if (entry.name === 'first-paint') {
|
|
120
|
-
queryParameters.fp = String(Math.floor(entry.startTime));
|
|
121
|
-
} else if (entry.name === 'first-contentful-paint') {
|
|
122
|
-
queryParameters.fcp = String(Math.floor(entry.startTime));
|
|
123
|
-
}
|
|
124
|
-
paintMetrics[entry.name] = Math.floor(entry.startTime); // this is consumed by Spa module
|
|
125
|
-
});
|
|
126
|
-
} catch (e) {}
|
|
103
|
+
queryParameters.fp = firstPaint.current.value;
|
|
104
|
+
queryParameters.fcp = firstContentfulPaint.current.value;
|
|
127
105
|
harvester.send({
|
|
128
106
|
endpoint: 'rum',
|
|
129
107
|
payload: {
|
|
@@ -1,5 +1,2 @@
|
|
|
1
1
|
import { FEATURE_NAMES } from '../../loaders/features/features';
|
|
2
|
-
export const FEATURE_NAME = FEATURE_NAMES.pageViewEvent;
|
|
3
|
-
export const TTFB = 'firstbyte';
|
|
4
|
-
export const FBTDC = 'domcontent';
|
|
5
|
-
export const FBTWL = 'windowload';
|
|
2
|
+
export const FEATURE_NAME = FEATURE_NAMES.pageViewEvent;
|
|
@@ -1,32 +1,10 @@
|
|
|
1
|
-
import { handle } from '../../../common/event-emitter/handle';
|
|
2
|
-
import { isiOS } from '../../../common/constants/runtime';
|
|
3
1
|
import { InstrumentBase } from '../../utils/instrument-base';
|
|
4
2
|
import * as CONSTANTS from '../constants';
|
|
5
|
-
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
6
|
-
import { getRuntime } from '../../../common/config/config';
|
|
7
|
-
import { onDOMContentLoaded, onWindowLoad } from '../../../common/window/load';
|
|
8
|
-
import { now } from '../../../common/timing/now';
|
|
9
3
|
export class Instrument extends InstrumentBase {
|
|
10
4
|
static featureName = CONSTANTS.FEATURE_NAME;
|
|
11
5
|
constructor(agentIdentifier, aggregator) {
|
|
12
6
|
let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
13
7
|
super(agentIdentifier, aggregator, CONSTANTS.FEATURE_NAME, auto);
|
|
14
|
-
if ((typeof PerformanceNavigationTiming === 'undefined' || isiOS) && typeof PerformanceTiming !== 'undefined') {
|
|
15
|
-
// For majority browser versions in which PNT exists, we can get load timings later from the nav entry (in the aggregate portion). At minimum, PT should exist for main window.
|
|
16
|
-
// *cli Mar'23 - iOS 15.2 & 15.4 testing in Sauce still fails with onTTFB. Hence, all iOS will fallback to this for now. Unknown if this is similar in nature to iOSBelow16 bug.
|
|
17
|
-
const agentRuntime = getRuntime(agentIdentifier);
|
|
18
|
-
agentRuntime[CONSTANTS.TTFB] = Math.max(Date.now() - agentRuntime.offset, 0);
|
|
19
|
-
onDOMContentLoaded(() => {
|
|
20
|
-
agentRuntime[CONSTANTS.FBTDC] = Math.max(now() - agentRuntime[CONSTANTS.TTFB], 0);
|
|
21
|
-
});
|
|
22
|
-
onWindowLoad(() => {
|
|
23
|
-
const timeNow = now();
|
|
24
|
-
agentRuntime[CONSTANTS.FBTWL] = Math.max(timeNow - agentRuntime[CONSTANTS.TTFB], 0);
|
|
25
|
-
handle('timing', ['load', timeNow], undefined, FEATURE_NAMES.pageViewTiming, this.ee);
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
// Else, inference: inside worker or some other env where these events are irrelevant. They'll get filled in with 0s in RUM call.
|
|
29
|
-
|
|
30
8
|
this.importAggregator();
|
|
31
9
|
}
|
|
32
10
|
}
|