@atlaskit/react-ufo 5.1.3 → 5.2.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.
Files changed (40) hide show
  1. package/AGENTS.md +426 -0
  2. package/CHANGELOG.md +22 -0
  3. package/dist/cjs/create-payload/index.js +3 -3
  4. package/dist/cjs/hidden-timing/index.js +135 -0
  5. package/dist/cjs/interaction-metrics/index.js +11 -3
  6. package/dist/cjs/interaction-metrics-init/index.js +3 -0
  7. package/dist/cjs/set-terminal-error/index.js +11 -3
  8. package/dist/cjs/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +39 -27
  9. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +22 -7
  10. package/dist/es2019/create-payload/index.js +3 -3
  11. package/dist/es2019/hidden-timing/index.js +128 -0
  12. package/dist/es2019/interaction-metrics/index.js +10 -2
  13. package/dist/es2019/interaction-metrics-init/index.js +4 -1
  14. package/dist/es2019/set-terminal-error/index.js +12 -4
  15. package/dist/es2019/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +17 -4
  16. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +22 -7
  17. package/dist/esm/create-payload/index.js +4 -4
  18. package/dist/esm/hidden-timing/index.js +130 -0
  19. package/dist/esm/interaction-metrics/index.js +10 -2
  20. package/dist/esm/interaction-metrics-init/index.js +4 -1
  21. package/dist/esm/set-terminal-error/index.js +12 -4
  22. package/dist/esm/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +39 -27
  23. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +22 -7
  24. package/dist/types/common/react-ufo-payload-schema.d.ts +1 -0
  25. package/dist/types/common/vc/types.d.ts +2 -0
  26. package/dist/types/create-terminal-error-payload/index.d.ts +4 -0
  27. package/dist/types/hidden-timing/index.d.ts +42 -0
  28. package/dist/types/interaction-metrics/index.d.ts +8 -0
  29. package/dist/types/set-terminal-error/index.d.ts +4 -0
  30. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.d.ts +3 -3
  31. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/types.d.ts +12 -0
  32. package/dist/types-ts4.5/common/react-ufo-payload-schema.d.ts +1 -0
  33. package/dist/types-ts4.5/common/vc/types.d.ts +2 -0
  34. package/dist/types-ts4.5/create-terminal-error-payload/index.d.ts +4 -0
  35. package/dist/types-ts4.5/hidden-timing/index.d.ts +42 -0
  36. package/dist/types-ts4.5/interaction-metrics/index.d.ts +8 -0
  37. package/dist/types-ts4.5/set-terminal-error/index.d.ts +4 -0
  38. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.d.ts +3 -3
  39. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/types.d.ts +12 -0
  40. package/package.json +10 -1
