@atlaskit/react-ufo 3.3.1 → 3.3.3

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 (73) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/create-payload/index.js +106 -163
  3. package/dist/cjs/create-payload/utils/get-interaction-status.js +37 -0
  4. package/dist/cjs/create-payload/utils/get-page-visibility-up-to-ttai.js +12 -0
  5. package/dist/cjs/create-payload/utils/get-ssr-done-time-value.js +14 -0
  6. package/dist/cjs/create-payload/utils/get-vc-metrics.js +96 -0
  7. package/dist/cjs/interaction-metrics-init/index.js +11 -9
  8. package/dist/cjs/vc/index.js +6 -2
  9. package/dist/cjs/vc/vc-observer-new/get-element-name.js +19 -6
  10. package/dist/cjs/vc/vc-observer-new/index.js +6 -3
  11. package/dist/cjs/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +4 -2
  12. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/canvas-pixel.js +10 -11
  13. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +23 -30
  14. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.js +7 -7
  15. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.js +3 -3
  16. package/dist/cjs/vc/vc-observer-new/window-event-observer/index.js +5 -1
  17. package/dist/es2019/create-payload/index.js +14 -73
  18. package/dist/es2019/create-payload/utils/get-interaction-status.js +31 -0
  19. package/dist/es2019/create-payload/utils/get-page-visibility-up-to-ttai.js +8 -0
  20. package/dist/es2019/create-payload/utils/get-ssr-done-time-value.js +5 -0
  21. package/dist/es2019/create-payload/utils/get-vc-metrics.js +53 -0
  22. package/dist/es2019/interaction-metrics-init/index.js +11 -9
  23. package/dist/es2019/vc/index.js +6 -2
  24. package/dist/es2019/vc/vc-observer-new/get-element-name.js +19 -6
  25. package/dist/es2019/vc/vc-observer-new/index.js +7 -3
  26. package/dist/es2019/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +4 -0
  27. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/canvas-pixel.js +1 -2
  28. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +15 -12
  29. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.js +5 -4
  30. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.js +3 -2
  31. package/dist/es2019/vc/vc-observer-new/window-event-observer/index.js +5 -1
  32. package/dist/esm/create-payload/index.js +99 -156
  33. package/dist/esm/create-payload/utils/get-interaction-status.js +31 -0
  34. package/dist/esm/create-payload/utils/get-page-visibility-up-to-ttai.js +6 -0
  35. package/dist/esm/create-payload/utils/get-ssr-done-time-value.js +5 -0
  36. package/dist/esm/create-payload/utils/get-vc-metrics.js +89 -0
  37. package/dist/esm/interaction-metrics-init/index.js +11 -9
  38. package/dist/esm/vc/index.js +6 -2
  39. package/dist/esm/vc/vc-observer-new/get-element-name.js +19 -6
  40. package/dist/esm/vc/vc-observer-new/index.js +6 -3
  41. package/dist/esm/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +4 -2
  42. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/canvas-pixel.js +10 -11
  43. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +23 -30
  44. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.js +7 -7
  45. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.js +3 -3
  46. package/dist/esm/vc/vc-observer-new/window-event-observer/index.js +5 -1
  47. package/dist/types/config/index.d.ts +1 -0
  48. package/dist/types/create-payload/index.d.ts +1 -1
  49. package/dist/types/create-payload/utils/get-interaction-status.d.ts +27 -0
  50. package/dist/types/create-payload/utils/get-page-visibility-up-to-ttai.d.ts +2 -0
  51. package/dist/types/create-payload/utils/get-ssr-done-time-value.d.ts +2 -0
  52. package/dist/types/create-payload/utils/get-vc-metrics.d.ts +5 -0
  53. package/dist/types/vc/vc-observer-new/index.d.ts +3 -2
  54. package/dist/types/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +1 -1
  55. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.d.ts +2 -2
  56. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.d.ts +2 -1
  57. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.d.ts +2 -1
  58. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/types.d.ts +2 -0
  59. package/dist/types/vc/vc-observer-new/metric-calculator/types.d.ts +2 -0
  60. package/dist/types-ts4.5/config/index.d.ts +1 -0
  61. package/dist/types-ts4.5/create-payload/index.d.ts +1 -1
  62. package/dist/types-ts4.5/create-payload/utils/get-interaction-status.d.ts +27 -0
  63. package/dist/types-ts4.5/create-payload/utils/get-page-visibility-up-to-ttai.d.ts +2 -0
  64. package/dist/types-ts4.5/create-payload/utils/get-ssr-done-time-value.d.ts +2 -0
  65. package/dist/types-ts4.5/create-payload/utils/get-vc-metrics.d.ts +5 -0
  66. package/dist/types-ts4.5/vc/vc-observer-new/index.d.ts +3 -2
  67. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +1 -1
  68. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.d.ts +2 -2
  69. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.d.ts +2 -1
  70. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.d.ts +2 -1
  71. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/types.d.ts +2 -0
  72. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/types.d.ts +2 -0
  73. package/package.json +5 -2
