@atlaskit/react-ufo 4.6.0 → 4.6.2

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 (29) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/create-post-interaction-log-payload/get-late-mutations.js +15 -3
  3. package/dist/cjs/create-post-interaction-log-payload/index.js +2 -1
  4. package/dist/cjs/hidden-timing/index.js +11 -7
  5. package/dist/cjs/vc/vc-observer-new/index.js +74 -11
  6. package/dist/cjs/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +101 -60
  7. package/dist/es2019/create-post-interaction-log-payload/get-late-mutations.js +12 -3
  8. package/dist/es2019/create-post-interaction-log-payload/index.js +2 -1
  9. package/dist/es2019/hidden-timing/index.js +11 -7
  10. package/dist/es2019/vc/vc-observer-new/index.js +67 -10
  11. package/dist/es2019/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +42 -11
  12. package/dist/esm/create-post-interaction-log-payload/get-late-mutations.js +15 -3
  13. package/dist/esm/create-post-interaction-log-payload/index.js +2 -1
  14. package/dist/esm/hidden-timing/index.js +11 -7
  15. package/dist/esm/vc/vc-observer-new/index.js +74 -11
  16. package/dist/esm/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +101 -60
  17. package/dist/types/common/react-ufo-payload-schema.d.ts +2 -0
  18. package/dist/types/common/vc/types.d.ts +7 -0
  19. package/dist/types/create-post-interaction-log-payload/get-late-mutations.d.ts +2 -2
  20. package/dist/types/vc/vc-observer/getVCRevisionDebugDetails.d.ts +1 -1
  21. package/dist/types/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +1 -0
  22. package/dist/types/vc/vc-observer-new/types.d.ts +5 -0
  23. package/dist/types-ts4.5/common/react-ufo-payload-schema.d.ts +2 -0
  24. package/dist/types-ts4.5/common/vc/types.d.ts +7 -0
  25. package/dist/types-ts4.5/create-post-interaction-log-payload/get-late-mutations.d.ts +2 -2
  26. package/dist/types-ts4.5/vc/vc-observer/getVCRevisionDebugDetails.d.ts +1 -1
  27. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +1 -0
  28. package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +5 -0
  29. package/package.json +7 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/ufo-interaction-ignore
2
2
 