@@ -30,7 +30,8 @@ async function calculateTTVCPercentiles({
30
30
  async function calculateTTVCPercentilesWithDebugInfo({
31
31
  viewport,
32
32
  orderedEntries,
33
- startTime
33
+ startTime,
34
+ calculateSpeedIndex = false
34
35
  }) {
35
36
  const canvas = new ViewportCanvas(viewport, fg('platform_ufo_canvas_heatmap_full_precision') ? 1 : 0.25);
36
37
  const elementMap = new Map();
@@ -50,7 +51,7 @@ async function calculateTTVCPercentilesWithDebugInfo({
50
51
  const timePixelCounts = await canvas.getPixelCounts();
51
52
  const canvasDimensions = canvas.getScaledDimensions();
52
53
  const totalPixels = canvasDimensions.width * canvasDimensions.height;
53
- return calculatePercentilesWithDebugInfo(timePixelCounts, elementMap, totalPixels, startTime);
54
+ return calculatePercentilesWithDebugInfo(timePixelCounts, elementMap, totalPixels, startTime, calculateSpeedIndex);
54
55
  }
55
56
  export default calculateTTVCPercentiles;
56
57
  export function calculatePercentiles(timePixelCounts, elementMap, unorderedPercentiles, totalPixels, startTime) {
@@ -96,21 +97,35 @@ export function calculatePercentiles(timePixelCounts, elementMap, unorderedPerce
96
97
  }
97
98
  return results;
98
99
  }
99
- export function calculatePercentilesWithDebugInfo(timePixelCounts, elementMap, totalPixels, startTime) {
100
- const results = new Array(elementMap.size);
100
+ export function calculatePercentilesWithDebugInfo(timePixelCounts, elementMap, totalPixels, startTime, calculateSpeedIndex = false) {
101
+ const entries = new Array(elementMap.size);
101
102
  let cumulativePixels = 0;
103
+ let speedIndex = 0;
104
+ let previousPercentCovered = 0;
102
105
  const sortedEntries = Array.from(timePixelCounts.entries()).sort(([timeA], [timeB]) => Number(timeA) - Number(timeB));
103
106
  for (let i = 0; i < sortedEntries.length; i++) {
104
107
  const [time, pixelCount] = sortedEntries[i];
105
108
  cumulativePixels += pixelCount;
106
109
  const percentCovered = cumulativePixels / totalPixels * 100;
107
110
  const entryDatas = elementMap.get(time) || [];
108
- results[i] = {
109
- time: Math.round(Number(time - startTime)),
111
+ const relativeTime = Math.round(Number(time - startTime));
112
+ entries[i] = {
113
+ time: relativeTime,
110
114
  viewportPercentage: percentCovered,
111
115
  entries: Array.from(entryDatas)
112
116
  };
117
+
118
+ // Speed index calculation: sum of (time × incremental viewport percentage)
119
+ // Only calculate when feature flag is enabled
120
+ if (calculateSpeedIndex) {
121
+ const ratioDelta = (percentCovered - previousPercentCovered) / 100;
122
+ speedIndex += relativeTime * ratioDelta;
123
+ previousPercentCovered = percentCovered;
124
+ }
113
125
  }
114
- return results;
126
+ return {
127
+ entries,
128
+ speedIndex: Math.round(speedIndex)
129
+ };
115
130
  }
116
131
  export { calculateTTVCPercentilesWithDebugInfo };
@@ -1,5 +1,5 @@
1
1
  import _objectWithoutProperties from"@babel/runtime/helpers/objectWithoutProperties";import _asyncToGenerator from"@babel/runtime/helpers/asyncToGenerator";import _toConsumableArray from"@babel/runtime/helpers/toConsumableArray";import _slicedToArray from"@babel/runtime/helpers/slicedToArray";import _defineProperty from"@babel/runtime/helpers/defineProperty";var _excluded=["labelStack"];import _regeneratorRuntime from"@babel/runtime/regenerator";function _createForOfIteratorHelper(r,e){var t="undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(!t){if(Array.isArray(r)||(t=_unsupportedIterableToArray(r))||e&&r&&"number"==typeof r.length){t&&(r=t);var _n=0,F=function F(){};return{s:F,n:function n(){return _n>=r.length?{done:!0}:{done:!1,value:r[_n++]};},e:function e(r){throw r;},f:F};}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}var o,a=!0,u=!1;return{s:function s(){t=t.call(r);},n:function n(){var r=t.next();return a=r.done,r;},e:function e(r){u=!0,o=r;},f:function f(){try{a||null==t.return||t.return();}finally{if(u)throw o;}}};}function _unsupportedIterableToArray(r,a){if(r){if("string"==typeof r)return _arrayLikeToArray(r,a);var t={}.toString.call(r).slice(8,-1);return"Object"===t&&r.constructor&&(t=r.constructor.name),"Map"===t||"Set"===t?Array.from(r):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?_arrayLikeToArray(r,a):void 0;}}function _arrayLikeToArray(r,a){(null==a||a>r.length)&&(a=r.length);for(var e=0,n=Array(a);e<a;e++)n[e]=r[e];return n;}function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);r&&(o=o.filter(function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable;})),t.push.apply(t,o);}return t;}function _objectSpread(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?ownKeys(Object(t),!0).forEach(function(r){_defineProperty(e,r,t[r]);}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):ownKeys(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r));});}return e;}import{getDocument}from'@atlaskit/browser-apis';import{fg}from'@atlaskit/platform-feature-flags';// Import common utilities
2
- import{getLighthouseMetrics}from'../additional-payload';import{CHRReporter}from'../assets';import*as bundleEvalTiming from'../bundle-eval-timing';import coinflip from'../coinflip';import{getConfig,getExperimentalInteractionRate,getUfoNameOverrides,shouldUseRawDataThirdPartyBehavior}from'../config';import{getExperimentalVCMetrics}from'../create-experimental-interaction-metrics-payload';import{getBm3Timings}from'../custom-timings';import{getGlobalErrorCount}from'../global-error-handler';import{getEarliestHiddenTiming,getHasHiddenTimingBeforeSetup,getPageVisibilityState,isOpenedInBackground}from'../hidden-timing';import*as initialPageLoadExtraTiming from'../initial-page-load-extra-timing';import{interactionSpans as atlaskitInteractionSpans}from'../interaction-metrics';import{createMemoryStateReport,createPressureStateReport}from'../machine-utilisation';import*as resourceTiming from'../resource-timing';import{filterResourceTimings}from'../resource-timing/common/utils/resource-timing-buffer';import{roundEpsilon}from'../round-number';import*as ssr from'../ssr';import{buildSegmentTree,getOldSegmentsLabelStack,labelStackStartWith,optimizeLabelStack,sanitizeUfoName,stringifyLabelStackFully}from'./common/utils';import{createCriticalMetricsPayloads}from'./critical-metrics-payload';import{addPerformanceMeasures}from'./utils/add-performance-measures';import{getBatteryInfoToLegacyFormat}from'./utils/get-battery-info';import{getBrowserMetadataToLegacyFormat}from'./utils/get-browser-metadata';import getInteractionStatus from'./utils/get-interaction-status';import{getMoreAccuratePageVisibilityUpToTTAI}from'./utils/get-more-accurate-page-visibility-up-to-ttai';import{getNavigationMetricsToLegacyFormat}from'./utils/get-navigation-metrics';import getPageVisibilityUpToTTAI from'./utils/get-page-visibility-up-to-ttai';import{getPaintMetricsToLegacyFormat}from'./utils/get-paint-metrics';import getPayloadSize from'./utils/get-payload-size';import{getReactUFOPayloadVersion}from'./utils/get-react-ufo-payload-version';import getSSRDoneTimeValue from'./utils/get-ssr-done-time-value';import getSSRSuccessUtil from'./utils/get-ssr-success';import getTTAI from'./utils/get-ttai';import getVCMetrics from'./utils/get-vc-metrics';import{getVisibilityStateFromPerformance}from'./utils/get-visibility-state-from-performance';import{optimizeApdex}from'./utils/optimize-apdex';import{optimizeCustomTimings}from'./utils/optimize-custom-timings';import{optimizeHoldInfo}from'./utils/optimize-hold-info';import{optimizeMarks}from'./utils/optimize-marks';import{optimizeReactProfilerTimings}from'./utils/optimize-react-profiler-timings';import{optimizeRequestInfo}from'./utils/optimize-request-info';import{optimizeSpans}from'./utils/optimize-spans';var MAX_PAYLOAD_SIZE=230;function getUfoNameOverride(interaction){var ufoName=interaction.ufoName,apdex=interaction.apdex;try{var ufoNameOverrides=getUfoNameOverrides();if(ufoNameOverrides!=null){var metricKey=apdex.length>0?apdex[0].key:'';if(ufoNameOverrides[ufoName][metricKey]){return ufoNameOverrides[ufoName][metricKey];}}return ufoName;}catch(_unused){return ufoName;}}function getEarliestLegacyStopTime(interaction,labelStack){var earliestLegacyStopTime=null;interaction.apdex.forEach(function(a){var _a$labelStack;if(!(a!==null&&a!==void 0&&a.stopTime)){return;}if(!labelStackStartWith((_a$labelStack=a.labelStack)!==null&&_a$labelStack!==void 0?_a$labelStack:[],labelStack)){return;}if(a.stopTime>interaction.start&&(earliestLegacyStopTime!==null&&earliestLegacyStopTime!==void 0?earliestLegacyStopTime:a.stopTime)>=a.stopTime){earliestLegacyStopTime=a.stopTime;}});return earliestLegacyStopTime;}function getBm3EndTimeOrFallbackValue(interaction){var _getEarliestLegacySto;var labelStack=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[];var fallbackValue=arguments.length>2&&arguments[2]!==undefined?arguments[2]:interaction.end;if(interaction.type==='press'){return fallbackValue;}return(_getEarliestLegacySto=getEarliestLegacyStopTime(interaction,labelStack))!==null&&_getEarliestLegacySto!==void 0?_getEarliestLegacySto:fallbackValue;}function getPageVisibilityUpToTTI(interaction){var start=interaction.start;var bm3EndTimeOrInteractionEndTime=getBm3EndTimeOrFallbackValue(interaction);return getPageVisibilityState(start,bm3EndTimeOrInteractionEndTime);}function getMoreAccuratePageVisibilityUpToTTI(interaction){var old=getPageVisibilityUpToTTI(interaction);var tti=getEarliestLegacyStopTime(interaction,[]);if(!tti){return old;}var buffered=getVisibilityStateFromPerformance(tti);if(!buffered){return old;}if(buffered!==old){return'mixed';}return old;}function getResourceTimings(start,end){var _resourceTiming$getRe;return(_resourceTiming$getRe=resourceTiming.getResourceTimings(start,end))!==null&&_resourceTiming$getRe!==void 0?_resourceTiming$getRe:undefined;}function getBundleEvalTimings(start){return bundleEvalTiming.getBundleEvalTimings(start);}function getSSRPhaseSuccess(type){return type==='page_load'?ssr.getSSRPhaseSuccess():undefined;}function getSSRFeatureFlags(type){return type==='page_load'?ssr.getSSRFeatureFlags():undefined;}function getPPSMetrics(interaction){var _interaction$apdex;var start=interaction.start,end=interaction.end;var config=getConfig();var interactionStatus=getInteractionStatus(interaction);var pageVisibilityUpToTTAI=getPageVisibilityUpToTTAI(interaction);var tti=(_interaction$apdex=interaction.apdex)===null||_interaction$apdex===void 0||(_interaction$apdex=_interaction$apdex[0])===null||_interaction$apdex===void 0?void 0:_interaction$apdex.stopTime;var ttai=interactionStatus.originalInteractionStatus==='SUCCEEDED'&&pageVisibilityUpToTTAI==='visible'?Math.round(end-start):undefined;var PPSMetricsAtTTI=tti!==undefined?getLighthouseMetrics({start:start,stop:tti}):null;var PPSMetricsAtTTAI=ttai!==undefined?getLighthouseMetrics({start:start,stop:interaction.end}):null;if(fg('platform_ufo_remove_deprecated_config_fields')){if(PPSMetricsAtTTAI!==null){return PPSMetricsAtTTAI;}}else{if(config!==null&&config!==void 0&&config.shouldCalculateLighthouseMetricsFromTTAI&&PPSMetricsAtTTAI!==null){return PPSMetricsAtTTAI;}if(PPSMetricsAtTTI!==null){return _objectSpread(_objectSpread({},PPSMetricsAtTTI),{},{'metrics@ttai':PPSMetricsAtTTAI});}}return{};}function getSSRProperties(type){var ssrPhases=getSSRPhaseSuccess(type);return _objectSpread(_objectSpread({'ssr:success':(ssrPhases===null||ssrPhases===void 0?void 0:ssrPhases.done)!=null?ssrPhases.done:getSSRSuccessUtil(type),'ssr:featureFlags':getSSRFeatureFlags(type)},(ssrPhases===null||ssrPhases===void 0?void 0:ssrPhases.earlyFlush)!=null?{'ssr:earlyflush:success':ssrPhases.earlyFlush}:null),(ssrPhases===null||ssrPhases===void 0?void 0:ssrPhases.prefetch)!=null?{'ssr:prefetch:success':ssrPhases.prefetch}:null);}function getAssetsMetrics(interaction,SSRDoneTime){try{var config=getConfig();var type=interaction.type;var allowedTypes=['page_load'];var assetsConfig=config===null||config===void 0?void 0:config.assetsConfig;if(!allowedTypes.includes(type)||!assetsConfig){// Skip if: type not allowed or assetsClassification isn't configured
2
+ import{getLighthouseMetrics}from'../additional-payload';import{CHRReporter}from'../assets';import*as bundleEvalTiming from'../bundle-eval-timing';import coinflip from'../coinflip';import{getConfig,getExperimentalInteractionRate,getUfoNameOverrides,shouldUseRawDataThirdPartyBehavior}from'../config';import{getExperimentalVCMetrics}from'../create-experimental-interaction-metrics-payload';import{getBm3Timings}from'../custom-timings';import{getGlobalErrorCount}from'../global-error-handler';import{getEarliestHiddenTiming,getHasHiddenTimingBeforeSetup,getPageVisibilityState,isOpenedInBackground,isTabThrottled}from'../hidden-timing';import*as initialPageLoadExtraTiming from'../initial-page-load-extra-timing';import{interactionSpans as atlaskitInteractionSpans}from'../interaction-metrics';import{createMemoryStateReport,createPressureStateReport}from'../machine-utilisation';import*as resourceTiming from'../resource-timing';import{filterResourceTimings}from'../resource-timing/common/utils/resource-timing-buffer';import{roundEpsilon}from'../round-number';import*as ssr from'../ssr';import{buildSegmentTree,getOldSegmentsLabelStack,labelStackStartWith,optimizeLabelStack,sanitizeUfoName,stringifyLabelStackFully}from'./common/utils';import{createCriticalMetricsPayloads}from'./critical-metrics-payload';import{addPerformanceMeasures}from'./utils/add-performance-measures';import{getBatteryInfoToLegacyFormat}from'./utils/get-battery-info';import{getBrowserMetadataToLegacyFormat}from'./utils/get-browser-metadata';import getInteractionStatus from'./utils/get-interaction-status';import{getMoreAccuratePageVisibilityUpToTTAI}from'./utils/get-more-accurate-page-visibility-up-to-ttai';import{getNavigationMetricsToLegacyFormat}from'./utils/get-navigation-metrics';import getPageVisibilityUpToTTAI from'./utils/get-page-visibility-up-to-ttai';import{getPaintMetricsToLegacyFormat}from'./utils/get-paint-metrics';import getPayloadSize from'./utils/get-payload-size';import{getReactUFOPayloadVersion}from'./utils/get-react-ufo-payload-version';import getSSRDoneTimeValue from'./utils/get-ssr-done-time-value';import getSSRSuccessUtil from'./utils/get-ssr-success';import getTTAI from'./utils/get-ttai';import getVCMetrics from'./utils/get-vc-metrics';import{getVisibilityStateFromPerformance}from'./utils/get-visibility-state-from-performance';import{optimizeApdex}from'./utils/optimize-apdex';import{optimizeCustomTimings}from'./utils/optimize-custom-timings';import{optimizeHoldInfo}from'./utils/optimize-hold-info';import{optimizeMarks}from'./utils/optimize-marks';import{optimizeReactProfilerTimings}from'./utils/optimize-react-profiler-timings';import{optimizeRequestInfo}from'./utils/optimize-request-info';import{optimizeSpans}from'./utils/optimize-spans';var MAX_PAYLOAD_SIZE=230;function getUfoNameOverride(interaction){var ufoName=interaction.ufoName,apdex=interaction.apdex;try{var ufoNameOverrides=getUfoNameOverrides();if(ufoNameOverrides!=null){var metricKey=apdex.length>0?apdex[0].key:'';if(ufoNameOverrides[ufoName][metricKey]){return ufoNameOverrides[ufoName][metricKey];}}return ufoName;}catch(_unused){return ufoName;}}function getEarliestLegacyStopTime(interaction,labelStack){var earliestLegacyStopTime=null;interaction.apdex.forEach(function(a){var _a$labelStack;if(!(a!==null&&a!==void 0&&a.stopTime)){return;}if(!labelStackStartWith((_a$labelStack=a.labelStack)!==null&&_a$labelStack!==void 0?_a$labelStack:[],labelStack)){return;}if(a.stopTime>interaction.start&&(earliestLegacyStopTime!==null&&earliestLegacyStopTime!==void 0?earliestLegacyStopTime:a.stopTime)>=a.stopTime){earliestLegacyStopTime=a.stopTime;}});return earliestLegacyStopTime;}function getBm3EndTimeOrFallbackValue(interaction){var _getEarliestLegacySto;var labelStack=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[];var fallbackValue=arguments.length>2&&arguments[2]!==undefined?arguments[2]:interaction.end;if(interaction.type==='press'){return fallbackValue;}return(_getEarliestLegacySto=getEarliestLegacyStopTime(interaction,labelStack))!==null&&_getEarliestLegacySto!==void 0?_getEarliestLegacySto:fallbackValue;}function getPageVisibilityUpToTTI(interaction){var start=interaction.start;var bm3EndTimeOrInteractionEndTime=getBm3EndTimeOrFallbackValue(interaction);return getPageVisibilityState(start,bm3EndTimeOrInteractionEndTime);}function getMoreAccuratePageVisibilityUpToTTI(interaction){var old=getPageVisibilityUpToTTI(interaction);var tti=getEarliestLegacyStopTime(interaction,[]);if(!tti){return old;}var buffered=getVisibilityStateFromPerformance(tti);if(!buffered){return old;}if(buffered!==old){return'mixed';}return old;}function getResourceTimings(start,end){var _resourceTiming$getRe;return(_resourceTiming$getRe=resourceTiming.getResourceTimings(start,end))!==null&&_resourceTiming$getRe!==void 0?_resourceTiming$getRe:undefined;}function getBundleEvalTimings(start){return bundleEvalTiming.getBundleEvalTimings(start);}function getSSRPhaseSuccess(type){return type==='page_load'?ssr.getSSRPhaseSuccess():undefined;}function getSSRFeatureFlags(type){return type==='page_load'?ssr.getSSRFeatureFlags():undefined;}function getPPSMetrics(interaction){var _interaction$apdex;var start=interaction.start,end=interaction.end;var config=getConfig();var interactionStatus=getInteractionStatus(interaction);var pageVisibilityUpToTTAI=getPageVisibilityUpToTTAI(interaction);var tti=(_interaction$apdex=interaction.apdex)===null||_interaction$apdex===void 0||(_interaction$apdex=_interaction$apdex[0])===null||_interaction$apdex===void 0?void 0:_interaction$apdex.stopTime;var ttai=interactionStatus.originalInteractionStatus==='SUCCEEDED'&&pageVisibilityUpToTTAI==='visible'?Math.round(end-start):undefined;var PPSMetricsAtTTI=tti!==undefined?getLighthouseMetrics({start:start,stop:tti}):null;var PPSMetricsAtTTAI=ttai!==undefined?getLighthouseMetrics({start:start,stop:interaction.end}):null;if(fg('platform_ufo_remove_deprecated_config_fields')){if(PPSMetricsAtTTAI!==null){return PPSMetricsAtTTAI;}}else{if(config!==null&&config!==void 0&&config.shouldCalculateLighthouseMetricsFromTTAI&&PPSMetricsAtTTAI!==null){return PPSMetricsAtTTAI;}if(PPSMetricsAtTTI!==null){return _objectSpread(_objectSpread({},PPSMetricsAtTTI),{},{'metrics@ttai':PPSMetricsAtTTAI});}}return{};}function getSSRProperties(type){var ssrPhases=getSSRPhaseSuccess(type);return _objectSpread(_objectSpread({'ssr:success':(ssrPhases===null||ssrPhases===void 0?void 0:ssrPhases.done)!=null?ssrPhases.done:getSSRSuccessUtil(type),'ssr:featureFlags':getSSRFeatureFlags(type)},(ssrPhases===null||ssrPhases===void 0?void 0:ssrPhases.earlyFlush)!=null?{'ssr:earlyflush:success':ssrPhases.earlyFlush}:null),(ssrPhases===null||ssrPhases===void 0?void 0:ssrPhases.prefetch)!=null?{'ssr:prefetch:success':ssrPhases.prefetch}:null);}function getAssetsMetrics(interaction,SSRDoneTime){try{var config=getConfig();var type=interaction.type;var allowedTypes=['page_load'];var assetsConfig=config===null||config===void 0?void 0:config.assetsConfig;if(!allowedTypes.includes(type)||!assetsConfig){// Skip if: type not allowed or assetsClassification isn't configured
3
3
  return{};}var reporter=new CHRReporter();var resourceTimings=filterResourceTimings(interaction.start,interaction.end);var assets=reporter.get(resourceTimings,assetsConfig,SSRDoneTime);if(assets){// Only add assets in case it exists
4
4
  return{'event:assets':assets};}return{};}catch(_unused2){// Skip CHR in case of error
5
5
  return{};}}function getTracingContextData(interaction){var trace=interaction.trace,start=interaction.start;var tracingContextData={};if(trace){tracingContextData={'ufo:tracingContext':{'X-B3-TraceId':trace.traceId,'X-B3-SpanId':trace.spanId,// eslint-disable-next-line compat/compat
@@ -9,13 +9,13 @@ try{return acc+item.cssRules.length;}catch(_unused3){return acc;}},0);var styleE
9
9
  getInitialPageLoadSSRMetrics=function getInitialPageLoadSSRMetrics(){var _config$ssr;if(!isPageLoad){return{};}var config=getConfig();var SSRDoneTimeValue=getSSRDoneTimeValue(config);var SSRDoneTime=SSRDoneTimeValue!==undefined?{SSRDoneTime:Math.round(SSRDoneTimeValue)}:{};var isBM3ConfigSSRDoneAsFmp=interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp;var isUFOConfigSSRDoneAsFmp=interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp||!!(config!==null&&config!==void 0&&(_config$ssr=config.ssr)!==null&&_config$ssr!==void 0&&_config$ssr.getSSRDoneTime);if(!experimental&&(isBM3ConfigSSRDoneAsFmp||isUFOConfigSSRDoneAsFmp)&&SSRDoneTimeValue!==undefined){try{performance.mark("FMP",{startTime:SSRDoneTimeValue,detail:{devtools:{dataType:'marker'}}});}catch(_unused6){}}return _objectSpread(_objectSpread({},SSRDoneTime),{},{isBM3ConfigSSRDoneAsFmp:isBM3ConfigSSRDoneAsFmp,isUFOConfigSSRDoneAsFmp:isUFOConfigSSRDoneAsFmp});};pageLoadInteractionMetrics=getInitialPageLoadSSRMetrics();// Detailed payload. Page visibility = visible
10
10
  getDetailedInteractionMetrics=function getDetailedInteractionMetrics(resourceTimings){if(experimental||window.__UFO_COMPACT_PAYLOAD__||!isDetailedPayload){return{};}var spans=[].concat(_toConsumableArray(interaction.spans),_toConsumableArray(atlaskitInteractionSpans));atlaskitInteractionSpans.length=0;var shouldInclude3pHolds=shouldUseRawDataThirdPartyBehavior(ufoName,type);var basePayload={errors:interaction.errors.map(function(_ref2){var labelStack=_ref2.labelStack,others=_objectWithoutProperties(_ref2,_excluded);return _objectSpread(_objectSpread({},others),{},{labelStack:labelStack&&optimizeLabelStack(labelStack,getReactUFOPayloadVersion(interaction.type))});}),holdActive:_toConsumableArray(interaction.holdActive.values()),redirects:optimizeRedirects(interaction.redirects,start),holdInfo:optimizeHoldInfo(experimental?interaction.holdExpInfo:interaction.holdInfo,start,getReactUFOPayloadVersion(interaction.type)),spans:optimizeSpans(spans,start,getReactUFOPayloadVersion(interaction.type)),requestInfo:optimizeRequestInfo(interaction.requestInfo,start,getReactUFOPayloadVersion(interaction.type)),customTimings:optimizeCustomTimings(interaction.customTimings,start),bundleEvalTimings:objectToArray(getBundleEvalTimings(start)),resourceTimings:objectToArray(resourceTimings)};// Include third-party holds when feature flag is active
11
11
  if(shouldInclude3pHolds){var _interaction$hold3pIn;return _objectSpread(_objectSpread({},basePayload),{},{hold3pActive:interaction.hold3pActive?_toConsumableArray(interaction.hold3pActive.values()):[],hold3pInfo:optimizeHoldInfo((_interaction$hold3pIn=interaction.hold3pInfo)!==null&&_interaction$hold3pIn!==void 0?_interaction$hold3pIn:[],start,getReactUFOPayloadVersion(interaction.type))});}return basePayload;};// Page load & detailed payload
12
- getPageLoadDetailedInteractionMetrics=function getPageLoadDetailedInteractionMetrics(){var _config$ssr2,_config$ssr2$getSSRTi;if(!isPageLoad||!isDetailedPayload){return{};}var initialPageLoadExtraTimings=objectToArray(initialPageLoadExtraTiming.getTimings());var config=getConfig();var defaultSSRTimings=objectToArray(ssr.getSSRTimings());var ssrTimingsFromConfig=config===null||config===void 0||(_config$ssr2=config.ssr)===null||_config$ssr2===void 0||(_config$ssr2$getSSRTi=_config$ssr2.getSSRTimings)===null||_config$ssr2$getSSRTi===void 0?void 0:_config$ssr2$getSSRTi.call(_config$ssr2);return{initialPageLoadExtraTimings:initialPageLoadExtraTimings,SSRTimings:ssrTimingsFromConfig?[].concat(_toConsumableArray(ssrTimingsFromConfig),_toConsumableArray(defaultSSRTimings)):defaultSSRTimings};};if(experimental){expTTAI=getTTAI(interaction);}else{regularTTAI=getTTAI(interaction);}newUFOName=sanitizeUfoName(ufoName);resourceTimings=getResourceTimings(start,end);_context.t0=Promise;_context.t1=vcMetrics;if(_context.t1){_context.next=29;break;}_context.next=28;return getVCMetrics(interaction);case 28:_context.t1=_context.sent;case 29:_context.t2=_context.t1;_context.t3=experimental?getExperimentalVCMetrics(interaction):Promise.resolve(undefined);_context.t4=getPaintMetricsToLegacyFormat(type,end);_context.t5=getBatteryInfoToLegacyFormat();_context.t6=[_context.t2,_context.t3,_context.t4,_context.t5];_context.next=36;return _context.t0.all.call(_context.t0,_context.t6);case 36:_yield$Promise$all=_context.sent;_yield$Promise$all2=_slicedToArray(_yield$Promise$all,4);finalVCMetrics=_yield$Promise$all2[0];experimentalMetrics=_yield$Promise$all2[1];paintMetrics=_yield$Promise$all2[2];batteryInfo=_yield$Promise$all2[3];if(!experimental){addPerformanceMeasures(interaction.start,_toConsumableArray((finalVCMetrics===null||finalVCMetrics===void 0?void 0:finalVCMetrics['ufo:vc:rev'])||[]));}getReactHydrationStats=function getReactHydrationStats(){if(!hydration){return{};}return{hydration:hydration};};payload={actionSubject:'experience',action:'measured',eventType:'operational',source:'measured',tags:['observability'],attributes:{properties:_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({// basic
12
+ getPageLoadDetailedInteractionMetrics=function getPageLoadDetailedInteractionMetrics(){var _config$ssr2,_config$ssr2$getSSRTi;if(!isPageLoad||!isDetailedPayload){return{};}var initialPageLoadExtraTimings=objectToArray(initialPageLoadExtraTiming.getTimings());var config=getConfig();var defaultSSRTimings=objectToArray(ssr.getSSRTimings());var ssrTimingsFromConfig=config===null||config===void 0||(_config$ssr2=config.ssr)===null||_config$ssr2===void 0||(_config$ssr2$getSSRTi=_config$ssr2.getSSRTimings)===null||_config$ssr2$getSSRTi===void 0?void 0:_config$ssr2$getSSRTi.call(_config$ssr2);return{initialPageLoadExtraTimings:initialPageLoadExtraTimings,SSRTimings:ssrTimingsFromConfig?[].concat(_toConsumableArray(ssrTimingsFromConfig),_toConsumableArray(defaultSSRTimings)):defaultSSRTimings};};if(experimental){expTTAI=getTTAI(interaction);}else{regularTTAI=getTTAI(interaction);}newUFOName=sanitizeUfoName(ufoName);resourceTimings=getResourceTimings(start,end);_context.t0=Promise;_context.t1=vcMetrics;if(_context.t1){_context.next=29;break;}_context.next=28;return getVCMetrics(interaction);case 28:_context.t1=_context.sent;case 29:_context.t2=_context.t1;_context.t3=experimental?getExperimentalVCMetrics(interaction):Promise.resolve(undefined);_context.t4=getPaintMetricsToLegacyFormat(type,end);_context.t5=getBatteryInfoToLegacyFormat();_context.t6=[_context.t2,_context.t3,_context.t4,_context.t5];_context.next=36;return _context.t0.all.call(_context.t0,_context.t6);case 36:_yield$Promise$all=_context.sent;_yield$Promise$all2=_slicedToArray(_yield$Promise$all,4);finalVCMetrics=_yield$Promise$all2[0];experimentalMetrics=_yield$Promise$all2[1];paintMetrics=_yield$Promise$all2[2];batteryInfo=_yield$Promise$all2[3];if(!experimental){addPerformanceMeasures(interaction.start,_toConsumableArray((finalVCMetrics===null||finalVCMetrics===void 0?void 0:finalVCMetrics['ufo:vc:rev'])||[]));}getReactHydrationStats=function getReactHydrationStats(){if(!hydration){return{};}return{hydration:hydration};};payload={actionSubject:'experience',action:'measured',eventType:'operational',source:'measured',tags:['observability'],attributes:{properties:_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({// basic
13
13
  'event:hostname':((_window$location=window.location)===null||_window$location===void 0?void 0:_window$location.hostname)||'unknown','event:product':config.product,'event:population':config.population,'event:schema':'1.0.0','event:sizeInKb':0,'event:source':{name:'react-ufo/web',version:getReactUFOPayloadVersion(interaction.type)},'event:region':config.region||'unknown','experience:key':experimental?'custom.experimental-interaction-metrics':'custom.interaction-metrics','experience:name':newUFOName,// Include CPU usage monitoring data
14
- 'event:cpu:usage':createPressureStateReport(interaction.start,interaction.end),'event:memory:usage':createMemoryStateReport(interaction.start,interaction.end)},criticalPayloadCount!==undefined?{'ufo:multipayload':true,'ufo:criticalPayloadCount':criticalPayloadCount}:{}),fg('platform_ufo_browser_backgrounded_abort_timestamp')?{'ufo:pageVisibilityHiddenTimestamp':getEarliestHiddenTiming(interaction.start,interaction.end)}:{}),{},{'ufo:wasPageHiddenBeforeInit':getHasHiddenTimingBeforeSetup(),'ufo:isOpenedInBackground':isOpenedInBackground(interaction.type)},getBrowserMetadataToLegacyFormat()),batteryInfo),getSSRProperties(type)),getAssetsMetrics(interaction,pageLoadInteractionMetrics===null||pageLoadInteractionMetrics===void 0?void 0:pageLoadInteractionMetrics.SSRDoneTime)),getPPSMetrics(interaction)),paintMetrics),getNavigationMetricsToLegacyFormat(type)),finalVCMetrics),experimentalMetrics),(_config$additionalPay=config.additionalPayloadData)===null||_config$additionalPay===void 0?void 0:_config$additionalPay.call(config,interaction)),getTracingContextData(interaction)),getStylesheetMetrics()),getErrorCounts(interaction)),getReactHydrationStats()),{},{interactionMetrics:_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({namePrefix:config.namePrefix||'',segmentPrefix:config.segmentPrefix||'',interactionId:interactionId,pageVisibilityAtTTI:pageVisibilityAtTTI,pageVisibilityAtTTAI:pageVisibilityAtTTAI,experimental__pageVisibilityAtTTI:moreAccuratePageVisibilityAtTTI,experimental__pageVisibilityAtTTAI:moreAccuratePageVisibilityAtTTAI,// raw interaction metrics
14
+ 'event:cpu:usage':createPressureStateReport(interaction.start,interaction.end),'event:memory:usage':createMemoryStateReport(interaction.start,interaction.end)},criticalPayloadCount!==undefined?{'ufo:multipayload':true,'ufo:criticalPayloadCount':criticalPayloadCount}:{}),fg('platform_ufo_browser_backgrounded_abort_timestamp')?{'ufo:pageVisibilityHiddenTimestamp':getEarliestHiddenTiming(interaction.start,interaction.end)}:{}),{},{'ufo:wasPageHiddenBeforeInit':getHasHiddenTimingBeforeSetup(),'ufo:isOpenedInBackground':isOpenedInBackground(interaction.type)},fg('platform_ufo_is_tab_throttled')?{'ufo:isTabThrottled':isTabThrottled(start,end)}:{}),getBrowserMetadataToLegacyFormat()),batteryInfo),getSSRProperties(type)),getAssetsMetrics(interaction,pageLoadInteractionMetrics===null||pageLoadInteractionMetrics===void 0?void 0:pageLoadInteractionMetrics.SSRDoneTime)),getPPSMetrics(interaction)),paintMetrics),getNavigationMetricsToLegacyFormat(type)),finalVCMetrics),experimentalMetrics),(_config$additionalPay=config.additionalPayloadData)===null||_config$additionalPay===void 0?void 0:_config$additionalPay.call(config,interaction)),getTracingContextData(interaction)),getStylesheetMetrics()),getErrorCounts(interaction)),getReactHydrationStats()),{},{interactionMetrics:_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({namePrefix:config.namePrefix||'',segmentPrefix:config.segmentPrefix||'',interactionId:interactionId,pageVisibilityAtTTI:pageVisibilityAtTTI,pageVisibilityAtTTAI:pageVisibilityAtTTAI,experimental__pageVisibilityAtTTI:moreAccuratePageVisibilityAtTTI,experimental__pageVisibilityAtTTAI:moreAccuratePageVisibilityAtTTAI,// raw interaction metrics
15
15
  rate:rate,routeName:routeName,type:type,abortReason:abortReason,featureFlags:featureFlags,previousInteractionName:previousInteractionName,isPreviousInteractionAborted:isPreviousInteractionAborted,abortedByInteractionName:abortedByInteractionName,// performance
16
16
  apdex:optimizeApdex(interaction.apdex,getReactUFOPayloadVersion(interaction.type)),end:Math.round(end)},interaction.end3p?{end3p:Math.round(interaction.end3p)}:{}),{},{start:Math.round(start),segments:getReactUFOPayloadVersion(interaction.type)==='2.0.0'?segmentTree:getOldSegmentsLabelStack(segments,interaction.type),marks:optimizeMarks(interaction.marks,getReactUFOPayloadVersion(interaction.type)),customData:optimizeCustomData(interaction),reactProfilerTimings:optimizeReactProfilerTimings(interaction.reactProfilerTimings,start,getReactUFOPayloadVersion(interaction.type)),minorInteractions:interaction.minorInteractions},responsiveness?{responsiveness:responsiveness}:{}),labelStack),pageLoadInteractionMetrics),getDetailedInteractionMetrics(resourceTimings)),getPageLoadDetailedInteractionMetrics()),getBm3TrackerTimings(interaction)),{},{'metric:ttai':experimental?regularTTAI||expTTAI:undefined,'metric:experimental:ttai':expTTAI},unknownElementName?{unknownElementName:unknownElementName}:{}),unknownElementHierarchy?{unknownElementHierarchy:unknownElementHierarchy}:{}),'ufo:payloadTime':roundEpsilon(performance.now()-interactionPayloadStart)})}};if(experimental){regularTTAI=undefined;expTTAI=undefined;}if(fg('platform_ufo_enable_vc_raw_data')){size=getPayloadSize(payload.attributes.properties);vcRev=payload.attributes.properties['ufo:vc:rev'];rawData=vcRev.find(function(item){return item.revision==='raw-handler';});if(rawData){rawDataSize=getPayloadSize(rawData);payload.attributes.properties['ufo:vc:raw:size']=rawDataSize;if(size>MAX_PAYLOAD_SIZE&&Array.isArray(vcRev)&&vcRev.length>0){payload.attributes.properties['ufo:vc:rev']=vcRev.filter(function(item){return item.revision!=='raw-handler';});payload.attributes.properties['ufo:vc:raw:removed']=true;}}payload.attributes.properties['event:sizeInKb']=getPayloadSize(payload.attributes.properties);}else{payload.attributes.properties['event:sizeInKb']=getPayloadSize(payload.attributes.properties);}// in order of importance, first one being least important
