govuk_publishing_components 39.1.0 → 39.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,6 +22,242 @@
22
22
  (function () {
23
23
  'use strict';
24
24
 
25
+ function now() {
26
+ return Date.now ? Date.now() : +new Date();
27
+ }
28
+
29
+ var LogEvent = {
30
+ // Internal events
31
+ EvaluationStart: 1,
32
+ EvaluationEnd: 2,
33
+ InitCalled: 3,
34
+ MarkCalled: 4,
35
+ MeasureCalled: 5,
36
+ AddDataCalled: 6,
37
+ SendCalled: 7,
38
+ ForceSampleCalled: 8,
39
+ DataCollectionStart: 9,
40
+ UnloadHandlerTriggered: 10,
41
+ OnloadHandlerTriggered: 11,
42
+ MarkLoadTimeCalled: 12,
43
+ SendCancelledPageHidden: 13,
44
+ // Data collection events
45
+ SessionIsSampled: 21,
46
+ SessionIsNotSampled: 22,
47
+ MainBeaconSent: 23,
48
+ UserTimingBeaconSent: 24,
49
+ InteractionBeaconSent: 25,
50
+ CustomDataBeaconSent: 26,
51
+ // Metric information
52
+ NavigationStart: 41,
53
+ PerformanceEntryReceived: 42,
54
+ PerformanceEntryProcessed: 43,
55
+ // Errors
56
+ PerformanceObserverError: 51,
57
+ InputEventPermissionError: 52,
58
+ InnerHtmlAccessError: 53,
59
+ EventTargetAccessError: 54,
60
+ CookieReadError: 55,
61
+ CookieSetError: 56,
62
+ PageLabelEvaluationError: 57,
63
+ // Browser support messages
64
+ NavTimingNotSupported: 71,
65
+ PaintTimingNotSupported: 72,
66
+ // POST beacon events
67
+ PostBeaconInitialised: 80,
68
+ PostBeaconSendCalled: 81,
69
+ PostBeaconTimeoutReached: 82,
70
+ PostBeaconSent: 83,
71
+ PostBeaconAlreadySent: 84,
72
+ PostBeaconCancelled: 85,
73
+ PostBeaconStopRecording: 86,
74
+ PostBeaconMetricRejected: 87,
75
+ PostBeaconDisabled: 88,
76
+ PostBeaconSendFailed: 89,
77
+ };
78
+ var Logger = /** @class */ (function () {
79
+ function Logger() {
80
+ this.events = [];
81
+ }
82
+ Logger.prototype.logEvent = function (event, args) {
83
+ if (args === void 0) { args = []; }
84
+ this.events.push([now(), event, args]);
85
+ };
86
+ Logger.prototype.getEvents = function () {
87
+ return this.events;
88
+ };
89
+ return Logger;
90
+ }());
91
+
92
+ var START_MARK = "LUX_start";
93
+ var END_MARK = "LUX_end";
94
+ var BOOLEAN_TRUE = "true";
95
+
96
+ function floor(x) {
97
+ return Math.floor(x);
98
+ }
99
+ var max = Math.max;
100
+ var round = Math.round;
101
+ /**
102
+ * Clamp a number so that it is never less than 0
103
+ */
104
+ function clamp(x) {
105
+ return max(0, x);
106
+ }
107
+ function sortNumeric(a, b) {
108
+ return a - b;
109
+ }
110
+
111
+ var scriptStartTime = now();
112
+
113
+ var _a;
114
+ // If the various performance APIs aren't available, we export an empty object to
115
+ // prevent having to make regular typeof checks.
116
+ var performance = window.performance || {};
117
+ var timing = performance.timing || {
118
+ activationStart: 0,
119
+ // If performance.timing isn't available, we attempt to polyfill the navigationStart value.
120
+ // Our first attempt is from LUX.ns, which is the time that the snippet execution began. If this
121
+ // is not available, we fall back to the time that the current script execution began.
122
+ navigationStart: ((_a = window.LUX) === null || _a === void 0 ? void 0 : _a.ns) || scriptStartTime,
123
+ };
124
+ function navigationType() {
125
+ if (performance.navigation && typeof performance.navigation.type !== "undefined") {
126
+ return performance.navigation.type;
127
+ }
128
+ return "";
129
+ }
130
+ function getNavigationEntry() {
131
+ var navEntries = getEntriesByType("navigation");
132
+ if (navEntries.length) {
133
+ var nativeEntry = navEntries[0];
134
+ var entry_1 = {
135
+ navigationStart: 0,
136
+ activationStart: 0,
137
+ };
138
+ for (var key in nativeEntry) {
139
+ entry_1[key] = nativeEntry[key];
140
+ }
141
+ return entry_1;
142
+ }
143
+ var navType = navigationType();
144
+ var entry = {
145
+ navigationStart: 0,
146
+ activationStart: 0,
147
+ startTime: 0,
148
+ type: navType == 2 ? "back_forward" : navType === 1 ? "reload" : "navigate",
149
+ };
150
+ if (true) {
151
+ for (var key in timing) {
152
+ if (typeof timing[key] === "number" && key !== "navigationStart") {
153
+ entry[key] = floor(timing[key] - timing.navigationStart);
154
+ }
155
+ }
156
+ }
157
+ return entry;
158
+ }
159
+ /**
160
+ * Simple wrapper around performance.getEntriesByType to provide fallbacks for
161
+ * legacy browsers, and work around edge cases where undefined is returned instead
162
+ * of an empty PerformanceEntryList.
163
+ */
164
+ function getEntriesByType(type) {
165
+ if (typeof performance.getEntriesByType === "function") {
166
+ var entries = performance.getEntriesByType(type);
167
+ if (entries && entries.length) {
168
+ return entries;
169
+ }
170
+ }
171
+ return [];
172
+ }
173
+ /**
174
+ * Simple wrapper around performance.getEntriesByName to provide fallbacks for
175
+ * legacy browsers, and work around edge cases where undefined is returned instead
176
+ * of an empty PerformanceEntryList.
177
+ */
178
+ function getEntriesByName(type) {
179
+ if (typeof performance.getEntriesByName === "function") {
180
+ var entries = performance.getEntriesByName(type);
181
+ if (entries && entries.length) {
182
+ return entries;
183
+ }
184
+ }
185
+ return [];
186
+ }
187
+
188
+ /**
189
+ * Milliseconds since navigationStart representing when the page was restored from the bfcache
190
+ */
191
+ var pageRestoreTime;
192
+ function setPageRestoreTime(time) {
193
+ pageRestoreTime = time;
194
+ }
195
+ function getPageRestoreTime() {
196
+ return pageRestoreTime;
197
+ }
198
+ /**
199
+ * To measure the way a user experienced a metric, we measure metrics relative to the time the user
200
+ * started viewing the page. On prerendered pages, this is activationStart. On bfcache restores, this
201
+ * is the page restore time. On all other pages this value will be zero.
202
+ */
203
+ function getZeroTime() {
204
+ var _a;
205
+ return max(getPageRestoreTime() || 0, getNavigationEntry().activationStart, ((_a = getEntriesByName(START_MARK).pop()) === null || _a === void 0 ? void 0 : _a.startTime) || 0);
206
+ }
207
+ /**
208
+ * Most time-based metrics that LUX reports should be relative to the "zero" marker, rounded down
209
+ * to the nearest unit so as not to report times in the future, and clamped to zero.
210
+ */
211
+ function processTimeMetric(value) {
212
+ return clamp(floor(value - getZeroTime()));
213
+ }
214
+ /**
215
+ * Returns the number of milliseconds since navigationStart.
216
+ */
217
+ function msSinceNavigationStart() {
218
+ if (performance.now) {
219
+ return floor(performance.now());
220
+ }
221
+ return now() - timing.navigationStart;
222
+ }
223
+ /**
224
+ * Returns the number of milliseconds since the current page was initialized. For SPAs, this is the
225
+ * time since the last LUX.init() call.
226
+ */
227
+ function msSincePageInit() {
228
+ var sinceNavigationStart = msSinceNavigationStart();
229
+ var startMark = getEntriesByName(START_MARK).pop();
230
+ if (startMark) {
231
+ return floor(sinceNavigationStart - startMark.startTime);
232
+ }
233
+ return sinceNavigationStart;
234
+ }
235
+
236
+ function padStart(str, length, char) {
237
+ while (str.length < length) {
238
+ str = char + str;
239
+ }
240
+ return str;
241
+ }
242
+
243
+ var VERSION = "4.0.20";
244
+ /**
245
+ * Returns the version of the script as a float to be stored in legacy systems that do not support
246
+ * string versions.
247
+ */
248
+ function versionAsFloat(ver) {
249
+ if (ver === void 0) { ver = VERSION; }
250
+ var parts = ver.split(".");
251
+ return parseFloat(parts[0] + "." + padStart(parts[1], 2, "0") + padStart(parts[2], 2, "0"));
252
+ }
253
+
254
+ var sendBeaconFallback = function (url, data) {
255
+ var xhr = new XMLHttpRequest();
256
+ xhr.open("POST", url, true);
257
+ xhr.setRequestHeader("content-type", "application/json");
258
+ xhr.send(String(data));
259
+ };
260
+ var sendBeacon = "sendBeacon" in navigator ? navigator.sendBeacon.bind(navigator) : sendBeaconFallback;
25
261
  /**
26
262
  * Fit an array of user timing delimited strings into a URL and return both the entries that fit and
27
263
  * the remaining entries that didn't fit.
@@ -38,31 +274,162 @@
38
274
  }
39
275
  return [beaconUtValues, remainingUtValues];
40
276
  }
277
+ var Beacon = /** @class */ (function () {
278
+ function Beacon(opts) {
279
+ var _this = this;
280
+ this.isRecording = true;
281
+ this.isSent = false;
282
+ this.maxMeasureTimeout = 0;
283
+ this.onBeforeSendCbs = [];
284
+ this.startTime = opts.startTime || getZeroTime();
285
+ this.config = opts.config;
286
+ this.logger = opts.logger;
287
+ this.customerId = opts.customerId;
288
+ this.sessionId = opts.sessionId;
289
+ this.pageId = opts.pageId;
290
+ this.metricData = {};
291
+ this.maxMeasureTimeout = window.setTimeout(function () {
292
+ _this.logger.logEvent(LogEvent.PostBeaconTimeoutReached);
293
+ _this.stopRecording();
294
+ _this.send();
295
+ }, this.config.maxMeasureTime);
296
+ this.logger.logEvent(LogEvent.PostBeaconInitialised);
297
+ }
298
+ Beacon.prototype.isBeingSampled = function () {
299
+ var bucket = parseInt(String(this.sessionId).slice(-2));
300
+ return bucket < this.config.samplerate;
301
+ };
302
+ Beacon.prototype.stopRecording = function () {
303
+ this.isRecording = false;
304
+ this.logger.logEvent(LogEvent.PostBeaconStopRecording);
305
+ };
306
+ Beacon.prototype.setMetricData = function (metric, data) {
307
+ if (!this.isRecording) {
308
+ this.logger.logEvent(LogEvent.PostBeaconMetricRejected, [metric]);
309
+ return;
310
+ }
311
+ this.metricData[metric] = data;
312
+ };
313
+ Beacon.prototype.hasMetricData = function () {
314
+ return Object.keys(this.metricData).length > 0;
315
+ };
316
+ Beacon.prototype.beaconUrl = function () {
317
+ return this.config.beaconUrlV2;
318
+ };
319
+ Beacon.prototype.onBeforeSend = function (cb) {
320
+ this.onBeforeSendCbs.push(cb);
321
+ };
322
+ Beacon.prototype.send = function () {
323
+ this.logger.logEvent(LogEvent.PostBeaconSendCalled);
324
+ if (!this.config.enablePostBeacon) {
325
+ this.logger.logEvent(LogEvent.PostBeaconDisabled);
326
+ return;
327
+ }
328
+ for (var _i = 0, _a = this.onBeforeSendCbs; _i < _a.length; _i++) {
329
+ var cb = _a[_i];
330
+ cb();
331
+ }
332
+ if (!this.isBeingSampled()) {
333
+ return;
334
+ }
335
+ if (!this.hasMetricData() && !this.config.allowEmptyPostBeacon) {
336
+ // TODO: This is only required while the new beacon is supplementary. Once it's the primary
337
+ // beacon, we should send it regardless of how much metric data it has.
338
+ this.logger.logEvent(LogEvent.PostBeaconCancelled);
339
+ return;
340
+ }
341
+ if (this.isSent) {
342
+ this.logger.logEvent(LogEvent.PostBeaconAlreadySent);
343
+ return;
344
+ }
345
+ // Only clear the max measure timeout if there's data to send.
346
+ clearTimeout(this.maxMeasureTimeout);
347
+ var beaconUrl = this.beaconUrl();
348
+ var payload = Object.assign({
349
+ customerId: this.customerId,
350
+ measureDuration: msSincePageInit(),
351
+ pageId: this.pageId,
352
+ scriptVersion: VERSION,
353
+ sessionId: this.sessionId,
354
+ startTime: this.startTime,
355
+ }, this.metricData);
356
+ try {
357
+ sendBeacon(beaconUrl, JSON.stringify(payload));
358
+ this.isSent = true;
359
+ this.logger.logEvent(LogEvent.PostBeaconSent, [beaconUrl, payload]);
360
+ }
361
+ catch (e) {
362
+ this.logger.logEvent(LogEvent.PostBeaconSendFailed, [e]);
363
+ }
364
+ };
365
+ return Beacon;
366
+ }());
367
+
368
+ // Wrapper to support older browsers (<= IE8)
369
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
370
+ function addListener(type, callback, useCapture) {
371
+ if (useCapture === void 0) { useCapture = false; }
372
+ if (addEventListener) {
373
+ addEventListener(type, callback, useCapture);
374
+ }
375
+ else if (window.attachEvent && true) {
376
+ window.attachEvent("on" + type, callback);
377
+ }
378
+ }
379
+ // Wrapper to support older browsers (<= IE8)
380
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
381
+ function removeListener(type, callback, useCapture) {
382
+ if (useCapture === void 0) { useCapture = false; }
383
+ if (removeEventListener) {
384
+ removeEventListener(type, callback, useCapture);
385
+ }
386
+ else if (window.detachEvent && true) {
387
+ window.detachEvent("on" + type, callback);
388
+ }
389
+ }
390
+
391
+ function onPageLoad(callback) {
392
+ if (document.readyState === "complete") {
393
+ // The onload event has already fired
394
+ callback();
395
+ }
396
+ else {
397
+ // Listen for the onload event and run the callback after a short delay
398
+ addListener("load", function () {
399
+ setTimeout(callback, 200);
400
+ });
401
+ }
402
+ }
41
403
 
42
404
  var luxOrigin = "https://lux.speedcurve.com";
43
405
  function fromObject(obj) {
44
406
  var autoMode = getProperty(obj, "auto", true);
45
407
  return {
408
+ allowEmptyPostBeacon: getProperty(obj, "allowEmptyPostBeacon", false),
46
409
  auto: autoMode,
47
410
  beaconUrl: getProperty(obj, "beaconUrl", luxOrigin + "/lux/"),
411
+ beaconUrlV2: getProperty(obj, "beaconUrlV2", "https://beacon.speedcurve.com/store"),
48
412
  conversions: getProperty(obj, "conversions"),
49
413
  cookieDomain: getProperty(obj, "cookieDomain"),
50
414
  customerid: getProperty(obj, "customerid"),
415
+ enablePostBeacon: getProperty(obj, "enablePostBeacon", true),
51
416
  errorBeaconUrl: getProperty(obj, "errorBeaconUrl", luxOrigin + "/error/"),
417
+ interactionBeaconDelay: getProperty(obj, "interactionBeaconDelay", 200),
52
418
  jspagelabel: getProperty(obj, "jspagelabel"),
53
419
  label: getProperty(obj, "label"),
54
420
  maxBeaconUrlLength: getProperty(obj, "maxBeaconUrlLength", 8190),
55
421
  maxBeaconUTEntries: getProperty(obj, "maxBeaconUTEntries", 20),
56
422
  maxErrors: getProperty(obj, "maxErrors", 5),
57
423
  maxMeasureTime: getProperty(obj, "maxMeasureTime", 60000),
424
+ measureUntil: getProperty(obj, "measureUntil", "onload"),
58
425
  minMeasureTime: getProperty(obj, "minMeasureTime", 0),
59
426
  newBeaconOnPageShow: getProperty(obj, "newBeaconOnPageShow", false),
427
+ pagegroups: getProperty(obj, "pagegroups"),
60
428
  samplerate: getProperty(obj, "samplerate", 100),
61
429
  sendBeaconOnPageHidden: getProperty(obj, "sendBeaconOnPageHidden", autoMode),
62
430
  serverTiming: getProperty(obj, "serverTiming"),
63
431
  trackErrors: getProperty(obj, "trackErrors", true),
64
432
  trackHiddenPages: getProperty(obj, "trackHiddenPages", false),
65
- pagegroups: getProperty(obj, "pagegroups"),
66
433
  };
67
434
  }
68
435
  function getProperty(obj, key, defaultValue) {
@@ -72,9 +439,7 @@
72
439
  return defaultValue;
73
440
  }
74
441
 
75
- var START_MARK = "LUX_start";
76
- var END_MARK = "LUX_end";
77
- var BOOLEAN_TRUE = "true";
442
+ var SESSION_COOKIE_NAME = "lux_uid";
78
443
 
79
444
  var customDataValues = {};
80
445
  var updatedCustomData = {};
@@ -117,93 +482,6 @@
117
482
  return encodeURIComponent(strings.join(","));
118
483
  }
119
484
 
120
- function floor(x) {
121
- return Math.floor(x);
122
- }
123
- var max = Math.max;
124
- var round = Math.round;
125
- /**
126
- * Clamp a number so that it is never less than 0
127
- */
128
- function clamp(x) {
129
- return max(0, x);
130
- }
131
- function sortNumeric(a, b) {
132
- return a - b;
133
- }
134
-
135
- function now() {
136
- return Date.now ? Date.now() : +new Date();
137
- }
138
-
139
- var scriptStartTime = now();
140
-
141
- var _a;
142
- // If the various performance APIs aren't available, we export an empty object to
143
- // prevent having to make regular typeof checks.
144
- var performance = window.performance || {};
145
- var timing = performance.timing || {
146
- // If performance.timing isn't available, we attempt to polyfill the navigationStart value.
147
- // Our first attempt is from LUX.ns, which is the time that the snippet execution began. If this
148
- // is not available, we fall back to the time that the current script execution began.
149
- navigationStart: ((_a = window.LUX) === null || _a === void 0 ? void 0 : _a.ns) || scriptStartTime,
150
- };
151
- function msSinceNavigationStart() {
152
- if (performance.now) {
153
- return floor(performance.now());
154
- }
155
- return now() - timing.navigationStart;
156
- }
157
- function navigationType() {
158
- if (performance.navigation && typeof performance.navigation.type !== "undefined") {
159
- return performance.navigation.type;
160
- }
161
- return "";
162
- }
163
- function getNavigationEntry() {
164
- var navEntries = getEntriesByType("navigation");
165
- if (navEntries.length) {
166
- var nativeEntry = navEntries[0];
167
- var entry_1 = {
168
- navigationStart: 0,
169
- activationStart: 0,
170
- };
171
- for (var key in nativeEntry) {
172
- entry_1[key] = nativeEntry[key];
173
- }
174
- return entry_1;
175
- }
176
- var navType = navigationType();
177
- var entry = {
178
- navigationStart: 0,
179
- activationStart: 0,
180
- startTime: 0,
181
- type: navType == 2 ? "back_forward" : navType === 1 ? "reload" : "navigate",
182
- };
183
- if (true) {
184
- for (var key in timing) {
185
- if (typeof timing[key] === "number" && key !== "navigationStart") {
186
- entry[key] = floor(timing[key] - timing.navigationStart);
187
- }
188
- }
189
- }
190
- return entry;
191
- }
192
- /**
193
- * Simple wrapper around performance.getEntriesByType to provide fallbacks for
194
- * legacy browsers, and work around edge cases where undefined is returned instead
195
- * of an empty PerformanceEntryList.
196
- */
197
- function getEntriesByType(type) {
198
- if (typeof performance.getEntriesByType === "function") {
199
- var entries = performance.getEntriesByType(type);
200
- if (entries && entries.length) {
201
- return entries;
202
- }
203
- }
204
- return [];
205
- }
206
-
207
485
  function isVisible() {
208
486
  if (document.visibilityState) {
209
487
  return document.visibilityState === "visible";
@@ -264,37 +542,40 @@
264
542
  }
265
543
  var MAX_SELECTOR_LENGTH = 100;
266
544
  function getNodeSelector(node, selector) {
267
- if (selector === void 0) {
268
- selector = "";
269
- }
270
- try {
271
- if (selector && (node.nodeType === 9 || selector.length > MAX_SELECTOR_LENGTH || !node.parentNode)) {
272
- // Final selector.
273
- return selector;
274
- }
275
- var el = node;
276
- // Our first preference is to use the data-sctrack attribute from anywhere in the tree
277
- var trackId = getClosestScTrackAttribute(el);
278
- if (trackId) {
279
- return trackId;
280
- }
281
- if (el.id) {
282
- // Once we've found an element with ID we return the selector.
283
- return "#" + el.id + (selector ? ">" + selector : "");
284
- }
285
- else {
286
- // Otherwise attempt to get parent elements recursively
287
- var name_1 = el.nodeType === 1 ? el.nodeName.toLowerCase() : el.nodeName.toUpperCase();
288
- var classes = el.className ? "." + el.className.replace(/\s+/g, ".") : "";
289
- var currentSelector = name_1 + classes + (selector ? ">" + selector : "");
290
- if (el.parentNode) {
291
- var selectorWithParent = getNodeSelector(el.parentNode, currentSelector);
292
- if (selectorWithParent.length < MAX_SELECTOR_LENGTH) {
293
- return selectorWithParent;
545
+ if (selector === void 0) { selector = ""; }
546
+ try {
547
+ if (selector &&
548
+ (node.nodeType === 9 || selector.length > MAX_SELECTOR_LENGTH || !node.parentNode)) {
549
+ // Final selector.
550
+ return selector;
551
+ }
552
+ var el = node;
553
+ // Our first preference is to use the data-sctrack attribute from anywhere in the tree
554
+ var trackId = getClosestScTrackAttribute(el);
555
+ if (trackId) {
556
+ return trackId;
557
+ }
558
+ if (el.id) {
559
+ // Once we've found an element with ID we return the selector.
560
+ return "#" + el.id + (selector ? ">" + selector : "");
561
+ }
562
+ else if (el) {
563
+ // Otherwise attempt to get parent elements recursively
564
+ var name_1 = el.nodeType === 1 ? el.nodeName.toLowerCase() : el.nodeName.toUpperCase();
565
+ var classes = el.className ? "." + el.className.replace(/\s+/g, ".") : "";
566
+ // Remove classes until the selector is short enough
567
+ while ((name_1 + classes).length > MAX_SELECTOR_LENGTH) {
568
+ classes = classes.split(".").slice(0, -1).join(".");
294
569
  }
570
+ var currentSelector = name_1 + classes + (selector ? ">" + selector : "");
571
+ if (el.parentNode) {
572
+ var selectorWithParent = getNodeSelector(el.parentNode, currentSelector);
573
+ if (selectorWithParent.length < MAX_SELECTOR_LENGTH) {
574
+ return selectorWithParent;
575
+ }
576
+ }
577
+ return currentSelector;
295
578
  }
296
- return currentSelector;
297
- }
298
579
  }
299
580
  catch (error) {
300
581
  // Do nothing.
@@ -320,72 +601,40 @@
320
601
  return flags | flag;
321
602
  }
322
603
 
323
- var LogEvent = {
324
- // Internal events
325
- EvaluationStart: 1,
326
- EvaluationEnd: 2,
327
- InitCalled: 3,
328
- MarkCalled: 4,
329
- MeasureCalled: 5,
330
- AddDataCalled: 6,
331
- SendCalled: 7,
332
- ForceSampleCalled: 8,
333
- DataCollectionStart: 9,
334
- UnloadHandlerTriggered: 10,
335
- OnloadHandlerTriggered: 11,
336
- MarkLoadTimeCalled: 12,
337
- SendCancelledPageHidden: 13,
338
- // Data collection events
339
- SessionIsSampled: 21,
340
- SessionIsNotSampled: 22,
341
- MainBeaconSent: 23,
342
- UserTimingBeaconSent: 24,
343
- InteractionBeaconSent: 25,
344
- CustomDataBeaconSent: 26,
345
- // Metric information
346
- NavigationStart: 41,
347
- PerformanceEntryReceived: 42,
348
- PerformanceEntryProcessed: 43,
349
- // Errors
350
- PerformanceObserverError: 51,
351
- InputEventPermissionError: 52,
352
- InnerHtmlAccessError: 53,
353
- EventTargetAccessError: 54,
354
- CookieReadError: 55,
355
- CookieSetError: 56,
356
- PageLabelEvaluationError: 57,
357
- // Browser support messages
358
- NavTimingNotSupported: 71,
359
- PaintTimingNotSupported: 72,
360
- };
361
- var Logger = /** @class */ (function () {
362
- function Logger() {
363
- this.events = [];
364
- }
365
- Logger.prototype.logEvent = function (event, args) {
366
- if (args === void 0) { args = []; }
367
- this.events.push([now(), event, args]);
368
- };
369
- Logger.prototype.getEvents = function () {
370
- return this.events;
371
- };
372
- return Logger;
373
- })();
374
-
375
604
  var sessionValue = 0;
376
605
  var sessionEntries = [];
606
+ var sessionAttributions = [];
607
+ var largestEntry;
377
608
  var maximumSessionValue = 0;
378
- function addEntry$2(entry) {
609
+ function processEntry$2(entry) {
379
610
  if (!entry.hadRecentInput) {
380
611
  var firstEntry = sessionEntries[0];
381
612
  var latestEntry = sessionEntries[sessionEntries.length - 1];
382
- if (sessionEntries.length && (entry.startTime - latestEntry.startTime >= 1000 || entry.startTime - firstEntry.startTime >= 5000)) {
383
- sessionValue = entry.value;
384
- sessionEntries = [entry];
613
+ var sources = entry.sources
614
+ ? entry.sources
615
+ .filter(function (source) { return source.node; })
616
+ .map(function (source) { return ({
617
+ value: entry.value,
618
+ startTime: processTimeMetric(entry.startTime),
619
+ elementSelector: getNodeSelector(source.node),
620
+ elementType: source.node.nodeName,
621
+ }); })
622
+ : [];
623
+ if (sessionEntries.length &&
624
+ (entry.startTime - latestEntry.startTime >= 1000 ||
625
+ entry.startTime - firstEntry.startTime >= 5000)) {
626
+ sessionValue = entry.value;
627
+ sessionEntries = [entry];
628
+ sessionAttributions = sources;
629
+ largestEntry = entry;
385
630
  }
386
631
  else {
387
632
  sessionValue += entry.value;
388
633
  sessionEntries.push(entry);
634
+ sessionAttributions = sessionAttributions.concat(sources);
635
+ if (!largestEntry || entry.value > largestEntry.value) {
636
+ largestEntry = entry;
637
+ }
389
638
  }
390
639
  maximumSessionValue = max(maximumSessionValue, sessionValue);
391
640
  }
@@ -394,9 +643,20 @@
394
643
  sessionValue = 0;
395
644
  sessionEntries = [];
396
645
  maximumSessionValue = 0;
646
+ largestEntry = undefined;
397
647
  }
398
- function getCLS() {
399
- return maximumSessionValue;
648
+ function getData$2() {
649
+ return {
650
+ value: maximumSessionValue,
651
+ startTime: sessionEntries[0] ? processTimeMetric(sessionEntries[0].startTime) : null,
652
+ largestEntry: largestEntry
653
+ ? {
654
+ value: largestEntry.value,
655
+ startTime: processTimeMetric(largestEntry.startTime),
656
+ }
657
+ : null,
658
+ sources: sessionAttributions.length ? sessionAttributions : null,
659
+ };
400
660
  }
401
661
 
402
662
  /**
@@ -416,23 +676,27 @@
416
676
  slowestEntries = [];
417
677
  slowestEntriesMap = {};
418
678
  }
419
- function addEntry$1(entry) {
679
+ function processEntry$1(entry) {
420
680
  if (entry.interactionId || (entry.entryType === "first-input" && !entryExists(entry))) {
421
- var duration = entry.duration,
422
- startTime = entry.startTime,
423
- interactionId = entry.interactionId,
424
- processingStart = entry.processingStart,
425
- processingEnd = entry.processingEnd,
426
- target = entry.target;
681
+ var duration = entry.duration, startTime = entry.startTime, interactionId = entry.interactionId, name_1 = entry.name, processingStart = entry.processingStart, processingEnd = entry.processingEnd, target = entry.target;
682
+ var processingTime = processingEnd - processingStart;
427
683
  var existingEntry = slowestEntriesMap[interactionId];
428
684
  var selector = target ? getNodeSelector(target) : null;
429
685
  if (existingEntry) {
430
- if (existingEntry.duration < duration) {
686
+ var longerDuration = duration > existingEntry.duration;
687
+ var sameWithLongerProcessingTime = duration === existingEntry.duration && processingTime > existingEntry.processingTime;
688
+ if (longerDuration || sameWithLongerProcessingTime) {
689
+ // Only replace an existing interation if the duration is longer, or if the duration is the
690
+ // same but the processing time is longer. The logic around this is that the interaction with
691
+ // longer processing time is likely to be the event that actually had a handler.
431
692
  existingEntry.duration = duration;
432
- existingEntry.startTime = startTime;
433
- existingEntry.processingStart = processingStart;
693
+ existingEntry.name = name_1;
434
694
  existingEntry.processingEnd = processingEnd;
695
+ existingEntry.processingStart = processingStart;
696
+ existingEntry.processingTime = processingTime;
435
697
  existingEntry.selector = selector;
698
+ existingEntry.startTime = startTime;
699
+ existingEntry.target = target;
436
700
  }
437
701
  }
438
702
  else {
@@ -440,10 +704,13 @@
440
704
  slowestEntriesMap[interactionId] = {
441
705
  duration: duration,
442
706
  interactionId: interactionId,
443
- startTime: startTime,
444
- processingStart: processingStart,
707
+ name: name_1,
445
708
  processingEnd: processingEnd,
709
+ processingStart: processingStart,
710
+ processingTime: processingTime,
446
711
  selector: selector,
712
+ startTime: startTime,
713
+ target: target,
447
714
  };
448
715
  slowestEntries.push(slowestEntriesMap[interactionId]);
449
716
  }
@@ -465,6 +732,29 @@
465
732
  var index = Math.min(slowestEntries.length - 1, Math.floor(getInteractionCount() / 50));
466
733
  return slowestEntries[index];
467
734
  }
735
+ function getData$1() {
736
+ var _a;
737
+ var interaction = getHighPercentileInteraction();
738
+ if (!interaction) {
739
+ return undefined;
740
+ }
741
+ return {
742
+ value: interaction.duration,
743
+ startTime: processTimeMetric(interaction.startTime),
744
+ subParts: {
745
+ inputDelay: clamp(floor(interaction.processingStart - interaction.startTime)),
746
+ processingTime: clamp(floor(interaction.processingTime)),
747
+ presentationDelay: clamp(floor(interaction.startTime + interaction.duration - interaction.processingEnd)),
748
+ },
749
+ attribution: interaction.selector
750
+ ? {
751
+ elementSelector: interaction.selector,
752
+ elementType: ((_a = interaction.target) === null || _a === void 0 ? void 0 : _a.nodeName) || "",
753
+ eventType: interaction.name,
754
+ }
755
+ : null,
756
+ };
757
+ }
468
758
  function getInteractionCount() {
469
759
  if ("interactionCount" in performance) {
470
760
  return performance.interactionCount;
@@ -472,6 +762,47 @@
472
762
  return interactionCountEstimate;
473
763
  }
474
764
 
765
+ var lcpEntry;
766
+ function processEntry(entry) {
767
+ if (!lcpEntry || entry.startTime > lcpEntry.startTime) {
768
+ lcpEntry = entry;
769
+ }
770
+ }
771
+ function getData() {
772
+ if (!lcpEntry) {
773
+ return undefined;
774
+ }
775
+ var subParts = null;
776
+ if (lcpEntry.url) {
777
+ var lcpResource = getEntriesByType("resource").find(function (resource) { return resource.name === lcpEntry.url; });
778
+ if (lcpResource) {
779
+ var navEntry = getNavigationEntry();
780
+ var responseStart = navEntry.responseStart || timing.responseStart;
781
+ var activationStart = navEntry.activationStart;
782
+ var ttfb = max(0, responseStart - activationStart);
783
+ var lcpStartTime = lcpResource.startTime;
784
+ var lcpRequestStart = (lcpResource.requestStart || lcpStartTime) - activationStart;
785
+ var lcpResponseEnd = max(lcpRequestStart, lcpResource.responseEnd - activationStart);
786
+ var lcpRenderTime = max(lcpResponseEnd, lcpStartTime - activationStart);
787
+ subParts = {
788
+ resourceLoadDelay: clamp(floor(lcpRequestStart - ttfb)),
789
+ resourceLoadTime: clamp(floor(lcpResponseEnd - lcpRequestStart)),
790
+ elementRenderDelay: clamp(floor(lcpRenderTime - lcpResponseEnd)),
791
+ };
792
+ }
793
+ }
794
+ return {
795
+ value: processTimeMetric(lcpEntry.startTime),
796
+ subParts: subParts,
797
+ attribution: lcpEntry.element
798
+ ? {
799
+ elementSelector: getNodeSelector(lcpEntry.element),
800
+ elementType: lcpEntry.element.nodeName,
801
+ }
802
+ : null,
803
+ };
804
+ }
805
+
475
806
  var ALL_ENTRIES = [];
476
807
  function observe(type, callback, options) {
477
808
  if (typeof PerformanceObserver === "function" &&
@@ -577,10 +908,9 @@
577
908
  // -------------------------------------------------------------------------
578
909
  /// End
579
910
  // -------------------------------------------------------------------------
580
- var SCRIPT_VERSION = "314";
581
911
  var logger = new Logger();
582
912
  var globalConfig = fromObject(LUX);
583
- logger.logEvent(LogEvent.EvaluationStart, [SCRIPT_VERSION, globalConfig]);
913
+ logger.logEvent(LogEvent.EvaluationStart, [VERSION, JSON.stringify(globalConfig)]);
584
914
  // Variable aliases that allow the minifier to reduce file size.
585
915
  var document = window.document;
586
916
  var addEventListener = window.addEventListener;
@@ -605,7 +935,7 @@
605
935
  new Image().src =
606
936
  globalConfig.errorBeaconUrl +
607
937
  "?v=" +
608
- SCRIPT_VERSION +
938
+ versionAsFloat() +
609
939
  "&id=" +
610
940
  getCustomerId() +
611
941
  "&fn=" +
@@ -627,6 +957,30 @@
627
957
  }
628
958
  }
629
959
  addEventListener("error", errorHandler);
960
+ // Bitmask of flags for this session & page
961
+ var gFlags = 0;
962
+ var gaMarks = [];
963
+ var gaMeasures = [];
964
+ var ghIx = {}; // hash for Interaction Metrics (scroll, click, keyboard)
965
+ var gbLuxSent = 0; // have we sent the LUX data? (avoid sending twice in unload)
966
+ var gbNavSent = 0; // have we sent the Nav Timing beacon yet? (avoid sending twice for SPA)
967
+ var gbIxSent = 0; // have we sent the IX data? (avoid sending twice for SPA)
968
+ var gbFirstPV = 1; // this is the first page view (vs. a SPA "soft nav")
969
+ var gSessionTimeout = 30 * 60; // number of seconds after which we consider a session to have "timed out" (used for calculating bouncerate)
970
+ var gSyncId = createSyncId(); // if we send multiple beacons, use this to sync them (eg, LUX & IX) (also called "luxid")
971
+ var gUid = refreshUniqueId(gSyncId); // cookie for this session ("Unique ID")
972
+ var gCustomDataTimeout; // setTimeout timer for sending a Custom data beacon after onload
973
+ var gMaxMeasureTimeout; // setTimeout timer for sending the beacon after a maximum measurement time
974
+ var initPostBeacon = function () {
975
+ return new Beacon({
976
+ config: globalConfig,
977
+ logger: logger,
978
+ customerId: getCustomerId(),
979
+ sessionId: gUid,
980
+ pageId: gSyncId,
981
+ });
982
+ };
983
+ var beacon = initPostBeacon();
630
984
  var logEntry = function (entry) {
631
985
  logger.logEvent(LogEvent.PerformanceEntryReceived, [entry]);
632
986
  };
@@ -635,74 +989,67 @@
635
989
  addEntry(entry);
636
990
  logEntry(entry);
637
991
  };
638
- // Before long tasks were buffered, we added a PerformanceObserver to the lux.js snippet to capture
639
- // any long tasks that occurred before the full script was loaded. To deal with this, we process
640
- // all of the snippet long tasks, and we check for double-ups in the new PerformanceObserver.
641
- var snippetLongTasks = typeof window.LUX_al === "object" ? window.LUX_al : [];
642
- snippetLongTasks.forEach(processAndLogEntry);
643
992
  try {
644
- observe("longtask", function (entry) {
645
- if (ALL_ENTRIES.indexOf(entry) === -1) {
646
- processAndLogEntry(entry);
647
- }
648
- });
993
+ observe("longtask", processAndLogEntry);
649
994
  observe("largest-contentful-paint", processAndLogEntry);
650
995
  observe("element", processAndLogEntry);
651
996
  observe("paint", processAndLogEntry);
997
+ observe("largest-contentful-paint", function (entry) {
998
+ // Process the LCP entry for the legacy beacon
999
+ processAndLogEntry(entry);
1000
+ // Process the LCP entry for the new beacon
1001
+ processEntry(entry);
1002
+ beacon.setMetricData("lcp", getData());
1003
+ });
652
1004
  observe("layout-shift", function (entry) {
653
- addEntry$2(entry);
1005
+ processEntry$2(entry);
1006
+ beacon.setMetricData("cls", getData$2());
654
1007
  logEntry(entry);
655
1008
  });
1009
+ var handleINPEntry_1 = function (entry) {
1010
+ processEntry$1(entry);
1011
+ var data = getData$1();
1012
+ if (data) {
1013
+ beacon.setMetricData("inp", data);
1014
+ }
1015
+ };
656
1016
  observe("first-input", function (entry) {
1017
+ logEntry(entry);
657
1018
  var entryTime = entry.processingStart - entry.startTime;
658
1019
  if (!gFirstInputDelay || gFirstInputDelay < entryTime) {
659
1020
  gFirstInputDelay = floor(entryTime);
660
1021
  }
661
1022
  // Allow first-input events to be considered for INP
662
- addEntry$1(entry);
1023
+ handleINPEntry_1(entry);
663
1024
  });
664
- // TODO: Add { durationThreshold: 40 } once performance.interactionCount is widely supported.
1025
+ // TODO: Set durationThreshold to 40 once performance.interactionCount is widely supported.
665
1026
  // Right now we have to count every event to get the total interaction count so that we can
666
1027
  // estimate a high percentile value for INP.
667
- observe("event", addEntry$1);
1028
+ observe("event", function (entry) {
1029
+ handleINPEntry_1(entry);
1030
+ // It's useful to log the interactionId, but it is not serialised by default. Annoyingly, we
1031
+ // need to manually serialize our own object with the keys we want.
1032
+ logEntry({
1033
+ interactionId: entry.interactionId,
1034
+ name: entry.name,
1035
+ entryType: entry.entryType,
1036
+ startTime: entry.startTime,
1037
+ duration: entry.duration,
1038
+ processingStart: entry.processingStart,
1039
+ processingEnd: entry.processingEnd,
1040
+ });
1041
+ }, { durationThreshold: 0 });
668
1042
  }
669
1043
  catch (e) {
670
1044
  logger.logEvent(LogEvent.PerformanceObserverError, [e]);
671
1045
  }
672
- // Bitmask of flags for this session & page
673
- var gFlags = 0;
674
- var gaMarks = [];
675
- var gaMeasures = [];
676
- var ghIx = {}; // hash for Interaction Metrics (scroll, click, keyboard)
677
- var gbLuxSent = 0; // have we sent the LUX data? (avoid sending twice in unload)
678
- var gbNavSent = 0; // have we sent the Nav Timing beacon yet? (avoid sending twice for SPA)
679
- var gbIxSent = 0; // have we sent the IX data? (avoid sending twice for SPA)
680
- var gbFirstPV = 1; // this is the first page view (vs. a SPA "soft nav")
681
- var gSessionTimeout = 30 * 60; // number of seconds after which we consider a session to have "timed out" (used for calculating bouncerate)
682
- var gSyncId = createSyncId(); // if we send multiple beacons, use this to sync them (eg, LUX & IX) (also called "luxid")
683
- var gUid = refreshUniqueId(gSyncId); // cookie for this session ("Unique ID")
684
- var gCustomDataTimeout; // setTimeout timer for sending a Custom data beacon after onload
685
- var gMaxMeasureTimeout; // setTimeout timer for sending the beacon after a maximum measurement time
686
- var pageRestoreTime; // ms since navigationStart representing when the page was restored from the bfcache
687
- /**
688
- * To measure the way a user experienced a metric, we measure metrics relative to the time the user
689
- * started viewing the page. On prerendered pages, this is activationStart. On bfcache restores, this
690
- * is the page restore time. On all other pages this value will be zero.
691
- */
692
- var getZeroTime = function () {
693
- var _a;
694
- return max(pageRestoreTime || 0, getNavigationEntry().activationStart, ((_a = _getMark(START_MARK)) === null || _a === void 0 ? void 0 : _a.startTime) || 0);
695
- };
696
- /**
697
- * Most time-based metrics that LUX reports should be relative to the "zero" marker, rounded down
698
- * to the nearest unit so as not to report times in the future, and clamped to zero.
699
- */
700
- var processTimeMetric = function (value) { return clamp(floor(value - getZeroTime())); };
701
1046
  /**
702
1047
  * Some values should only be reported if they are non-zero. The exception to this is when the page
703
1048
  * was prerendered or restored from BF cache
704
1049
  */
705
- var shouldReportValue = function (value) { return value > 0 || pageRestoreTime || wasPrerendered(); };
1050
+ var shouldReportValue = function (value) {
1051
+ return value > 0 || getPageRestoreTime() || wasPrerendered();
1052
+ };
706
1053
  if (_sample()) {
707
1054
  logger.logEvent(LogEvent.SessionIsSampled, [globalConfig.samplerate]);
708
1055
  }
@@ -764,7 +1111,7 @@
764
1111
  return;
765
1112
  }
766
1113
  if (bCancelable) {
767
- var now_1 = _now(true);
1114
+ var now_1 = msSinceNavigationStart();
768
1115
  var eventTimeStamp = evt.timeStamp;
769
1116
  if (eventTimeStamp > 1520000000) {
770
1117
  // If the event timeStamp is an epoch time instead of a time relative to NavigationStart,
@@ -791,23 +1138,6 @@
791
1138
  addEventListener(eventType, onInput, ghListenerOptions);
792
1139
  });
793
1140
  ////////////////////// FID END
794
- /**
795
- * Returns the time elapsed (in ms) since navigationStart. For SPAs, returns
796
- * the time elapsed since the last LUX.init call.
797
- *
798
- * When `absolute = true` the time is always relative to navigationStart, even
799
- * in SPAs.
800
- */
801
- function _now(absolute) {
802
- var sinceNavigationStart = msSinceNavigationStart();
803
- var startMark = _getMark(START_MARK);
804
- // For SPA page views, we use our internal mark as a reference point
805
- if (startMark && !absolute) {
806
- return floor(sinceNavigationStart - startMark.startTime);
807
- }
808
- // For "regular" page views, we can use performance.now() if it's available...
809
- return sinceNavigationStart;
810
- }
811
1141
  // This is a wrapper around performance.mark that falls back to a polyfill when the User Timing
812
1142
  // API isn't supported.
813
1143
  function _mark() {
@@ -825,7 +1155,7 @@
825
1155
  if (true) {
826
1156
  var name_1 = args[0];
827
1157
  var detail = ((_a = args[1]) === null || _a === void 0 ? void 0 : _a.detail) || null;
828
- var startTime = ((_b = args[1]) === null || _b === void 0 ? void 0 : _b.startTime) || _now();
1158
+ var startTime = ((_b = args[1]) === null || _b === void 0 ? void 0 : _b.startTime) || msSincePageInit();
829
1159
  var entry = {
830
1160
  entryType: "mark",
831
1161
  duration: 0,
@@ -888,7 +1218,7 @@
888
1218
  if (true) {
889
1219
  var navEntry = getNavigationEntry();
890
1220
  var startTime = typeof startMarkName === "number" ? startMarkName : 0;
891
- var endTime = typeof endMarkName === "number" ? endMarkName : _now();
1221
+ var endTime = typeof endMarkName === "number" ? endMarkName : msSincePageInit();
892
1222
  var throwError = function (missingMark) {
893
1223
  throw new DOMException("Failed to execute 'measure' on 'Performance': The mark '" +
894
1224
  missingMark +
@@ -1132,13 +1462,12 @@
1132
1462
  var median = arrayMedian(aValues);
1133
1463
  return { count: count, median: median, max: max, fci: fci };
1134
1464
  }
1135
- function getCLS$1() {
1465
+ function getCLS() {
1136
1466
  if (!("LayoutShift" in self)) {
1137
1467
  return undefined;
1138
1468
  }
1139
- // The DCLS column in Redshift is REAL (FLOAT4) which stores a maximum
1140
- // of 6 significant digits.
1141
- return getCLS().toFixed(6);
1469
+ var clsData = getData$2();
1470
+ return clsData.value.toFixed(6);
1142
1471
  }
1143
1472
  // Return the median value from an array of integers.
1144
1473
  function arrayMedian(aValues) {
@@ -1276,6 +1605,7 @@
1276
1605
  reset();
1277
1606
  nErrors = 0;
1278
1607
  gFirstInputDelay = undefined;
1608
+ beacon = initPostBeacon();
1279
1609
  // Clear flags then set the flag that init was called (ie, this is a SPA).
1280
1610
  if (clearFlags) {
1281
1611
  gFlags = 0;
@@ -1298,10 +1628,13 @@
1298
1628
  var num = 0;
1299
1629
  for (var i = 0, len = aElems.length; i < len; i++) {
1300
1630
  var e = aElems[i];
1301
- if (e.src && !e.async && !e.defer && 0 !== (e.compareDocumentPosition(lastViewportElem) & 4)) {
1302
- // If the script has a SRC and async is false and it occurs BEFORE the last viewport element,
1303
- // then increment the counter.
1304
- num++;
1631
+ if (e.src &&
1632
+ !e.async &&
1633
+ !e.defer &&
1634
+ 0 !== (e.compareDocumentPosition(lastViewportElem) & 4)) {
1635
+ // If the script has a SRC and async is false and it occurs BEFORE the last viewport element,
1636
+ // then increment the counter.
1637
+ num++;
1305
1638
  }
1306
1639
  }
1307
1640
  return num;
@@ -1318,7 +1651,7 @@
1318
1651
  e.onloadcssdefined ||
1319
1652
  "print" === e.media ||
1320
1653
  "style" === e.as ||
1321
- (typeof e.onload === "function" && e.media === "all"));
1654
+ (typeof e.onload === "function" && e.media === "all")) ;
1322
1655
  else {
1323
1656
  nBlocking++;
1324
1657
  }
@@ -1384,9 +1717,9 @@
1384
1717
  var ns = timing.navigationStart;
1385
1718
  var startMark = _getMark(START_MARK);
1386
1719
  var endMark = _getMark(END_MARK);
1387
- if (startMark && endMark && !pageRestoreTime) {
1720
+ if (startMark && endMark && !getPageRestoreTime()) {
1388
1721
  // This is a SPA page view, so send the SPA marks & measures instead of Nav Timing.
1389
- // Note: pageRestoreTime indicates this was a bfcache restore, which we don't want to treat as a SPA.
1722
+ // Note: getPageRestoreTime() indicates this was a bfcache restore, which we don't want to treat as a SPA.
1390
1723
  var start = floor(startMark.startTime); // the start mark is "zero"
1391
1724
  ns += start; // "navigationStart" for a SPA is the real navigationStart plus the start mark
1392
1725
  var end = floor(endMark.startTime) - start; // delta from start mark
@@ -1423,7 +1756,7 @@
1423
1756
  };
1424
1757
  var loadEventStartStr = prefixNTValue("loadEventStart", "ls", true);
1425
1758
  var loadEventEndStr = prefixNTValue("loadEventEnd", "le", true);
1426
- if (pageRestoreTime && startMark && endMark) {
1759
+ if (getPageRestoreTime() && startMark && endMark) {
1427
1760
  // For bfcache restores, we set the load time to the time it took for the page to be restored.
1428
1761
  var loadTime = floor(endMark.startTime - startMark.startTime);
1429
1762
  loadEventStartStr = "ls" + loadTime;
@@ -1434,8 +1767,8 @@
1434
1767
  s = [
1435
1768
  ns,
1436
1769
  "as" + clamp(navEntry_1.activationStart),
1437
- redirect && !pageRestoreTime ? prefixNTValue("redirectStart", "rs") : "",
1438
- redirect && !pageRestoreTime ? prefixNTValue("redirectEnd", "re") : "",
1770
+ redirect && !getPageRestoreTime() ? prefixNTValue("redirectStart", "rs") : "",
1771
+ redirect && !getPageRestoreTime() ? prefixNTValue("redirectEnd", "re") : "",
1439
1772
  prefixNTValue("fetchStart", "fs"),
1440
1773
  prefixNTValue("domainLookupStart", "ds"),
1441
1774
  prefixNTValue("domainLookupEnd", "de"),
@@ -1542,9 +1875,9 @@
1542
1875
  return [
1543
1876
  "&INP=" + details.duration,
1544
1877
  details.selector ? "&INPs=" + encodeURIComponent(details.selector) : "",
1545
- "&INPt=" + clamp(floor(details.startTime)),
1878
+ "&INPt=" + floor(details.startTime),
1546
1879
  "&INPi=" + clamp(floor(details.processingStart - details.startTime)),
1547
- "&INPp=" + clamp(floor(details.processingEnd - details.processingStart)),
1880
+ "&INPp=" + clamp(floor(details.processingTime)),
1548
1881
  "&INPd=" + clamp(floor(details.startTime + details.duration - details.processingEnd)),
1549
1882
  ].join("");
1550
1883
  }
@@ -1657,7 +1990,12 @@
1657
1990
  var vw = document.documentElement.clientWidth;
1658
1991
  // Return true if the top-left corner is in the viewport and it has width & height.
1659
1992
  var lt = findPos(e);
1660
- return lt[0] >= 0 && lt[1] >= 0 && lt[0] < vw && lt[1] < vh && e.offsetWidth > 0 && e.offsetHeight > 0;
1993
+ return (lt[0] >= 0 &&
1994
+ lt[1] >= 0 &&
1995
+ lt[0] < vw &&
1996
+ lt[1] < vh &&
1997
+ e.offsetWidth > 0 &&
1998
+ e.offsetHeight > 0);
1661
1999
  }
1662
2000
  // Return an array containing the top & left coordinates of the element.
1663
2001
  // from http://www.quirksmode.org/js/findpos.html
@@ -1687,7 +2025,7 @@
1687
2025
  gMaxMeasureTimeout = setTimeout(function () {
1688
2026
  gFlags = addFlag(gFlags, Flags.BeaconSentAfterTimeout);
1689
2027
  _sendLux();
1690
- }, globalConfig.maxMeasureTime - _now());
2028
+ }, globalConfig.maxMeasureTime - msSincePageInit());
1691
2029
  }
1692
2030
  function clearMaxMeasureTimeout() {
1693
2031
  if (gMaxMeasureTimeout) {
@@ -1696,7 +2034,7 @@
1696
2034
  }
1697
2035
  function _getBeaconUrl(customData) {
1698
2036
  var queryParams = [
1699
- "v=" + SCRIPT_VERSION,
2037
+ "v=" + versionAsFloat(),
1700
2038
  "id=" + getCustomerId(),
1701
2039
  "sid=" + gSyncId,
1702
2040
  "uid=" + gUid,
@@ -1727,7 +2065,7 @@
1727
2065
  !gSyncId ||
1728
2066
  !_sample() || // OUTSIDE the sampled range
1729
2067
  gbLuxSent // LUX data already sent
1730
- ) {
2068
+ ) {
1731
2069
  return;
1732
2070
  }
1733
2071
  logger.logEvent(LogEvent.DataCollectionStart);
@@ -1752,7 +2090,7 @@
1752
2090
  }
1753
2091
  var sET = elementTimingValues(); // Element Timing data
1754
2092
  var sCPU = cpuTimes();
1755
- var CLS = getCLS$1();
2093
+ var CLS = getCLS();
1756
2094
  var sLuxjs = selfLoading();
1757
2095
  if (!isVisible()) {
1758
2096
  gFlags = addFlag(gFlags, Flags.VisibilityStateNotVisible);
@@ -1839,7 +2177,7 @@
1839
2177
  gbIxSent = sIx ? 1 : 0;
1840
2178
  // Send other beacons for JUST User Timing.
1841
2179
  while (remainingUtValues.length) {
1842
- (_a = fitUserTimingEntries(remainingUtValues, globalConfig, baseUrl)), (beaconUtValues = _a[0]), (remainingUtValues = _a[1]);
2180
+ _a = fitUserTimingEntries(remainingUtValues, globalConfig, baseUrl), beaconUtValues = _a[0], remainingUtValues = _a[1];
1843
2181
  var utBeaconUrl = baseUrl + "&UT=" + beaconUtValues.join(",");
1844
2182
  logger.logEvent(LogEvent.UserTimingBeaconSent, [utBeaconUrl]);
1845
2183
  _sendBeacon(utBeaconUrl);
@@ -1848,7 +2186,7 @@
1848
2186
  var ixTimerId;
1849
2187
  function _sendIxAfterDelay() {
1850
2188
  clearTimeout(ixTimerId);
1851
- ixTimerId = setTimeout(_sendIx, 100);
2189
+ ixTimerId = setTimeout(_sendIx, globalConfig.interactionBeaconDelay);
1852
2190
  }
1853
2191
  // Beacon back the IX data separately (need to sync with LUX beacon on the backend).
1854
2192
  function _sendIx() {
@@ -1906,7 +2244,7 @@
1906
2244
  // Note for scroll input we don't remove the handlers or send the IX beacon because we want to
1907
2245
  // capture click and key events as well, since these are typically more important than scrolls.
1908
2246
  if (typeof ghIx["s"] === "undefined") {
1909
- ghIx["s"] = _now();
2247
+ ghIx["s"] = msSincePageInit();
1910
2248
  }
1911
2249
  }
1912
2250
  function _keyHandler(e) {
@@ -1924,7 +2262,7 @@
1924
2262
  return;
1925
2263
  }
1926
2264
  if (typeof ghIx["k"] === "undefined") {
1927
- ghIx["k"] = _now();
2265
+ ghIx["k"] = msSincePageInit();
1928
2266
  if (e && e.target instanceof Element) {
1929
2267
  var trackId = getNodeSelector(e.target);
1930
2268
  if (trackId) {
@@ -1940,7 +2278,7 @@
1940
2278
  }
1941
2279
  function _clickHandler(e) {
1942
2280
  if (typeof ghIx["c"] === "undefined") {
1943
- ghIx["c"] = _now();
2281
+ ghIx["c"] = msSincePageInit();
1944
2282
  // Only one interaction type is recorded. Scrolls are considered less important, so delete
1945
2283
  // any scroll times if they exist.
1946
2284
  delete ghIx["s"];
@@ -1969,34 +2307,13 @@
1969
2307
  }
1970
2308
  _removeIxHandlers();
1971
2309
  }
1972
- // Wrapper to support older browsers (<= IE8)
1973
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1974
- function addListener(type, callback, useCapture) {
1975
- if (useCapture === void 0) { useCapture = false; }
1976
- if (addEventListener) {
1977
- addEventListener(type, callback, useCapture);
1978
- }
1979
- else if (window.attachEvent && true) {
1980
- window.attachEvent("on" + type, callback);
1981
- }
1982
- }
1983
- // Wrapper to support older browsers (<= IE8)
1984
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1985
- function removeListener(type, callback, useCapture) {
1986
- if (useCapture === void 0) { useCapture = false; }
1987
- if (removeEventListener) {
1988
- removeEventListener(type, callback, useCapture);
1989
- }
1990
- else if (window.detachEvent && true) {
1991
- window.detachEvent("on" + type, callback);
1992
- }
1993
- }
1994
2310
  function _addUnloadHandlers() {
1995
2311
  var onunload = function () {
1996
2312
  gFlags = addFlag(gFlags, Flags.BeaconSentFromUnloadHandler);
1997
2313
  logger.logEvent(LogEvent.UnloadHandlerTriggered);
1998
2314
  _sendLux();
1999
2315
  _sendIx();
2316
+ beacon.send();
2000
2317
  };
2001
2318
  // As well as visibilitychange, we also listen for pagehide. This is really only for browsers
2002
2319
  // with buggy visibilitychange implementations. For much older browsers that don't support
@@ -2033,14 +2350,14 @@
2033
2350
  // "00" matches all sample rates
2034
2351
  return Number(new Date()) + "00000";
2035
2352
  }
2036
- return Number(new Date()) + _padLeft(String(round(100000 * Math.random())), "00000");
2353
+ return Number(new Date()) + padStart(String(round(100000 * Math.random())), 5, "0");
2037
2354
  }
2038
2355
  // Unique ID (also known as Session ID)
2039
2356
  // We use this to track all the page views in a single user session.
2040
2357
  // If there is NOT a UID then set it to the new value (which is the same as the "sync ID" for this page).
2041
2358
  // Refresh its expiration date and return its value.
2042
2359
  function refreshUniqueId(newValue) {
2043
- var uid = _getCookie("lux_uid");
2360
+ var uid = _getCookie(SESSION_COOKIE_NAME);
2044
2361
  if (!uid || uid.length < 11) {
2045
2362
  uid = newValue;
2046
2363
  }
@@ -2058,7 +2375,7 @@
2058
2375
  return uid;
2059
2376
  }
2060
2377
  function setUniqueId(uid) {
2061
- _setCookie("lux_uid", uid, gSessionTimeout);
2378
+ _setCookie(SESSION_COOKIE_NAME, uid, gSessionTimeout);
2062
2379
  return uid;
2063
2380
  }
2064
2381
  // We use gUid (session ID) to do sampling. We make this available to customers so
@@ -2120,18 +2437,13 @@
2120
2437
  "=" +
2121
2438
  escape(value) +
2122
2439
  (seconds ? "; max-age=" + seconds : "") +
2123
- (globalConfig.cookieDomain ? "; domain=" +
2124
- globalConfig.cookieDomain : "") +
2440
+ (globalConfig.cookieDomain ? "; domain=" + globalConfig.cookieDomain : "") +
2125
2441
  "; path=/; SameSite=Lax";
2126
2442
  }
2127
2443
  catch (e) {
2128
2444
  logger.logEvent(LogEvent.CookieSetError);
2129
2445
  }
2130
2446
  }
2131
- // "padding" MUST be the length of the resulting string, eg, "0000" if you want a result of length 4.
2132
- function _padLeft(str, padding) {
2133
- return (padding + str).slice(-padding.length);
2134
- }
2135
2447
  // Set "LUX.auto=false" to disable send results automatically and
2136
2448
  // instead you must call LUX.send() explicitly.
2137
2449
  if (globalConfig.auto) {
@@ -2144,22 +2456,15 @@
2144
2456
  }
2145
2457
  };
2146
2458
  var sendBeaconAfterMinimumMeasureTime_1 = function () {
2147
- var elapsedTime = _now();
2459
+ var elapsedTime = msSincePageInit();
2148
2460
  var timeRemaining = globalConfig.minMeasureTime - elapsedTime;
2149
2461
  if (timeRemaining <= 0) {
2150
2462
  logger.logEvent(LogEvent.OnloadHandlerTriggered, [
2151
2463
  elapsedTime,
2152
2464
  globalConfig.minMeasureTime,
2153
2465
  ]);
2154
- if (document.readyState === "complete") {
2155
- // If onload has already passed, send the beacon now.
2156
- sendBeaconWhenVisible_1();
2157
- }
2158
- else {
2159
- // Ow, send the beacon slightly after window.onload.
2160
- addListener("load", function () {
2161
- setTimeout(sendBeaconWhenVisible_1, 200);
2162
- });
2466
+ if (globalConfig.measureUntil === "onload") {
2467
+ onPageLoad(sendBeaconWhenVisible_1);
2163
2468
  }
2164
2469
  }
2165
2470
  else {
@@ -2176,7 +2481,7 @@
2176
2481
  addEventListener("pageshow", function (event) {
2177
2482
  if (event.persisted) {
2178
2483
  // Record the timestamp of the bfcache restore
2179
- pageRestoreTime = event.timeStamp;
2484
+ setPageRestoreTime(event.timeStamp);
2180
2485
  // In Chromium, document.visibilityState is still "hidden" when pageshow fires after a bfcache
2181
2486
  // restore. Wrapping this in a setTimeout ensures the browser has enough time to update the
2182
2487
  // visibility.
@@ -2185,7 +2490,7 @@
2185
2490
  if (gbLuxSent) {
2186
2491
  // If the beacon was already sent for this page, we start a new page view and mark the
2187
2492
  // load time as the time it took to restore the page.
2188
- _init(pageRestoreTime, false);
2493
+ _init(getPageRestoreTime(), false);
2189
2494
  _markLoadTime();
2190
2495
  }
2191
2496
  // Flag the current page as a bfcache restore
@@ -2214,11 +2519,15 @@
2214
2519
  globalLux.markLoadTime = _markLoadTime;
2215
2520
  globalLux.send = function () {
2216
2521
  logger.logEvent(LogEvent.SendCalled);
2522
+ beacon.send();
2217
2523
  _sendLux();
2218
2524
  };
2219
2525
  globalLux.addData = _addData;
2220
2526
  globalLux.getSessionId = _getUniqueId; // so customers can do their own sampling
2221
- globalLux.getDebug = function () { return logger.getEvents(); };
2527
+ globalLux.getDebug = function () {
2528
+ console.log("SpeedCurve RUM debugging documentation: https://support.speedcurve.com/docs/rum-js-api#luxgetdebug");
2529
+ return logger.getEvents();
2530
+ };
2222
2531
  globalLux.forceSample = function () {
2223
2532
  logger.logEvent(LogEvent.ForceSampleCalled);
2224
2533
  setUniqueId(createSyncId(true));
@@ -2228,7 +2537,7 @@
2228
2537
  };
2229
2538
  globalLux.cmd = _runCommand;
2230
2539
  // Public properties
2231
- globalLux.version = SCRIPT_VERSION;
2540
+ globalLux.version = VERSION;
2232
2541
  /**
2233
2542
  * Run a command from the command queue
2234
2543
  */