diff options
| author | Tianren Dong <tianrendong.dtr@gmail.com> | 2026-05-31 13:59:42 -0400 |
|---|---|---|
| committer | Tianren Dong <tianrendong.dtr@gmail.com> | 2026-05-31 13:59:42 -0400 |
| commit | 0fc5b8950601a36dfffdc8f7163bb12fb94f353e (patch) | |
| tree | 8bbd4992530c2fb8de6db032c79964c73c9c1fa0 /extensions/chrome-profile-bridge/browser-extension | |
| parent | ea6c25d1ace29ba5c4d01b02ba33f130d2f6f4ff (diff) | |
0.15.28: bridge self-heal, timeout diagnostics, pressKeyInPage helper, DOMRect serialization, stale-target errors, pageMutated wording
Diffstat (limited to 'extensions/chrome-profile-bridge/browser-extension')
| -rw-r--r-- | extensions/chrome-profile-bridge/browser-extension/manifest.json | 2 | ||||
| -rw-r--r-- | extensions/chrome-profile-bridge/browser-extension/service_worker.js | 29 |
2 files changed, 27 insertions, 4 deletions
diff --git a/extensions/chrome-profile-bridge/browser-extension/manifest.json b/extensions/chrome-profile-bridge/browser-extension/manifest.json index 00b2b90..b6ef0fc 100644 --- a/extensions/chrome-profile-bridge/browser-extension/manifest.json +++ b/extensions/chrome-profile-bridge/browser-extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Pi Chrome Connector", - "version": "0.15.27", + "version": "0.15.28", "description": "Lets Pi control tabs in Chrome via a local connector at 127.0.0.1.", "permissions": [ "tabs", diff --git a/extensions/chrome-profile-bridge/browser-extension/service_worker.js b/extensions/chrome-profile-bridge/browser-extension/service_worker.js index afa962b..f269afa 100644 --- a/extensions/chrome-profile-bridge/browser-extension/service_worker.js +++ b/extensions/chrome-profile-bridge/browser-extension/service_worker.js @@ -787,6 +787,20 @@ async function getTabByParams(params) { if (params.targetId !== undefined) { const id = Number(params.targetId); tab = tabs.find((candidate) => candidate.id === id); + if (!tab?.id) { + // Chrome tab ids are not stable across reloads/navigations; a long session can hold a + // stale id. Surface the current tabs so the caller can re-target instead of guessing. + const listed = tabs + .filter((candidate) => candidate.id !== undefined) + .slice(0, 20) + .map((candidate) => ` ${candidate.id}${candidate.active ? " *" : ""}\t${(candidate.title || "(untitled)").slice(0, 60)}\t${candidate.url || ""}`) + .join("\n"); + throw new Error( + `No Chrome tab with id ${id} (it was likely closed or replaced). ` + + `Re-target with chrome_tab list, or pass urlIncludes/titleIncludes instead of targetId.\n` + + `Current tabs:\n${listed || " (none)"}`, + ); + } } else if (params.urlIncludes) { tab = tabs.find((candidate) => (candidate.url || "").includes(params.urlIncludes)); } else if (params.titleIncludes) { @@ -826,6 +840,7 @@ const HELPER_FUNCS = [ printableKeyCode, dispatchKeyEvent, typeCharacter, + pressKeyInPage, scrollPage, ]; @@ -882,6 +897,14 @@ async function evaluateInTab(params) { if (typeof v === "symbol") return { kind: "symbol", description: v.description }; if (typeof v === "bigint") return { kind: "bigint", value: v.toString() }; if (v instanceof Error) return { kind: "error", name: v.name, message: v.message, stack: v.stack }; + // DOMRect/DOMRectReadOnly (and getBoundingClientRect results) have non-enumerable + // properties, so JSON.stringify yields `{}`. Expand the fields explicitly. + if ((typeof DOMRectReadOnly !== "undefined" && v instanceof DOMRectReadOnly) || + (typeof DOMRect !== "undefined" && v instanceof DOMRect) || + (v && typeof v === "object" && typeof v.toJSON === "function" && + typeof v.width === "number" && typeof v.height === "number" && typeof v.top === "number")) { + return { x: v.x, y: v.y, width: v.width, height: v.height, top: v.top, right: v.right, bottom: v.bottom, left: v.left }; + } return v; }; // Compile via the Function constructor. We try expression form first so callers can pass @@ -1927,7 +1950,7 @@ async function typeIntoPage(selector, uid, text, pressEnter) { element.focus(); if (!(element.isContentEditable || "value" in element)) throw new Error("Focused element is not text-editable"); for (const ch of Array.from(text)) await typeCharacter(element, ch); - if (pressEnter) pressKeyInPage("Enter"); + if (pressEnter) await pressKeyInPage("Enter"); const finalValue = "value" in element ? element.value : element.textContent; const valueMatches = "value" in element ? element.value.includes(text) : (element.textContent || "").includes(text); const pageMutated = pageHash() !== before; @@ -1947,7 +1970,7 @@ async function typeIntoPage(selector, uid, text, pressEnter) { }; } -function fillPage(selector, uid, text, submit) { +async function fillPage(selector, uid, text, submit) { installPiChromeInstrumentation(); const before = pageHash(); let element = elementBySelectorOrUid(selector, uid) || document.activeElement; @@ -1964,7 +1987,7 @@ function fillPage(selector, uid, text, submit) { } else { throw new Error("Focused element is not text-editable"); } - if (submit) pressKeyInPage("Enter"); + if (submit) await pressKeyInPage("Enter"); return { selector, uid, length: String(text).length, submit, input: "dom", |