17
17
  // we can add more fields as necessary
18
- interactionMetricsFieldsToTrim=['requestInfo','featureFlags','resourceTimings'];properties=payload.attributes.properties;interactionMetrics=properties.interactionMetrics;if(!interactionMetrics){_context.next=74;break;}_iterator=_createForOfIteratorHelper(interactionMetricsFieldsToTrim);_context.prev=52;_iterator.s();case 54:if((_step=_iterator.n()).done){_context.next=66;break;}field=_step.value;if(!(getPayloadSize(properties)<=MAX_PAYLOAD_SIZE)){_context.next=58;break;}return _context.abrupt("continue",64);case 58:interactionMetrics[field]=undefined;properties['event:isTrimmed']=true;trimmedFields=properties['event:trimmedFields'];if(!Array.isArray(trimmedFields)){trimmedFields=[];}trimmedFields.push("interactionMetrics.".concat(field));properties['event:trimmedFields']=trimmedFields;case 64:_context.next=54;break;case 66:_context.next=71;break;case 68:_context.prev=68;_context.t7=_context["catch"](52);_iterator.e(_context.t7);case 71:_context.prev=71;_iterator.f();return _context.finish(71);case 74:return _context.abrupt("return",payload);case 75:case"end":return _context.stop();}},_callee,null,[[52,68,71,74]]);}));return _createInteractionMetricsPayload.apply(this,arguments);}export function createPayloads(_x6,_x7){return _createPayloads.apply(this,arguments);}function _createPayloads(){_createPayloads=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(interactionId,interaction){var ufoNameOverride,modifiedInteraction,payloads,isCriticalMetricsEnabled,vcMetrics,criticalMetricsPayloads,criticalPayloadCount,interactionMetricsPayload;return _regeneratorRuntime.wrap(function _callee2$(_context2){while(1)switch(_context2.prev=_context2.next){case 0:ufoNameOverride=getUfoNameOverride(interaction);modifiedInteraction=_objectSpread(_objectSpread({},interaction),{},{ufoName:ufoNameOverride});payloads=[];isCriticalMetricsEnabled=fg('platform_ufo_critical_metrics_payload');// Calculate VC metrics once to avoid duplicate expensive calculations
18
+ interactionMetricsFieldsToTrim=fg('ufo_remove_featureflags_from_trimmed_fields')?['requestInfo','resourceTimings']:['requestInfo','featureFlags','resourceTimings'];properties=payload.attributes.properties;interactionMetrics=properties.interactionMetrics;if(!interactionMetrics){_context.next=74;break;}_iterator=_createForOfIteratorHelper(interactionMetricsFieldsToTrim);_context.prev=52;_iterator.s();case 54:if((_step=_iterator.n()).done){_context.next=66;break;}field=_step.value;if(!(getPayloadSize(properties)<=MAX_PAYLOAD_SIZE)){_context.next=58;break;}return _context.abrupt("continue",64);case 58:interactionMetrics[field]=undefined;properties['event:isTrimmed']=true;trimmedFields=properties['event:trimmedFields'];if(!Array.isArray(trimmedFields)){trimmedFields=[];}trimmedFields.push("interactionMetrics.".concat(field));properties['event:trimmedFields']=trimmedFields;case 64:_context.next=54;break;case 66:_context.next=71;break;case 68:_context.prev=68;_context.t7=_context["catch"](52);_iterator.e(_context.t7);case 71:_context.prev=71;_iterator.f();return _context.finish(71);case 74:return _context.abrupt("return",payload);case 75:case"end":return _context.stop();}},_callee,null,[[52,68,71,74]]);}));return _createInteractionMetricsPayload.apply(this,arguments);}export function createPayloads(_x6,_x7){return _createPayloads.apply(this,arguments);}function _createPayloads(){_createPayloads=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(interactionId,interaction){var ufoNameOverride,modifiedInteraction,payloads,isCriticalMetricsEnabled,vcMetrics,criticalMetricsPayloads,criticalPayloadCount,interactionMetricsPayload;return _regeneratorRuntime.wrap(function _callee2$(_context2){while(1)switch(_context2.prev=_context2.next){case 0:ufoNameOverride=getUfoNameOverride(interaction);modifiedInteraction=_objectSpread(_objectSpread({},interaction),{},{ufoName:ufoNameOverride});payloads=[];isCriticalMetricsEnabled=fg('platform_ufo_critical_metrics_payload');// Calculate VC metrics once to avoid duplicate expensive calculations
19
19
  _context2.next=6;return getVCMetrics(interaction);case 6:vcMetrics=_context2.sent;if(!isCriticalMetricsEnabled){_context2.next=13;break;}_context2.next=10;return createCriticalMetricsPayloads(interactionId,interaction,vcMetrics);case 10:_context2.t0=_context2.sent;_context2.next=14;break;case 13:_context2.t0=[];case 14:criticalMetricsPayloads=_context2.t0;payloads.push.apply(payloads,_toConsumableArray(criticalMetricsPayloads));criticalPayloadCount=isCriticalMetricsEnabled?criticalMetricsPayloads.length:undefined;_context2.next=19;return createInteractionMetricsPayload(modifiedInteraction,interactionId,undefined,criticalPayloadCount,vcMetrics);case 19:interactionMetricsPayload=_context2.sent;payloads.push(interactionMetricsPayload);return _context2.abrupt("return",payloads.filter(Boolean));case 22:case"end":return _context2.stop();}},_callee2);}));return _createPayloads.apply(this,arguments);}export function createExperimentalMetricsPayload(_x8,_x9){return _createExperimentalMetricsPayload.apply(this,arguments);}function _createExperimentalMetricsPayload(){_createExperimentalMetricsPayload=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(interactionId,interaction){var config,ufoName,rate,pageVisibilityState,result;return _regeneratorRuntime.wrap(function _callee3$(_context3){while(1)switch(_context3.prev=_context3.next){case 0:config=getConfig();if(config){_context3.next=3;break;}throw Error('UFO Configuration not provided');case 3:ufoName=sanitizeUfoName(interaction.ufoName);rate=getExperimentalInteractionRate(ufoName,interaction.type);if(coinflip(rate)){_context3.next=7;break;}return _context3.abrupt("return",null);case 7:pageVisibilityState=getPageVisibilityState(interaction.start,interaction.end);if(!(pageVisibilityState!=='visible')){_context3.next=10;break;}return _context3.abrupt("return",null);case 10:_context3.next=12;return createInteractionMetricsPayload(interaction,interactionId,true);case 12:result=_context3.sent;return _context3.abrupt("return",result);case 14:case"end":return _context3.stop();}},_callee3);}));return _createExperimentalMetricsPayload.apply(this,arguments);}export function createExtraSearchPageInteractionPayload(_x0,_x1){return _createExtraSearchPageInteractionPayload.apply(this,arguments);}function _createExtraSearchPageInteractionPayload(){_createExtraSearchPageInteractionPayload=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(interactionId,interaction){var SAIN_HOLD_NAMES,NAME_OVERRIDE,SEARCH_PAGE_SMART_ANSWERS_SEGMENT_LABEL,newInteractionId,newEnd,holdInfo,reactProfilerTimings,lastHold,isLastHoldSAIN,lastFilteredTime,filteredReactProfilerTimings,lastTiming,modifiedInteraction,payloads,vcMetrics,interactionMetricsPayload;return _regeneratorRuntime.wrap(function _callee4$(_context4){while(1)switch(_context4.prev=_context4.next){case 0:SAIN_HOLD_NAMES=['search-ai-dialog-visible-text-loading','search-ai-dialog-all-text-loading'];NAME_OVERRIDE='search-page-ignoring-smart-answers';SEARCH_PAGE_SMART_ANSWERS_SEGMENT_LABEL='search-page-smart-answers';newInteractionId="".concat(interactionId,"-ignoring-smart-answers");// Calculate a new end time which excludes SAIN holds
20
20
  holdInfo=interaction.holdInfo,reactProfilerTimings=interaction.reactProfilerTimings;lastHold=holdInfo.at(-1);isLastHoldSAIN=Boolean(lastHold&&SAIN_HOLD_NAMES.includes(lastHold.name));// A new end time is only calculated if the last hold is a SAIN hold
21
21
  if(isLastHoldSAIN){lastFilteredTime=null;filteredReactProfilerTimings=reactProfilerTimings.filter(function(timing){if(timing.commitTime===lastFilteredTime){return false;}var isTimingSmartAnswersInSearch=timing.labelStack.some(function(label){return label.name===SEARCH_PAGE_SMART_ANSWERS_SEGMENT_LABEL;});if(isTimingSmartAnswersInSearch){lastFilteredTime=timing.commitTime;return false;}return true;});lastTiming=filteredReactProfilerTimings.at(-1);if(lastTiming){newEnd=lastTiming.commitTime;}}modifiedInteraction=_objectSpread(_objectSpread({},interaction),{},{end:newEnd!==null&&newEnd!==void 0?newEnd:interaction.end,holdInfo:[],knownSegments:[],reactProfilerTimings:[],ufoName:NAME_OVERRIDE});payloads=[];_context4.next=12;return getVCMetrics(interaction,false,true);case 12:vcMetrics=_context4.sent;_context4.next=15;return createInteractionMetricsPayload(modifiedInteraction,newInteractionId,undefined,undefined,vcMetrics);case 15:interactionMetricsPayload=_context4.sent;payloads.push(interactionMetricsPayload);return _context4.abrupt("return",payloads.filter(Boolean));case 18:case"end":return _context4.stop();}},_callee4);}));return _createExtraSearchPageInteractionPayload.apply(this,arguments);}
