@insitue/sdk 0.1.3 → 0.1.4

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  mountCaptureOnly
3
- } from "./chunk-PRCHVT5A.js";
4
- import "./chunk-RYS5Z2BU.js";
3
+ } from "./chunk-TTH4NBFA.js";
4
+ import "./chunk-65BGOX2M.js";
5
5
  export {
6
6
  mountCaptureOnly
7
7
  };
@@ -1641,19 +1641,62 @@ async function toCanvas(node, options = {}) {
1641
1641
  }
1642
1642
 
1643
1643
  // src/capture.ts
1644
- function crossOrigin(url) {
1645
- if (!url || url.startsWith("data:") || url.startsWith("blob:")) {
1646
- return false;
1647
- }
1648
- try {
1649
- return new URL(url, location.href).origin !== location.origin;
1650
- } catch {
1651
- return false;
1652
- }
1644
+ var IMAGE_PLACEHOLDER = "data:image/svg+xml;base64," + (typeof btoa !== "undefined" ? btoa(
1645
+ '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><rect width="32" height="32" fill="#e8e8e8"/><path d="M0 0 L32 32 M32 0 L0 32" stroke="#b0b0b0" stroke-width="1.5"/></svg>'
1646
+ ) : "");
1647
+ async function preResolveImages() {
1648
+ const restorations = [];
1649
+ const failedImages = /* @__PURE__ */ new Set();
1650
+ const images = Array.from(
1651
+ document.querySelectorAll("img")
1652
+ ).filter(
1653
+ (img) => !img.closest?.("#insitu-root, [data-insitu-layer]")
1654
+ );
1655
+ await Promise.all(
1656
+ images.map(async (img) => {
1657
+ const srcToFetch = img.currentSrc || img.src;
1658
+ if (!srcToFetch || srcToFetch.startsWith("data:") || srcToFetch.startsWith("blob:")) {
1659
+ return;
1660
+ }
1661
+ try {
1662
+ const res = await fetch(srcToFetch, { cache: "force-cache" });
1663
+ if (!res.ok) {
1664
+ failedImages.add(img);
1665
+ return;
1666
+ }
1667
+ const blob = await res.blob();
1668
+ const dataUrl = await new Promise((resolve, reject) => {
1669
+ const reader = new FileReader();
1670
+ reader.onload = () => resolve(reader.result);
1671
+ reader.onerror = () => reject(reader.error);
1672
+ reader.readAsDataURL(blob);
1673
+ });
1674
+ const origSrc = img.getAttribute("src");
1675
+ const origSrcset = img.getAttribute("srcset");
1676
+ restorations.push(() => {
1677
+ if (origSrc != null) img.setAttribute("src", origSrc);
1678
+ else img.removeAttribute("src");
1679
+ if (origSrcset != null) img.setAttribute("srcset", origSrcset);
1680
+ else img.removeAttribute("srcset");
1681
+ });
1682
+ img.removeAttribute("srcset");
1683
+ img.src = dataUrl;
1684
+ try {
1685
+ await img.decode();
1686
+ } catch {
1687
+ }
1688
+ } catch {
1689
+ failedImages.add(img);
1690
+ }
1691
+ })
1692
+ );
1693
+ return {
1694
+ restore: () => {
1695
+ for (const r3 of restorations) r3();
1696
+ },
1697
+ failedImages
1698
+ };
1653
1699
  }
1654
- var IMAGE_PLACEHOLDER = "data:image/svg+xml;utf8," + encodeURIComponent(
1655
- `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><rect width="32" height="32" fill="#e8e8e8"/><path d="M0 0 L32 32 M32 0 L0 32" stroke="#b0b0b0" stroke-width="1.5"/></svg>`
1656
- );
1657
1700
  function findContextAncestor(el) {
1658
1701
  const minW = 420;
1659
1702
  const minH = 140;
@@ -1675,37 +1718,42 @@ async function renderViewportCrop(cropRect, pixelRatio) {
1675
1718
  const bodyBg = getComputedStyle(document.body).backgroundColor;
1676
1719
  const htmlBg = getComputedStyle(document.documentElement).backgroundColor;
1677
1720
  const backgroundColor = bodyBg && bodyBg !== "rgba(0, 0, 0, 0)" && bodyBg !== "transparent" ? bodyBg : htmlBg && htmlBg !== "rgba(0, 0, 0, 0)" && htmlBg !== "transparent" ? htmlBg : "#ffffff";
1678
- const fullCanvas = await toCanvas(document.documentElement, {
1679
- pixelRatio,
1680
- cacheBust: true,
1681
- backgroundColor,
1682
- imagePlaceholder: IMAGE_PLACEHOLDER,
1683
- // Only filter out our own overlay layers — leave cross-origin
1684
- // <img>s in place so embedImages can fetch+inline them.
1685
- filter: (n2) => !(n2 instanceof Element && n2.closest?.("#insitu-root, [data-insitu-layer]"))
1686
- });
1687
- const sx = window.scrollX;
1688
- const sy = window.scrollY;
1689
- const out = document.createElement("canvas");
1690
- out.width = Math.max(1, Math.round(cropRect.width * pixelRatio));
1691
- out.height = Math.max(1, Math.round(cropRect.height * pixelRatio));
1692
- const ctx = out.getContext("2d");
1693
- if (!ctx) return null;
1694
- ctx.drawImage(
1695
- fullCanvas,
1696
- Math.round((cropRect.x + sx) * pixelRatio),
1697
- Math.round((cropRect.y + sy) * pixelRatio),
1698
- Math.round(cropRect.width * pixelRatio),
1699
- Math.round(cropRect.height * pixelRatio),
1700
- 0,
1701
- 0,
1702
- out.width,
1703
- out.height
1704
- );
1705
- if (looksBlankUniform(ctx, out.width, out.height)) {
1706
- return null;
1721
+ const { restore: restoreImages, failedImages } = await preResolveImages();
1722
+ try {
1723
+ const fullCanvas = await toCanvas(document.documentElement, {
1724
+ pixelRatio,
1725
+ // cacheBust off — we've already swapped srcs to data URLs.
1726
+ cacheBust: false,
1727
+ backgroundColor,
1728
+ imagePlaceholder: IMAGE_PLACEHOLDER,
1729
+ // Strip only our own overlay layers.
1730
+ filter: (n2) => !(n2 instanceof Element && n2.closest?.("#insitu-root, [data-insitu-layer]"))
1731
+ });
1732
+ const sx = window.scrollX;
1733
+ const sy = window.scrollY;
1734
+ const out = document.createElement("canvas");
1735
+ out.width = Math.max(1, Math.round(cropRect.width * pixelRatio));
1736
+ out.height = Math.max(1, Math.round(cropRect.height * pixelRatio));
1737
+ const ctx = out.getContext("2d");
1738
+ if (!ctx) return { dataUrl: null, failedImages };
1739
+ ctx.drawImage(
1740
+ fullCanvas,
1741
+ Math.round((cropRect.x + sx) * pixelRatio),
1742
+ Math.round((cropRect.y + sy) * pixelRatio),
1743
+ Math.round(cropRect.width * pixelRatio),
1744
+ Math.round(cropRect.height * pixelRatio),
1745
+ 0,
1746
+ 0,
1747
+ out.width,
1748
+ out.height
1749
+ );
1750
+ if (looksBlankUniform(ctx, out.width, out.height)) {
1751
+ return { dataUrl: null, failedImages };
1752
+ }
1753
+ return { dataUrl: out.toDataURL("image/png"), failedImages };
1754
+ } finally {
1755
+ restoreImages();
1707
1756
  }
1708
- return out.toDataURL("image/png");
1709
1757
  }
1710
1758
  function looksBlankUniform(ctx, w3, h3) {
1711
1759
  if (w3 < 4 || h3 < 4) return false;
@@ -1724,7 +1772,7 @@ function looksBlankUniform(ctx, w3, h3) {
1724
1772
  }
1725
1773
  return new Set(samples).size === 1;
1726
1774
  }
1727
- function assessCaptureQuality(cropRect) {
1775
+ function assessCaptureQuality(cropRect, failedImages) {
1728
1776
  const out = {
1729
1777
  unembeddableImages: 0,
1730
1778
  hasVideo: false,
@@ -1739,13 +1787,7 @@ function assessCaptureQuality(cropRect) {
1739
1787
  const overlaps = r3.right >= cropRect.x && r3.left <= cropRect.x + cropRect.width && r3.bottom >= cropRect.y && r3.top <= cropRect.y + cropRect.height;
1740
1788
  if (!overlaps) continue;
1741
1789
  if (el instanceof HTMLImageElement) {
1742
- const src = el.currentSrc || el.src;
1743
- if (!src) continue;
1744
- const browserLoaded = el.complete && el.naturalWidth > 0;
1745
- const corsSafe = !crossOrigin(src) || el.crossOrigin != null;
1746
- if (!browserLoaded || !corsSafe) {
1747
- out.unembeddableImages++;
1748
- }
1790
+ if (failedImages.has(el)) out.unembeddableImages++;
1749
1791
  } else if (el instanceof HTMLVideoElement) {
1750
1792
  if (r3.width > 0 && r3.height > 0) out.hasVideo = true;
1751
1793
  } else if (el instanceof HTMLCanvasElement) {
@@ -1972,11 +2014,9 @@ async function buildBundle(sel) {
1972
2014
  let layer1Result = null;
1973
2015
  let quality = null;
1974
2016
  if (!skipLayer1) {
1975
- layer1Result = await renderViewportCrop(
1976
- cropRect,
1977
- Math.min(dpr, 1.5)
1978
- );
1979
- quality = assessCaptureQuality(cropRect);
2017
+ const r3 = await renderViewportCrop(cropRect, Math.min(dpr, 1.5));
2018
+ layer1Result = r3.dataUrl;
2019
+ quality = assessCaptureQuality(cropRect, r3.failedImages);
1980
2020
  }
1981
2021
  const imperfect = !layer1Result || quality != null && (quality.unembeddableImages > 0 || quality.hasVideo || quality.hasCanvas);
1982
2022
  if (imperfect || skipLayer1) {
@@ -15,7 +15,7 @@ import {
15
15
  setCaptureSettings,
16
16
  stopDisplayMedia,
17
17
  y
18
- } from "./chunk-RYS5Z2BU.js";
18
+ } from "./chunk-65BGOX2M.js";
19
19
 
20
20
  // src/client.ts
21
21
  var CompanionClient = class {
@@ -10,7 +10,7 @@ import {
10
10
  retryDisplayMedia,
11
11
  stopDisplayMedia,
12
12
  y
13
- } from "./chunk-RYS5Z2BU.js";
13
+ } from "./chunk-65BGOX2M.js";
14
14
 
15
15
  // src/capture-only.ts
16
16
  var DEFAULT_INGEST = "https://www.insitue.com/api/v1/capture";
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  mountCaptureOnly
3
- } from "./chunk-PRCHVT5A.js";
3
+ } from "./chunk-TTH4NBFA.js";
4
4
  import {
5
5
  mountInSitue
6
- } from "./chunk-VWPAKOUW.js";
7
- import "./chunk-RYS5Z2BU.js";
6
+ } from "./chunk-7GRJ5SZQ.js";
7
+ import "./chunk-65BGOX2M.js";
8
8
 
9
9
  // src/InSitue.tsx
10
10
  import { useEffect } from "react";
package/dist/overlay.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  mountInSitue
3
- } from "./chunk-VWPAKOUW.js";
4
- import "./chunk-RYS5Z2BU.js";
3
+ } from "./chunk-7GRJ5SZQ.js";
4
+ import "./chunk-65BGOX2M.js";
5
5
  export {
6
6
  mountInSitue
7
7
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@insitue/sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "InSitue capture SDK — drop one snippet into your deployed app; your users point at a bug, InSitue opens a verified pull request.",
5
5
  "license": "MIT",
6
6
  "type": "module",