@fogg/bug-reporter 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1562,6 +1562,87 @@ function createSelectionOverlay() {
1562
1562
  document.body.appendChild(overlay);
1563
1563
  });
1564
1564
  }
1565
+ function rectsIntersect(a, b) {
1566
+ return !(a.left + a.width <= b.left || b.left + b.width <= a.left || a.top + a.height <= b.top || b.top + b.height <= a.top);
1567
+ }
1568
+ function intersectsCrossOriginIframe(selection) {
1569
+ const iframes = Array.from(document.querySelectorAll("iframe"));
1570
+ for (const iframe of iframes) {
1571
+ const rect = iframe.getBoundingClientRect();
1572
+ if (rect.width <= 0 || rect.height <= 0) {
1573
+ continue;
1574
+ }
1575
+ if (!rectsIntersect(selection, {
1576
+ left: rect.left,
1577
+ top: rect.top,
1578
+ width: rect.width,
1579
+ height: rect.height
1580
+ })) {
1581
+ continue;
1582
+ }
1583
+ try {
1584
+ if (!iframe.contentWindow || !iframe.contentDocument) {
1585
+ return true;
1586
+ }
1587
+ void iframe.contentDocument.location.href;
1588
+ } catch (e) {
1589
+ return true;
1590
+ }
1591
+ }
1592
+ return false;
1593
+ }
1594
+ async function captureWithDisplayMedia(selection) {
1595
+ var _a;
1596
+ if (!((_a = navigator.mediaDevices) == null ? void 0 : _a.getDisplayMedia)) {
1597
+ throw new BugReporterError("CAPTURE_ERROR", "This page contains iframe content that needs screen-capture permission.");
1598
+ }
1599
+ let stream = null;
1600
+ const video = document.createElement("video");
1601
+ video.muted = true;
1602
+ video.playsInline = true;
1603
+ try {
1604
+ stream = await navigator.mediaDevices.getDisplayMedia({
1605
+ video: true,
1606
+ audio: false
1607
+ });
1608
+ video.srcObject = stream;
1609
+ await video.play();
1610
+ if (!video.videoWidth || !video.videoHeight) {
1611
+ await new Promise((resolve) => {
1612
+ video.onloadedmetadata = () => resolve();
1613
+ });
1614
+ }
1615
+ if (!video.videoWidth || !video.videoHeight) {
1616
+ throw new BugReporterError("CAPTURE_ERROR", "Could not read screen-capture frame.");
1617
+ }
1618
+ const scaleX = video.videoWidth / window.innerWidth;
1619
+ const scaleY = video.videoHeight / window.innerHeight;
1620
+ const sx = Math.max(0, Math.round(selection.left * scaleX));
1621
+ const sy = Math.max(0, Math.round(selection.top * scaleY));
1622
+ const sw = Math.max(1, Math.round(selection.width * scaleX));
1623
+ const sh = Math.max(1, Math.round(selection.height * scaleY));
1624
+ const canvas = document.createElement("canvas");
1625
+ canvas.width = sw;
1626
+ canvas.height = sh;
1627
+ const context = canvas.getContext("2d");
1628
+ if (!context) {
1629
+ throw new BugReporterError("CAPTURE_ERROR", "Canvas 2D context unavailable.");
1630
+ }
1631
+ context.drawImage(video, sx, sy, sw, sh, 0, 0, sw, sh);
1632
+ return await canvasToBlob(canvas);
1633
+ } catch (error) {
1634
+ if (error instanceof BugReporterError) {
1635
+ throw error;
1636
+ }
1637
+ if (error instanceof DOMException && error.name === "NotAllowedError") {
1638
+ throw new BugReporterError("PERMISSION_DENIED", "Permission denied for screen capture.", error);
1639
+ }
1640
+ throw new BugReporterError("CAPTURE_ERROR", "Fallback screen capture failed.", error);
1641
+ } finally {
1642
+ stream == null ? void 0 : stream.getTracks().forEach((track) => track.stop());
1643
+ video.srcObject = null;
1644
+ }
1645
+ }
1565
1646
  function canvasToBlob(canvas) {
1566
1647
  return new Promise((resolve, reject) => {
1567
1648
  canvas.toBlob((blob) => {
@@ -1578,6 +1659,9 @@ async function captureScreenshotArea(options) {
1578
1659
  const masked = applyMasking(options.maskSelectors);
1579
1660
  const textChanges = scrubText(document.body, options.redactTextPatterns);
1580
1661
  try {
1662
+ if (intersectsCrossOriginIframe(selection)) {
1663
+ return await captureWithDisplayMedia(selection);
1664
+ }
1581
1665
  const baseCanvas = await html2canvas__default.default(document.documentElement, {
1582
1666
  useCORS: true,
1583
1667
  scrollX: -window.scrollX,
@@ -1603,6 +1687,15 @@ async function captureScreenshotArea(options) {
1603
1687
  context.drawImage(baseCanvas, sx, sy, sw, sh, 0, 0, sw, sh);
1604
1688
  return await canvasToBlob(cropped);
1605
1689
  } catch (error) {
1690
+ if (!intersectsCrossOriginIframe(selection)) {
1691
+ try {
1692
+ return await captureWithDisplayMedia(selection);
1693
+ } catch (fallbackError) {
1694
+ if (fallbackError instanceof BugReporterError) {
1695
+ throw fallbackError;
1696
+ }
1697
+ }
1698
+ }
1606
1699
  if (error instanceof BugReporterError) {
1607
1700
  throw error;
1608
1701
  }