@@ -151,4 +151,134 @@ export function getPageVisibilityState(start, end) {
151
151
  hiddenState = timings[startIdx].hidden ? 'hidden' : 'visible';
152
152
  }
153
153
  return hiddenState;
154
+ }
155
+
156
+ // Throttle detection configuration
157
+ // Expected interval for timer checks (in milliseconds)
158
+ var THROTTLE_CHECK_INTERVAL_MS = 1000;
159
+ // Threshold for considering a timer as throttled (50% drift tolerance)
160
+ var THROTTLE_DRIFT_THRESHOLD = 1.5;
161
+ // Maximum number of throttle measurements to store (circular buffer)
162
+ var THROTTLE_BUFFER_SIZE = 120;
163
+ // Circular buffer to store throttle measurements
164
+ var throttleMeasurements = [];
165
+ var throttleInsertIndex = 0;
166
+ var throttleIntervalId = null;
167
+ var lastThrottleCheckTime = null;
168
+ var throttleSetupDone = false;
169
+ function recordThrottleMeasurement(expectedElapsed, actualElapsed) {
170
+ var isThrottled = actualElapsed > expectedElapsed * THROTTLE_DRIFT_THRESHOLD;
171
+ throttleMeasurements[throttleInsertIndex] = {
172
+ time: performance.now(),
173
+ expectedElapsed: expectedElapsed,
174
+ actualElapsed: actualElapsed,
175
+ isThrottled: isThrottled
176
+ };
177
+ throttleInsertIndex = (throttleInsertIndex + 1) % THROTTLE_BUFFER_SIZE;
178
+ }
179
+ function throttleCheckCallback() {
180
+ var currentTime = performance.now();
181
+ if (lastThrottleCheckTime !== null) {
182
+ var actualElapsed = currentTime - lastThrottleCheckTime;
183
+ recordThrottleMeasurement(THROTTLE_CHECK_INTERVAL_MS, actualElapsed);
184
+ }
185
+ lastThrottleCheckTime = currentTime;
186
+ }
187
+
188
+ /**
189
+ * Sets up the throttle detection mechanism.
190
+ * This should be called early in the page lifecycle.
191
+ * Uses a periodic timer to detect browser throttling by measuring timer drift.
192
+ */
193
+ export function setupThrottleDetection() {
194
+ if (throttleSetupDone) {
195
+ return;
196
+ }
197
+ throttleSetupDone = true;
198
+
199
+ // Record the initial timestamp
200
+ lastThrottleCheckTime = performance.now();
201
+
202
+ // Start the periodic timer for throttle detection
203
+ throttleIntervalId = setInterval(throttleCheckCallback, THROTTLE_CHECK_INTERVAL_MS);
204
+ }
205
+
206
+ /**
207
+ * Stops the throttle detection mechanism.
208
+ * Useful for cleanup in tests or when the feature is no longer needed.
209
+ */
210
+ export function stopThrottleDetection() {
211
+ if (throttleIntervalId !== null) {
212
+ clearInterval(throttleIntervalId);
213
+ throttleIntervalId = null;
214
+ }
215
+ lastThrottleCheckTime = null;
216
+ throttleSetupDone = false;
217
+ throttleMeasurements.length = 0;
218
+ throttleInsertIndex = 0;
219
+ }
220
+
221
+ /**
222
+ * Checks if the tab was throttled at any point during the specified time window.
223
+ * Returns true if any timer measurement showed significant drift (throttling).
224
+ *
225
+ * @param startTime - The start timestamp of the window to check (DOMHighResTimeStamp)
226
+ * @param endTime - The end timestamp of the window to check (DOMHighResTimeStamp)
227
+ * @returns boolean - true if throttling was detected during the time window, false otherwise
228
+ */
229
+ export function isTabThrottled(startTime, endTime) {
230
+ // Input validation
231
+ if (!Number.isFinite(startTime) || !Number.isFinite(endTime) || startTime >= endTime) {
232
+ return false;
233
+ }
234
+
235
+ // No measurements available
236
+ if (throttleMeasurements.length === 0) {
237
+ return false;
238
+ }
239
+
240
+ // Check if any measurement within the time window indicates throttling
241
+ for (var i = 0; i < throttleMeasurements.length; i++) {
242
+ var measurement = throttleMeasurements[i];
243
+ if (measurement && measurement.time >= startTime && measurement.time <= endTime && measurement.isThrottled) {
244
+ return true;
245
+ }
246
+ }
247
+ return false;
248
+ }
249
+
250
+ /**
251
+ * Gets detailed throttle information for debugging purposes.
252
+ * Returns all throttle measurements within the specified time window.
253
+ *
254
+ * @param startTime - The start timestamp of the window to check
255
+ * @param endTime - The end timestamp of the window to check
256
+ * @returns Array of throttle measurements within the time window
257
+ */
258
+ export function getThrottleMeasurements(startTime, endTime) {
259
+ // Input validation
260
+ if (!Number.isFinite(startTime) || !Number.isFinite(endTime) || startTime >= endTime) {
261
+ return [];
262
+ }
263
+ return throttleMeasurements.filter(function (measurement) {
264
+ return measurement && measurement.time >= startTime && measurement.time <= endTime;
265
+ });
266
+ }
267
+
268
+ /**
269
+ * Injects a fake throttle measurement for testing purposes.
270
+ * This allows integration tests to simulate throttling scenarios.
271
+ *
272
+ * @param measurement - The throttle measurement to inject
273
+ */
274
+ export function __injectThrottleMeasurementForTesting(measurement) {
275
+ throttleMeasurements[throttleInsertIndex] = measurement;
276
+ throttleInsertIndex = (throttleInsertIndex + 1) % THROTTLE_BUFFER_SIZE;
277
+ }
278
+
279
+ // Expose testing API on window for integration tests
280
+ if (typeof window !== 'undefined') {
281
+ window.__reactUfoHiddenTiming = {
282
+ __injectThrottleMeasurementForTesting: __injectThrottleMeasurementForTesting
283
+ };
154
284
  }
