@newrelic/browser-agent 1.304.0 → 1.305.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 +8 -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 +4 -2
- package/dist/cjs/common/timing/nav-timing.js +7 -2
- package/dist/cjs/common/util/mfe.js +4 -4
- package/dist/cjs/common/vitals/constants.js +1 -0
- package/dist/cjs/common/vitals/load-time.js +27 -0
- package/dist/cjs/common/vitals/time-to-first-byte.js +1 -1
- package/dist/cjs/common/window/load.js +19 -1
- package/dist/cjs/features/generic_events/aggregate/index.js +1 -1
- package/dist/cjs/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +5 -9
- package/dist/cjs/features/generic_events/instrument/index.js +28 -33
- package/dist/cjs/features/page_view_event/aggregate/index.js +7 -8
- package/dist/cjs/features/page_view_timing/aggregate/index.js +5 -4
- package/dist/cjs/features/session_trace/aggregate/index.js +1 -1
- package/dist/cjs/features/soft_navigations/aggregate/index.js +3 -5
- package/dist/cjs/features/spa/instrument/index.js +8 -0
- package/dist/cjs/loaders/api/register.js +1 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/constants/runtime.js +2 -1
- package/dist/esm/common/timing/nav-timing.js +7 -2
- package/dist/esm/common/util/mfe.js +4 -4
- package/dist/esm/common/vitals/constants.js +1 -0
- package/dist/esm/common/vitals/load-time.js +20 -0
- package/dist/esm/common/vitals/time-to-first-byte.js +2 -2
- package/dist/esm/common/window/load.js +19 -1
- package/dist/esm/features/generic_events/aggregate/index.js +1 -1
- package/dist/esm/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +5 -9
- package/dist/esm/features/generic_events/instrument/index.js +28 -33
- package/dist/esm/features/page_view_event/aggregate/index.js +8 -9
- package/dist/esm/features/page_view_timing/aggregate/index.js +5 -4
- package/dist/esm/features/session_trace/aggregate/index.js +2 -2
- package/dist/esm/features/soft_navigations/aggregate/index.js +3 -5
- package/dist/esm/features/spa/instrument/index.js +8 -0
- package/dist/esm/loaders/api/register.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/constants/runtime.d.ts +1 -0
- package/dist/types/common/constants/runtime.d.ts.map +1 -1
- package/dist/types/common/timing/nav-timing.d.ts.map +1 -1
- package/dist/types/common/util/mfe.d.ts +2 -5
- package/dist/types/common/util/mfe.d.ts.map +1 -1
- package/dist/types/common/vitals/constants.d.ts +1 -0
- package/dist/types/common/vitals/load-time.d.ts +3 -0
- package/dist/types/common/vitals/load-time.d.ts.map +1 -0
- package/dist/types/common/window/load.d.ts +10 -1
- package/dist/types/common/window/load.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/user-actions/user-actions-aggregator.d.ts +0 -1
- package/dist/types/features/generic_events/aggregate/user-actions/user-actions-aggregator.d.ts.map +1 -1
- package/dist/types/features/generic_events/instrument/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.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/instrument/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/constants/runtime.js +2 -0
- package/src/common/timing/nav-timing.js +7 -2
- package/src/common/util/mfe.js +4 -4
- package/src/common/vitals/constants.js +1 -0
- package/src/common/vitals/load-time.js +23 -0
- package/src/common/vitals/time-to-first-byte.js +2 -2
- package/src/common/window/load.js +18 -1
- package/src/features/generic_events/aggregate/index.js +1 -1
- package/src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +5 -9
- package/src/features/generic_events/instrument/index.js +35 -37
- package/src/features/page_view_event/aggregate/index.js +8 -9
- package/src/features/page_view_timing/aggregate/index.js +2 -4
- package/src/features/session_trace/aggregate/index.js +2 -2
- package/src/features/soft_navigations/aggregate/index.js +3 -4
- package/src/features/spa/instrument/index.js +6 -0
- package/src/loaders/api/register.js +1 -1
|
@@ -3,14 +3,31 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { windowAddEventListener, documentAddEventListener } from '../event-listener/event-listener-opts'
|
|
6
|
+
import { single } from '../util/invoke'
|
|
6
7
|
|
|
7
8
|
export function checkState () {
|
|
8
9
|
return (typeof document === 'undefined' || document.readyState === 'complete')
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Executes a callback when the window 'load' event fires, or immediately if the load event has already occurred.
|
|
14
|
+
* Sets up a backup polling mechanism in the rare case that the browser does not fire the load event when the page has loaded,
|
|
15
|
+
* such as in certain iframe scenarios like ChatGPT connector frames. Cannot use document.readystatechange event here because
|
|
16
|
+
* it blocks back/forward cache in Safari browsers.
|
|
17
|
+
* @param {Function} cb
|
|
18
|
+
* @param {boolean} [useCapture]
|
|
19
|
+
* @returns {void}
|
|
20
|
+
*/
|
|
11
21
|
export function onWindowLoad (cb, useCapture) {
|
|
12
22
|
if (checkState()) return cb()
|
|
13
|
-
|
|
23
|
+
const singleCb = single(cb)
|
|
24
|
+
const poll = setInterval(() => {
|
|
25
|
+
if (checkState()) {
|
|
26
|
+
clearInterval(poll)
|
|
27
|
+
singleCb()
|
|
28
|
+
}
|
|
29
|
+
}, 500)
|
|
30
|
+
windowAddEventListener('load', singleCb, useCapture)
|
|
14
31
|
}
|
|
15
32
|
|
|
16
33
|
export function onDOMContentLoaded (cb) {
|
|
@@ -61,7 +61,7 @@ export class Aggregate extends AggregateBase {
|
|
|
61
61
|
|
|
62
62
|
let addUserAction = () => { /** no-op */ }
|
|
63
63
|
if (isBrowserScope && agentRef.init.user_actions.enabled) {
|
|
64
|
-
this.#userActionAggregator = new UserActionsAggregator(
|
|
64
|
+
this.#userActionAggregator = new UserActionsAggregator()
|
|
65
65
|
this.harvestOpts.beforeUnload = () => addUserAction?.(this.#userActionAggregator.aggregationEvent)
|
|
66
66
|
|
|
67
67
|
addUserAction = (aggregatedUserAction) => {
|
|
@@ -12,15 +12,13 @@ export class UserActionsAggregator {
|
|
|
12
12
|
/** @type {AggregatedUserAction=} */
|
|
13
13
|
#aggregationEvent = undefined
|
|
14
14
|
#aggregationKey = ''
|
|
15
|
-
#ufEnabled = false
|
|
16
15
|
#deadClickTimer = undefined
|
|
17
16
|
#domObserver = undefined
|
|
18
17
|
#errorClickTimer = undefined
|
|
19
18
|
|
|
20
|
-
constructor (
|
|
21
|
-
if (
|
|
19
|
+
constructor () {
|
|
20
|
+
if (gosNREUMOriginals().o.MO) {
|
|
22
21
|
this.#domObserver = new MutationObserver(this.isLiveClick.bind(this))
|
|
23
|
-
this.#ufEnabled = true
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
|
|
@@ -52,15 +50,13 @@ export class UserActionsAggregator {
|
|
|
52
50
|
} else {
|
|
53
51
|
// return the prev existing one (if there is one)
|
|
54
52
|
const finishedEvent = this.#aggregationEvent
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
this.#errorClickCleanup()
|
|
58
|
-
}
|
|
53
|
+
this.#deadClickCleanup()
|
|
54
|
+
this.#errorClickCleanup()
|
|
59
55
|
|
|
60
56
|
// then start new event aggregation
|
|
61
57
|
this.#aggregationKey = aggregationKey
|
|
62
58
|
this.#aggregationEvent = new AggregatedUserAction(evt, selectorInfo)
|
|
63
|
-
if (
|
|
59
|
+
if (evt.type === 'click' && (selectorInfo.hasButton || selectorInfo.hasLink)) {
|
|
64
60
|
this.#deadClickSetup(this.#aggregationEvent)
|
|
65
61
|
this.#errorClickSetup()
|
|
66
62
|
}
|
|
@@ -27,7 +27,6 @@ export class Instrument extends InstrumentBase {
|
|
|
27
27
|
constructor (agentRef) {
|
|
28
28
|
super(agentRef, FEATURE_NAME)
|
|
29
29
|
const websocketsEnabled = agentRef.init.feature_flags.includes('websockets')
|
|
30
|
-
const ufEnabled = agentRef.init.feature_flags.includes('user_frustrations')
|
|
31
30
|
|
|
32
31
|
/** config values that gate whether the generic events aggregator should be imported at all */
|
|
33
32
|
const genericEventSourceConfigs = [
|
|
@@ -47,14 +46,12 @@ export class Instrument extends InstrumentBase {
|
|
|
47
46
|
setupMeasureAPI(agentRef)
|
|
48
47
|
|
|
49
48
|
let historyEE, websocketsEE
|
|
50
|
-
if (
|
|
49
|
+
if (websocketsEnabled) websocketsEE = wrapWebSocket(this.ee)
|
|
50
|
+
if (isBrowserScope) {
|
|
51
51
|
wrapFetch(this.ee)
|
|
52
52
|
wrapXhr(this.ee)
|
|
53
53
|
historyEE = wrapHistory(this.ee)
|
|
54
|
-
}
|
|
55
|
-
if (websocketsEnabled) websocketsEE = wrapWebSocket(this.ee)
|
|
56
54
|
|
|
57
|
-
if (isBrowserScope) {
|
|
58
55
|
if (agentRef.init.user_actions.enabled) {
|
|
59
56
|
OBSERVED_EVENTS.forEach(eventType =>
|
|
60
57
|
windowAddEventListener(eventType, (evt) => handle('ua', [evt], undefined, this.featureName, this.ee), true)
|
|
@@ -63,42 +60,40 @@ export class Instrument extends InstrumentBase {
|
|
|
63
60
|
const debounceHandler = debounce((evt) => { handle('ua', [evt], undefined, this.featureName, this.ee) }, 500, { leading: true })
|
|
64
61
|
windowAddEventListener(eventType, debounceHandler)
|
|
65
62
|
}
|
|
66
|
-
|
|
63
|
+
// Capture is not used here so that we don't get element focus/blur events, only the window's as they do not bubble. They are also not cancellable, so no worries about being front of line.
|
|
67
64
|
)
|
|
68
65
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
xhr.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
})
|
|
83
|
-
this.ee.on('fetch-start', (fetchArguments) => {
|
|
84
|
-
if (fetchArguments.length >= 1 && !isInternalTraffic(extractUrl(fetchArguments[0]))) {
|
|
85
|
-
handle('uaXhr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
function isInternalTraffic (url) {
|
|
90
|
-
const parsedUrl = parseUrl(url)
|
|
91
|
-
return agentRef.beacons.includes(parsedUrl.hostname + ':' + parsedUrl.port)
|
|
66
|
+
globalScope.addEventListener('error', () => {
|
|
67
|
+
handle('uaErr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
|
|
68
|
+
}, eventListenerOpts(false, this.removeOnAbort?.signal))
|
|
69
|
+
|
|
70
|
+
this.ee.on('open-xhr-start', (args, xhr) => {
|
|
71
|
+
if (!isInternalTraffic(args[1])) {
|
|
72
|
+
xhr.addEventListener('readystatechange', () => {
|
|
73
|
+
if (xhr.readyState === 2) { // HEADERS_RECEIVED
|
|
74
|
+
handle('uaXhr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
|
|
75
|
+
}
|
|
76
|
+
})
|
|
92
77
|
}
|
|
78
|
+
})
|
|
79
|
+
this.ee.on('fetch-start', (fetchArguments) => {
|
|
80
|
+
if (fetchArguments.length >= 1 && !isInternalTraffic(extractUrl(fetchArguments[0]))) {
|
|
81
|
+
handle('uaXhr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
|
|
82
|
+
}
|
|
83
|
+
})
|
|
93
84
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
85
|
+
function isInternalTraffic (url) {
|
|
86
|
+
const parsedUrl = parseUrl(url)
|
|
87
|
+
return agentRef.beacons.includes(parsedUrl.hostname + ':' + parsedUrl.port)
|
|
88
|
+
}
|
|
98
89
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
90
|
+
historyEE.on('pushState-end', navigationChange)
|
|
91
|
+
historyEE.on('replaceState-end', navigationChange)
|
|
92
|
+
window.addEventListener('hashchange', navigationChange, eventListenerOpts(true, this.removeOnAbort?.signal))
|
|
93
|
+
window.addEventListener('popstate', navigationChange, eventListenerOpts(true, this.removeOnAbort?.signal))
|
|
94
|
+
|
|
95
|
+
function navigationChange () {
|
|
96
|
+
historyEE.emit('navChange')
|
|
102
97
|
}
|
|
103
98
|
}
|
|
104
99
|
|
|
@@ -108,7 +103,10 @@ export class Instrument extends InstrumentBase {
|
|
|
108
103
|
handle('browserPerformance.resource', [entry], undefined, this.featureName, this.ee)
|
|
109
104
|
})
|
|
110
105
|
})
|
|
111
|
-
observer.observe({
|
|
106
|
+
observer.observe({
|
|
107
|
+
type: 'resource',
|
|
108
|
+
buffered: true
|
|
109
|
+
})
|
|
112
110
|
}
|
|
113
111
|
}
|
|
114
112
|
if (websocketsEnabled) { // this can apply outside browser scope such as in worker
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import { globalScope, isBrowserScope, originTime } from '../../../common/constants/runtime'
|
|
5
|
+
import { globalScope, isBrowserScope, originTime, supportsNavTimingL2 } from '../../../common/constants/runtime'
|
|
6
6
|
import { addPT, addPN } from '../../../common/timing/nav-timing'
|
|
7
7
|
import { stringify } from '../../../common/util/stringify'
|
|
8
8
|
import { isValid } from '../../../common/config/info'
|
|
@@ -46,9 +46,8 @@ export class Aggregate extends AggregateBase {
|
|
|
46
46
|
this.timeToFirstByte = Math.max(value, this.timeToFirstByte)
|
|
47
47
|
this.firstByteToWindowLoad = Math.max(Math.round(navEntry.loadEventEnd - this.timeToFirstByte), this.firstByteToWindowLoad) // our "frontend" duration
|
|
48
48
|
this.firstByteToDomContent = Math.max(Math.round(navEntry.domContentLoadedEventEnd - this.timeToFirstByte), this.firstByteToDomContent) // our "dom processing" duration
|
|
49
|
-
|
|
50
|
-
this.sendRum()
|
|
51
49
|
})
|
|
50
|
+
setTimeout(this.sendRum.bind(this), 0) // we want to sendRum after ttfb has reported something, but we dont want to wait forever incase TTFB fails to report in niche environments.
|
|
52
51
|
} else {
|
|
53
52
|
// worker agent build does not get TTFB values, use default 0 values
|
|
54
53
|
this.sendRum()
|
|
@@ -94,14 +93,14 @@ export class Aggregate extends AggregateBase {
|
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
if (globalScope.performance) {
|
|
97
|
-
if (
|
|
96
|
+
if (supportsNavTimingL2()) { // Navigation Timing level 2 API that replaced PerformanceTiming & PerformanceNavigation
|
|
98
97
|
const navTimingEntry = globalScope?.performance?.getEntriesByType('navigation')?.[0]
|
|
99
98
|
const perf = ({
|
|
100
99
|
timing: addPT(originTime, navTimingEntry, {}),
|
|
101
100
|
navigation: addPN(navTimingEntry, {})
|
|
102
101
|
})
|
|
103
102
|
queryParameters.perf = stringify(perf)
|
|
104
|
-
} else if (typeof PerformanceTiming !== 'undefined') { // Safari pre-15
|
|
103
|
+
} else if (typeof PerformanceTiming !== 'undefined') { // Modern Safari iFrames and Safari pre-15 do not support level 2 timing.
|
|
105
104
|
const perf = ({
|
|
106
105
|
timing: addPT(originTime, globalScope.performance.timing, {}, true),
|
|
107
106
|
navigation: addPN(globalScope.performance.navigation, {})
|
|
@@ -161,12 +160,12 @@ export class Aggregate extends AggregateBase {
|
|
|
161
160
|
const encoded = textEncoder.encode(value)
|
|
162
161
|
return acc + encoded.byteLength
|
|
163
162
|
}, 0)
|
|
164
|
-
|
|
163
|
+
const BCSError = 'BCS/Error/'
|
|
165
164
|
// Send SMs about failed RUM request
|
|
166
165
|
const body = {
|
|
167
166
|
sm: [{
|
|
168
167
|
params: {
|
|
169
|
-
name:
|
|
168
|
+
name: BCSError + status
|
|
170
169
|
},
|
|
171
170
|
stats: {
|
|
172
171
|
c: 1
|
|
@@ -174,7 +173,7 @@ export class Aggregate extends AggregateBase {
|
|
|
174
173
|
},
|
|
175
174
|
{
|
|
176
175
|
params: {
|
|
177
|
-
name: '
|
|
176
|
+
name: BCSError + 'Dropped/Bytes'
|
|
178
177
|
},
|
|
179
178
|
stats: {
|
|
180
179
|
c: 1,
|
|
@@ -183,7 +182,7 @@ export class Aggregate extends AggregateBase {
|
|
|
183
182
|
},
|
|
184
183
|
{
|
|
185
184
|
params: {
|
|
186
|
-
name: '
|
|
185
|
+
name: BCSError + 'Duration/Ms'
|
|
187
186
|
},
|
|
188
187
|
stats: {
|
|
189
188
|
c: 1,
|
|
@@ -14,11 +14,11 @@ import { firstContentfulPaint } from '../../../common/vitals/first-contentful-pa
|
|
|
14
14
|
import { firstPaint } from '../../../common/vitals/first-paint'
|
|
15
15
|
import { interactionToNextPaint } from '../../../common/vitals/interaction-to-next-paint'
|
|
16
16
|
import { largestContentfulPaint } from '../../../common/vitals/largest-contentful-paint'
|
|
17
|
-
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte'
|
|
18
17
|
import { subscribeToVisibilityChange } from '../../../common/window/page-visibility'
|
|
19
18
|
import { VITAL_NAMES } from '../../../common/vitals/constants'
|
|
20
19
|
import { initiallyHidden } from '../../../common/constants/runtime'
|
|
21
20
|
import { eventOrigin } from '../../../common/util/event-origin'
|
|
21
|
+
import { loadTime } from '../../../common/vitals/load-time'
|
|
22
22
|
|
|
23
23
|
export class Aggregate extends AggregateBase {
|
|
24
24
|
static featureName = FEATURE_NAME
|
|
@@ -43,9 +43,7 @@ export class Aggregate extends AggregateBase {
|
|
|
43
43
|
firstContentfulPaint.subscribe(this.#handleVitalMetric)
|
|
44
44
|
largestContentfulPaint.subscribe(this.#handleVitalMetric)
|
|
45
45
|
interactionToNextPaint.subscribe(this.#handleVitalMetric)
|
|
46
|
-
|
|
47
|
-
this.addTiming('load', Math.round(attrs.navigationEntry.loadEventEnd))
|
|
48
|
-
})
|
|
46
|
+
loadTime.subscribe(({ name, value }) => { this.addTiming(name, Math.round(value)) })
|
|
49
47
|
subscribeToVisibilityChange(() => {
|
|
50
48
|
/* Downstream, the event consumer interprets all timing node value as ms-unit and converts it to seconds via division by 1000. CLS is unitless so this normally is a problem.
|
|
51
49
|
bel.6 schema also doesn't support decimal values, of which cls within [0,1). However, the two nicely cancels out, and we can multiply cls by 1000 to both negate the division
|
|
@@ -7,7 +7,7 @@ import { FEATURE_NAME } from '../constants'
|
|
|
7
7
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
8
8
|
import { TraceStorage } from './trace/storage'
|
|
9
9
|
import { obj as encodeObj } from '../../../common/url/encode'
|
|
10
|
-
import { globalScope } from '../../../common/constants/runtime'
|
|
10
|
+
import { globalScope, supportsNavTimingL2 } from '../../../common/constants/runtime'
|
|
11
11
|
import { MODE, SESSION_EVENTS } from '../../../common/session/constants'
|
|
12
12
|
import { applyFnToProps } from '../../../common/util/traverse'
|
|
13
13
|
import { cleanURL } from '../../../common/url/clean-url'
|
|
@@ -62,7 +62,7 @@ export class Aggregate extends AggregateBase {
|
|
|
62
62
|
if (this.sessionId !== sessionState.value || (eventType === 'cross-tab' && sessionState.sessionTraceMode === MODE.OFF)) this.abort(2)
|
|
63
63
|
})
|
|
64
64
|
|
|
65
|
-
if (
|
|
65
|
+
if (supportsNavTimingL2()) {
|
|
66
66
|
this.traceStorage.storeTiming(globalScope.performance?.getEntriesByType?.('navigation')[0])
|
|
67
67
|
} else {
|
|
68
68
|
this.traceStorage.storeTiming(globalScope.performance?.timing, true)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { handle } from '../../../common/event-emitter/handle'
|
|
6
6
|
import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
7
7
|
import { single } from '../../../common/util/invoke'
|
|
8
|
-
import {
|
|
8
|
+
import { loadTime } from '../../../common/vitals/load-time'
|
|
9
9
|
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
10
10
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
11
11
|
import { API_TRIGGER_NAME, FEATURE_NAME, INTERACTION_STATUS, INTERACTION_TRIGGERS, IPL_TRIGGER_NAME, NO_LONG_TASK_WINDOW, POPSTATE_MERGE_WINDOW, POPSTATE_TRIGGER } from '../constants'
|
|
@@ -31,10 +31,9 @@ export class Aggregate extends AggregateBase {
|
|
|
31
31
|
this.events.add(ixn) // add the iPL ixn to the buffer for harvest
|
|
32
32
|
this.initialPageLoadInteraction = null
|
|
33
33
|
})
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
|
|
35
|
+
loadTime.subscribe(({ value: loadEventTime }) => {
|
|
36
36
|
this.initialPageLoadInteraction.done(loadEventTime)
|
|
37
|
-
// Report metric on the initial page load time
|
|
38
37
|
this.reportSupportabilityMetric('SoftNav/Interaction/InitialPageLoad/Duration/Ms', Math.round(loadEventTime))
|
|
39
38
|
})
|
|
40
39
|
|
|
@@ -16,6 +16,7 @@ import { wrapFetch } from '../../../common/wrap/wrap-fetch'
|
|
|
16
16
|
import { wrapHistory } from '../../../common/wrap/wrap-history'
|
|
17
17
|
import { wrapMutation } from '../../../common/wrap/wrap-mutation'
|
|
18
18
|
import { setupInteractionAPI } from '../../../loaders/api/interaction'
|
|
19
|
+
import { onWindowLoad } from '../../../common/window/load'
|
|
19
20
|
|
|
20
21
|
const {
|
|
21
22
|
FEATURE_NAME, START, END, BODY, CB_END, JS_TIME, FETCH, FN_START, CB_START, FN_END
|
|
@@ -81,6 +82,11 @@ export class Instrument extends InstrumentBase {
|
|
|
81
82
|
historyEE.on('pushState-end', trackURLChange)
|
|
82
83
|
historyEE.on('replaceState-end', trackURLChange)
|
|
83
84
|
|
|
85
|
+
/** niche cases like GPT apps cause no window.load event to fire - which breaks IPLs - so manually force one through the pipe */
|
|
86
|
+
onWindowLoad(() => {
|
|
87
|
+
eventsEE.emit(FN_START, [[{ type: 'load' }], window], undefined, true)
|
|
88
|
+
})
|
|
89
|
+
|
|
84
90
|
window.addEventListener('hashchange', trackURLChange, eventListenerOpts(true, this.removeOnAbort?.signal))
|
|
85
91
|
window.addEventListener('load', trackURLChange, eventListenerOpts(true, this.removeOnAbort?.signal))
|
|
86
92
|
window.addEventListener('popstate', function () {
|
|
@@ -45,7 +45,7 @@ function register (agentRef, target, parent) {
|
|
|
45
45
|
warn(54, 'newrelic.register')
|
|
46
46
|
|
|
47
47
|
target ||= {}
|
|
48
|
-
target.
|
|
48
|
+
target.type = 'MFE'
|
|
49
49
|
target.licenseKey ||= agentRef.info.licenseKey // will inherit the license key from the container agent if not provided for brevity. A future state may dictate that we need different license keys to do different things.
|
|
50
50
|
target.blocked = false
|
|
51
51
|
target.parent = parent || {}
|