govuk_publishing_components 39.2.4 → 39.2.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cdf41c9c036ffe0122a00d9cda5483c76b1a98d717abfe645eb40e2c6daea9e1
4
- data.tar.gz: bf83fabdd5e6a86b9fb74489e3dfdffc03afd231109f3a8f4451a9c32900174d
3
+ metadata.gz: 58b7f11016cf45ea3d59c0a1dbc3f8c059869a37a82925845e803d3a060074ec
4
+ data.tar.gz: 2115ba949c309a7482fb08748d2abfdca8b01f2adb01557d45083cf812d30073
5
5
  SHA512:
6
- metadata.gz: cdf4614dd7fdb99ff54416adbcb34624f377c3520ac529c5d705e5057f95fda145d4177d327fb91f7e55b9230e062ef1dc42339c09bb3510825d9b1cb2eb08e9
7
- data.tar.gz: f47eca08480dc0d75a1be133d23eebf8d29edf0c68e31d9609b098b94e18731f38165bff89e697fa4d405c25b940e9b8d1f696e8b9cb7bed9fedfc17c93fb918
6
+ metadata.gz: 313d31ab1ab2882e1d684357c40f95fcb73e8ac020f9e056aba9f8e46e25ab87cfb4df2414bfe19fef62717c7a028b00a5e2fc5616be12c0ef7356eb311c621d
7
+ data.tar.gz: c532deea8617bef61052a66fdc7501ebaed45a7040db52c5bd8150415385abc2e6c03972a6a9fee30622753aec2308b7440103cda8e923dd1d6d5be4838f43de
@@ -22,6 +22,48 @@
22
22
  (function () {
23
23
  'use strict';
24
24
 
25
+ var Flags = {
26
+ InitCalled: 1 << 0,
27
+ NavTimingNotSupported: 1 << 1,
28
+ UserTimingNotSupported: 1 << 2,
29
+ VisibilityStateNotVisible: 1 << 3,
30
+ BeaconSentFromUnloadHandler: 1 << 4,
31
+ BeaconSentAfterTimeout: 1 << 5,
32
+ PageLabelFromDocumentTitle: 1 << 6,
33
+ PageLabelFromLabelProp: 1 << 7,
34
+ PageLabelFromGlobalVariable: 1 << 8,
35
+ PageLabelFromUrlPattern: 1 << 9,
36
+ PageWasPrerendered: 1 << 10,
37
+ PageWasBfCacheRestored: 1 << 11,
38
+ BeaconBlockedByCsp: 1 << 12,
39
+ };
40
+ function addFlag(flags, flag) {
41
+ return flags | flag;
42
+ }
43
+
44
+ // Wrapper to support older browsers (<= IE8)
45
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
+ function addListener(type, callback, useCapture) {
47
+ if (useCapture === void 0) { useCapture = false; }
48
+ if (addEventListener) {
49
+ addEventListener(type, callback, useCapture);
50
+ }
51
+ else if (window.attachEvent && true) {
52
+ window.attachEvent("on" + type, callback);
53
+ }
54
+ }
55
+ // Wrapper to support older browsers (<= IE8)
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+ function removeListener(type, callback, useCapture) {
58
+ if (useCapture === void 0) { useCapture = false; }
59
+ if (removeEventListener) {
60
+ removeEventListener(type, callback, useCapture);
61
+ }
62
+ else if (window.detachEvent && true) {
63
+ window.detachEvent("on" + type, callback);
64
+ }
65
+ }
66
+
25
67
  function now() {
26
68
  return Date.now ? Date.now() : +new Date();
27
69
  }
@@ -74,6 +116,7 @@
74
116
  PostBeaconMetricRejected: 87,
75
117
  PostBeaconDisabled: 88,
76
118
  PostBeaconSendFailed: 89,
119
+ PostBeaconCSPViolation: 90,
77
120
  };
78
121
  var Logger = /** @class */ (function () {
79
122
  function Logger() {
@@ -240,7 +283,7 @@
240
283
  return str;
241
284
  }
242
285
 
243
- var VERSION = "4.0.20";
286
+ var VERSION = "4.0.23";
244
287
  /**
245
288
  * Returns the version of the script as a float to be stored in legacy systems that do not support
246
289
  * string versions.
@@ -256,6 +299,7 @@
256
299
  xhr.open("POST", url, true);
257
300
  xhr.setRequestHeader("content-type", "application/json");
258
301
  xhr.send(String(data));
302
+ return true;
259
303
  };
260
304
  var sendBeacon = "sendBeacon" in navigator ? navigator.sendBeacon.bind(navigator) : sendBeaconFallback;
261
305
  /**
@@ -279,7 +323,9 @@
279
323
  var _this = this;
280
324
  this.isRecording = true;
281
325
  this.isSent = false;
326
+ this.sendRetries = 0;
282
327
  this.maxMeasureTimeout = 0;
328
+ this.flags = 0;
283
329
  this.onBeforeSendCbs = [];
284
330
  this.startTime = opts.startTime || getZeroTime();
285
331
  this.config = opts.config;
@@ -293,6 +339,33 @@
293
339
  _this.stopRecording();
294
340
  _this.send();
295
341
  }, this.config.maxMeasureTime);
342
+ addListener("securitypolicyviolation", function (e) {
343
+ if (e.disposition !== "report" && e.blockedURI === _this.config.beaconUrlV2 && "URL" in self) {
344
+ // Some websites might have CSP rules that allow the GET beacon, but not the POST beacon.
345
+ // We can detect this here and attempt to send the beacon to a fallback endpoint.
346
+ //
347
+ // If the fallback endpoint has not been provided in the config, we will fall back to using
348
+ // the POST beacon pathname on the GET beacon origin.
349
+ if (!_this.config.beaconUrlFallback) {
350
+ var getOrigin = new URL(_this.config.beaconUrl).origin;
351
+ var postPathname = new URL(_this.config.beaconUrlV2).pathname;
352
+ _this.config.beaconUrlFallback = getOrigin + postPathname;
353
+ }
354
+ // Update the V2 beacon URL
355
+ _this.config.beaconUrlV2 = _this.config.beaconUrlFallback;
356
+ _this.logger.logEvent(LogEvent.PostBeaconCSPViolation, [_this.config.beaconUrlV2]);
357
+ _this.addFlag(Flags.BeaconBlockedByCsp);
358
+ // Not all browsers return false if sendBeacon fails. In this case, `this.isSent` will be
359
+ // true, even though the beacon wasn't sent. We need to reset this flag to ensure we can
360
+ // retry sending the beacon.
361
+ _this.isSent = false;
362
+ // Try to send the beacon again
363
+ if (_this.sendRetries < 1) {
364
+ _this.sendRetries++;
365
+ _this.send();
366
+ }
367
+ }
368
+ });
296
369
  this.logger.logEvent(LogEvent.PostBeaconInitialised);
297
370
  }
298
371
  Beacon.prototype.isBeingSampled = function () {
@@ -310,6 +383,9 @@
310
383
  }
311
384
  this.metricData[metric] = data;
312
385
  };
386
+ Beacon.prototype.addFlag = function (flag) {
387
+ this.flags = addFlag(this.flags, flag);
388
+ };
313
389
  Beacon.prototype.hasMetricData = function () {
314
390
  return Object.keys(this.metricData).length > 0;
315
391
  };
@@ -347,6 +423,7 @@
347
423
  var beaconUrl = this.beaconUrl();
348
424
  var payload = Object.assign({
349
425
  customerId: this.customerId,
426
+ flags: this.flags,
350
427
  measureDuration: msSincePageInit(),
351
428
  pageId: this.pageId,
352
429
  scriptVersion: VERSION,
@@ -354,40 +431,21 @@
354
431
  startTime: this.startTime,
355
432
  }, this.metricData);
356
433
  try {
357
- sendBeacon(beaconUrl, JSON.stringify(payload));
358
- this.isSent = true;
359
- this.logger.logEvent(LogEvent.PostBeaconSent, [beaconUrl, payload]);
434
+ if (sendBeacon(beaconUrl, JSON.stringify(payload))) {
435
+ this.isSent = true;
436
+ this.logger.logEvent(LogEvent.PostBeaconSent, [beaconUrl, payload]);
437
+ }
360
438
  }
361
439
  catch (e) {
362
- this.logger.logEvent(LogEvent.PostBeaconSendFailed, [e]);
440
+ // Intentionally empty; handled below
441
+ }
442
+ if (!this.isSent) {
443
+ this.logger.logEvent(LogEvent.PostBeaconSendFailed, [beaconUrl, payload]);
363
444
  }
364
445
  };
365
446
  return Beacon;
366
447
  }());
367
448
 
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
449
  function onPageLoad(callback) {
392
450
  if (document.readyState === "complete") {
393
451
  // The onload event has already fired
@@ -408,6 +466,7 @@
408
466
  allowEmptyPostBeacon: getProperty(obj, "allowEmptyPostBeacon", false),
409
467
  auto: autoMode,
410
468
  beaconUrl: getProperty(obj, "beaconUrl", luxOrigin + "/lux/"),
469
+ beaconUrlFallback: getProperty(obj, "beaconUrlFallback"),
411
470
  beaconUrlV2: getProperty(obj, "beaconUrlV2", "https://beacon.speedcurve.com/store"),
412
471
  conversions: getProperty(obj, "conversions"),
413
472
  cookieDomain: getProperty(obj, "cookieDomain"),
@@ -543,39 +602,38 @@
543
602
  var MAX_SELECTOR_LENGTH = 100;
544
603
  function getNodeSelector(node, selector) {
545
604
  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(".");
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
- }
605
+ try {
606
+ if (selector && (node.nodeType === 9 || selector.length > MAX_SELECTOR_LENGTH || !node.parentNode)) {
607
+ // Final selector.
608
+ return selector;
609
+ }
610
+ var el = node;
611
+ // Our first preference is to use the data-sctrack attribute from anywhere in the tree
612
+ var trackId = getClosestScTrackAttribute(el);
613
+ if (trackId) {
614
+ return trackId;
615
+ }
616
+ if (el.id) {
617
+ // Once we've found an element with ID we return the selector.
618
+ return "#" + el.id + (selector ? ">" + selector : "");
619
+ }
620
+ else if (el) {
621
+ // Otherwise attempt to get parent elements recursively
622
+ var name_1 = el.nodeType === 1 ? el.nodeName.toLowerCase() : el.nodeName.toUpperCase();
623
+ var classes = el.className ? "." + el.className.replace(/\s+/g, ".") : "";
624
+ // Remove classes until the selector is short enough
625
+ while ((name_1 + classes).length > MAX_SELECTOR_LENGTH) {
626
+ classes = classes.split(".").slice(0, -1).join(".");
627
+ }
628
+ var currentSelector = name_1 + classes + (selector ? ">" + selector : "");
629
+ if (el.parentNode) {
630
+ var selectorWithParent = getNodeSelector(el.parentNode, currentSelector);
631
+ if (selectorWithParent.length < MAX_SELECTOR_LENGTH) {
632
+ return selectorWithParent;
576
633
  }
577
- return currentSelector;
578
634
  }
635
+ return currentSelector;
636
+ }
579
637
  }
580
638
  catch (error) {
581
639
  // Do nothing.
@@ -583,24 +641,6 @@
583
641
  return selector;
584
642
  }
585
643
 
586
- var Flags = {
587
- InitCalled: 1 << 0,
588
- NavTimingNotSupported: 1 << 1,
589
- UserTimingNotSupported: 1 << 2,
590
- VisibilityStateNotVisible: 1 << 3,
591
- BeaconSentFromUnloadHandler: 1 << 4,
592
- BeaconSentAfterTimeout: 1 << 5,
593
- PageLabelFromDocumentTitle: 1 << 6,
594
- PageLabelFromLabelProp: 1 << 7,
595
- PageLabelFromGlobalVariable: 1 << 8,
596
- PageLabelFromUrlPattern: 1 << 9,
597
- PageWasPrerendered: 1 << 10,
598
- PageWasBfCacheRestored: 1 << 11,
599
- };
600
- function addFlag(flags, flag) {
601
- return flags | flag;
602
- }
603
-
604
644
  var sessionValue = 0;
605
645
  var sessionEntries = [];
606
646
  var sessionAttributions = [];
@@ -620,23 +660,23 @@
620
660
  elementType: source.node.nodeName,
621
661
  }); })
622
662
  : [];
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;
630
- }
631
- else {
632
- sessionValue += entry.value;
633
- sessionEntries.push(entry);
634
- sessionAttributions = sessionAttributions.concat(sources);
635
- if (!largestEntry || entry.value > largestEntry.value) {
663
+ if (sessionEntries.length &&
664
+ (entry.startTime - latestEntry.startTime >= 1000 ||
665
+ entry.startTime - firstEntry.startTime >= 5000)) {
666
+ sessionValue = entry.value;
667
+ sessionEntries = [entry];
668
+ sessionAttributions = sources;
636
669
  largestEntry = entry;
637
- }
670
+ }
671
+ else {
672
+ sessionValue += entry.value;
673
+ sessionEntries.push(entry);
674
+ sessionAttributions = sessionAttributions.concat(sources);
675
+ if (!largestEntry || entry.value > largestEntry.value) {
676
+ largestEntry = entry;
638
677
  }
639
- maximumSessionValue = max(maximumSessionValue, sessionValue);
678
+ }
679
+ maximumSessionValue = max(maximumSessionValue, sessionValue);
640
680
  }
641
681
  }
642
682
  function reset$1() {
@@ -1060,6 +1100,7 @@
1060
1100
  if (!performance.timing) {
1061
1101
  logger.logEvent(LogEvent.NavTimingNotSupported);
1062
1102
  gFlags = addFlag(gFlags, Flags.NavTimingNotSupported);
1103
+ beacon.addFlag(Flags.NavTimingNotSupported);
1063
1104
  }
1064
1105
  logger.logEvent(LogEvent.NavigationStart, [timing.navigationStart]);
1065
1106
  ////////////////////// FID BEGIN
@@ -1165,6 +1206,7 @@
1165
1206
  };
1166
1207
  gaMarks.push(entry);
1167
1208
  gFlags = addFlag(gFlags, Flags.UserTimingNotSupported);
1209
+ beacon.addFlag(Flags.UserTimingNotSupported);
1168
1210
  return entry;
1169
1211
  }
1170
1212
  }
@@ -1267,6 +1309,7 @@
1267
1309
  };
1268
1310
  gaMeasures.push(entry);
1269
1311
  gFlags = addFlag(gFlags, Flags.UserTimingNotSupported);
1312
+ beacon.addFlag(Flags.UserTimingNotSupported);
1270
1313
  return entry;
1271
1314
  }
1272
1315
  }
@@ -1610,6 +1653,7 @@
1610
1653
  if (clearFlags) {
1611
1654
  gFlags = 0;
1612
1655
  gFlags = addFlag(gFlags, Flags.InitCalled);
1656
+ beacon.addFlag(Flags.InitCalled);
1613
1657
  }
1614
1658
  // Reset the maximum measure timeout
1615
1659
  createMaxMeasureTimeout();
@@ -1653,7 +1697,7 @@
1653
1697
  "style" === e.as ||
1654
1698
  (typeof e.onload === "function" && e.media === "all")) ;
1655
1699
  else {
1656
- nBlocking++;
1700
+ nBlocking++;
1657
1701
  }
1658
1702
  }
1659
1703
  }
@@ -2024,6 +2068,7 @@
2024
2068
  clearMaxMeasureTimeout();
2025
2069
  gMaxMeasureTimeout = setTimeout(function () {
2026
2070
  gFlags = addFlag(gFlags, Flags.BeaconSentAfterTimeout);
2071
+ beacon.addFlag(Flags.BeaconSentAfterTimeout);
2027
2072
  _sendLux();
2028
2073
  }, globalConfig.maxMeasureTime - msSincePageInit());
2029
2074
  }
@@ -2094,9 +2139,11 @@
2094
2139
  var sLuxjs = selfLoading();
2095
2140
  if (!isVisible()) {
2096
2141
  gFlags = addFlag(gFlags, Flags.VisibilityStateNotVisible);
2142
+ beacon.addFlag(Flags.VisibilityStateNotVisible);
2097
2143
  }
2098
2144
  if (wasPrerendered()) {
2099
2145
  gFlags = addFlag(gFlags, Flags.PageWasPrerendered);
2146
+ beacon.addFlag(Flags.PageWasPrerendered);
2100
2147
  }
2101
2148
  if (globalConfig.serverTiming) {
2102
2149
  var navEntry = getNavigationEntry();
@@ -2310,6 +2357,7 @@
2310
2357
  function _addUnloadHandlers() {
2311
2358
  var onunload = function () {
2312
2359
  gFlags = addFlag(gFlags, Flags.BeaconSentFromUnloadHandler);
2360
+ beacon.addFlag(Flags.BeaconSentFromUnloadHandler);
2313
2361
  logger.logEvent(LogEvent.UnloadHandlerTriggered);
2314
2362
  _sendLux();
2315
2363
  _sendIx();
@@ -2387,12 +2435,14 @@
2387
2435
  function _getPageLabel() {
2388
2436
  if (LUX.label) {
2389
2437
  gFlags = addFlag(gFlags, Flags.PageLabelFromLabelProp);
2438
+ beacon.addFlag(Flags.PageLabelFromLabelProp);
2390
2439
  return LUX.label;
2391
2440
  }
2392
2441
  if (typeof LUX.pagegroups !== "undefined") {
2393
2442
  var label = getMatchesFromPatternMap(LUX.pagegroups, location.hostname, location.pathname, true);
2394
2443
  if (label) {
2395
2444
  gFlags = addFlag(gFlags, Flags.PageLabelFromUrlPattern);
2445
+ beacon.addFlag(Flags.PageLabelFromUrlPattern);
2396
2446
  return label;
2397
2447
  }
2398
2448
  }
@@ -2402,6 +2452,7 @@
2402
2452
  var label = evaluateJsPageLabel();
2403
2453
  if (label) {
2404
2454
  gFlags = addFlag(gFlags, Flags.PageLabelFromGlobalVariable);
2455
+ beacon.addFlag(Flags.PageLabelFromGlobalVariable);
2405
2456
  return label;
2406
2457
  }
2407
2458
  }
@@ -2411,6 +2462,7 @@
2411
2462
  }
2412
2463
  // default to document.title
2413
2464
  gFlags = addFlag(gFlags, Flags.PageLabelFromDocumentTitle);
2465
+ beacon.addFlag(Flags.PageLabelFromDocumentTitle);
2414
2466
  return document.title;
2415
2467
  }
2416
2468
  function _getCookie(name) {
@@ -2495,6 +2547,7 @@
2495
2547
  }
2496
2548
  // Flag the current page as a bfcache restore
2497
2549
  gFlags = addFlag(gFlags, Flags.PageWasBfCacheRestored);
2550
+ beacon.addFlag(Flags.PageWasBfCacheRestored);
2498
2551
  }, 0);
2499
2552
  }
2500
2553
  });
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "39.2.4".freeze
2
+ VERSION = "39.2.5".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_publishing_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 39.2.4
4
+ version: 39.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - GOV.UK Dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-11 00:00:00.000000000 Z
11
+ date: 2024-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config