@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.js CHANGED
@@ -1538,6 +1538,87 @@ function createSelectionOverlay() {
1538
1538
  document.body.appendChild(overlay);
1539
1539
  });
1540
1540
  }
1541
+ function rectsIntersect(a, b) {
1542
+ 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);
1543
+ }
1544
+ function intersectsCrossOriginIframe(selection) {
1545
+ const iframes = Array.from(document.querySelectorAll("iframe"));
1546
+ for (const iframe of iframes) {
1547
+ const rect = iframe.getBoundingClientRect();
1548
+ if (rect.width <= 0 || rect.height <= 0) {
1549
+ continue;
1550
+ }
1551
+ if (!rectsIntersect(selection, {
1552
+ left: rect.left,
1553
+ top: rect.top,
1554
+ width: rect.width,
1555
+ height: rect.height
1556
+ })) {
1557
+ continue;
1558
+ }
1559
+ try {
1560
+ if (!iframe.contentWindow || !iframe.contentDocument) {
1561
+ return true;
1562
+ }
1563
+ void iframe.contentDocument.location.href;
1564
+ } catch (e) {
1565
+ return true;
1566
+ }
1567
+ }
1568
+ return false;
1569
+ }
1570
+ async function captureWithDisplayMedia(selection) {
1571
+ var _a;
1572
+ if (!((_a = navigator.mediaDevices) == null ? void 0 : _a.getDisplayMedia)) {
1573
+ throw new BugReporterError("CAPTURE_ERROR", "This page contains iframe content that needs screen-capture permission.");
1574
+ }
1575
+ let stream = null;
1576
+ const video = document.createElement("video");
1577
+ video.muted = true;
1578
+ video.playsInline = true;
1579
+ try {
1580
+ stream = await navigator.mediaDevices.getDisplayMedia({
1581
+ video: true,
1582
+ audio: false
1583
+ });
1584
+ video.srcObject = stream;
1585
+ await video.play();
1586
+ if (!video.videoWidth || !video.videoHeight) {
1587
+ await new Promise((resolve) => {
1588
+ video.onloadedmetadata = () => resolve();
1589
+ });
1590
+ }
1591
+ if (!video.videoWidth || !video.videoHeight) {
1592
+ throw new BugReporterError("CAPTURE_ERROR", "Could not read screen-capture frame.");
1593
+ }
1594
+ const scaleX = video.videoWidth / window.innerWidth;
1595
+ const scaleY = video.videoHeight / window.innerHeight;
1596
+ const sx = Math.max(0, Math.round(selection.left * scaleX));
1597
+ const sy = Math.max(0, Math.round(selection.top * scaleY));
1598
+ const sw = Math.max(1, Math.round(selection.width * scaleX));
1599
+ const sh = Math.max(1, Math.round(selection.height * scaleY));
1600
+ const canvas = document.createElement("canvas");
1601
+ canvas.width = sw;
1602
+ canvas.height = sh;
1603
+ const context = canvas.getContext("2d");
1604
+ if (!context) {
1605
+ throw new BugReporterError("CAPTURE_ERROR", "Canvas 2D context unavailable.");
1606
+ }
1607
+ context.drawImage(video, sx, sy, sw, sh, 0, 0, sw, sh);
1608
+ return await canvasToBlob(canvas);
1609
+ } catch (error) {
1610
+ if (error instanceof BugReporterError) {
1611
+ throw error;
1612
+ }
1613
+ if (error instanceof DOMException && error.name === "NotAllowedError") {
1614
+ throw new BugReporterError("PERMISSION_DENIED", "Permission denied for screen capture.", error);
1615
+ }
1616
+ throw new BugReporterError("CAPTURE_ERROR", "Fallback screen capture failed.", error);
1617
+ } finally {
1618
+ stream == null ? void 0 : stream.getTracks().forEach((track) => track.stop());
1619
+ video.srcObject = null;
1620
+ }
1621
+ }
1541
1622
  function canvasToBlob(canvas) {
1542
1623
  return new Promise((resolve, reject) => {
1543
1624
  canvas.toBlob((blob) => {
@@ -1554,6 +1635,9 @@ async function captureScreenshotArea(options) {
1554
1635
  const masked = applyMasking(options.maskSelectors);
1555
1636
  const textChanges = scrubText(document.body, options.redactTextPatterns);
1556
1637
  try {
1638
+ if (intersectsCrossOriginIframe(selection)) {
1639
+ return await captureWithDisplayMedia(selection);
1640
+ }
1557
1641
  const baseCanvas = await html2canvas(document.documentElement, {
1558
1642
  useCORS: true,
1559
1643
  scrollX: -window.scrollX,
@@ -1579,6 +1663,15 @@ async function captureScreenshotArea(options) {
1579
1663
  context.drawImage(baseCanvas, sx, sy, sw, sh, 0, 0, sw, sh);
1580
1664
  return await canvasToBlob(cropped);
1581
1665
  } catch (error) {
1666
+ if (!intersectsCrossOriginIframe(selection)) {
1667
+ try {
1668
+ return await captureWithDisplayMedia(selection);
1669
+ } catch (fallbackError) {
1670
+ if (fallbackError instanceof BugReporterError) {
1671
+ throw fallbackError;
1672
+ }
1673
+ }
1674
+ }
1582
1675
  if (error instanceof BugReporterError) {
1583
1676
  throw error;
1584
1677
  }