@@ -24,9 +24,12 @@ import { newVCObserver } from '../vc';
24
24
  import { interactions } from './common/constants';
25
25
  import InteractionExtraMetrics from './interaction-extra-metrics';
26
26
  import PostInteractionLog from './post-interaction-log';
27
- var PreviousInteractionLog = {
27
+ export var PreviousInteractionLog = {
28
+ id: undefined,
28
29
  name: undefined,
29
- isAborted: undefined
30
+ type: undefined,
31
+ isAborted: undefined,
32
+ timestamp: undefined
30
33
  };
31
34
  export var postInteractionLog = new PostInteractionLog();
32
35
  export var interactionExtraMetrics = new InteractionExtraMetrics();
@@ -704,6 +707,11 @@ function finishInteraction(id, data) {
704
707
  remove(id);
705
708
  }
706
709
  }
710
+ if (fg('platform_ufo_enable_terminal_errors')) {
711
+ PreviousInteractionLog.id = data.id;
712
+ PreviousInteractionLog.type = data.type;
713
+ PreviousInteractionLog.timestamp = data.end;
714
+ }
707
715
  PreviousInteractionLog.name = data.ufoName || 'unknown';
708
716
  PreviousInteractionLog.isAborted = data.abortReason != null;
709
717
  if (data.ufoName) {
@@ -8,7 +8,7 @@ import { setUFOConfig } from '../config';
8
8
  import { experimentalVC, sinkExperimentalHandler } from '../create-experimental-interaction-metrics-payload';
9
9
  import { sinkExtraSearchPageInteractionHandler } from '../create-extra-search-page-interaction-payload';
10
10
  import { setContextManager, UFOContextManager } from '../experience-trace-id-context/context-manager';
11
- import { setupHiddenTimingCapture } from '../hidden-timing';
11
+ import { setupHiddenTimingCapture, setupThrottleDetection } from '../hidden-timing';
12
12
  import { interactionExtraMetrics, postInteractionLog, sinkInteractionHandler, sinkPostInteractionLogHandler } from '../interaction-metrics';
13
13
  import { getPerformanceObserver } from '../interactions-performance-observer';
14
14
  import { initialiseMemoryObserver, initialisePressureObserver } from '../machine-utilisation';
@@ -178,6 +178,9 @@ export function init(analyticsWebClientAsync, config) {
178
178
  }
179
179
  setupHiddenTimingCapture();
180
180
  startLighthouseObserver();
181
+ if (fg('platform_ufo_is_tab_throttled')) {
182
+ setupThrottleDetection();
183
+ }
181
184
  initialized = true;
182
185
  if (typeof PerformanceObserver !== 'undefined') {
183
186
  var observer = getPerformanceObserver();
@@ -3,24 +3,32 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
3
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
4
  import { useEffect, useRef } from 'react';
5
5
  import { useInteractionContext } from '../interaction-context';
6
- import { getActiveInteraction } from '../interaction-metrics';
6
+ import { getActiveInteraction, PreviousInteractionLog } from '../interaction-metrics';
7
7
  var sinkHandlerFn = function sinkHandlerFn() {};
8
8
  export function sinkTerminalErrorHandler(fn) {
9
9
  sinkHandlerFn = fn;
10
10
  }
11
11
  export function setTerminalError(error, additionalAttributes, labelStack) {
12
- var _activeInteraction$uf, _activeInteraction$id, _activeInteraction$ty;
12
+ var _activeInteraction$uf, _activeInteraction$id, _activeInteraction$ty, _PreviousInteractionL, _PreviousInteractionL2, _PreviousInteractionL3;
13
13
  var activeInteraction = getActiveInteraction();
14
+ var currentTime = performance.now();
14
15
  var errorData = _objectSpread({
15
16
  errorType: error.name || 'Error',
16
17
  errorMessage: error.message.slice(0, 100),
17
- timestamp: performance.now()
18
+ timestamp: currentTime
18
19
  }, additionalAttributes);
20
+
21
+ // Calculate time since previous interaction
22
+ var timeSincePreviousInteraction = PreviousInteractionLog.timestamp != null ? currentTime - PreviousInteractionLog.timestamp : null;
19
23
  var context = {
20
24
  labelStack: labelStack !== null && labelStack !== void 0 ? labelStack : null,
21
25
  activeInteractionName: (_activeInteraction$uf = activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.ufoName) !== null && _activeInteraction$uf !== void 0 ? _activeInteraction$uf : null,
22
26
  activeInteractionId: (_activeInteraction$id = activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.id) !== null && _activeInteraction$id !== void 0 ? _activeInteraction$id : null,
23
- activeInteractionType: (_activeInteraction$ty = activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.type) !== null && _activeInteraction$ty !== void 0 ? _activeInteraction$ty : null
27
+ activeInteractionType: (_activeInteraction$ty = activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.type) !== null && _activeInteraction$ty !== void 0 ? _activeInteraction$ty : null,
28
+ previousInteractionId: (_PreviousInteractionL = PreviousInteractionLog.id) !== null && _PreviousInteractionL !== void 0 ? _PreviousInteractionL : null,
29
+ previousInteractionName: (_PreviousInteractionL2 = PreviousInteractionLog.name) !== null && _PreviousInteractionL2 !== void 0 ? _PreviousInteractionL2 : null,
30
+ previousInteractionType: (_PreviousInteractionL3 = PreviousInteractionLog.type) !== null && _PreviousInteractionL3 !== void 0 ? _PreviousInteractionL3 : null,
31
+ timeSincePreviousInteraction: timeSincePreviousInteraction
24
32
  };
25
33
  sinkHandlerFn(errorData, context);
26
34
  }
@@ -114,13 +114,14 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
114
114
  value: function () {
115
115
  var _calculateWithDebugInfo = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionType, isPageVisible, interactionId, dirtyReason, allEntries, include3p, excludeSmartAnswersInSearch, interactionAbortReason, includeSSRRatio) {
116
116
  var _window, _window2, _window3, _window4, _window6;
117
- var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, ssrRatio, _iterator4, _step4, _entry3, time, viewportPercentage, entries, elementNames, previousResult, i, percentile, enhancedVcLogs, shouldCalculate3p, shouldCalculateDebugDetails, sortedVcLogs, maxViewportPercentageAtTime, maxSoFar, _iterator5, _step5, log, getBiggestPreviousViewportPercentage, ignoredEntriesByTime, _iterator6, _step6, _entry4, _ignoredEntriesByTime, _viewportData$rect, _viewportData$previou, viewportData, timestamp, additionalVcLogs, _iterator7, _step7, _step7$value, _timestamp, ignoredEntries, _viewportPercentage, v3RevisionDebugDetails, _window5, _window5$__ufo_devtoo, _window7, _window7$__on_ufo_vc_;
117
+ var percentiles, viewportEntries, shouldCalculateSpeedIndex, _yield$calculateTTVCP, vcLogs, speedIndex, vcDetails, percentileIndex, entryDataBuffer, ssrRatio, _iterator4, _step4, _entry3, time, viewportPercentage, entries, elementNames, previousResult, i, percentile, enhancedVcLogs, shouldCalculate3p, shouldCalculateDebugDetails, sortedVcLogs, maxViewportPercentageAtTime, maxSoFar, _iterator5, _step5, log, getBiggestPreviousViewportPercentage, ignoredEntriesByTime, _iterator6, _step6, _entry4, _ignoredEntriesByTime, _viewportData$rect, _viewportData$previou, viewportData, timestamp, additionalVcLogs, _iterator7, _step7, _step7$value, _timestamp, ignoredEntries, _viewportPercentage, v3RevisionDebugDetails, _window5, _window5$__ufo_devtoo, _window7, _window7$__on_ufo_vc_;
118
118
  return _regeneratorRuntime.wrap(function _callee$(_context) {
119
119
  while (1) switch (_context.prev = _context.next) {
120
120
  case 0:
121
121
  percentiles = [25, 50, 75, 80, 85, 90, 95, 98, 99, 100];
122
122
  viewportEntries = this.filterViewportEntries(filteredEntries);
123
- _context.next = 4;
123
+ shouldCalculateSpeedIndex = fg('platform_ufo_ttvc_v4_speed_index');
124
+ _context.next = 5;
124
125
  return calculateTTVCPercentilesWithDebugInfo({
125
126
  viewport: {
126
127
  width: getViewportWidth(),
@@ -128,24 +129,27 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
128
129
  },
129
130
  startTime: startTime,
130
131
  stopTime: stopTime,
131
- orderedEntries: viewportEntries
132
+ orderedEntries: viewportEntries,
133
+ calculateSpeedIndex: shouldCalculateSpeedIndex
132
134
  });
133
- case 4:
134
- vcLogs = _context.sent;
135
+ case 5:
136
+ _yield$calculateTTVCP = _context.sent;
137
+ vcLogs = _yield$calculateTTVCP.entries;
138
+ speedIndex = _yield$calculateTTVCP.speedIndex;
135
139
  vcDetails = {};
136
140
  percentileIndex = 0;
137
141
  entryDataBuffer = new Set();
138
142
  ssrRatio = -1;
139
143
  if (!vcLogs) {
140
- _context.next = 30;
144
+ _context.next = 33;
141
145
  break;
142
146
  }
143
147
  _iterator4 = _createForOfIteratorHelper(vcLogs);
144
- _context.prev = 11;
148
+ _context.prev = 14;
145
149
  _iterator4.s();
146
- case 13:
150
+ case 16:
147
151
  if ((_step4 = _iterator4.n()).done) {
148
- _context.next = 22;
152
+ _context.next = 25;
149
153
  break;
150
154
  }
151
155
  _entry3 = _step4.value;
@@ -158,11 +162,11 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
158
162
 
159
163
  // Only process entries if we haven't reached all percentiles
160
164
  if (!(percentileIndex >= percentiles.length)) {
161
- _context.next = 19;
165
+ _context.next = 22;
162
166
  break;
163
167
  }
164
- return _context.abrupt("break", 22);
165
- case 19:
168
+ return _context.abrupt("break", 25);
169
+ case 22:
166
170
  // Check if this entry matches any checkpoint percentiles
167
171
  if (viewportPercentage >= percentiles[percentileIndex]) {
168
172
  elementNames = [];
@@ -193,21 +197,21 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
193
197
  return entryDataBuffer.add(e);
194
198
  });
195
199
  }
196
- case 20:
197
- _context.next = 13;
200
+ case 23:
201
+ _context.next = 16;
198
202
  break;
199
- case 22:
200
- _context.next = 27;
203
+ case 25:
204
+ _context.next = 30;
201
205
  break;
202
- case 24:
203
- _context.prev = 24;
204
- _context.t0 = _context["catch"](11);
205
- _iterator4.e(_context.t0);
206
206
  case 27:
207
207
  _context.prev = 27;
208
- _iterator4.f();
209
- return _context.finish(27);
208
+ _context.t0 = _context["catch"](14);
209
+ _iterator4.e(_context.t0);
210
210
  case 30:
211
+ _context.prev = 30;
212
+ _iterator4.f();
213
+ return _context.finish(30);
214
+ case 33:
211
215
  // Fill in any missing percentiles with the last known values
212
216
  previousResult = {
213
217
  t: 0,
@@ -367,13 +371,14 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
367
371
  }
368
372
  return _context.abrupt("return", {
369
373
  vcDetails: vcDetails,
370
- ssrRatio: ssrRatio
374
+ ssrRatio: ssrRatio,
375
+ speedIndex: speedIndex
371
376
  });
372
- case 42:
377
+ case 45:
373
378
  case "end":
374
379
  return _context.stop();
375
380
  }
376
- }, _callee, this, [[11, 24, 27, 30]]);
381
+ }, _callee, this, [[14, 27, 30, 33]]);
377
382
  }));
