extension(browser): v1.9.18 — propagate page-side throws, fix textarea fill

Two bugs caught while driving the SEC TCR form:

1) runFunc silently swallowed page-side errors.
   scripting.executeScript returns [{result, error, frameId}] per frame.
   We were mapping to r?.result which dropped the `error` field — when a
   page-side function threw, callers saw null instead of an error.

   Fix: keep the full InjectionResult shape and throw on first.error.

2) hanzo.fill called HTMLInputElement's value setter on a TEXTAREA.
   That throws TypeError "Illegal invocation" silently (now visible
   thanks to fix #1). The chained `|| HTMLTextAreaElement.prototype...`
   never executed because the first ?.set was truthy.

   Fix: per-tag dispatch — pick the matching prototype's native setter
   (INPUT/TEXTAREA/SELECT each get their own). Wrapped in try/catch with
   plain `el.value = value` as last resort.

Verified on www.sec.gov/forms/tcr-external-form:
  - hanzo.fill on textarea[name^="in_your_own_words"] now sets the value
  - hanzo.clear on same textarea now works
This commit is contained in:
zeekay
2026-06-10 11:47:16 -07:00
parent bb6ed472be
commit 5e270c061d
4 changed files with 30 additions and 13 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@hanzo/browser-extension",
"version": "1.9.17",
"version": "1.9.18",
"description": "Hanzo AI Browser Extension",
"main": "dist/background.js",
"scripts": {
+27 -10
View File
@@ -401,7 +401,10 @@ class HanzoFirefoxExtension {
args,
func: fn,
});
return Array.isArray(results) ? results.map((r: any) => r?.result) : [results];
// Keep the full InjectionResult shape ({result, error, frameId}) so
// we can propagate page-side throws (1.9.18). Previously we mapped
// to r?.result which silently dropped errors → callers saw null.
return Array.isArray(results) ? results : [results];
};
let out: any[];
try {
@@ -414,7 +417,11 @@ class HanzoFirefoxExtension {
`runFunc returned no frames for tab ${tabId} — page may be privileged or unloaded.`,
);
}
const result = out[0];
const first = out[0] || {};
if (first.error) {
throw new Error(`runFunc page-side error: ${first.error}`);
}
const result = first.result;
if (result && typeof result === 'object' && (result as any).__hanzo_error) {
throw new Error((result as any).__hanzo_error);
}
@@ -793,16 +800,26 @@ class HanzoFirefoxExtension {
const el = document.querySelector(selector) as HTMLInputElement | HTMLTextAreaElement | HTMLElement | null;
if (!el) return false;
try { (el as HTMLElement).scrollIntoView({ block: 'center', behavior: 'instant' as ScrollBehavior }); } catch (e) {}
(el as HTMLElement).focus();
try { (el as HTMLElement).focus(); } catch (e) {}
const tag = (el as HTMLElement).tagName;
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') {
const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set
|| Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
if (setter && (tag === 'INPUT' || tag === 'TEXTAREA')) {
setter.call(el, value);
} else {
(el as HTMLInputElement).value = value;
}
// React-compatible: per-tag native setter. Calling
// HTMLInputElement's setter on a TEXTAREA throws "Illegal
// invocation" — was the silent failure on SEC TCR (1.9.18 fix).
let setter: any = null;
try {
if (tag === 'TEXTAREA') {
setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
} else if (tag === 'INPUT') {
setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
} else if (tag === 'SELECT') {
setter = Object.getOwnPropertyDescriptor(window.HTMLSelectElement.prototype, 'value')?.set;
}
} catch (e) { setter = null; }
try {
if (setter) setter.call(el, value);
else (el as HTMLInputElement).value = value;
} catch (e) { (el as HTMLInputElement).value = value; }
el.dispatchEvent(new Event('input', { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));
return true;
+1 -1
View File
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Hanzo AI",
"version": "1.9.17",
"version": "1.9.18",
"description": "AI-powered dev assistant — click-to-code navigation, source maps, WebGPU AI, and MCP integration for Claude Code.",
"permissions": [
"activeTab",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Hanzo AI",
"version": "1.9.17",
"version": "1.9.18",
"description": "AI-powered dev assistant — click-to-code navigation, source maps, WebGPU AI, and MCP integration for Claude Code.",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxfXGh0lPUT5m04GKfjUwrLsV6pLaK3VcZuFRPogqAir2tzyLYnQPRtHynue9yvDyguIVnlkwvcwfDOYZrvH76zbw4s6onPBG8HqTKO6LQ9K3kdO1qBBkMMjdOgULQ1MrWThEbpU7NSTiwLYpEta/jAvrKRCAeKIlQE8p6htZmPy9aRUZuae66JgLcAlzD2vviX9sVB1asFABJVswL1RgZ55/8IzZaUrFjzOo9OHK4hmEOtudzkML+5silsAYdC+1BZugph2x94ai17YmZTCL1XyUa5Ke4q80cj+i9rOTgzhZs+mruyhL/AvNVOXilsgqCdNqSz77naWzC3pVGbxOewIDAQAB",
"permissions": [