From 693f1528956017551e8ce85c0760ef35daec5ccd Mon Sep 17 00:00:00 2001 From: Roshan Singh Date: Sat, 17 Jan 2026 06:20:02 +0000 Subject: [PATCH] Fix #1035: refresh extension tab metadata Handle Target.targetInfoChanged in extension relay so /json/list reflects updated title/url after navigation. Adds regression coverage. --- src/browser/extension-relay.test.ts | 26 ++++++++++++++++++++++++++ src/browser/extension-relay.ts | 17 +++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/browser/extension-relay.test.ts b/src/browser/extension-relay.test.ts index a976b31a6..172268832 100644 --- a/src/browser/extension-relay.test.ts +++ b/src/browser/extension-relay.test.ts @@ -152,9 +152,35 @@ describe("chrome extension relay server", () => { const list = (await fetch(`${cdpUrl}/json/list`).then((r) => r.json())) as Array<{ id?: string; url?: string; + title?: string; }>; expect(list.some((t) => t.id === "t1" && t.url === "https://example.com")).toBe(true); + // Simulate navigation updating tab metadata. + ext.send( + JSON.stringify({ + method: "forwardCDPEvent", + params: { + method: "Target.targetInfoChanged", + params: { + targetInfo: { + targetId: "t1", + type: "page", + title: "DER STANDARD", + url: "https://www.derstandard.at/", + }, + }, + }, + }), + ); + + const list2 = (await fetch(`${cdpUrl}/json/list`).then((r) => r.json())) as Array<{ + id?: string; + url?: string; + title?: string; + }>; + expect(list2.some((t) => t.id === "t1" && t.url === "https://www.derstandard.at/" && t.title === "DER STANDARD")).toBe(true); + const cdp = new WebSocket(`ws://127.0.0.1:${port}/cdp`); await waitForOpen(cdp); const q = createMessageQueue(cdp); diff --git a/src/browser/extension-relay.ts b/src/browser/extension-relay.ts index acf9b2129..00602a451 100644 --- a/src/browser/extension-relay.ts +++ b/src/browser/extension-relay.ts @@ -497,6 +497,23 @@ export async function ensureChromeExtensionRelayServer(opts: { return; } + // Keep cached tab metadata fresh for /json/list. + // After navigation, Chrome updates URL/title via Target.targetInfoChanged. + if (method === "Target.targetInfoChanged") { + const changed = (params ?? {}) as { targetInfo?: { targetId?: string; type?: string } }; + const targetInfo = changed?.targetInfo; + const targetId = targetInfo?.targetId; + if (targetId && (targetInfo?.type ?? "page") === "page") { + for (const [sid, target] of connectedTargets) { + if (target.targetId !== targetId) continue; + connectedTargets.set(sid, { + ...target, + targetInfo: { ...target.targetInfo, ...(targetInfo as object) }, + }); + } + } + } + broadcastToCdpClients({ method, params, sessionId }); } });