378
383
  function calculateWithDebugInfo(_x, _x2, _x3, _x4, _x5, _x6, _x7, _x8, _x9, _x0, _x1, _x10, _x11, _x12) {
379
384
  return _calculateWithDebugInfo.apply(this, arguments);
@@ -387,7 +392,7 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
387
392
  var _this = this,
388
393
  _vcDetails$90$t,
389
394
  _vcDetails$;
390
- var startTime, stopTime, orderedEntries, interactionId, isPostInteraction, include3p, excludeSmartAnswersInSearch, includeSSRRatio, interactionType, isPageVisible, interactionAbortReason, filteredEntries, isVCClean, dirtyReason, getVCCleanStatusResult, _yield$this$calculate, vcDetails, ssrRatio, result;
395
+ var startTime, stopTime, orderedEntries, interactionId, isPostInteraction, include3p, excludeSmartAnswersInSearch, includeSSRRatio, interactionType, isPageVisible, interactionAbortReason, filteredEntries, isVCClean, dirtyReason, getVCCleanStatusResult, _yield$this$calculate, vcDetails, ssrRatio, speedIndex, result;
391
396
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
392
397
  while (1) switch (_context2.prev = _context2.next) {
393
398
  case 0:
@@ -416,6 +421,7 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
416
421
  _yield$this$calculate = _context2.sent;
417
422
  vcDetails = _yield$this$calculate.vcDetails;
418
423
  ssrRatio = _yield$this$calculate.ssrRatio;
424
+ speedIndex = _yield$this$calculate.speedIndex;
419
425
  result = {
420
426
  revision: this.revisionNo,
421
427
  clean: true,
@@ -426,9 +432,15 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
426
432
  if (ssrRatio !== -1) {
427
433
  result.ssrRatio = ssrRatio;
428
434
  }
435
+
436
+ // speedIndex is only calculated when platform_ufo_ttvc_v4_speed_index is enabled,
437
+ // so we only include it in the result when it has a meaningful value (> 0)
438
+ if (speedIndex > 0) {
439
+ result.speedIndex = speedIndex;
440
+ }
429
441
  result.labelStacks = this.getLabelStacks(filteredEntries, isPostInteraction);
430
442
  return _context2.abrupt("return", result);
431
- case 17:
443
+ case 19:
432
444
  case "end":
433
445
  return _context2.stop();
434
446
  }
@@ -75,11 +75,11 @@ function calculateTTVCPercentilesWithDebugInfo(_x2) {
75
75
  }
76
76
  function _calculateTTVCPercentilesWithDebugInfo() {
77
77
  _calculateTTVCPercentilesWithDebugInfo = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref2) {
78
- var viewport, orderedEntries, startTime, canvas, elementMap, _iterator3, _step3, entry, rect, timePixelCounts, canvasDimensions, totalPixels;
78
+ var viewport, orderedEntries, startTime, _ref2$calculateSpeedI, calculateSpeedIndex, canvas, elementMap, _iterator3, _step3, entry, rect, timePixelCounts, canvasDimensions, totalPixels;
79
79
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
80
80
  while (1) switch (_context2.prev = _context2.next) {
81
81
  case 0:
82
- viewport = _ref2.viewport, orderedEntries = _ref2.orderedEntries, startTime = _ref2.startTime;
82
+ viewport = _ref2.viewport, orderedEntries = _ref2.orderedEntries, startTime = _ref2.startTime, _ref2$calculateSpeedI = _ref2.calculateSpeedIndex, calculateSpeedIndex = _ref2$calculateSpeedI === void 0 ? false : _ref2$calculateSpeedI;
83
83
  canvas = new ViewportCanvas(viewport, fg('platform_ufo_canvas_heatmap_full_precision') ? 1 : 0.25);
84
84
  elementMap = new Map();
85
85
  _iterator3 = _createForOfIteratorHelper(orderedEntries);
@@ -124,7 +124,7 @@ function _calculateTTVCPercentilesWithDebugInfo() {
124
124
  timePixelCounts = _context2.sent;
125
125
  canvasDimensions = canvas.getScaledDimensions();
126
126
  totalPixels = canvasDimensions.width * canvasDimensions.height;
127
- return _context2.abrupt("return", calculatePercentilesWithDebugInfo(timePixelCounts, elementMap, totalPixels, startTime));
127
+ return _context2.abrupt("return", calculatePercentilesWithDebugInfo(timePixelCounts, elementMap, totalPixels, startTime, calculateSpeedIndex));
128
128
  case 30:
129
129
  case "end":
130
130
  return _context2.stop();
@@ -199,8 +199,11 @@ export function calculatePercentiles(timePixelCounts, elementMap, unorderedPerce
199
199
  return results;
200
200
  }
201
201
  export function calculatePercentilesWithDebugInfo(timePixelCounts, elementMap, totalPixels, startTime) {
202
- var results = new Array(elementMap.size);
202
+ var calculateSpeedIndex = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
203
+ var entries = new Array(elementMap.size);
203
204
  var cumulativePixels = 0;
205
+ var speedIndex = 0;
206
+ var previousPercentCovered = 0;
204
207
  var sortedEntries = Array.from(timePixelCounts.entries()).sort(function (_ref7, _ref8) {
205
208
  var _ref9 = _slicedToArray(_ref7, 1),
206
209
  timeA = _ref9[0];
@@ -215,12 +218,24 @@ export function calculatePercentilesWithDebugInfo(timePixelCounts, elementMap, t
215
218
  cumulativePixels += pixelCount;
216
219
  var percentCovered = cumulativePixels / totalPixels * 100;
217
220
  var entryDatas = elementMap.get(time) || [];
218
- results[i] = {
219
- time: Math.round(Number(time - startTime)),
221
+ var relativeTime = Math.round(Number(time - startTime));
222
+ entries[i] = {
223
+ time: relativeTime,
220
224
  viewportPercentage: percentCovered,
221
225
  entries: Array.from(entryDatas)
222
226
  };
227
+
228
+ // Speed index calculation: sum of (time × incremental viewport percentage)
229
+ // Only calculate when feature flag is enabled
230
+ if (calculateSpeedIndex) {
231
+ var ratioDelta = (percentCovered - previousPercentCovered) / 100;
232
+ speedIndex += relativeTime * ratioDelta;
233
+ previousPercentCovered = percentCovered;
234
+ }
223
235
  }
224
- return results;
236
+ return {
237
+ entries: entries,
238
+ speedIndex: Math.round(speedIndex)
239
+ };
225
240
  }
226
241
  export { calculateTTVCPercentilesWithDebugInfo };
@@ -119,6 +119,7 @@ export type ReactUFOPayload = {
119
119
  'ufo:pageVisibilityHiddenTimestamp'?: number;
120
120
  'ufo:wasPageHiddenBeforeInit'?: boolean;
121
121
  'ufo:isOpenedInBackground'?: boolean;
122
+ 'ufo:isTabThrottled'?: boolean;
122
123
  interactionMetrics: {
123
124
  namePrefix: string;
124
125
  segmentPrefix: string;
@@ -117,6 +117,7 @@ export type RevisionPayloadVCDetails = Record<string, {
117
117
  export type CalculateTTVCResult = {
118
118
  vcDetails: RevisionPayloadVCDetails;
119
119
  ssrRatio: number;
120
+ speedIndex: number;
120
121
  };
121
122
  export type RawObservation = {
122
123
  t: number;
@@ -136,6 +137,7 @@ export type RevisionPayloadEntry = {
136
137
  vcDetails?: RevisionPayloadVCDetails;
137
138
  ratios?: VCRatioType;
138
139
  ssrRatio?: number;
140
+ speedIndex?: number;
139
141
  labelStacks?: VCLabelStacks;
140
142
  abortReason?: VCAbortReason | null;
141
143
  abortTimestamp?: number;