@@ -11,12 +11,15 @@ import { getBm3Timings } from '../custom-timings';
11
11
  import { getGlobalErrorCount } from '../global-error-handler';
12
12
  import { getPageVisibilityState } from '../hidden-timing';
13
13
  import * as initialPageLoadExtraTiming from '../initial-page-load-extra-timing';
14
- import { interactionSpans as atlaskitInteractionSpans, postInteractionLog } from '../interaction-metrics';
14
+ import { interactionSpans as atlaskitInteractionSpans } from '../interaction-metrics';
15
15
  import * as resourceTiming from '../resource-timing';
16
16
  import { roundEpsilon } from '../round-number';
17
17
  import * as ssr from '../ssr';
18
- import { getVCObserver } from '../vc';
19
18
  import { buildSegmentTree, labelStackStartWith, optimizeLabelStack, sanitizeUfoName, stringifyLabelStackFully } from './common/utils';
19
+ import getInteractionStatus from './utils/get-interaction-status';
20
+ import getPageVisibilityUpToTTAI from './utils/get-page-visibility-up-to-ttai';
21
+ import getSSRDoneTimeValue from './utils/get-ssr-done-time-value';
22
+ import getVCMetrics from './utils/get-vc-metrics';
20
23
  function getUfoNameOverride(interaction) {
21
24
  const {
22
25
  ufoName,
@@ -65,13 +68,6 @@ const getPageVisibilityUpToTTI = interaction => {
65
68
  const bm3EndTimeOrInteractionEndTime = getBm3EndTimeOrFallbackValue(interaction);
66
69
  return getPageVisibilityState(start, bm3EndTimeOrInteractionEndTime);
67
70
  };
68
- const getPageVisibilityUpToTTAI = interaction => {
69
- const {
70
- start,
71
- end
72
- } = interaction;
73
- return getPageVisibilityState(start, end);
74
- };
75
71
  const getVisibilityStateFromPerformance = stop => {
76
72
  try {
77
73
  const results = performance.getEntriesByType('visibility-state');
@@ -126,15 +122,6 @@ const getMoreAccuratePageVisibilityUpToTTAI = interaction => {
126
122
  }
127
123
  return old;
128
124
  };
129
- const getInteractionStatus = interaction => {
130
- const originalInteractionStatus = interaction.abortReason ? 'ABORTED' : 'SUCCEEDED';
131
- const hasBm3TTI = interaction.apdex.length > 0;
132
- const overrideStatus = hasBm3TTI ? 'SUCCEEDED' : originalInteractionStatus;
133
- return {
134
- originalInteractionStatus,
135
- overrideStatus
136
- };
137
- };
138
125
  const getResourceTimings = (start, end) => {
139
126
  var _resourceTiming$getRe;
140
127
  return (_resourceTiming$getRe = resourceTiming.getResourceTimings(start, end)) !== null && _resourceTiming$getRe !== void 0 ? _resourceTiming$getRe : undefined;
@@ -165,49 +152,6 @@ const getTTAI = interaction => {
165
152
  const pageVisibilityUpToTTAI = getPageVisibilityUpToTTAI(interaction);
166
153
  return !interaction.abortReason && pageVisibilityUpToTTAI === 'visible' ? Math.round(end - start) : undefined;
167
154
  };
168
- const getVCMetrics = async interaction => {
169
- var _config$vc, _config$vc$ssrWhiteli, _interaction$apdex, _interaction$apdex$, _config$experimentalI;
170
- const config = getConfig();
171
- if (!(config !== null && config !== void 0 && (_config$vc = config.vc) !== null && _config$vc !== void 0 && _config$vc.enabled)) {
172
- return {};
173
- }
174
- if (interaction.type !== 'page_load' && interaction.type !== 'transition') {
175
- return {};
176
- }
177
- const isSSREnabled = (config === null || config === void 0 ? void 0 : config.ssr) || (config === null || config === void 0 ? void 0 : (_config$vc$ssrWhiteli = config.vc.ssrWhitelist) === null || _config$vc$ssrWhiteli === void 0 ? void 0 : _config$vc$ssrWhiteli.includes(interaction.ufoName));
178
- const ssr = interaction.type === 'page_load' && isSSREnabled ? {
179
- ssr: getSSRDoneTimeValue(config)
180
- } : null;
181
- postInteractionLog.setVCObserverSSRConfig(ssr);
182
- const tti = (_interaction$apdex = interaction.apdex) === null || _interaction$apdex === void 0 ? void 0 : (_interaction$apdex$ = _interaction$apdex[0]) === null || _interaction$apdex$ === void 0 ? void 0 : _interaction$apdex$.stopTime;
183
- const prefix = 'ufo';
184
- const interactionStatus = getInteractionStatus(interaction);
185
- const pageVisibilityUpToTTAI = getPageVisibilityUpToTTAI(interaction);
186
- const result = await getVCObserver().getVCResult({
187
- start: interaction.start,
188
- stop: interaction.end,
189
- tti,
190
- prefix,
191
- vc: interaction.vc,
192
- isEventAborted: interactionStatus.originalInteractionStatus !== 'SUCCEEDED',
193
- ...ssr
194
- });
195
- if ((_config$experimentalI = config.experimentalInteractionMetrics) !== null && _config$experimentalI !== void 0 && _config$experimentalI.enabled) {
196
- getVCObserver().stop();
197
- }
198
- postInteractionLog.setLastInteractionFinishVCResult(result);
199
- const VC = result === null || result === void 0 ? void 0 : result['metrics:vc'];
200
- if (!VC || !(result !== null && result !== void 0 && result[`${prefix}:vc:clean`])) {
201
- return result;
202
- }
203
- if (interactionStatus.originalInteractionStatus !== 'SUCCEEDED' || pageVisibilityUpToTTAI !== 'visible') {
204
- return result;
205
- }
206
- return {
207
- ...result,
208
- 'metric:vc90': VC['90']
209
- };
210
- };
211
155
  const getNavigationMetrics = type => {
212
156
  if (type !== 'page_load') {
213
157
  return {};
@@ -255,7 +199,7 @@ const getNavigationMetrics = type => {
255
199
  };
256
200
  };
257
201
  const getPPSMetrics = interaction => {
258
- var _interaction$apdex2, _interaction$apdex2$;
202
+ var _interaction$apdex, _interaction$apdex$;
259
203
  const {
260
204
  start,
261
205
  end
@@ -263,7 +207,7 @@ const getPPSMetrics = interaction => {
263
207
  const config = getConfig();
264
208
  const interactionStatus = getInteractionStatus(interaction);
265
209
  const pageVisibilityUpToTTAI = getPageVisibilityUpToTTAI(interaction);
266
- const tti = (_interaction$apdex2 = interaction.apdex) === null || _interaction$apdex2 === void 0 ? void 0 : (_interaction$apdex2$ = _interaction$apdex2[0]) === null || _interaction$apdex2$ === void 0 ? void 0 : _interaction$apdex2$.stopTime;
210
+ const tti = (_interaction$apdex = interaction.apdex) === null || _interaction$apdex === void 0 ? void 0 : (_interaction$apdex$ = _interaction$apdex[0]) === null || _interaction$apdex$ === void 0 ? void 0 : _interaction$apdex$.stopTime;
267
211
  const ttai = interactionStatus.originalInteractionStatus === 'SUCCEEDED' && pageVisibilityUpToTTAI === 'visible' ? Math.round(end - start) : undefined;
268
212
  const PPSMetricsAtTTI = tti !== undefined ? getLighthouseMetrics({
269
213
  start,
@@ -635,10 +579,6 @@ function getBm3TrackerTimings(interaction) {
635
579
  legacyMetrics
636
580
  };
637
581
  }
638
- function getSSRDoneTimeValue(config) {
639
- var _config$ssr, _config$ssr2;
640
- return config !== null && config !== void 0 && (_config$ssr = config.ssr) !== null && _config$ssr !== void 0 && _config$ssr.getSSRDoneTime ? config === null || config === void 0 ? void 0 : (_config$ssr2 = config.ssr) === null || _config$ssr2 === void 0 ? void 0 : _config$ssr2.getSSRDoneTime() : ssr.getSSRDoneTime();
641
- }
642
582
  function getPayloadSize(payload) {
643
583
  return Math.round(new TextEncoder().encode(JSON.stringify(payload)).length / 1024);
644
584
  }
@@ -725,7 +665,7 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
725
665
  } : {};
726
666
  // Page Load
727
667
  const getPageLoadInteractionMetrics = () => {
728
- var _config$ssr3;
668
+ var _config$ssr;
729
669
  if (!isPageLoad) {
730
670
  return {};
731
671
  }
@@ -737,7 +677,7 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
737
677
  return {
738
678
  ...SSRDoneTime,
739
679
  isBM3ConfigSSRDoneAsFmp: interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp,
740
- isUFOConfigSSRDoneAsFmp: interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp || !!(config !== null && config !== void 0 && (_config$ssr3 = config.ssr) !== null && _config$ssr3 !== void 0 && _config$ssr3.getSSRDoneTime)
680
+ isUFOConfigSSRDoneAsFmp: interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp || !!(config !== null && config !== void 0 && (_config$ssr = config.ssr) !== null && _config$ssr !== void 0 && _config$ssr.getSSRDoneTime)
741
681
  };
742
682
  };
743
683
  // Detailed payload. Page visibility = visible
@@ -767,14 +707,14 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
767
707
  };
768
708
  // Page load & detailed payload
769
709
  const getPageLoadDetailedInteractionMetrics = () => {
770
- var _config$ssr4;
710
+ var _config$ssr2;
771
711
  if (!isPageLoad || !isDetailedPayload) {
772
712
  return {};
773
713
  }
774
714
  const config = getConfig();
775
715
  return {
776
716
  initialPageLoadExtraTimings: objectToArray(initialPageLoadExtraTiming.getTimings()),
777
- SSRTimings: config !== null && config !== void 0 && (_config$ssr4 = config.ssr) !== null && _config$ssr4 !== void 0 && _config$ssr4.getSSRTimings ? config.ssr.getSSRTimings() : objectToArray(ssr.getSSRTimings())
717
+ SSRTimings: config !== null && config !== void 0 && (_config$ssr2 = config.ssr) !== null && _config$ssr2 !== void 0 && _config$ssr2.getSSRTimings ? config.ssr.getSSRTimings() : objectToArray(ssr.getSSRTimings())
778
718
  };
779
719
  };
780
720
  if (experimental) {
@@ -877,7 +817,7 @@ export async function createPayloads(interactionId, interaction) {
877
817
  const interactionMetricsPayload = await createInteractionMetricsPayload(modifiedInteraction, interactionId);
878
818
  return [interactionMetricsPayload];
879
819
  }
880
- export function createExperimentalMetricsPayload(interactionId, interaction) {
820
+ export async function createExperimentalMetricsPayload(interactionId, interaction) {
881
821
  const config = getConfig();
882
822
  if (!config) {
883
823
  throw Error('UFO Configuration not provided');
@@ -891,5 +831,6 @@ export function createExperimentalMetricsPayload(interactionId, interaction) {
891
831
  if (pageVisibilityState !== 'visible') {
892
832
  return null;
893
833
  }
894
- return createInteractionMetricsPayload(interaction, interactionId, true);
834
+ const result = await createInteractionMetricsPayload(interaction, interactionId, true);
835
+ return result;
895
836
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Determines the interaction status based on abort reason and BM3 TTI presence.
3
+ *
4
+ * @param {InteractionMetrics} interaction - The interaction metrics object containing abort reason and apdex data
5
+ * @returns {{
6
+ * originalInteractionStatus: 'ABORTED' | 'SUCCEEDED',
7
+ * overrideStatus: 'ABORTED' | 'SUCCEEDED'
8
+ * }} An object containing both the original and override status
9
+ *
10
+ * @description
11
+ * This function evaluates the interaction status in two ways:
12
+ * 1. originalInteractionStatus: Based on whether there's an abort reason
13
+ * 2. overrideStatus: Based on the presence of BM3 TTI (apdex data)
14
+ *
15
+ * @example
16
+ * const interaction = {
17
+ * abortReason: null,
18
+ * apdex: [1, 2, 3]
19
+ * };
20
+ * const result = getInteractionStatus(interaction);
21
+ * // Returns: { originalInteractionStatus: 'SUCCEEDED', overrideStatus: 'SUCCEEDED' }
22
+ */
23
+ export default function getInteractionStatus(interaction) {
24
+ const originalInteractionStatus = interaction.abortReason ? 'ABORTED' : 'SUCCEEDED';
25
+ const hasBm3TTI = interaction.apdex.length > 0;
26
+ const overrideStatus = hasBm3TTI ? 'SUCCEEDED' : originalInteractionStatus;
27
+ return {
28
+ originalInteractionStatus,
29
+ overrideStatus
30
+ };
31
+ }
@@ -0,0 +1,8 @@
1
+ import { getPageVisibilityState } from '../../hidden-timing';
2
+ export default function getPageVisibilityUpToTTAI(interaction) {
3
+ const {
4
+ start,
5
+ end
6
+ } = interaction;
7
+ return getPageVisibilityState(start, end);
8
+ }
@@ -0,0 +1,5 @@
1
+ import * as ssr from '../../ssr';
2
+ export default function getSSRDoneTimeValue(config) {
3
+ var _config$ssr, _config$ssr2;
4
+ return config !== null && config !== void 0 && (_config$ssr = config.ssr) !== null && _config$ssr !== void 0 && _config$ssr.getSSRDoneTime ? config === null || config === void 0 ? void 0 : (_config$ssr2 = config.ssr) === null || _config$ssr2 === void 0 ? void 0 : _config$ssr2.getSSRDoneTime() : ssr.getSSRDoneTime();
5
+ }
@@ -0,0 +1,53 @@
1
+ import { fg } from '@atlaskit/platform-feature-flags';
2
+ import { getConfig } from '../../config';
3
+ import { postInteractionLog } from '../../interaction-metrics';
4
+ import { getVCObserver } from '../../vc';
5
+ import getInteractionStatus from './get-interaction-status';
6
+ import getPageVisibilityUpToTTAI from './get-page-visibility-up-to-ttai';
7
+ import getSSRDoneTimeValue from './get-ssr-done-time-value';
8
+ export default async function getVCMetrics(interaction) {
9
+ var _config$vc, _config$vc$ssrWhiteli, _interaction$apdex, _interaction$apdex$, _config$experimentalI;
10
+ const config = getConfig();
11
+ if (!(config !== null && config !== void 0 && (_config$vc = config.vc) !== null && _config$vc !== void 0 && _config$vc.enabled)) {
12
+ return {};
13
+ }
14
+ if (interaction.type !== 'page_load' && interaction.type !== 'transition') {
15
+ return {};
16
+ }
17
+ const interactionStatus = getInteractionStatus(interaction);
18
+ const pageVisibilityUpToTTAI = getPageVisibilityUpToTTAI(interaction);
19
+ if ((interactionStatus.originalInteractionStatus !== 'SUCCEEDED' || pageVisibilityUpToTTAI !== 'visible') && fg('platform_ufo_no_vc_on_aborted')) {
20
+ return {};
21
+ }
22
+ const isSSREnabled = (config === null || config === void 0 ? void 0 : config.ssr) || (config === null || config === void 0 ? void 0 : (_config$vc$ssrWhiteli = config.vc.ssrWhitelist) === null || _config$vc$ssrWhiteli === void 0 ? void 0 : _config$vc$ssrWhiteli.includes(interaction.ufoName));
23
+ const ssr = interaction.type === 'page_load' && isSSREnabled ? {
24
+ ssr: getSSRDoneTimeValue(config)
25
+ } : null;
26
+ postInteractionLog.setVCObserverSSRConfig(ssr);
27
+ const tti = (_interaction$apdex = interaction.apdex) === null || _interaction$apdex === void 0 ? void 0 : (_interaction$apdex$ = _interaction$apdex[0]) === null || _interaction$apdex$ === void 0 ? void 0 : _interaction$apdex$.stopTime;
28
+ const prefix = 'ufo';
29
+ const result = await getVCObserver().getVCResult({
30
+ start: interaction.start,
31
+ stop: interaction.end,
32
+ tti,
33
+ prefix,
34
+ vc: interaction.vc,
35
+ isEventAborted: interactionStatus.originalInteractionStatus !== 'SUCCEEDED',
36
+ ...ssr
37
+ });
38
+ if ((_config$experimentalI = config.experimentalInteractionMetrics) !== null && _config$experimentalI !== void 0 && _config$experimentalI.enabled) {
39
+ getVCObserver().stop();
40
+ }
41
+ postInteractionLog.setLastInteractionFinishVCResult(result);
42
+ const VC = result === null || result === void 0 ? void 0 : result['metrics:vc'];
43
+ if (!VC || !(result !== null && result !== void 0 && result[`${prefix}:vc:clean`])) {
44
+ return result;
45
+ }
46
+ if (interactionStatus.originalInteractionStatus !== 'SUCCEEDED' || pageVisibilityUpToTTAI !== 'visible') {
47
+ return result;
48
+ }
49
+ return {
50
+ ...result,
51
+ 'metric:vc90': VC['90']
52
+ };
53
+ }
@@ -28,17 +28,19 @@ function sinkInteraction(instance, payloadPackage) {
28
28
  function sinkExperimentalInteractionMetrics(instance, payloadPackage) {
29
29
  sinkExperimentalHandler((interactionId, interaction) => {
30
30
  scheduleCallback(idlePriority, () => {
31
- const payload = payloadPackage.createExperimentalMetricsPayload(interactionId, interaction);
32
- if (payload) {
33
- if (fg('enable_ufo_devtools_api_for_extra_events')) {
34
- // NOTE: This API is used by the UFO DevTool Chrome Extension and Criterion
35
- const devToolObserver = globalThis.__ufo_devtool_onUfoPayload;
36
- if (typeof devToolObserver === 'function') {
37
- devToolObserver === null || devToolObserver === void 0 ? void 0 : devToolObserver(payload);
31
+ const payloadPromise = payloadPackage.createExperimentalMetricsPayload(interactionId, interaction);
32
+ payloadPromise.then(payload => {
33
+ if (payload) {
34
+ if (fg('enable_ufo_devtools_api_for_extra_events')) {
35
+ // NOTE: This API is used by the UFO DevTool Chrome Extension and Criterion
36
+ const devToolObserver = globalThis.__ufo_devtool_onUfoPayload;
37
+ if (typeof devToolObserver === 'function') {
38
+ devToolObserver === null || devToolObserver === void 0 ? void 0 : devToolObserver(payload);
39
+ }
38
40
  }
41
+ instance.sendOperationalEvent(payload);
39
42
  }
40
- instance.sendOperationalEvent(payload);
41
- }
43
+ });
42
44
  });
43
45
  });
44
46
  }
@@ -1,11 +1,13 @@
1
1
  import { fg } from '@atlaskit/platform-feature-flags';
2
+ import { getConfig } from '../config';
2
3
  import { VCObserver } from './vc-observer';
3
4
  import VCObserverNew from './vc-observer-new';
4
5
  class VCObserverWrapper {
5
6
  constructor(opts = {}) {
7
+ var _getConfig, _getConfig$vc;
6
8
  this.oldVCObserver = new VCObserver(opts);
7
9
  this.newVCObserver = null;
8
- const isNewVCObserverEnabled = fg('platform_ufo_vc_observer_new');
10
+ const isNewVCObserverEnabled = fg('platform_ufo_vc_observer_new') || ((_getConfig = getConfig()) === null || _getConfig === void 0 ? void 0 : (_getConfig$vc = _getConfig.vc) === null || _getConfig$vc === void 0 ? void 0 : _getConfig$vc.enableVCObserverNew);
9
11
  if (isNewVCObserverEnabled) {
10
12
  this.newVCObserver = new VCObserverNew({
11
13
  selectorConfig: opts.selectorConfig
@@ -15,7 +17,9 @@ class VCObserverWrapper {
15
17
  start(startArg) {
16
18
  var _this$oldVCObserver, _this$newVCObserver;
17
19
  (_this$oldVCObserver = this.oldVCObserver) === null || _this$oldVCObserver === void 0 ? void 0 : _this$oldVCObserver.start(startArg);
18
- (_this$newVCObserver = this.newVCObserver) === null || _this$newVCObserver === void 0 ? void 0 : _this$newVCObserver.start();
20
+ (_this$newVCObserver = this.newVCObserver) === null || _this$newVCObserver === void 0 ? void 0 : _this$newVCObserver.start({
21
+ startTime: startArg.startTime
22
+ });
19
23
  }
20
24
  stop() {
21
25
  var _this$oldVCObserver2, _this$newVCObserver2;
@@ -4,7 +4,15 @@ function getAttributeSelector(element, attributeName) {
4
4
  if (!attrValue) {
5
5
  return '';
6
6
  }
7
- return `[${attributeName}="${encodeURIComponent(attrValue)}"]`;
7
+ return `[${attributeName}="${attrValue}"]`;
8
+ }
9
+ function isValidSelector(selector) {
10
+ try {
11
+ document.querySelector(selector);
12
+ return true;
13
+ } catch (err) {
14
+ return false;
15
+ }
8
16
  }
9
17
  function isSelectorUnique(selector) {
10
18
  return document.querySelectorAll(selector).length === 1;
@@ -12,11 +20,13 @@ function isSelectorUnique(selector) {
12
20
  function getUniqueSelector(selectorConfig, element) {
13
21
  let currentElement = element;
14
22
  const parts = [];
15
- while (currentElement && currentElement.localName !== 'body') {
23
+ const MAX_DEPTH = 3;
24
+ let currentDepth = 0;
25
+ while (currentElement && currentElement.localName !== 'body' && currentDepth <= MAX_DEPTH) {
16
26
  const tagName = currentElement.localName;
17
27
  let selectorPart = tagName;
18
- if (selectorConfig.id && currentElement.id) {
19
- selectorPart += `#${encodeURIComponent(currentElement.id)}`;
28
+ if (selectorConfig.id && currentElement.id && isValidSelector(`#${currentElement.id}`)) {
29
+ selectorPart += `#${currentElement.id}`;
20
30
  } else if (selectorConfig.dataVC) {
21
31
  selectorPart += getAttributeSelector(currentElement, 'data-vc');
22
32
  } else if (selectorConfig.testId) {
@@ -24,9 +34,11 @@ function getUniqueSelector(selectorConfig, element) {
24
34
  } else if (selectorConfig.role) {
25
35
  selectorPart += getAttributeSelector(currentElement, 'role');
26
36
  } else if (selectorConfig.className && currentElement.className) {
27
- const classNames = Array.from(currentElement.classList).map(encodeURIComponent).join('.');
37
+ const classNames = Array.from(currentElement.classList).join('.');
28
38
  if (classNames) {
29
- selectorPart += `.${classNames}`;
39
+ if (isValidSelector(`.${classNames}`)) {
40
+ selectorPart += `.${classNames}`;
41
+ }
30
42
  }
31
43
  }
32
44
  parts.unshift(selectorPart);
@@ -35,6 +47,7 @@ function getUniqueSelector(selectorConfig, element) {
35
47
  return potentialSelector;
36
48
  }
37
49
  currentElement = currentElement.parentElement;
50
+ currentDepth++;
38
51
  }
39
52
  const potentialSelector = parts.join(' > ').trim();
40
53
  if (!potentialSelector) {
@@ -14,7 +14,6 @@ const DEFAULT_SELECTOR_CONFIG = {
14
14
  export default class VCObserverNew {
15
15
  constructor(config) {
16
16
  var _config$selectorConfi;
17
- _defineProperty(this, "startTime", 0);
18
17
  _defineProperty(this, "viewportObserver", null);
19
18
  _defineProperty(this, "windowEventObserver", null);
20
19
  this.entriesTimeline = new EntriesTimeline();
@@ -63,10 +62,13 @@ export default class VCObserverNew {
63
62
  }
64
63
  });
65
64
  }
66
- start() {
65
+ start({
66
+ startTime
67
+ }) {
67
68
  var _this$viewportObserve, _this$windowEventObse;
68
69
  (_this$viewportObserve = this.viewportObserver) === null || _this$viewportObserve === void 0 ? void 0 : _this$viewportObserve.start();
69
70
  (_this$windowEventObse = this.windowEventObserver) === null || _this$windowEventObse === void 0 ? void 0 : _this$windowEventObse.start();
71
+ this.entriesTimeline.clear();
70
72
  }
71
73
  stop() {
72
74
  var _this$viewportObserve2, _this$windowEventObse2;
@@ -85,7 +87,9 @@ export default class VCObserverNew {
85
87
  stop
86
88
  });
87
89
  const fy25_03 = await calculator_fy25_03.calculate({
88
- orderedEntries
90
+ orderedEntries,
91
+ startTime: start,
92
+ stopTime: stop
89
93
  });
90
94
  if (fy25_03) {
91
95
  results.push(fy25_03);
@@ -6,6 +6,8 @@ export default class AbstractVCCalculatorBase {
6
6
  this.revisionNo = revisionNo;
7
7
  }
8
8
  async calculate({
9
+ startTime,
10
+ stopTime,
9
11
  orderedEntries
10
12
  }) {
11
13
  var _vcDetails$90$t, _vcDetails$;
@@ -25,6 +27,8 @@ export default class AbstractVCCalculatorBase {
25
27
  width: getViewportWidth(),
26
28
  height: getViewportHeight()
27
29
  },
30
+ startTime,
31
+ stopTime,
28
32
  orderedEntries: filteredEntries,
29
33
  percentiles: [25, 50, 75, 80, 85, 90, 95, 98, 99]
30
34
  });
@@ -172,7 +172,6 @@ export function getRGBComponents(n) {
172
172
  */
173
173
  export async function calculateDrawnPixelsRaw(imageData, scaleFactor, arraySize) {
174
174
  const data = imageData.data;
175
- const scaleCompensation = Math.round(1 / (scaleFactor * scaleFactor));
176
175
  const arr = new Uint32Array(arraySize);
177
176
  for (let i = 0; i < data.length; i += 4) {
178
177
  // Check alpha
@@ -184,7 +183,7 @@ export async function calculateDrawnPixelsRaw(imageData, scaleFactor, arraySize)
184
183
  // The | operator combines all bits together
185
184
  const color = data[i] << 16 | data[i + 1] << 8 | data[i + 2];
186
185
  const colorIndex = color - 1;
187
- arr[colorIndex] = (arr[colorIndex] || 0) + scaleCompensation;
186
+ arr[colorIndex] = (arr[colorIndex] || 0) + 1;
188
187
  }
189
188
  if (i % 10000 === 0) {
190
189
  await taskYield();
@@ -3,7 +3,8 @@ import { ViewportCanvas } from './canvas-pixel';
3
3
  export default async function calculateTTVCPercentiles({
4
4
  viewport,
5
5
  orderedEntries,
6
- percentiles
6
+ percentiles,
7
+ startTime
7
8
  }) {
8
9
  const canvas = new ViewportCanvas(viewport, fg('platform_ufo_canvas_heatmap_full_precision') ? 1 : 0.25);
9
10
  const elementMap = new Map();
@@ -22,10 +23,11 @@ export default async function calculateTTVCPercentiles({
22
23
 
23
24
  // Get pixel counts
24
25
  const timePixelCounts = await canvas.getPixelCounts();
25
- const viewportTotalPixels = viewport.width * viewport.height;
26
- return calculatePercentiles(timePixelCounts, elementMap, percentiles, viewportTotalPixels);
26
+ const canvasDimenstions = canvas.getScaledDimensions();
27
+ const totalPixels = canvasDimenstions.width * canvasDimenstions.height;
28
+ return calculatePercentiles(timePixelCounts, elementMap, percentiles, totalPixels, startTime);
27
29
  }
28
- export function calculatePercentiles(timePixelCounts, elementMap, unorderedPercentiles, totalPixels) {
30
+ export function calculatePercentiles(timePixelCounts, elementMap, unorderedPercentiles, totalPixels, startTime) {
29
31
  const results = {};
30
32
  let cumulativePixels = 0;
31
33
  const percentiles = unorderedPercentiles.sort((a, b) => a - b);
@@ -42,7 +44,7 @@ export function calculatePercentiles(timePixelCounts, elementMap, unorderedPerce
42
44
  let matchesAnyCheckpoints = false;
43
45
  while (percentileIndex < percentiles.length && percentCovered >= percentiles[percentileIndex]) {
44
46
  results[`${percentiles[percentileIndex]}`] = {
45
- t: Number(time),
47
+ t: Math.round(Number(time - startTime)),
46
48
  e: Array.from(domElementsBuffer)
47
49
  };
48
50
  percentileIndex++;
@@ -55,15 +57,16 @@ export function calculatePercentiles(timePixelCounts, elementMap, unorderedPerce
55
57
  break;
56
58
  }
57
59
  }
58
-
59
- // Fill in any missing percentiles
60
- for (const percentile of percentiles) {
60
+ let previousResult = {
61
+ t: 0,
62
+ e: []
63
+ };
64
+ for (let i = 0; i < percentiles.length; i++) {
65
+ const percentile = percentiles[i];
61
66
  if (!(percentile in results)) {
62
- results[`${percentile}`] = {
63
- t: 0,
64
- e: []
65
- };
67
+ results[`${percentile}`] = previousResult;
66
68
  }
69
+ previousResult = results[`${percentile}`];
67
70
  }
68
71
  return results;
69
72
  }
@@ -175,7 +175,7 @@ class Heatmap {
175
175
  }
176
176
  }
177
177
  }
178
- async getVCPercentMetrics(vcPercentCheckpoint) {
178
+ async getVCPercentMetrics(vcPercentCheckpoint, startTime) {
179
179
  const sortedCheckpoints = [...vcPercentCheckpoint].sort((a, b) => a - b);
180
180
  const flattenHeatmap = this.map.flat();
181
181
  const totalCells = flattenHeatmap.length;
@@ -232,7 +232,7 @@ class Heatmap {
232
232
  }
233
233
  matchesAnyCheckpoints = true;
234
234
  result[checkpoint.toString()] = {
235
- t: timestamp,
235
+ t: Math.round(timestamp - startTime),
236
236
  e: domElements
237
237
  };
238
238
  }
@@ -249,13 +249,14 @@ class Heatmap {
249
249
  export default async function calculateTTVCPercentiles({
250
250
  orderedEntries,
251
251
  viewport,
252
- percentiles
252
+ percentiles,
253
+ startTime
253
254
  }) {
254
255
  const heatmap = new Heatmap({
255
256
  viewport,
256
257
  heatmapSize: 200
257
258
  });
258
259
  await heatmap.applyEntriesToHeatmap(orderedEntries);
259
- const vcDetails = await heatmap.getVCPercentMetrics(percentiles);
260
+ const vcDetails = await heatmap.getVCPercentMetrics(percentiles, startTime);
260
261
  return vcDetails;
261
262
  }
@@ -4,7 +4,8 @@ import calculateUnionArea from './calc-union-area';
4
4
  export default async function calculateTTVCPercentiles({
5
5
  orderedEntries,
6
6
  viewport,
7
- percentiles
7
+ percentiles,
8
+ startTime
8
9
  }) {
9
10
  const sortedPercentiles = [...percentiles].sort((a, b) => a - b);
10
11
  const viewportArea = viewport.width * viewport.height;
@@ -43,7 +44,7 @@ export default async function calculateTTVCPercentiles({
43
44
  }
44
45
  matchesAnyCheckpoints = true;
45
46
  checkpoints[checkpoint.toString()] = {
46
- t: iEntry.time,
47
+ t: Math.round(iEntry.time - startTime),
47
48
  e: domElements
48
49
  };
49
50
  }
@@ -9,6 +9,9 @@ export default class WindowEventObserver {
9
9
  const unbindCallback = bind(window, {
10
10
  type,
11
11
  listener: event => {
12
+ if (!event.isTrusted) {
13
+ return;
14
+ }
12
15
  this.onEvent({
13
16
  time: event.timeStamp,
14
17
  type,
@@ -16,7 +19,8 @@ export default class WindowEventObserver {
16
19
  });
17
20
  },
18
21
  options: {
19
- passive: true
22
+ passive: true,
23
+ once: true
20
24
  }
21
25
  });
22
26
  this.unbindFns.push(unbindCallback);