3
+ ## 4.6.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`4dd6789885500`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/4dd6789885500) -
8
+ Fix unhandled hidden timing error
9
+ - [`25fbcd6f57e2f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/25fbcd6f57e2f) -
10
+ clean up fg
11
+
12
+ ## 4.6.1
13
+
14
+ ### Patch Changes
15
+
16
+ - [`a308f1abf3cf2`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a308f1abf3cf2) -
17
+ unify abort status within TTVC debug data
18
+
3
19
  ## 4.6.0
4
20
 
5
21
  ### Minor Changes
@@ -4,10 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
7
8
  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; } } }; }
8
9
  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; } }
9
10
  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; }
10
- function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios) {
11
+ function getLateMutations(vcDetails) {
12
+ var labelStacks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
13
+ var lastInteractionFinish = arguments.length > 2 ? arguments[2] : undefined;
14
+ var postInteractionFinishVCRatios = arguments.length > 3 ? arguments[3] : undefined;
11
15
  // Map to track which elements are already seen for each timestamp
12
16
  var seen = new Map();
13
17
  var result = [];
@@ -29,11 +33,19 @@ function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinis
29
33
  continue;
30
34
  }
31
35
  seenElements.add(element);
32
- result.push({
36
+ var lateMutation = {
33
37
  time: details.t,
34
38
  element: element,
35
39
  viewportHeatmapPercentage: (postInteractionFinishVCRatios === null || postInteractionFinishVCRatios === void 0 ? void 0 : postInteractionFinishVCRatios[element]) || 0
36
- });
40
+ };
41
+ if (labelStacks && (0, _platformFeatureFlags.fg)('platform_ufo_enable_late_mutation_label_stacks')) {
42
+ var labels = labelStacks[element];
43
+ if (labels) {
44
+ lateMutation.segment = labels.segment;
45
+ lateMutation.labelStack = labels.labelStack;
46
+ }
47
+ }
48
+ result.push(lateMutation);
37
49
  }
38
50
  } catch (err) {
39
51
  _iterator.e(err);
@@ -190,8 +190,9 @@ function createPostInteractionLogPayload(_ref2) {
190
190
  revisedVC90 = (_postInteractionFinis = postInteractionFinishRevision['metric:vc90']) !== null && _postInteractionFinis !== void 0 ? _postInteractionFinis : null;
191
191
  }
192
192
  var vcDetails = postInteractionFinishRevision.vcDetails;
193
+ var labelStacks = postInteractionFinishRevision.labelStacks;
193
194
  if (vcDetails) {
194
- lateMutations = (0, _getLateMutations.default)(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios);
195
+ lateMutations = (0, _getLateMutations.default)(vcDetails, labelStacks, lastInteractionFinish, postInteractionFinishVCRatios);
195
196
  }
196
197
  }
197
198
  return {
@@ -64,6 +64,11 @@ function setupHiddenTimingCapture() {
64
64
  }
65
65
  }
66
66
  function getPageVisibilityState(start, end) {
67
+ // Input validation - return default for invalid inputs
68
+ if (!Number.isFinite(start) || !Number.isFinite(end)) {
69
+ return 'visible';
70
+ }
71
+
67
72
  // Desirable default value is visible
68
73
  if (timings.length === 0) {
69
74
  return 'visible';
@@ -76,19 +81,18 @@ function getPageVisibilityState(start, end) {
76
81
  // currentSize is capped at SIZE.
77
82
  for (var i = 0; i < currentSize; i++) {
78
83
  var tmpIdx = (insertIndex + i) % currentSize;
79
- if (timings[tmpIdx].time <= end) {
84
+ // Add bounds checking before accessing array element
85
+ if (timings[tmpIdx] && timings[tmpIdx].time <= end) {
80
86
  endIdx = tmpIdx;
81
87
  if (timings[tmpIdx].time <= start) {
82
88
  startIdx = tmpIdx;
83
89
  }
84
90
  }
85
91
  }
86
- if (endIdx - startIdx === 0) {
87
- if (timings[startIdx].hidden) {
88
- hiddenState = 'hidden';
89
- } else {
90
- hiddenState = 'visible';
91
- }
92
+
93
+ // Add bounds checking before accessing timings array
94
+ if (endIdx - startIdx === 0 && timings[startIdx]) {
95
+ hiddenState = timings[startIdx].hidden ? 'hidden' : 'visible';
92
96
  }
93
97
  return hiddenState;
94
98
  }
@@ -12,6 +12,7 @@ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
12
12
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
13
13
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
14
14
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
15
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
15
16
  var _ssrPlaceholders = require("../vc-observer/observers/ssr-placeholders");
16
17
  var _entriesTimeline = _interopRequireDefault(require("./entries-timeline"));
17
18
  var _getElementName2 = _interopRequireDefault(require("./get-element-name"));
@@ -75,18 +76,27 @@ var VCObserverNew = exports.default = /*#__PURE__*/function () {
75
76
  if (element) {
76
77
  elementName = _this.getElementName(element);
77
78
  }
79
+ var data = {
80
+ type: type,
81
+ elementName: elementName,
82
+ rect: rect,
83
+ previousRect: previousRect,
84
+ visible: visible,
85
+ attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
86
+ oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
87
+ newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
88
+ };
89
+ if (element && _this.isPostInteraction && (0, _platformFeatureFlags.fg)('platform_ufo_enable_late_mutation_label_stacks')) {
90
+ var labelStacks = getLabelStacks(element);
91
+ if (labelStacks) {
92
+ Object.assign(data, {
93
+ labelStacks: labelStacks
94
+ });
95
+ }
96
+ }
78
97
  _this.entriesTimeline.push({
79
98
  time: time,
80
- data: {
81
- type: type,
82
- elementName: elementName,
83
- rect: rect,
84
- previousRect: previousRect,
85
- visible: visible,
86
- attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
87
- oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
88
- newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
89
- }
99
+ data: data
90
100
  });
91
101
  },
92
102
  // Pass SSR context to ViewportObserver
@@ -308,4 +318,57 @@ var VCObserverNew = exports.default = /*#__PURE__*/function () {
308
318
  return (0, _getElementName2.default)(this.selectorConfig, element);
309
319
  }
310
320
  }]);
311
- }();
321
+ }();
322
+ function labelStackFromFiber(fiber) {
323
+ var _fiber$child;
324
+ var value = fiber === null || fiber === void 0 || (_fiber$child = fiber.child) === null || _fiber$child === void 0 || (_fiber$child = _fiber$child.memoizedProps) === null || _fiber$child === void 0 ? void 0 : _fiber$child.value;
325
+ return Array.isArray(value === null || value === void 0 ? void 0 : value.labelStack) ? value.labelStack : [];
326
+ }
327
+ function labelStackToString(labelStack) {
328
+ return labelStack.map(function (label) {
329
+ return label.name;
330
+ }).join('/');
331
+ }
332
+ function labelStackToSegment(labelStack) {
333
+ var segmentIndex = -1;
334
+ for (var i = labelStack.length - 1; i >= 0; i--) {
335
+ if (labelStack[i].segmentId) {
336
+ segmentIndex = i;
337
+ break;
338
+ }
339
+ }
340
+ return labelStack.slice(0, segmentIndex + 1).map(function (label) {
341
+ return label.name;
342
+ }).join('/');
343
+ }
344
+ function traverseFiber(fiber) {
345
+ var segment = 'unknown';
346
+ var labelStackString = 'unknown';
347
+ var currentFiber = fiber;
348
+ while (currentFiber) {
349
+ if (currentFiber.type) {
350
+ var componentName = currentFiber.type.displayName || currentFiber.type.name;
351
+ if (componentName === 'UFOSegment' || componentName === 'UFOLabel') {
352
+ var labelStack = labelStackFromFiber(currentFiber);
353
+ labelStackString = labelStackToString(labelStack) || 'unknown';
354
+ segment = labelStackToSegment(labelStack) || 'unknown';
355
+ break;
356
+ }
357
+ }
358
+ currentFiber = currentFiber.return;
359
+ }
360
+ return {
361
+ segment: segment,
362
+ labelStack: labelStackString
363
+ };
364
+ }
365
+ function getLabelStacks(element) {
366
+ var reactFiberKey = Object.keys(element).find(function (key) {
367
+ return key.startsWith('__reactFiber$');
368
+ });
369
+ if (!reactFiberKey) {
370
+ return null;
371
+ }
372
+ var fiber = element[reactFiberKey];
373
+ return fiber ? traverseFiber(fiber) : null;
374
+ }
@@ -13,6 +13,9 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
13
13
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
14
14
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
15
15
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
16
+ var _getPageVisibilityUpToTtai = _interopRequireDefault(require("../../../create-payload/utils/get-page-visibility-up-to-ttai"));
17
+ var _interactionIdContext = require("../../../interaction-id-context");
18
+ var _constants = require("../../../interaction-metrics/common/constants");
16
19
  var _trackDisplayContentOccurrence = require("../viewport-observer/utils/track-display-content-occurrence");
17
20
  var _percentileCalc = require("./percentile-calc");
18
21
  var _getViewportHeight = _interopRequireDefault(require("./utils/get-viewport-height"));
@@ -82,21 +85,41 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
82
85
  }
83
86
  return ratios;
84
87
  }
88
+ }, {
89
+ key: "getLabelStacks",
90
+ value: function getLabelStacks(filteredEntries) {
91
+ var labelStacks = {};
92
+ var _iterator3 = _createForOfIteratorHelper(filteredEntries),
93
+ _step3;
94
+ try {
95
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
96
+ var _entry2 = _step3.value;
97
+ if ('elementName' in _entry2.data && _entry2.data.labelStacks) {
98
+ labelStacks[_entry2.data.elementName] = {
99
+ segment: _entry2.data.labelStacks.segment,
100
+ labelStack: _entry2.data.labelStacks.labelStack
101
+ };
102
+ }
103
+ }
104
+ } catch (err) {
105
+ _iterator3.e(err);
106
+ } finally {
107
+ _iterator3.f();
108
+ }
109
+ return labelStacks;
110
+ }
85
111
  }, {
86
112
  key: "calculateWithDebugInfo",
87
113
  value: function () {
88
114
  var _calculateWithDebugInfo = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason, allEntries, include3p) {
89
115
  var _window, _window2, _window3, _window5;
90
- var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, _iterator3, _step3, _entry2, time, viewportPercentage, entries, elementNames, previousResult, i, percentile, enhancedVcLogs, shouldCalculate3p, shouldCalculateDebugDetails, sortedVcLogs, maxViewportPercentageAtTime, maxSoFar, _iterator4, _step4, log, getBiggestPreviousViewportPercentage, ignoredEntriesByTime, _iterator5, _step5, _entry3, _ignoredEntriesByTime, _viewportData$rect, _viewportData$previou, viewportData, timestamp, additionalVcLogs, _iterator6, _step6, _step6$value, _timestamp, ignoredEntries, _viewportPercentage, v3RevisionDebugDetails, _window4, _window4$__ufo_devtoo, _window6, _window6$__on_ufo_vc_;
116
+ var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, _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, _activeInteractionId$, activeInteractionId, activeInteraction, pageVisibilityUpToTTAI, isBackgrounded, _window4, _window4$__ufo_devtoo, _window6, _window6$__on_ufo_vc_;
91
117
  return _regenerator.default.wrap(function _callee$(_context) {
92
118
  while (1) switch (_context.prev = _context.next) {
93
119
  case 0:
94
- percentiles = [25, 50, 75, 80, 85, 90, 95, 98, 99];
95
- if ((0, _platformFeatureFlags.fg)('platform_ufo_send_vc_100')) {
96
- percentiles.push(100);
97
- }
120
+ percentiles = [25, 50, 75, 80, 85, 90, 95, 98, 99, 100];
98
121
  viewportEntries = this.filterViewportEntries(filteredEntries);
99
- _context.next = 5;
122
+ _context.next = 4;
100
123
  return (0, _percentileCalc.calculateTTVCPercentilesWithDebugInfo)({
101
124
  viewport: {
102
125
  width: (0, _getViewportWidth.default)(),
@@ -106,31 +129,31 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
106
129
  stopTime: stopTime,
107
130
  orderedEntries: viewportEntries
108
131
  });
109
- case 5:
132
+ case 4:
110
133
  vcLogs = _context.sent;
111
134
  vcDetails = {};
112
135
  percentileIndex = 0;
113
136
  entryDataBuffer = new Set();
114
137
  if (!vcLogs) {
115
- _context.next = 29;
138
+ _context.next = 28;
116
139
  break;
117
140
  }
118
- _iterator3 = _createForOfIteratorHelper(vcLogs);
119
- _context.prev = 11;
120
- _iterator3.s();
121
- case 13:
122
- if ((_step3 = _iterator3.n()).done) {
123
- _context.next = 21;
141
+ _iterator4 = _createForOfIteratorHelper(vcLogs);
142
+ _context.prev = 10;
143
+ _iterator4.s();
144
+ case 12:
145
+ if ((_step4 = _iterator4.n()).done) {
146
+ _context.next = 20;
124
147
  break;
125
148
  }
126
- _entry2 = _step3.value;
127
- time = _entry2.time, viewportPercentage = _entry2.viewportPercentage, entries = _entry2.entries; // Only process entries if we haven't reached all percentiles
149
+ _entry3 = _step4.value;
150
+ time = _entry3.time, viewportPercentage = _entry3.viewportPercentage, entries = _entry3.entries; // Only process entries if we haven't reached all percentiles
128
151
  if (!(percentileIndex >= percentiles.length)) {
129
- _context.next = 18;
152
+ _context.next = 17;
130
153
  break;
131
154
  }
132
- return _context.abrupt("break", 21);
133
- case 18:
155
+ return _context.abrupt("break", 20);
156
+ case 17:
134
157
  // Check if this entry matches any checkpoint percentiles
135
158
  if (viewportPercentage >= percentiles[percentileIndex]) {
136
159
  elementNames = entries.map(function (e) {
@@ -152,21 +175,21 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
152
175
  return entryDataBuffer.add(e);
153
176
  });
154
177
  }
155
- case 19:
156
- _context.next = 13;
178
+ case 18:
179
+ _context.next = 12;
157
180
  break;
158
- case 21:
159
- _context.next = 26;
181
+ case 20:
182
+ _context.next = 25;
160
183
  break;
161
- case 23:
162
- _context.prev = 23;
163
- _context.t0 = _context["catch"](11);
164
- _iterator3.e(_context.t0);
165
- case 26:
166
- _context.prev = 26;
167
- _iterator3.f();
168
- return _context.finish(26);
169
- case 29:
184
+ case 22:
185
+ _context.prev = 22;
186
+ _context.t0 = _context["catch"](10);
187
+ _iterator4.e(_context.t0);
188
+ case 25:
189
+ _context.prev = 25;
190
+ _iterator4.f();
191
+ return _context.finish(25);
192
+ case 28:
170
193
  // Fill in any missing percentiles with the last known values
171
194
  previousResult = {
172
195
  t: 0,
@@ -202,10 +225,10 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
202
225
  }); // Pre-calculate max viewport percentage up to each time for efficient lookups
203
226
  maxViewportPercentageAtTime = new Map();
204
227
  maxSoFar = 0;
205
- _iterator4 = _createForOfIteratorHelper(sortedVcLogs);
228
+ _iterator5 = _createForOfIteratorHelper(sortedVcLogs);
206
229
  try {
207
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
208
- log = _step4.value;
230
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
231
+ log = _step5.value;
209
232
  if (log.viewportPercentage !== null) {
210
233
  maxSoFar = Math.max(maxSoFar, log.viewportPercentage);
211
234
  maxViewportPercentageAtTime.set(log.time, maxSoFar);
@@ -214,9 +237,9 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
214
237
 
215
238
  // Helper function to find the biggest previous viewport percentage
216
239
  } catch (err) {
217
- _iterator4.e(err);
240
+ _iterator5.e(err);
218
241
  } finally {
219
- _iterator4.f();
242
+ _iterator5.f();
220
243
  }
221
244
  getBiggestPreviousViewportPercentage = function getBiggestPreviousViewportPercentage(targetTime) {
222
245
  // Binary search for the largest time <= targetTime
@@ -235,13 +258,13 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
235
258
  return result >= 0 ? maxViewportPercentageAtTime.get(sortedVcLogs[result].time) || null : null;
236
259
  }; // Group ignored entries by timestamp
237
260
  ignoredEntriesByTime = new Map();
238
- _iterator5 = _createForOfIteratorHelper(allEntries);
261
+ _iterator6 = _createForOfIteratorHelper(allEntries);
239
262
  try {
240
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
241
- _entry3 = _step5.value;
242
- if ('rect' in _entry3.data && !this.isEntryIncluded(_entry3, include3p)) {
243
- viewportData = _entry3.data;
244
- timestamp = Math.round(_entry3.time);
263
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
264
+ _entry4 = _step6.value;
265
+ if ('rect' in _entry4.data && !this.isEntryIncluded(_entry4, include3p)) {
266
+ viewportData = _entry4.data;
267
+ timestamp = Math.round(_entry4.time);
245
268
  if (!ignoredEntriesByTime.has(timestamp)) {
246
269
  ignoredEntriesByTime.set(timestamp, []);
247
270
  }
@@ -256,15 +279,15 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
256
279
 
257
280
  // Add ignored entries to vcLogs
258
281
  } catch (err) {
259
- _iterator5.e(err);
282
+ _iterator6.e(err);
260
283
  } finally {
261
- _iterator5.f();
284
+ _iterator6.f();
262
285
  }
263
286
  additionalVcLogs = [];
264
- _iterator6 = _createForOfIteratorHelper(ignoredEntriesByTime);
287
+ _iterator7 = _createForOfIteratorHelper(ignoredEntriesByTime);
265
288
  try {
266
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
267
- _step6$value = (0, _slicedToArray2.default)(_step6.value, 2), _timestamp = _step6$value[0], ignoredEntries = _step6$value[1];
289
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
290
+ _step7$value = (0, _slicedToArray2.default)(_step7.value, 2), _timestamp = _step7$value[0], ignoredEntries = _step7$value[1];
268
291
  if (ignoredEntries.length > 0) {
269
292
  _viewportPercentage = getBiggestPreviousViewportPercentage(_timestamp);
270
293
  additionalVcLogs.push({
@@ -277,9 +300,9 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
277
300
 
278
301
  // Combine and sort all vcLogs
279
302
  } catch (err) {
280
- _iterator6.e(err);
303
+ _iterator7.e(err);
281
304
  } finally {
282
- _iterator6.f();
305
+ _iterator7.f();
283
306
  }
284
307
  enhancedVcLogs = [].concat((0, _toConsumableArray2.default)(enhancedVcLogs), additionalVcLogs).sort(function (a, b) {
285
308
  return a.time - b.time;
@@ -289,13 +312,28 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
289
312
  // Only create debug details if callbacks exist
290
313
  v3RevisionDebugDetails = null;
291
314
  if (shouldCalculateDebugDetails) {
292
- v3RevisionDebugDetails = {
293
- revision: this.revisionNo,
294
- isClean: isVCClean,
295
- abortReason: dirtyReason,
296
- vcLogs: enhancedVcLogs,
297
- interactionId: interactionId
298
- };
315
+ if ((0, _platformFeatureFlags.fg)('platform_ufo_unify_abort_status_in_ttvc_debug_data')) {
316
+ // NOTE: using this instead of directly calling `getActiveInteraction()` to get around circular dependencies
317
+ activeInteractionId = (0, _interactionIdContext.getInteractionId)();
318
+ activeInteraction = _constants.interactions.get((_activeInteractionId$ = activeInteractionId.current) !== null && _activeInteractionId$ !== void 0 ? _activeInteractionId$ : '');
319
+ pageVisibilityUpToTTAI = activeInteraction ? (0, _getPageVisibilityUpToTtai.default)(activeInteraction) : null;
320
+ isBackgrounded = pageVisibilityUpToTTAI !== 'visible';
321
+ v3RevisionDebugDetails = {
322
+ revision: this.revisionNo,
323
+ isClean: isVCClean && !(activeInteraction !== null && activeInteraction !== void 0 && activeInteraction.abortReason) && !isBackgrounded,
324
+ abortReason: isBackgrounded ? 'browser_backgrounded' : dirtyReason !== null && dirtyReason !== void 0 ? dirtyReason : activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.abortReason,
325
+ vcLogs: enhancedVcLogs,
326
+ interactionId: interactionId
327
+ };
328
+ } else {
329
+ v3RevisionDebugDetails = {
330
+ revision: this.revisionNo,
331
+ isClean: isVCClean,
332
+ abortReason: dirtyReason,
333
+ vcLogs: enhancedVcLogs,
334
+ interactionId: interactionId
335
+ };
336
+ }
299
337
  }
300
338
 
301
339
  // Handle devtool callback
@@ -326,11 +364,11 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
326
364
  }
327
365
  }
328
366
  return _context.abrupt("return", vcDetails);
329
- case 41:
367
+ case 40:
330
368
  case "end":
331
369
  return _context.stop();
332
370
  }
333
- }, _callee, this, [[11, 23, 26, 29]]);
371
+ }, _callee, this, [[10, 22, 25, 28]]);
334
372
  }));
335
373
  function calculateWithDebugInfo(_x, _x2, _x3, _x4, _x5, _x6, _x7, _x8, _x9) {
336
374
  return _calculateWithDebugInfo.apply(this, arguments);
@@ -379,11 +417,14 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
379
417
  vcDetails: vcDetails !== null && vcDetails !== void 0 ? vcDetails : undefined
380
418
  };
381
419
  result.ratios = this.calculateRatios(filteredEntries);
420
+ if (isPostInteraction) {
421
+ result.labelStacks = this.getLabelStacks(filteredEntries);
422
+ }
382
423
  if ((0, _platformFeatureFlags.fg)('platform_ufo_display_content_track_occurrence')) {
383
424
  result.displayContentsOccurrence = _trackDisplayContentOccurrence.cssIssueOccurrence;
384
425
  }
385
426
  return _context2.abrupt("return", result);
386
- case 14:
427
+ case 15:
387
428
  case "end":
388
429
  return _context2.stop();
389
430
  }
@@ -1,4 +1,5 @@
1
- function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios) {
1
+ import { fg } from '@atlaskit/platform-feature-flags';
2
+ function getLateMutations(vcDetails, labelStacks = {}, lastInteractionFinish, postInteractionFinishVCRatios) {
2
3
  // Map to track which elements are already seen for each timestamp
3
4
  const seen = new Map();
4
5
  const result = [];
@@ -16,11 +17,19 @@ function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinis
16
17
  continue;
17
18
  }
18
19
  seenElements.add(element);
19
- result.push({
20
+ const lateMutation = {
20
21
  time: details.t,
21
22
  element,
22
23
  viewportHeatmapPercentage: (postInteractionFinishVCRatios === null || postInteractionFinishVCRatios === void 0 ? void 0 : postInteractionFinishVCRatios[element]) || 0
23
- });
24
+ };
25
+ if (labelStacks && fg('platform_ufo_enable_late_mutation_label_stacks')) {
26
+ const labels = labelStacks[element];
27
+ if (labels) {
28
+ lateMutation.segment = labels.segment;
29
+ lateMutation.labelStack = labels.labelStack;
30
+ }
31
+ }
32
+ result.push(lateMutation);
24
33
  }
25
34
  }
26
35
  return result;
@@ -173,8 +173,9 @@ function createPostInteractionLogPayload({
173
173
  revisedVC90 = (_postInteractionFinis = postInteractionFinishRevision['metric:vc90']) !== null && _postInteractionFinis !== void 0 ? _postInteractionFinis : null;
174
174
  }
175
175
  const vcDetails = postInteractionFinishRevision.vcDetails;
176
+ const labelStacks = postInteractionFinishRevision.labelStacks;
176
177
  if (vcDetails) {
177
- lateMutations = getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios);
178
+ lateMutations = getLateMutations(vcDetails, labelStacks, lastInteractionFinish, postInteractionFinishVCRatios);
178
179
  }
179
180
  }
180
181
  return {
@@ -57,6 +57,11 @@ export function setupHiddenTimingCapture() {
57
57
  }
58
58
  }
59
59
  export function getPageVisibilityState(start, end) {
60
+ // Input validation - return default for invalid inputs
61
+ if (!Number.isFinite(start) || !Number.isFinite(end)) {
62
+ return 'visible';
63
+ }
64
+
60
65
  // Desirable default value is visible
61
66
  if (timings.length === 0) {
62
67
  return 'visible';
@@ -69,19 +74,18 @@ export function getPageVisibilityState(start, end) {
69
74
  // currentSize is capped at SIZE.
70
75
  for (let i = 0; i < currentSize; i++) {
71
76
  const tmpIdx = (insertIndex + i) % currentSize;
72
- if (timings[tmpIdx].time <= end) {
77
+ // Add bounds checking before accessing array element
78
+ if (timings[tmpIdx] && timings[tmpIdx].time <= end) {
73
79
  endIdx = tmpIdx;
74
80
  if (timings[tmpIdx].time <= start) {
75
81
  startIdx = tmpIdx;
76
82
  }
77
83
  }
78
84
  }
79
- if (endIdx - startIdx === 0) {
80
- if (timings[startIdx].hidden) {
81
- hiddenState = 'hidden';
82
- } else {
83
- hiddenState = 'visible';
84
- }
85
+
86
+ // Add bounds checking before accessing timings array
87
+ if (endIdx - startIdx === 0 && timings[startIdx]) {
88
+ hiddenState = timings[startIdx].hidden ? 'hidden' : 'visible';
85
89
  }
86
90
  return hiddenState;
87
91
  }