@atlaskit/react-ufo 3.14.3 → 3.14.4
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/create-payload/critical-metrics-payload/index.js +38 -0
- package/dist/cjs/create-payload/critical-metrics-payload/root-metrics.js +180 -0
- package/dist/cjs/create-payload/critical-metrics-payload/segment-metrics/create-segment-metrics.js +251 -0
- package/dist/cjs/create-payload/critical-metrics-payload/segment-metrics/get-is-root-segment.js +9 -0
- package/dist/cjs/create-payload/critical-metrics-payload/segment-metrics/get-segment-id.js +15 -0
- package/dist/cjs/create-payload/critical-metrics-payload/segment-metrics/get-segment-status.js +59 -0
- package/dist/cjs/create-payload/critical-metrics-payload/segment-metrics/has-segment-failed.js +17 -0
- package/dist/cjs/create-payload/critical-metrics-payload/segment-metrics/is-label-stack-under-segment.js +11 -0
- package/dist/cjs/create-payload/critical-metrics-payload/types.js +5 -0
- package/dist/cjs/create-payload/index.js +122 -214
- package/dist/cjs/create-payload/utils/find-matching-legacy-metric.js +15 -0
- package/dist/cjs/create-payload/utils/get-browser-metadata.js +87 -0
- package/dist/cjs/create-payload/utils/get-fmp.js +52 -0
- package/dist/cjs/create-payload/utils/get-navigation-metrics.js +66 -0
- package/dist/cjs/create-payload/utils/get-paint-metrics.js +124 -0
- package/dist/cjs/create-payload/utils/get-payload-size.js +17 -0
- package/dist/cjs/create-payload/utils/get-react-ufo-payload-version.js +3 -1
- package/dist/cjs/create-payload/utils/get-ssr-success.js +15 -0
- package/dist/cjs/create-payload/utils/get-ttai.js +14 -0
- package/dist/cjs/create-payload/utils/get-tti.js +38 -0
- package/dist/cjs/interaction-metrics/index.js +25 -0
- package/dist/es2019/create-payload/critical-metrics-payload/index.js +6 -0
- package/dist/es2019/create-payload/critical-metrics-payload/root-metrics.js +166 -0
- package/dist/es2019/create-payload/critical-metrics-payload/segment-metrics/create-segment-metrics.js +155 -0
- package/dist/es2019/create-payload/critical-metrics-payload/segment-metrics/get-is-root-segment.js +3 -0
- package/dist/es2019/create-payload/critical-metrics-payload/segment-metrics/get-segment-id.js +9 -0
- package/dist/es2019/create-payload/critical-metrics-payload/segment-metrics/get-segment-status.js +40 -0
- package/dist/es2019/create-payload/critical-metrics-payload/segment-metrics/has-segment-failed.js +10 -0
- package/dist/es2019/create-payload/critical-metrics-payload/segment-metrics/is-label-stack-under-segment.js +5 -0
- package/dist/es2019/create-payload/critical-metrics-payload/types.js +1 -0
- package/dist/es2019/create-payload/index.js +55 -151
- package/dist/es2019/create-payload/utils/find-matching-legacy-metric.js +7 -0
- package/dist/es2019/create-payload/utils/get-browser-metadata.js +79 -0
- package/dist/es2019/create-payload/utils/get-fmp.js +47 -0
- package/dist/es2019/create-payload/utils/get-navigation-metrics.js +59 -0
- package/dist/es2019/create-payload/utils/get-paint-metrics.js +78 -0
- package/dist/es2019/create-payload/utils/get-payload-size.js +11 -0
- package/dist/es2019/create-payload/utils/get-react-ufo-payload-version.js +2 -1
- package/dist/es2019/create-payload/utils/get-ssr-success.js +7 -0
- package/dist/es2019/create-payload/utils/get-ttai.js +9 -0
- package/dist/es2019/create-payload/utils/get-tti.js +35 -0
- package/dist/es2019/interaction-metrics/index.js +24 -0
- package/dist/esm/create-payload/critical-metrics-payload/index.js +31 -0
- package/dist/esm/create-payload/critical-metrics-payload/root-metrics.js +174 -0
- package/dist/esm/create-payload/critical-metrics-payload/segment-metrics/create-segment-metrics.js +244 -0
- package/dist/esm/create-payload/critical-metrics-payload/segment-metrics/get-is-root-segment.js +3 -0
- package/dist/esm/create-payload/critical-metrics-payload/segment-metrics/get-segment-id.js +9 -0
- package/dist/esm/create-payload/critical-metrics-payload/segment-metrics/get-segment-status.js +52 -0
- package/dist/esm/create-payload/critical-metrics-payload/segment-metrics/has-segment-failed.js +10 -0
- package/dist/esm/create-payload/critical-metrics-payload/segment-metrics/is-label-stack-under-segment.js +5 -0
- package/dist/esm/create-payload/critical-metrics-payload/types.js +1 -0
- package/dist/esm/create-payload/index.js +121 -210
- package/dist/esm/create-payload/utils/find-matching-legacy-metric.js +9 -0
- package/dist/esm/create-payload/utils/get-browser-metadata.js +79 -0
- package/dist/esm/create-payload/utils/get-fmp.js +47 -0
- package/dist/esm/create-payload/utils/get-navigation-metrics.js +59 -0
- package/dist/esm/create-payload/utils/get-paint-metrics.js +119 -0
- package/dist/esm/create-payload/utils/get-payload-size.js +11 -0
- package/dist/esm/create-payload/utils/get-react-ufo-payload-version.js +2 -1
- package/dist/esm/create-payload/utils/get-ssr-success.js +7 -0
- package/dist/esm/create-payload/utils/get-ttai.js +7 -0
- package/dist/esm/create-payload/utils/get-tti.js +33 -0
- package/dist/esm/interaction-metrics/index.js +24 -0
- package/dist/types/common/common/types.d.ts +1 -1
- package/dist/types/common/react-ufo-payload-schema.d.ts +23 -2
- package/dist/types/create-payload/critical-metrics-payload/index.d.ts +6 -0
- package/dist/types/create-payload/critical-metrics-payload/root-metrics.d.ts +7 -0
- package/dist/types/create-payload/critical-metrics-payload/segment-metrics/create-segment-metrics.d.ts +3 -0
- package/dist/types/create-payload/critical-metrics-payload/segment-metrics/get-is-root-segment.d.ts +2 -0
- package/dist/types/create-payload/critical-metrics-payload/segment-metrics/get-segment-id.d.ts +2 -0
- package/dist/types/create-payload/critical-metrics-payload/segment-metrics/get-segment-status.d.ts +7 -0
- package/dist/types/create-payload/critical-metrics-payload/segment-metrics/has-segment-failed.d.ts +2 -0
- package/dist/types/create-payload/critical-metrics-payload/segment-metrics/is-label-stack-under-segment.d.ts +2 -0
- package/dist/types/create-payload/critical-metrics-payload/types.d.ts +128 -0
- package/dist/types/create-payload/index.d.ts +339 -834
- package/dist/types/create-payload/utils/find-matching-legacy-metric.d.ts +5 -0
- package/dist/types/create-payload/utils/get-browser-metadata.d.ts +21 -0
- package/dist/types/create-payload/utils/get-fmp.d.ts +6 -0
- package/dist/types/create-payload/utils/get-navigation-metrics.d.ts +29 -0
- package/dist/types/create-payload/utils/get-paint-metrics.d.ts +13 -0
- package/dist/types/create-payload/utils/get-payload-size.d.ts +1 -0
- package/dist/types/create-payload/utils/get-react-ufo-payload-version.d.ts +2 -1
- package/dist/types/create-payload/utils/get-ssr-success.d.ts +2 -0
- package/dist/types/create-payload/utils/get-ttai.d.ts +2 -0
- package/dist/types/create-payload/utils/get-tti.d.ts +7 -0
- package/dist/types/interaction-metrics/index.d.ts +1 -0
- package/dist/types-ts4.5/common/common/types.d.ts +1 -1
- package/dist/types-ts4.5/common/react-ufo-payload-schema.d.ts +23 -2
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/index.d.ts +6 -0
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/root-metrics.d.ts +7 -0
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/segment-metrics/create-segment-metrics.d.ts +3 -0
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/segment-metrics/get-is-root-segment.d.ts +2 -0
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/segment-metrics/get-segment-id.d.ts +2 -0
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/segment-metrics/get-segment-status.d.ts +7 -0
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/segment-metrics/has-segment-failed.d.ts +2 -0
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/segment-metrics/is-label-stack-under-segment.d.ts +2 -0
- package/dist/types-ts4.5/create-payload/critical-metrics-payload/types.d.ts +130 -0
- package/dist/types-ts4.5/create-payload/index.d.ts +339 -834
- package/dist/types-ts4.5/create-payload/utils/find-matching-legacy-metric.d.ts +5 -0
- package/dist/types-ts4.5/create-payload/utils/get-browser-metadata.d.ts +21 -0
- package/dist/types-ts4.5/create-payload/utils/get-fmp.d.ts +6 -0
- package/dist/types-ts4.5/create-payload/utils/get-navigation-metrics.d.ts +29 -0
- package/dist/types-ts4.5/create-payload/utils/get-paint-metrics.d.ts +13 -0
- package/dist/types-ts4.5/create-payload/utils/get-payload-size.d.ts +1 -0
- package/dist/types-ts4.5/create-payload/utils/get-react-ufo-payload-version.d.ts +2 -1
- package/dist/types-ts4.5/create-payload/utils/get-ssr-success.d.ts +2 -0
- package/dist/types-ts4.5/create-payload/utils/get-ttai.d.ts +2 -0
- package/dist/types-ts4.5/create-payload/utils/get-tti.d.ts +7 -0
- package/dist/types-ts4.5/interaction-metrics/index.d.ts +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { getConfig } from '../../../config';
|
|
2
|
+
import getBrowserMetadata from '../../utils/get-browser-metadata';
|
|
3
|
+
import getPageVisibilityUpToTTAI from '../../utils/get-page-visibility-up-to-ttai';
|
|
4
|
+
import { LATEST_REACT_UFO_PAYLOAD_VERSION } from '../../utils/get-react-ufo-payload-version';
|
|
5
|
+
import getIsRootSegment from './get-is-root-segment';
|
|
6
|
+
import getSegmentId from './get-segment-id';
|
|
7
|
+
import getSegmentStatus from './get-segment-status';
|
|
8
|
+
export async function createSegmentMetricsPayloads(interactionId, interaction) {
|
|
9
|
+
var _interaction$cohortin;
|
|
10
|
+
const config = getConfig();
|
|
11
|
+
if (!config) {
|
|
12
|
+
throw Error('UFO Configuration not provided');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Get browser metadata (using compact nested format)
|
|
16
|
+
const browserMetadata = getBrowserMetadata();
|
|
17
|
+
|
|
18
|
+
// Process cohorting custom data
|
|
19
|
+
const cohortingCustomData = (_interaction$cohortin = interaction.cohortingCustomData) !== null && _interaction$cohortin !== void 0 && _interaction$cohortin.size ? Object.fromEntries(interaction.cohortingCustomData) : undefined;
|
|
20
|
+
const pageVisibilityAtTTAI = getPageVisibilityUpToTTAI(interaction);
|
|
21
|
+
const {
|
|
22
|
+
knownSegments,
|
|
23
|
+
reactProfilerTimings,
|
|
24
|
+
rate,
|
|
25
|
+
routeName,
|
|
26
|
+
previousInteractionName,
|
|
27
|
+
isPreviousInteractionAborted,
|
|
28
|
+
abortedByInteractionName
|
|
29
|
+
} = interaction;
|
|
30
|
+
|
|
31
|
+
// Group segments by name and select the first segment for each name
|
|
32
|
+
const segmentsByName = new Map();
|
|
33
|
+
for (const segment of knownSegments) {
|
|
34
|
+
const segmentId = getSegmentId(segment.labelStack);
|
|
35
|
+
|
|
36
|
+
// skip if no segmentId
|
|
37
|
+
if (!segmentId) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const name = segment.labelStack[segment.labelStack.length - 1].name;
|
|
41
|
+
const isRootSegment = getIsRootSegment(segment.labelStack);
|
|
42
|
+
const segmentProfilerTimings = reactProfilerTimings.filter(timing => {
|
|
43
|
+
const timingSegmentId = getSegmentId(timing.labelStack);
|
|
44
|
+
// check if labelStack matches exactly
|
|
45
|
+
return timingSegmentId === segmentId;
|
|
46
|
+
}).sort((a, b) => {
|
|
47
|
+
return a.startTime - b.startTime;
|
|
48
|
+
});
|
|
49
|
+
const firstMountTiming = segmentProfilerTimings.find(timing => {
|
|
50
|
+
return timing.type === 'mount';
|
|
51
|
+
});
|
|
52
|
+
if (!firstMountTiming) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const firstMountTime = isRootSegment ? interaction.start : firstMountTiming.startTime;
|
|
56
|
+
|
|
57
|
+
// Check if we already have a segment with this name
|
|
58
|
+
const existingEntry = segmentsByName.get(name);
|
|
59
|
+
if (!existingEntry || firstMountTime < existingEntry.firstMountTime) {
|
|
60
|
+
// Either first time seeing this name, or this segment mounted earlier
|
|
61
|
+
segmentsByName.set(name, {
|
|
62
|
+
segment,
|
|
63
|
+
firstMountTime
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Create payloads only for the selected segments (first one per name)
|
|
69
|
+
const payloads = [];
|
|
70
|
+
for (const {
|
|
71
|
+
segment
|
|
72
|
+
} of segmentsByName.values()) {
|
|
73
|
+
var _window$location;
|
|
74
|
+
const segmentId = getSegmentId(segment.labelStack);
|
|
75
|
+
const name = segment.labelStack[segment.labelStack.length - 1].name;
|
|
76
|
+
const isRootSegment = getIsRootSegment(segment.labelStack);
|
|
77
|
+
const segmentProfilerTimings = reactProfilerTimings.filter(timing => {
|
|
78
|
+
const timingSegmentId = getSegmentId(timing.labelStack);
|
|
79
|
+
// check if labelStack matches exactly
|
|
80
|
+
return timingSegmentId === segmentId;
|
|
81
|
+
}).sort((a, b) => {
|
|
82
|
+
return a.startTime - b.startTime;
|
|
83
|
+
});
|
|
84
|
+
const firstMountTiming = segmentProfilerTimings.find(timing => {
|
|
85
|
+
return timing.type === 'mount';
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// We already checked this exists in the grouping phase
|
|
89
|
+
if (!firstMountTiming) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const lastTiming = segmentProfilerTimings[segmentProfilerTimings.length - 1];
|
|
93
|
+
const startTime = isRootSegment ? interaction.start : firstMountTiming.startTime;
|
|
94
|
+
const endTime = lastTiming.commitTime;
|
|
95
|
+
const ttai = Math.round(endTime - startTime);
|
|
96
|
+
const {
|
|
97
|
+
status,
|
|
98
|
+
abortReason: segmentAbortReason
|
|
99
|
+
} = getSegmentStatus(interaction, segment);
|
|
100
|
+
const properties = {
|
|
101
|
+
// Basic metadata
|
|
102
|
+
'event:hostname': ((_window$location = window.location) === null || _window$location === void 0 ? void 0 : _window$location.hostname) || 'unknown',
|
|
103
|
+
'event:product': config.product,
|
|
104
|
+
'event:schema': '1.0.0',
|
|
105
|
+
'event:region': config.region || 'unknown',
|
|
106
|
+
'event:source': {
|
|
107
|
+
name: 'react-ufo/web',
|
|
108
|
+
version: LATEST_REACT_UFO_PAYLOAD_VERSION
|
|
109
|
+
},
|
|
110
|
+
'experience:key': 'custom.ufo.critical-metrics',
|
|
111
|
+
'experience:name': name,
|
|
112
|
+
// Browser metadata (compact nested format)
|
|
113
|
+
browser: browserMetadata.browser,
|
|
114
|
+
device: browserMetadata.device,
|
|
115
|
+
network: browserMetadata.network,
|
|
116
|
+
time: browserMetadata.time,
|
|
117
|
+
metrics: {
|
|
118
|
+
ttai,
|
|
119
|
+
tti: ttai
|
|
120
|
+
},
|
|
121
|
+
interactionId,
|
|
122
|
+
type: 'page_segment_load',
|
|
123
|
+
rate,
|
|
124
|
+
routeName: routeName !== null && routeName !== void 0 ? routeName : undefined,
|
|
125
|
+
// Performance timings
|
|
126
|
+
start: Math.round(startTime),
|
|
127
|
+
end: Math.round(endTime),
|
|
128
|
+
// Status and outcome
|
|
129
|
+
status,
|
|
130
|
+
abortReason: segmentAbortReason,
|
|
131
|
+
previousInteractionName,
|
|
132
|
+
isPreviousInteractionAborted,
|
|
133
|
+
abortedByInteractionName,
|
|
134
|
+
pageVisibilityAtTTAI,
|
|
135
|
+
// Basic error count (not detailed error count)
|
|
136
|
+
errorCount: interaction.errors.length,
|
|
137
|
+
// Cohorting custom data
|
|
138
|
+
...(Object.keys(cohortingCustomData || {}).length > 0 && {
|
|
139
|
+
cohortingCustomData
|
|
140
|
+
})
|
|
141
|
+
};
|
|
142
|
+
const payload = {
|
|
143
|
+
actionSubject: 'experience',
|
|
144
|
+
action: 'measured',
|
|
145
|
+
eventType: 'operational',
|
|
146
|
+
source: 'measured',
|
|
147
|
+
tags: ['observability'],
|
|
148
|
+
attributes: {
|
|
149
|
+
properties: properties
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
payloads.push(payload);
|
|
153
|
+
}
|
|
154
|
+
return payloads;
|
|
155
|
+
}
|
package/dist/es2019/create-payload/critical-metrics-payload/segment-metrics/get-segment-status.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import getInteractionStatus from '../../utils/get-interaction-status';
|
|
2
|
+
import getSegmentId from './get-segment-id';
|
|
3
|
+
import hasSegmentFailed from './has-segment-failed';
|
|
4
|
+
import isLabelStackUnderSegment from './is-label-stack-under-segment';
|
|
5
|
+
export default function getSegmentStatus(interaction, segment) {
|
|
6
|
+
const segmentId = getSegmentId(segment.labelStack);
|
|
7
|
+
|
|
8
|
+
// Get the root interaction status info
|
|
9
|
+
const rootInteractionStatus = getInteractionStatus(interaction);
|
|
10
|
+
const rootStatus = rootInteractionStatus.originalInteractionStatus;
|
|
11
|
+
const rootAbortReason = interaction.abortReason;
|
|
12
|
+
const isInteractionsAbortedByNewInteraction = rootStatus === 'ABORTED' && rootAbortReason === 'new_interaction';
|
|
13
|
+
const isInteractionsAbortedByTransition = rootStatus === 'ABORTED' && rootAbortReason === 'transition';
|
|
14
|
+
let status = 'SUCCEEDED';
|
|
15
|
+
let abortReason;
|
|
16
|
+
|
|
17
|
+
// Check if this specific segment has failed
|
|
18
|
+
if (segmentId && hasSegmentFailed(interaction.errors, segmentId)) {
|
|
19
|
+
status = 'FAILED';
|
|
20
|
+
} else if (isInteractionsAbortedByNewInteraction) {
|
|
21
|
+
status = 'ABORTED';
|
|
22
|
+
abortReason = 'new_interaction';
|
|
23
|
+
} else if (isInteractionsAbortedByTransition) {
|
|
24
|
+
status = 'ABORTED';
|
|
25
|
+
abortReason = 'transition';
|
|
26
|
+
} else if (segmentId) {
|
|
27
|
+
// Check for active holds that are under this segment
|
|
28
|
+
for (const activeHold of interaction.holdActive.values()) {
|
|
29
|
+
if (isLabelStackUnderSegment(activeHold.labelStack, segmentId)) {
|
|
30
|
+
status = 'ABORTED';
|
|
31
|
+
abortReason = 'timeout';
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
status,
|
|
38
|
+
abortReason
|
|
39
|
+
};
|
|
40
|
+
}
|
package/dist/es2019/create-payload/critical-metrics-payload/segment-metrics/has-segment-failed.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import getSegmentId from './get-segment-id';
|
|
2
|
+
export default function hasSegmentFailed(errors, segmentId) {
|
|
3
|
+
return errors.some(error => {
|
|
4
|
+
if (!error.labelStack) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const errorSegmentId = getSegmentId(error.labelStack);
|
|
8
|
+
return errorSegmentId === segmentId;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { getDocument } from '@atlaskit/browser-apis';
|
|
2
2
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
|
+
|
|
4
|
+
// Import common utilities
|
|
5
|
+
|
|
3
6
|
import { getLighthouseMetrics } from '../additional-payload';
|
|
4
7
|
import { CHRReporter } from '../assets';
|
|
5
8
|
import * as bundleEvalTiming from '../bundle-eval-timing';
|
|
@@ -17,10 +20,17 @@ import { filterResourceTimings } from '../resource-timing/common/utils/resource-
|
|
|
17
20
|
import { roundEpsilon } from '../round-number';
|
|
18
21
|
import * as ssr from '../ssr';
|
|
19
22
|
import { buildSegmentTree, labelStackStartWith, optimizeLabelStack, sanitizeUfoName, stringifyLabelStackFully } from './common/utils';
|
|
23
|
+
import { createCriticalMetricsPayloads } from './critical-metrics-payload';
|
|
24
|
+
import { getBrowserMetadataToLegacyFormat } from './utils/get-browser-metadata';
|
|
20
25
|
import getInteractionStatus from './utils/get-interaction-status';
|
|
26
|
+
import { getNavigationMetricsToLegacyFormat } from './utils/get-navigation-metrics';
|
|
21
27
|
import getPageVisibilityUpToTTAI from './utils/get-page-visibility-up-to-ttai';
|
|
28
|
+
import { getPaintMetricsToLegacyFormat } from './utils/get-paint-metrics';
|
|
29
|
+
import getPayloadSize from './utils/get-payload-size';
|
|
22
30
|
import { getReactUFOPayloadVersion } from './utils/get-react-ufo-payload-version';
|
|
23
31
|
import getSSRDoneTimeValue from './utils/get-ssr-done-time-value';
|
|
32
|
+
import getSSRSuccessUtil from './utils/get-ssr-success';
|
|
33
|
+
import getTTAI from './utils/get-ttai';
|
|
24
34
|
import getVCMetrics from './utils/get-vc-metrics';
|
|
25
35
|
function getUfoNameOverride(interaction) {
|
|
26
36
|
const {
|
|
@@ -131,119 +141,12 @@ function getResourceTimings(start, end) {
|
|
|
131
141
|
function getBundleEvalTimings(start) {
|
|
132
142
|
return bundleEvalTiming.getBundleEvalTimings(start);
|
|
133
143
|
}
|
|
134
|
-
function getSSRSuccess(type) {
|
|
135
|
-
return type === 'page_load' ? ssr.getSSRSuccess() : undefined;
|
|
136
|
-
}
|
|
137
144
|
function getSSRPhaseSuccess(type) {
|
|
138
145
|
return type === 'page_load' ? ssr.getSSRPhaseSuccess() : undefined;
|
|
139
146
|
}
|
|
140
147
|
function getSSRFeatureFlags(type) {
|
|
141
148
|
return type === 'page_load' ? ssr.getSSRFeatureFlags() : undefined;
|
|
142
149
|
}
|
|
143
|
-
const getLCP = end => {
|
|
144
|
-
return new Promise(resolve => {
|
|
145
|
-
let observer;
|
|
146
|
-
const timeout = setTimeout(() => {
|
|
147
|
-
var _observer;
|
|
148
|
-
(_observer = observer) === null || _observer === void 0 ? void 0 : _observer.disconnect();
|
|
149
|
-
resolve(null);
|
|
150
|
-
}, 200);
|
|
151
|
-
const performanceObserverCallback = list => {
|
|
152
|
-
const entries = Array.from(list.getEntries());
|
|
153
|
-
const lastEntry = entries.reduce((agg, entry) => {
|
|
154
|
-
// Use the latest LCP candidate before TTAI
|
|
155
|
-
if (entry.startTime <= end && (agg === null || agg.startTime < entry.startTime)) {
|
|
156
|
-
return entry;
|
|
157
|
-
}
|
|
158
|
-
return agg;
|
|
159
|
-
}, null);
|
|
160
|
-
clearTimeout(timeout);
|
|
161
|
-
if (!lastEntry || lastEntry === null) {
|
|
162
|
-
resolve(null);
|
|
163
|
-
} else {
|
|
164
|
-
resolve(lastEntry.startTime);
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
observer = new PerformanceObserver(performanceObserverCallback);
|
|
168
|
-
observer.observe({
|
|
169
|
-
type: 'largest-contentful-paint',
|
|
170
|
-
buffered: true
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
};
|
|
174
|
-
async function getPaintMetrics(type, end) {
|
|
175
|
-
if (type !== 'page_load') {
|
|
176
|
-
return {};
|
|
177
|
-
}
|
|
178
|
-
const metrics = {};
|
|
179
|
-
performance.getEntriesByType('paint').forEach(entry => {
|
|
180
|
-
if (entry.name === 'first-paint') {
|
|
181
|
-
metrics['metric:fp'] = Math.round(entry.startTime);
|
|
182
|
-
}
|
|
183
|
-
if (entry.name === 'first-contentful-paint') {
|
|
184
|
-
metrics['metric:fcp'] = Math.round(entry.startTime);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
const lcp = await getLCP(end);
|
|
188
|
-
if (lcp) {
|
|
189
|
-
metrics['metric:lcp'] = Math.round(lcp);
|
|
190
|
-
}
|
|
191
|
-
return metrics;
|
|
192
|
-
}
|
|
193
|
-
function getTTAI(interaction) {
|
|
194
|
-
const {
|
|
195
|
-
start,
|
|
196
|
-
end
|
|
197
|
-
} = interaction;
|
|
198
|
-
const pageVisibilityUpToTTAI = getPageVisibilityUpToTTAI(interaction);
|
|
199
|
-
return !interaction.abortReason && pageVisibilityUpToTTAI === 'visible' ? Math.round(end - start) : undefined;
|
|
200
|
-
}
|
|
201
|
-
function getNavigationMetrics(type) {
|
|
202
|
-
if (type !== 'page_load') {
|
|
203
|
-
return {};
|
|
204
|
-
}
|
|
205
|
-
const entries = performance.getEntriesByType('navigation');
|
|
206
|
-
if (entries.length === 0) {
|
|
207
|
-
return {};
|
|
208
|
-
}
|
|
209
|
-
const navigation = entries[0];
|
|
210
|
-
const metrics = {
|
|
211
|
-
// From https://www.w3.org/TR/resource-timing/
|
|
212
|
-
redirectStart: Math.round(navigation.redirectStart),
|
|
213
|
-
redirectEnd: Math.round(navigation.redirectEnd),
|
|
214
|
-
fetchStart: Math.round(navigation.fetchStart),
|
|
215
|
-
domainLookupStart: Math.round(navigation.domainLookupStart),
|
|
216
|
-
domainLookupEnd: Math.round(navigation.domainLookupEnd),
|
|
217
|
-
connectStart: Math.round(navigation.connectStart),
|
|
218
|
-
connectEnd: Math.round(navigation.connectEnd),
|
|
219
|
-
secureConnectionStart: Math.round(navigation.secureConnectionStart),
|
|
220
|
-
requestStart: Math.round(navigation.requestStart),
|
|
221
|
-
responseStart: Math.round(navigation.responseStart),
|
|
222
|
-
responseEnd: Math.round(navigation.responseEnd),
|
|
223
|
-
encodedBodySize: Math.round(navigation.encodedBodySize),
|
|
224
|
-
decodedBodySize: Math.round(navigation.decodedBodySize),
|
|
225
|
-
transferSize: Math.round(navigation.transferSize),
|
|
226
|
-
// From https://www.w3.org/TR/navigation-timing-2/
|
|
227
|
-
redirectCount: navigation.redirectCount,
|
|
228
|
-
type: navigation.type,
|
|
229
|
-
unloadEventEnd: Math.round(navigation.unloadEventEnd),
|
|
230
|
-
unloadEventStart: Math.round(navigation.unloadEventStart),
|
|
231
|
-
workerStart: Math.round(navigation.workerStart),
|
|
232
|
-
nextHopProtocol: navigation.nextHopProtocol
|
|
233
|
-
|
|
234
|
-
// The following properties are ignored because they provided limited value on a modern stack (e.g. the content
|
|
235
|
-
// is usually rendered and interactive before the dom is fully parsed, dont't play well with streamed content...)
|
|
236
|
-
// * domComplete
|
|
237
|
-
// * domContentLoadedEventEnd
|
|
238
|
-
// * domContentLoadedEventStart
|
|
239
|
-
// * domInteractive
|
|
240
|
-
// * loadEventEnd
|
|
241
|
-
// * loadEventStart
|
|
242
|
-
};
|
|
243
|
-
return {
|
|
244
|
-
'metrics:navigation': metrics
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
150
|
function getPPSMetrics(interaction) {
|
|
248
151
|
var _interaction$apdex, _interaction$apdex$;
|
|
249
152
|
const {
|
|
@@ -277,7 +180,7 @@ function getPPSMetrics(interaction) {
|
|
|
277
180
|
function getSSRProperties(type) {
|
|
278
181
|
const ssrPhases = getSSRPhaseSuccess(type);
|
|
279
182
|
return {
|
|
280
|
-
'ssr:success':
|
|
183
|
+
'ssr:success': getSSRSuccessUtil(type),
|
|
281
184
|
'ssr:featureFlags': getSSRFeatureFlags(type),
|
|
282
185
|
...((ssrPhases === null || ssrPhases === void 0 ? void 0 : ssrPhases.earlyFlush) != null ? {
|
|
283
186
|
'ssr:earlyflush:success': ssrPhases.earlyFlush
|
|
@@ -314,33 +217,6 @@ function getAssetsMetrics(interaction, SSRDoneTime) {
|
|
|
314
217
|
return {};
|
|
315
218
|
}
|
|
316
219
|
}
|
|
317
|
-
function getBrowserMetadata() {
|
|
318
|
-
const data = {};
|
|
319
|
-
const now = new Date();
|
|
320
|
-
data['event:localHour'] = now.getHours(); // returns the hours for this date according to local time
|
|
321
|
-
data['event:localDayOfWeek'] = now.getDay(); // Sunday - Saturday : 0 - 6
|
|
322
|
-
data['event:localTimezoneOffset'] = now.getTimezoneOffset(); // A number representing the difference, in minutes, between the date as evaluated in the UTC time zone and as evaluated in the local time zone.
|
|
323
|
-
|
|
324
|
-
if (navigator.userAgent != null) {
|
|
325
|
-
const browser = Bowser.getParser(navigator.userAgent);
|
|
326
|
-
data['event:browser:name'] = browser.getBrowserName();
|
|
327
|
-
data['event:browser:version'] = browser.getBrowserVersion();
|
|
328
|
-
}
|
|
329
|
-
if (navigator.hardwareConcurrency != null) {
|
|
330
|
-
data['event:cpus'] = navigator.hardwareConcurrency;
|
|
331
|
-
}
|
|
332
|
-
if (navigator.deviceMemory != null) {
|
|
333
|
-
data['event:memory'] = navigator.deviceMemory;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// eslint-disable-next-line compat/compat
|
|
337
|
-
if (navigator.connection != null) {
|
|
338
|
-
data['event:network:effectiveType'] = navigator.connection.effectiveType;
|
|
339
|
-
data['event:network:rtt'] = navigator.connection.rtt;
|
|
340
|
-
data['event:network:downlink'] = navigator.connection.downlink;
|
|
341
|
-
}
|
|
342
|
-
return data;
|
|
343
|
-
}
|
|
344
220
|
function getTracingContextData(interaction) {
|
|
345
221
|
const {
|
|
346
222
|
trace,
|
|
@@ -362,6 +238,7 @@ function getTracingContextData(interaction) {
|
|
|
362
238
|
function optimizeCustomData(interaction) {
|
|
363
239
|
const {
|
|
364
240
|
customData,
|
|
241
|
+
cohortingCustomData,
|
|
365
242
|
legacyMetrics
|
|
366
243
|
} = interaction;
|
|
367
244
|
const customDataMap = customData.reduce((result, {
|
|
@@ -377,6 +254,17 @@ function optimizeCustomData(interaction) {
|
|
|
377
254
|
});
|
|
378
255
|
return result;
|
|
379
256
|
}, new Map());
|
|
257
|
+
|
|
258
|
+
// Merge cohorting custom data into the same map
|
|
259
|
+
if (cohortingCustomData && cohortingCustomData.size > 0) {
|
|
260
|
+
var _interaction$labelSta, _customDataMap$get$da, _customDataMap$get, _interaction$labelSta2;
|
|
261
|
+
const label = stringifyLabelStackFully((_interaction$labelSta = interaction.labelStack) !== null && _interaction$labelSta !== void 0 ? _interaction$labelSta : []);
|
|
262
|
+
const value = (_customDataMap$get$da = (_customDataMap$get = customDataMap.get(label)) === null || _customDataMap$get === void 0 ? void 0 : _customDataMap$get.data) !== null && _customDataMap$get$da !== void 0 ? _customDataMap$get$da : {};
|
|
263
|
+
customDataMap.set(label, {
|
|
264
|
+
labelStack: optimizeLabelStack((_interaction$labelSta2 = interaction.labelStack) !== null && _interaction$labelSta2 !== void 0 ? _interaction$labelSta2 : [], getReactUFOPayloadVersion(interaction.type)),
|
|
265
|
+
data: Object.assign(value, Object.fromEntries(cohortingCustomData))
|
|
266
|
+
});
|
|
267
|
+
}
|
|
380
268
|
if (legacyMetrics) {
|
|
381
269
|
const legacyMetricsFiltered = legacyMetrics.filter(item => item.type === 'PAGE_LOAD').reduce((result, currentValue) => {
|
|
382
270
|
for (const [key, value] of Object.entries(currentValue.custom || {})) {
|
|
@@ -633,14 +521,15 @@ function getBm3TrackerTimings(interaction) {
|
|
|
633
521
|
legacyMetrics
|
|
634
522
|
};
|
|
635
523
|
}
|
|
636
|
-
function getPayloadSize(payload) {
|
|
637
|
-
return Math.round(new TextEncoder().encode(JSON.stringify(payload)).length / 1024);
|
|
638
|
-
}
|
|
639
524
|
function getStylesheetMetrics() {
|
|
640
525
|
try {
|
|
641
|
-
const
|
|
526
|
+
const doc = getDocument();
|
|
527
|
+
if (!doc) {
|
|
528
|
+
return {};
|
|
529
|
+
}
|
|
530
|
+
const stylesheets = Array.from(doc.styleSheets);
|
|
642
531
|
const stylesheetCount = stylesheets.length;
|
|
643
|
-
const cssrules = Array.from(
|
|
532
|
+
const cssrules = Array.from(doc.styleSheets).reduce((acc, item) => {
|
|
644
533
|
// Other domain stylesheets throw a SecurityError
|
|
645
534
|
try {
|
|
646
535
|
return acc + item.cssRules.length;
|
|
@@ -648,9 +537,9 @@ function getStylesheetMetrics() {
|
|
|
648
537
|
return acc;
|
|
649
538
|
}
|
|
650
539
|
}, 0);
|
|
651
|
-
const styleElements =
|
|
652
|
-
const styleProps =
|
|
653
|
-
const styleDeclarations = Array.from(
|
|
540
|
+
const styleElements = doc.querySelectorAll('style').length;
|
|
541
|
+
const styleProps = doc.querySelectorAll('[style]');
|
|
542
|
+
const styleDeclarations = Array.from(doc.querySelectorAll('[style]')).reduce((acc, item) => {
|
|
654
543
|
try {
|
|
655
544
|
if ('style' in item) {
|
|
656
545
|
return acc + item.style.length;
|
|
@@ -680,7 +569,7 @@ function getErrorCounts(interaction) {
|
|
|
680
569
|
'ufo:errors:count': interaction.errors.length
|
|
681
570
|
};
|
|
682
571
|
}
|
|
683
|
-
async function createInteractionMetricsPayload(interaction, interactionId, experimental) {
|
|
572
|
+
async function createInteractionMetricsPayload(interaction, interactionId, experimental, criticalPayloadCount, vcMetrics) {
|
|
684
573
|
var _window$location, _config$additionalPay;
|
|
685
574
|
const interactionPayloadStart = performance.now();
|
|
686
575
|
const config = getConfig();
|
|
@@ -779,7 +668,7 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
|
|
|
779
668
|
}
|
|
780
669
|
const newUFOName = sanitizeUfoName(ufoName);
|
|
781
670
|
const resourceTimings = getResourceTimings(start, end);
|
|
782
|
-
const [
|
|
671
|
+
const [finalVCMetrics, experimentalMetrics, paintMetrics] = await Promise.all([vcMetrics || (await getVCMetrics(interaction)), experimental ? getExperimentalVCMetrics(interaction) : Promise.resolve(undefined), getPaintMetricsToLegacyFormat(type, end)]);
|
|
783
672
|
const payload = {
|
|
784
673
|
actionSubject: 'experience',
|
|
785
674
|
action: 'measured',
|
|
@@ -806,14 +695,18 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
|
|
|
806
695
|
...(fg('platform_ufo_report_memory_usage') ? {
|
|
807
696
|
'event:memory:usage': createMemoryStateReport(interaction.start, interaction.end)
|
|
808
697
|
} : {}),
|
|
698
|
+
...(criticalPayloadCount !== undefined ? {
|
|
699
|
+
'ufo:multipayload': true,
|
|
700
|
+
'ufo:criticalPayloadCount': criticalPayloadCount
|
|
701
|
+
} : {}),
|
|
809
702
|
// root
|
|
810
|
-
...
|
|
703
|
+
...getBrowserMetadataToLegacyFormat(),
|
|
811
704
|
...getSSRProperties(type),
|
|
812
705
|
...getAssetsMetrics(interaction, pageLoadInteractionMetrics === null || pageLoadInteractionMetrics === void 0 ? void 0 : pageLoadInteractionMetrics.SSRDoneTime),
|
|
813
706
|
...getPPSMetrics(interaction),
|
|
814
707
|
...paintMetrics,
|
|
815
|
-
...
|
|
816
|
-
...
|
|
708
|
+
...getNavigationMetricsToLegacyFormat(type),
|
|
709
|
+
...finalVCMetrics,
|
|
817
710
|
...experimentalMetrics,
|
|
818
711
|
...((_config$additionalPay = config.additionalPayloadData) === null || _config$additionalPay === void 0 ? void 0 : _config$additionalPay.call(config, interaction)),
|
|
819
712
|
...getTracingContextData(interaction),
|
|
@@ -884,8 +777,19 @@ export async function createPayloads(interactionId, interaction) {
|
|
|
884
777
|
...interaction,
|
|
885
778
|
ufoName: ufoNameOverride
|
|
886
779
|
};
|
|
887
|
-
const
|
|
888
|
-
|
|
780
|
+
const payloads = [];
|
|
781
|
+
const isCriticalMetricsEnabled = fg('platform_ufo_critical_metrics_payload');
|
|
782
|
+
|
|
783
|
+
// Calculate VC metrics once to avoid duplicate expensive calculations
|
|
784
|
+
const vcMetrics = await getVCMetrics(interaction);
|
|
785
|
+
|
|
786
|
+
// typeof Promise<CriticalMetricsPayload[]>
|
|
787
|
+
const criticalMetricsPayloads = isCriticalMetricsEnabled ? await createCriticalMetricsPayloads(interactionId, interaction, vcMetrics) : [];
|
|
788
|
+
payloads.push(...criticalMetricsPayloads);
|
|
789
|
+
const criticalPayloadCount = isCriticalMetricsEnabled ? criticalMetricsPayloads.length : undefined;
|
|
790
|
+
const interactionMetricsPayload = await createInteractionMetricsPayload(modifiedInteraction, interactionId, undefined, criticalPayloadCount, vcMetrics);
|
|
791
|
+
payloads.push(interactionMetricsPayload);
|
|
792
|
+
return payloads.filter(Boolean);
|
|
889
793
|
}
|
|
890
794
|
export async function createExperimentalMetricsPayload(interactionId, interaction) {
|
|
891
795
|
const config = getConfig();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find matching legacy metric by experience name and type
|
|
3
|
+
*/
|
|
4
|
+
export function findMatchingLegacyMetric(interaction, experienceName) {
|
|
5
|
+
var _interaction$legacyMe;
|
|
6
|
+
return (_interaction$legacyMe = interaction.legacyMetrics) === null || _interaction$legacyMe === void 0 ? void 0 : _interaction$legacyMe.find(metric => (metric.key === experienceName || metric.config.reactUFOName === experienceName) && metric.type === 'PAGE_LOAD');
|
|
7
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import Bowser from 'bowser-ultralight';
|
|
2
|
+
export default function getBrowserMetadata() {
|
|
3
|
+
const data = {
|
|
4
|
+
time: {
|
|
5
|
+
localHour: 0,
|
|
6
|
+
localDayOfWeek: 0,
|
|
7
|
+
localTimezoneOffset: 0
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
const now = new Date();
|
|
11
|
+
data.time.localHour = now.getHours(); // returns the hours for this date according to local time
|
|
12
|
+
data.time.localDayOfWeek = now.getDay(); // Sunday - Saturday : 0 - 6
|
|
13
|
+
data.time.localTimezoneOffset = now.getTimezoneOffset(); // A number representing the difference, in minutes, between the date as evaluated in the UTC time zone and as evaluated in the local time zone.
|
|
14
|
+
|
|
15
|
+
if (typeof navigator !== 'undefined' && navigator.userAgent != null) {
|
|
16
|
+
const browser = Bowser.getParser(navigator.userAgent);
|
|
17
|
+
data.browser = {
|
|
18
|
+
name: browser.getBrowserName(),
|
|
19
|
+
version: browser.getBrowserVersion()
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency != null) {
|
|
23
|
+
if (!data.device) {
|
|
24
|
+
data.device = {};
|
|
25
|
+
}
|
|
26
|
+
data.device.cpus = navigator.hardwareConcurrency;
|
|
27
|
+
}
|
|
28
|
+
if (typeof navigator !== 'undefined' && navigator.deviceMemory != null) {
|
|
29
|
+
if (!data.device) {
|
|
30
|
+
data.device = {};
|
|
31
|
+
}
|
|
32
|
+
data.device.memory = navigator.deviceMemory;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line compat/compat
|
|
36
|
+
if (typeof navigator !== 'undefined' && navigator.connection != null) {
|
|
37
|
+
data.network = {
|
|
38
|
+
effectiveType: navigator.connection.effectiveType,
|
|
39
|
+
rtt: navigator.connection.rtt,
|
|
40
|
+
downlink: navigator.connection.downlink
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Helper function to get browser metadata in legacy colon format for backward compatibility
|
|
47
|
+
export function getBrowserMetadataToLegacyFormat() {
|
|
48
|
+
const metadata = getBrowserMetadata();
|
|
49
|
+
const legacyFormat = {};
|
|
50
|
+
|
|
51
|
+
// Time data
|
|
52
|
+
legacyFormat['event:localHour'] = metadata.time.localHour;
|
|
53
|
+
legacyFormat['event:localDayOfWeek'] = metadata.time.localDayOfWeek;
|
|
54
|
+
legacyFormat['event:localTimezoneOffset'] = metadata.time.localTimezoneOffset;
|
|
55
|
+
|
|
56
|
+
// Browser data
|
|
57
|
+
if (metadata.browser) {
|
|
58
|
+
legacyFormat['event:browser:name'] = metadata.browser.name;
|
|
59
|
+
legacyFormat['event:browser:version'] = metadata.browser.version;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Device data
|
|
63
|
+
if (metadata.device) {
|
|
64
|
+
if (metadata.device.cpus !== undefined) {
|
|
65
|
+
legacyFormat['event:cpus'] = metadata.device.cpus;
|
|
66
|
+
}
|
|
67
|
+
if (metadata.device.memory !== undefined) {
|
|
68
|
+
legacyFormat['event:memory'] = metadata.device.memory;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Network data
|
|
73
|
+
if (metadata.network) {
|
|
74
|
+
legacyFormat['event:network:effectiveType'] = metadata.network.effectiveType;
|
|
75
|
+
legacyFormat['event:network:rtt'] = metadata.network.rtt;
|
|
76
|
+
legacyFormat['event:network:downlink'] = metadata.network.downlink;
|
|
77
|
+
}
|
|
78
|
+
return legacyFormat;
|
|
79
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getConfig } from '../../config';
|
|
2
|
+
import { findMatchingLegacyMetric } from './find-matching-legacy-metric';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Calculate FMP (First Meaningful Paint) based on interaction type and configuration
|
|
6
|
+
* FMP is calculated based on legacy metrics or marks depending on interaction type and configuration
|
|
7
|
+
*/
|
|
8
|
+
export function getFMP(interaction, experienceName) {
|
|
9
|
+
var _config$ssr, _config$ssr$getSSRDon, _config$ssr2;
|
|
10
|
+
const {
|
|
11
|
+
start,
|
|
12
|
+
type,
|
|
13
|
+
marks
|
|
14
|
+
} = interaction;
|
|
15
|
+
const config = getConfig();
|
|
16
|
+
const ssrDoneTime = config === null || config === void 0 ? void 0 : (_config$ssr = config.ssr) === null || _config$ssr === void 0 ? void 0 : (_config$ssr$getSSRDon = _config$ssr.getSSRDoneTime) === null || _config$ssr$getSSRDon === void 0 ? void 0 : _config$ssr$getSSRDon.call(_config$ssr);
|
|
17
|
+
const isBM3ConfigSSRDoneAsFmp = interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp;
|
|
18
|
+
const isUFOConfigSSRDoneAsFmp = interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp || !!(config !== null && config !== void 0 && (_config$ssr2 = config.ssr) !== null && _config$ssr2 !== void 0 && _config$ssr2.getSSRDoneTime);
|
|
19
|
+
|
|
20
|
+
// Find matching legacy metric
|
|
21
|
+
const matchingLegacyMetric = findMatchingLegacyMetric(interaction, experienceName);
|
|
22
|
+
let fmp;
|
|
23
|
+
if (type === 'page_load' || type === 'transition') {
|
|
24
|
+
if (interaction.legacyMetrics && matchingLegacyMetric) {
|
|
25
|
+
// Check if legacy metric has FMP
|
|
26
|
+
const legacyFmp = matchingLegacyMetric.fmp; // BM3Event doesn't have fmp in types, but it might exist
|
|
27
|
+
if (legacyFmp) {
|
|
28
|
+
fmp = Math.round(legacyFmp - start);
|
|
29
|
+
}
|
|
30
|
+
// If no FMP in legacy metric, return undefined (don't calculate fallback)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (type === 'page_load' && fmp === undefined) {
|
|
34
|
+
if (isBM3ConfigSSRDoneAsFmp || isUFOConfigSSRDoneAsFmp) {
|
|
35
|
+
var _marks$find;
|
|
36
|
+
const foundMark = marks === null || marks === void 0 ? void 0 : (_marks$find = marks.find(mark => mark.name === 'fmp')) === null || _marks$find === void 0 ? void 0 : _marks$find.time;
|
|
37
|
+
if (foundMark) {
|
|
38
|
+
fmp = Math.round(foundMark - start);
|
|
39
|
+
} else if (ssrDoneTime) {
|
|
40
|
+
fmp = Math.round(ssrDoneTime - start);
|
|
41
|
+
}
|
|
42
|
+
// If no FMP mark and no SSR done time, fmp remains undefined
|
|
43
|
+
}
|
|
44
|
+
// If not using SSR config, fmp remains undefined for page_load without legacy metrics
|
|
45
|
+
}
|
|
46
|
+
return fmp;
|
|
47
|
+
}
|