@merittdev/horus-lens 0.1.0 → 0.2.0
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/browser.cjs +1290 -142
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +2 -2
- package/dist/{chunk-MTQ3IO4U.js → chunk-JXSK4JG4.js} +273 -12
- package/dist/chunk-JXSK4JG4.js.map +1 -0
- package/dist/{chunk-A6SNBIRS.js → chunk-UT7E5LCG.js} +1017 -130
- package/dist/chunk-UT7E5LCG.js.map +1 -0
- package/dist/index.cjs +272 -11
- package/dist/index.cjs.map +1 -1
- package/dist/{index.d-BA540Fae.d.ts → index.d-BtnbCqUx.d.ts} +39 -1
- package/dist/index.d-Cyvb07sp.d.cts +301 -0
- package/dist/index.d-Cyvb07sp.d.ts +301 -0
- package/dist/{index.d-DOCLVJGS.d.cts → index.d-QzZn4EMM.d.cts} +39 -1
- package/dist/index.d.cts +355 -37
- package/dist/index.d.ts +355 -37
- package/dist/index.js +1 -1
- package/dist/lens.min.js +163 -43
- package/dist/lens.min.js.map +1 -1
- package/dist/react.cjs +1290 -142
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-A6SNBIRS.js.map +0 -1
- package/dist/chunk-MTQ3IO4U.js.map +0 -1
- package/dist/index.d-Bzgtl7-B.d.cts +0 -161
- package/dist/index.d-Bzgtl7-B.d.ts +0 -161
package/dist/index.cjs
CHANGED
|
@@ -14633,15 +14633,86 @@ var TargetElementSchema = external_exports.object({
|
|
|
14633
14633
|
boundingRect: external_exports.object({ x: external_exports.number(), y: external_exports.number(), width: external_exports.number(), height: external_exports.number() }).optional(),
|
|
14634
14634
|
reactComponents: external_exports.array(external_exports.string()).optional()
|
|
14635
14635
|
});
|
|
14636
|
-
var
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
14644
|
-
|
|
14636
|
+
var annotationCommon = {
|
|
14637
|
+
id: external_exports.string().optional(),
|
|
14638
|
+
/** Any CSS color string. */
|
|
14639
|
+
color: external_exports.string().optional(),
|
|
14640
|
+
strokeWidth: external_exports.number().optional()
|
|
14641
|
+
};
|
|
14642
|
+
var AnnotationPointSchema = external_exports.object({ x: external_exports.number(), y: external_exports.number() });
|
|
14643
|
+
var AnnotationSchema = external_exports.discriminatedUnion("kind", [
|
|
14644
|
+
external_exports.object({
|
|
14645
|
+
...annotationCommon,
|
|
14646
|
+
kind: external_exports.literal("rect"),
|
|
14647
|
+
x: external_exports.number(),
|
|
14648
|
+
y: external_exports.number(),
|
|
14649
|
+
width: external_exports.number(),
|
|
14650
|
+
height: external_exports.number(),
|
|
14651
|
+
/**
|
|
14652
|
+
* OPTIONAL, kept for back-compat with 0.1.x clients that emit
|
|
14653
|
+
* viewport-anchored rects. New clients emit document-pixel rects with no
|
|
14654
|
+
* viewport.
|
|
14655
|
+
*/
|
|
14656
|
+
viewport: external_exports.object({ width: external_exports.number(), height: external_exports.number() }).optional()
|
|
14657
|
+
}),
|
|
14658
|
+
external_exports.object({
|
|
14659
|
+
...annotationCommon,
|
|
14660
|
+
kind: external_exports.literal("ellipse"),
|
|
14661
|
+
x: external_exports.number(),
|
|
14662
|
+
y: external_exports.number(),
|
|
14663
|
+
width: external_exports.number(),
|
|
14664
|
+
height: external_exports.number()
|
|
14665
|
+
}),
|
|
14666
|
+
external_exports.object({
|
|
14667
|
+
...annotationCommon,
|
|
14668
|
+
kind: external_exports.literal("blur"),
|
|
14669
|
+
x: external_exports.number(),
|
|
14670
|
+
y: external_exports.number(),
|
|
14671
|
+
width: external_exports.number(),
|
|
14672
|
+
height: external_exports.number()
|
|
14673
|
+
}),
|
|
14674
|
+
external_exports.object({
|
|
14675
|
+
...annotationCommon,
|
|
14676
|
+
kind: external_exports.literal("arrow"),
|
|
14677
|
+
x1: external_exports.number(),
|
|
14678
|
+
y1: external_exports.number(),
|
|
14679
|
+
x2: external_exports.number(),
|
|
14680
|
+
y2: external_exports.number()
|
|
14681
|
+
}),
|
|
14682
|
+
external_exports.object({
|
|
14683
|
+
...annotationCommon,
|
|
14684
|
+
kind: external_exports.literal("line"),
|
|
14685
|
+
x1: external_exports.number(),
|
|
14686
|
+
y1: external_exports.number(),
|
|
14687
|
+
x2: external_exports.number(),
|
|
14688
|
+
y2: external_exports.number()
|
|
14689
|
+
}),
|
|
14690
|
+
external_exports.object({
|
|
14691
|
+
...annotationCommon,
|
|
14692
|
+
kind: external_exports.literal("pencil"),
|
|
14693
|
+
points: external_exports.array(AnnotationPointSchema).min(2)
|
|
14694
|
+
}),
|
|
14695
|
+
external_exports.object({
|
|
14696
|
+
...annotationCommon,
|
|
14697
|
+
kind: external_exports.literal("highlighter"),
|
|
14698
|
+
points: external_exports.array(AnnotationPointSchema).min(2)
|
|
14699
|
+
}),
|
|
14700
|
+
external_exports.object({
|
|
14701
|
+
...annotationCommon,
|
|
14702
|
+
kind: external_exports.literal("text"),
|
|
14703
|
+
x: external_exports.number(),
|
|
14704
|
+
y: external_exports.number(),
|
|
14705
|
+
text: external_exports.string(),
|
|
14706
|
+
fontSize: external_exports.number().optional()
|
|
14707
|
+
}),
|
|
14708
|
+
external_exports.object({
|
|
14709
|
+
...annotationCommon,
|
|
14710
|
+
kind: external_exports.literal("step"),
|
|
14711
|
+
x: external_exports.number(),
|
|
14712
|
+
y: external_exports.number(),
|
|
14713
|
+
n: external_exports.number()
|
|
14714
|
+
})
|
|
14715
|
+
]);
|
|
14645
14716
|
var AssetKindSchema = external_exports.enum(["replay", "console", "network", "dom", "screenshot", "attachment"]);
|
|
14646
14717
|
var AssetRefSchema = external_exports.object({
|
|
14647
14718
|
kind: AssetKindSchema,
|
|
@@ -29381,6 +29452,11 @@ var ReplayRecorder = class {
|
|
|
29381
29452
|
emit: (event, isCheckout) => this.onEmit(event, isCheckout),
|
|
29382
29453
|
checkoutEveryNms: this.windowMs,
|
|
29383
29454
|
recordCanvas: false,
|
|
29455
|
+
// Inline same-origin + CORS images as data URIs at snapshot time so the
|
|
29456
|
+
// dashboard replay paints on a different origin (tainted cross-origin
|
|
29457
|
+
// images fall back to their URL, which is fine for public CDNs).
|
|
29458
|
+
inlineImages: true,
|
|
29459
|
+
collectFonts: true,
|
|
29384
29460
|
// Keep the Lens overlay itself out of every recording.
|
|
29385
29461
|
blockSelector: `#${LENS_OVERLAY_HOST_ID}`
|
|
29386
29462
|
});
|
|
@@ -29487,7 +29563,20 @@ var ReplayRecorder = class {
|
|
|
29487
29563
|
console.warn("[lens] rrweb recording unavailable; replay disabled", err);
|
|
29488
29564
|
}
|
|
29489
29565
|
};
|
|
29490
|
-
|
|
29566
|
+
var SVG_RASTERIZE_TIMEOUT_MS = 3e3;
|
|
29567
|
+
function computeCropRect(crop, scale, rasterWidth, rasterHeight) {
|
|
29568
|
+
let sx = Math.round(crop.x * scale);
|
|
29569
|
+
let sy = Math.round(crop.y * scale);
|
|
29570
|
+
let sw = Math.round(crop.width * scale);
|
|
29571
|
+
let sh = Math.round(crop.height * scale);
|
|
29572
|
+
sx = Math.max(0, Math.min(sx, rasterWidth));
|
|
29573
|
+
sy = Math.max(0, Math.min(sy, rasterHeight));
|
|
29574
|
+
sw = Math.min(sw, rasterWidth - sx);
|
|
29575
|
+
sh = Math.min(sh, rasterHeight - sy);
|
|
29576
|
+
if (sw <= 0 || sh <= 0) return null;
|
|
29577
|
+
return { sx, sy, sw, sh };
|
|
29578
|
+
}
|
|
29579
|
+
async function captureScreenshot(excludeHost, crop, composite) {
|
|
29491
29580
|
if (typeof document === "undefined" || typeof window === "undefined") return null;
|
|
29492
29581
|
try {
|
|
29493
29582
|
const viewportPixels = window.innerWidth * window.innerHeight || 1;
|
|
@@ -29497,6 +29586,15 @@ async function captureScreenshot(excludeHost) {
|
|
|
29497
29586
|
scale,
|
|
29498
29587
|
type: "image/jpeg",
|
|
29499
29588
|
quality: 0.82,
|
|
29589
|
+
// JPEG has no alpha — transparent page regions (and any capture box
|
|
29590
|
+
// extending past short content) would otherwise encode as BLACK.
|
|
29591
|
+
backgroundColor: "#ffffff",
|
|
29592
|
+
// When compositing annotations, force the capture box to the editor's
|
|
29593
|
+
// document measurement (scrollHeight-based). modern-screenshot otherwise
|
|
29594
|
+
// sizes from documentElement's bounding box, which on pages SHORTER than
|
|
29595
|
+
// the viewport is the content height only — marks drawn in the lower
|
|
29596
|
+
// viewport band would fall off the raster and the crop would clamp short.
|
|
29597
|
+
...composite ? { width: composite.docWidth, height: composite.docHeight } : {},
|
|
29500
29598
|
// Exclude the overlay from the capture CLONE — never hide the live node.
|
|
29501
29599
|
filter: (node2) => node2 !== excludeHost,
|
|
29502
29600
|
// Per-resource fetch budget: a single slow cross-origin image must not
|
|
@@ -29521,12 +29619,171 @@ async function captureScreenshot(excludeHost) {
|
|
|
29521
29619
|
);
|
|
29522
29620
|
return null;
|
|
29523
29621
|
}
|
|
29622
|
+
if (composite) {
|
|
29623
|
+
const baked = await compositeScreenshot(blob2, composite, scale, crop);
|
|
29624
|
+
if (baked) return baked;
|
|
29625
|
+
if (composite.blurRegions.length > 0) {
|
|
29626
|
+
console.warn(
|
|
29627
|
+
"[lens] screenshot compositing failed with active redactions; dropping screenshot to avoid leaking un-blurred content"
|
|
29628
|
+
);
|
|
29629
|
+
return null;
|
|
29630
|
+
}
|
|
29631
|
+
}
|
|
29632
|
+
if (crop) {
|
|
29633
|
+
const cropped = await cropBlob(blob2, crop, scale);
|
|
29634
|
+
return cropped ?? blob2;
|
|
29635
|
+
}
|
|
29524
29636
|
return blob2;
|
|
29525
29637
|
} catch (err) {
|
|
29526
29638
|
console.warn("[lens] screenshot capture failed:", err);
|
|
29527
29639
|
return null;
|
|
29528
29640
|
}
|
|
29529
29641
|
}
|
|
29642
|
+
async function compositeScreenshot(blob2, composite, scale, crop) {
|
|
29643
|
+
try {
|
|
29644
|
+
if (typeof createImageBitmap !== "function" || typeof document === "undefined") return null;
|
|
29645
|
+
const bitmap = await createImageBitmap(blob2);
|
|
29646
|
+
const canvas = document.createElement("canvas");
|
|
29647
|
+
canvas.width = bitmap.width;
|
|
29648
|
+
canvas.height = bitmap.height;
|
|
29649
|
+
const ctx = canvas.getContext("2d");
|
|
29650
|
+
if (!ctx) {
|
|
29651
|
+
bitmap.close?.();
|
|
29652
|
+
return null;
|
|
29653
|
+
}
|
|
29654
|
+
ctx.fillStyle = "#ffffff";
|
|
29655
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
29656
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
29657
|
+
bitmap.close?.();
|
|
29658
|
+
applyBlurRegions(ctx, canvas, composite.blurRegions, scale);
|
|
29659
|
+
await drawSvgOverlay(ctx, composite, scale);
|
|
29660
|
+
if (crop) {
|
|
29661
|
+
const rect = computeCropRect(crop, scale, canvas.width, canvas.height);
|
|
29662
|
+
if (rect) {
|
|
29663
|
+
const out = document.createElement("canvas");
|
|
29664
|
+
out.width = rect.sw;
|
|
29665
|
+
out.height = rect.sh;
|
|
29666
|
+
const octx = out.getContext("2d");
|
|
29667
|
+
if (octx) {
|
|
29668
|
+
octx.drawImage(canvas, rect.sx, rect.sy, rect.sw, rect.sh, 0, 0, rect.sw, rect.sh);
|
|
29669
|
+
return await canvasToJpegBlob(out);
|
|
29670
|
+
}
|
|
29671
|
+
}
|
|
29672
|
+
}
|
|
29673
|
+
return await canvasToJpegBlob(canvas);
|
|
29674
|
+
} catch (err) {
|
|
29675
|
+
console.warn("[lens] screenshot compositing failed:", err);
|
|
29676
|
+
return null;
|
|
29677
|
+
}
|
|
29678
|
+
}
|
|
29679
|
+
function applyBlurRegions(ctx, canvas, regions, scale) {
|
|
29680
|
+
if (regions.length === 0) return;
|
|
29681
|
+
const filterSupported = typeof ctx.filter === "string";
|
|
29682
|
+
const blurPx = Math.max(8, 12 * scale);
|
|
29683
|
+
const pad = Math.ceil(blurPx);
|
|
29684
|
+
for (const region of regions) {
|
|
29685
|
+
const x = Math.max(0, Math.min(Math.round(region.x * scale), canvas.width));
|
|
29686
|
+
const y = Math.max(0, Math.min(Math.round(region.y * scale), canvas.height));
|
|
29687
|
+
const w = Math.min(Math.round(region.width * scale), canvas.width - x);
|
|
29688
|
+
const h = Math.min(Math.round(region.height * scale), canvas.height - y);
|
|
29689
|
+
if (w <= 0 || h <= 0) continue;
|
|
29690
|
+
if (!filterSupported) {
|
|
29691
|
+
ctx.fillStyle = "rgba(127,127,127,1)";
|
|
29692
|
+
ctx.fillRect(x, y, w, h);
|
|
29693
|
+
continue;
|
|
29694
|
+
}
|
|
29695
|
+
const px = Math.max(0, x - pad);
|
|
29696
|
+
const py = Math.max(0, y - pad);
|
|
29697
|
+
const pw = Math.min(canvas.width, x + w + pad) - px;
|
|
29698
|
+
const ph = Math.min(canvas.height, y + h + pad) - py;
|
|
29699
|
+
if (pw <= 0 || ph <= 0) continue;
|
|
29700
|
+
const temp = document.createElement("canvas");
|
|
29701
|
+
temp.width = pw;
|
|
29702
|
+
temp.height = ph;
|
|
29703
|
+
const tctx = temp.getContext("2d");
|
|
29704
|
+
if (!tctx) {
|
|
29705
|
+
ctx.fillStyle = "rgba(127,127,127,1)";
|
|
29706
|
+
ctx.fillRect(x, y, w, h);
|
|
29707
|
+
continue;
|
|
29708
|
+
}
|
|
29709
|
+
tctx.filter = `blur(${blurPx}px)`;
|
|
29710
|
+
tctx.drawImage(canvas, px, py, pw, ph, 0, 0, pw, ph);
|
|
29711
|
+
tctx.filter = "none";
|
|
29712
|
+
ctx.save();
|
|
29713
|
+
ctx.beginPath();
|
|
29714
|
+
ctx.rect(x, y, w, h);
|
|
29715
|
+
ctx.clip();
|
|
29716
|
+
ctx.drawImage(temp, px, py);
|
|
29717
|
+
ctx.restore();
|
|
29718
|
+
}
|
|
29719
|
+
}
|
|
29720
|
+
async function drawSvgOverlay(ctx, composite, scale) {
|
|
29721
|
+
const { svgMarkup, docWidth, docHeight } = composite;
|
|
29722
|
+
if (!svgMarkup) return;
|
|
29723
|
+
const img = await loadSvgImage(svgMarkup);
|
|
29724
|
+
if (!img) return;
|
|
29725
|
+
try {
|
|
29726
|
+
ctx.drawImage(img, 0, 0, docWidth * scale, docHeight * scale);
|
|
29727
|
+
} catch (err) {
|
|
29728
|
+
console.warn("[lens] annotation overlay draw failed:", err);
|
|
29729
|
+
}
|
|
29730
|
+
}
|
|
29731
|
+
function loadSvgImage(svg) {
|
|
29732
|
+
return new Promise((resolve) => {
|
|
29733
|
+
if (typeof Image !== "function") {
|
|
29734
|
+
resolve(null);
|
|
29735
|
+
return;
|
|
29736
|
+
}
|
|
29737
|
+
let settled = false;
|
|
29738
|
+
const finish = (result2) => {
|
|
29739
|
+
if (settled) return;
|
|
29740
|
+
settled = true;
|
|
29741
|
+
clearTimeout(timer);
|
|
29742
|
+
resolve(result2);
|
|
29743
|
+
};
|
|
29744
|
+
const timer = setTimeout(() => {
|
|
29745
|
+
console.warn("[lens] annotation overlay rasterization timed out");
|
|
29746
|
+
finish(null);
|
|
29747
|
+
}, SVG_RASTERIZE_TIMEOUT_MS);
|
|
29748
|
+
const img = new Image();
|
|
29749
|
+
img.onload = () => finish(img);
|
|
29750
|
+
img.onerror = () => {
|
|
29751
|
+
console.warn("[lens] annotation overlay failed to rasterize");
|
|
29752
|
+
finish(null);
|
|
29753
|
+
};
|
|
29754
|
+
img.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
|
|
29755
|
+
});
|
|
29756
|
+
}
|
|
29757
|
+
function canvasToJpegBlob(canvas) {
|
|
29758
|
+
return new Promise((resolve) => {
|
|
29759
|
+
canvas.toBlob((out) => resolve(out), "image/jpeg", 0.82);
|
|
29760
|
+
});
|
|
29761
|
+
}
|
|
29762
|
+
async function cropBlob(blob2, crop, scale) {
|
|
29763
|
+
try {
|
|
29764
|
+
if (typeof createImageBitmap !== "function" || typeof document === "undefined") return null;
|
|
29765
|
+
const bitmap = await createImageBitmap(blob2);
|
|
29766
|
+
const rect = computeCropRect(crop, scale, bitmap.width, bitmap.height);
|
|
29767
|
+
if (!rect) {
|
|
29768
|
+
bitmap.close?.();
|
|
29769
|
+
return null;
|
|
29770
|
+
}
|
|
29771
|
+
const canvas = document.createElement("canvas");
|
|
29772
|
+
canvas.width = rect.sw;
|
|
29773
|
+
canvas.height = rect.sh;
|
|
29774
|
+
const ctx = canvas.getContext("2d");
|
|
29775
|
+
if (!ctx) {
|
|
29776
|
+
bitmap.close?.();
|
|
29777
|
+
return null;
|
|
29778
|
+
}
|
|
29779
|
+
ctx.drawImage(bitmap, rect.sx, rect.sy, rect.sw, rect.sh, 0, 0, rect.sw, rect.sh);
|
|
29780
|
+
bitmap.close?.();
|
|
29781
|
+
return await canvasToJpegBlob(canvas);
|
|
29782
|
+
} catch (err) {
|
|
29783
|
+
console.warn("[lens] screenshot crop failed:", err);
|
|
29784
|
+
return null;
|
|
29785
|
+
}
|
|
29786
|
+
}
|
|
29530
29787
|
function parseBrowser(ua) {
|
|
29531
29788
|
if (!ua) return void 0;
|
|
29532
29789
|
const checks = [
|
|
@@ -29791,7 +30048,11 @@ var LensClient = class {
|
|
|
29791
30048
|
const wantErrors = include.errors !== false;
|
|
29792
30049
|
const wantScreenshot = include.screenshot !== false;
|
|
29793
30050
|
const wantDom = include.dom !== false;
|
|
29794
|
-
const screenshotPromise = this.screenshotEnabled && wantScreenshot ? captureScreenshot(
|
|
30051
|
+
const screenshotPromise = this.screenshotEnabled && wantScreenshot ? captureScreenshot(
|
|
30052
|
+
input2.excludeFromScreenshot,
|
|
30053
|
+
input2.screenshotCrop,
|
|
30054
|
+
input2.annotationComposite
|
|
30055
|
+
) : Promise.resolve(null);
|
|
29795
30056
|
const replayEvents = wantReplay ? this.replay?.snapshot() ?? [] : [];
|
|
29796
30057
|
const errorEntries = this.errorBuffer.drain();
|
|
29797
30058
|
const consoleTail = this.consoleBuffer.tail(CONSOLE_TAIL_SIZE);
|