hypha-debugger 0.2.0 → 0.2.2
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/hypha-debugger.js
CHANGED
|
@@ -13852,6 +13852,23 @@
|
|
|
13852
13852
|
* Images are downscaled before being returned so agents don't receive
|
|
13853
13853
|
* multi-megabyte base64 payloads that can crash their context window.
|
|
13854
13854
|
*/
|
|
13855
|
+
/** Extract a useful string from an unknown error value. */
|
|
13856
|
+
function errorMessage(err) {
|
|
13857
|
+
if (!err)
|
|
13858
|
+
return "Unknown error";
|
|
13859
|
+
if (typeof err === "string")
|
|
13860
|
+
return err;
|
|
13861
|
+
if (err.message)
|
|
13862
|
+
return err.message;
|
|
13863
|
+
if (err instanceof Event)
|
|
13864
|
+
return `Event: ${err.type}`;
|
|
13865
|
+
try {
|
|
13866
|
+
return JSON.stringify(err);
|
|
13867
|
+
}
|
|
13868
|
+
catch {
|
|
13869
|
+
return String(err);
|
|
13870
|
+
}
|
|
13871
|
+
}
|
|
13855
13872
|
/**
|
|
13856
13873
|
* Resize an image data URL via a canvas. Returns a new data URL at the
|
|
13857
13874
|
* requested format/quality. Maintains aspect ratio: fits within
|
|
@@ -13861,31 +13878,34 @@
|
|
|
13861
13878
|
return new Promise((resolve, reject) => {
|
|
13862
13879
|
const img = new Image();
|
|
13863
13880
|
img.onload = () => {
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
|
|
13873
|
-
|
|
13874
|
-
|
|
13875
|
-
|
|
13876
|
-
|
|
13881
|
+
try {
|
|
13882
|
+
const srcW = img.naturalWidth;
|
|
13883
|
+
const srcH = img.naturalHeight;
|
|
13884
|
+
const scale = Math.min(maxWidth / srcW, maxHeight / srcH, 1);
|
|
13885
|
+
const dstW = Math.max(1, Math.round(srcW * scale));
|
|
13886
|
+
const dstH = Math.max(1, Math.round(srcH * scale));
|
|
13887
|
+
const canvas = document.createElement("canvas");
|
|
13888
|
+
canvas.width = dstW;
|
|
13889
|
+
canvas.height = dstH;
|
|
13890
|
+
const ctx = canvas.getContext("2d");
|
|
13891
|
+
if (!ctx) {
|
|
13892
|
+
reject(new Error("Could not get 2D canvas context"));
|
|
13893
|
+
return;
|
|
13894
|
+
}
|
|
13895
|
+
if (format === "jpeg") {
|
|
13896
|
+
ctx.fillStyle = "#ffffff";
|
|
13897
|
+
ctx.fillRect(0, 0, dstW, dstH);
|
|
13898
|
+
}
|
|
13899
|
+
ctx.drawImage(img, 0, 0, dstW, dstH);
|
|
13900
|
+
const mime = format === "jpeg" ? "image/jpeg" : "image/png";
|
|
13901
|
+
const out = canvas.toDataURL(mime, quality);
|
|
13902
|
+
resolve({ dataUrl: out, width: dstW, height: dstH });
|
|
13877
13903
|
}
|
|
13878
|
-
|
|
13879
|
-
|
|
13880
|
-
ctx.fillStyle = "#ffffff";
|
|
13881
|
-
ctx.fillRect(0, 0, dstW, dstH);
|
|
13904
|
+
catch (drawErr) {
|
|
13905
|
+
reject(new Error(`Canvas resize failed: ${errorMessage(drawErr)}`));
|
|
13882
13906
|
}
|
|
13883
|
-
ctx.drawImage(img, 0, 0, dstW, dstH);
|
|
13884
|
-
const mime = format === "jpeg" ? "image/jpeg" : "image/png";
|
|
13885
|
-
const out = canvas.toDataURL(mime, quality);
|
|
13886
|
-
resolve({ dataUrl: out, width: dstW, height: dstH });
|
|
13887
13907
|
};
|
|
13888
|
-
img.onerror = () => reject(new Error(
|
|
13908
|
+
img.onerror = (ev) => reject(new Error(`Failed to load captured image for resizing${ev instanceof Event ? ` (${ev.type})` : ""}`));
|
|
13889
13909
|
img.src = dataUrl;
|
|
13890
13910
|
});
|
|
13891
13911
|
}
|
|
@@ -13925,6 +13945,7 @@
|
|
|
13925
13945
|
pixelRatio: 1, // always capture at 1x — we'll resize after
|
|
13926
13946
|
cacheBust: true,
|
|
13927
13947
|
skipAutoScale: true,
|
|
13948
|
+
skipFonts: true, // CORS-blocked stylesheets can hang font inlining
|
|
13928
13949
|
filter: (el) => {
|
|
13929
13950
|
// Exclude the debugger overlay and cursor from screenshots
|
|
13930
13951
|
return (el.id !== "hypha-debugger-host" &&
|
|
@@ -13938,25 +13959,51 @@
|
|
|
13938
13959
|
captureOptions.height = viewportH;
|
|
13939
13960
|
}
|
|
13940
13961
|
let dataUrl;
|
|
13941
|
-
|
|
13942
|
-
|
|
13962
|
+
try {
|
|
13963
|
+
const capturePromise = fmt === "jpeg" ? toJpeg(node, captureOptions) : toPng(node, captureOptions);
|
|
13964
|
+
// Hard timeout: pages with cross-origin resources can make
|
|
13965
|
+
// html-to-image wait indefinitely on blocked fetches.
|
|
13966
|
+
const timeoutMs = 15000;
|
|
13967
|
+
dataUrl = await Promise.race([
|
|
13968
|
+
capturePromise,
|
|
13969
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Screenshot capture timed out after ${timeoutMs}ms (likely CORS-blocked resources)`)), timeoutMs)),
|
|
13970
|
+
]);
|
|
13971
|
+
}
|
|
13972
|
+
catch (captureErr) {
|
|
13973
|
+
return {
|
|
13974
|
+
error: `Capture failed (html-to-image): ${errorMessage(captureErr)}`,
|
|
13975
|
+
};
|
|
13943
13976
|
}
|
|
13944
|
-
|
|
13945
|
-
|
|
13977
|
+
// Resize down to fit within (maxW × maxH) and re-encode. If resize
|
|
13978
|
+
// fails (e.g. data URL too large to load back into an Image), fall
|
|
13979
|
+
// back to returning the original capture so the caller still gets
|
|
13980
|
+
// something useful.
|
|
13981
|
+
try {
|
|
13982
|
+
const resized = await resizeDataUrl(dataUrl, maxW, maxH, fmt, qual);
|
|
13983
|
+
const sizeKb = Math.round((resized.dataUrl.length * 0.75) / 1024);
|
|
13984
|
+
return {
|
|
13985
|
+
data: resized.dataUrl,
|
|
13986
|
+
format: fmt,
|
|
13987
|
+
width: resized.width,
|
|
13988
|
+
height: resized.height,
|
|
13989
|
+
size_kb: sizeKb,
|
|
13990
|
+
};
|
|
13991
|
+
}
|
|
13992
|
+
catch (resizeErr) {
|
|
13993
|
+
const rect = node.getBoundingClientRect();
|
|
13994
|
+
const sizeKb = Math.round((dataUrl.length * 0.75) / 1024);
|
|
13995
|
+
return {
|
|
13996
|
+
data: dataUrl,
|
|
13997
|
+
format: fmt,
|
|
13998
|
+
width: Math.round(rect.width),
|
|
13999
|
+
height: Math.round(rect.height),
|
|
14000
|
+
size_kb: sizeKb,
|
|
14001
|
+
warning: `Resize failed, returning original: ${errorMessage(resizeErr)}`,
|
|
14002
|
+
};
|
|
13946
14003
|
}
|
|
13947
|
-
// Resize down to fit within (maxW × maxH) and re-encode
|
|
13948
|
-
const resized = await resizeDataUrl(dataUrl, maxW, maxH, fmt, qual);
|
|
13949
|
-
const sizeKb = Math.round((resized.dataUrl.length * 0.75) / 1024); // rough base64 → bytes
|
|
13950
|
-
return {
|
|
13951
|
-
data: resized.dataUrl,
|
|
13952
|
-
format: fmt,
|
|
13953
|
-
width: resized.width,
|
|
13954
|
-
height: resized.height,
|
|
13955
|
-
size_kb: sizeKb,
|
|
13956
|
-
};
|
|
13957
14004
|
}
|
|
13958
14005
|
catch (err) {
|
|
13959
|
-
return { error: `Screenshot failed: ${err
|
|
14006
|
+
return { error: `Screenshot failed: ${errorMessage(err)}` };
|
|
13960
14007
|
}
|
|
13961
14008
|
}
|
|
13962
14009
|
takeScreenshot.__schema__ = {
|
|
@@ -17418,7 +17465,14 @@
|
|
|
17418
17465
|
if (viewport_only !== undefined) {
|
|
17419
17466
|
ctrl.config.viewportExpansion = viewport_only ? 0 : -1;
|
|
17420
17467
|
}
|
|
17421
|
-
|
|
17468
|
+
// Hard timeout: pages with heavy DOMs or cross-origin iframes can
|
|
17469
|
+
// make the tree walk take much longer than expected. Don't leave
|
|
17470
|
+
// the HTTP caller waiting forever.
|
|
17471
|
+
const timeoutMs = 15000;
|
|
17472
|
+
return Promise.race([
|
|
17473
|
+
ctrl.getBrowserState(),
|
|
17474
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`get_browser_state timed out after ${timeoutMs}ms (complex DOM or cross-origin iframes)`)), timeoutMs)),
|
|
17475
|
+
]);
|
|
17422
17476
|
}
|
|
17423
17477
|
getBrowserState.__schema__ = {
|
|
17424
17478
|
name: "getBrowserState",
|