Browser: add URL fallback for relay tab matching (#1999)
Co-authored-by: João Paulo Furtado <jonit-dev@users.noreply.github.com>
This commit is contained in:
@@ -13,6 +13,7 @@ Status: unreleased.
|
|||||||
- Docs: add Render deployment guide. (#1975) Thanks @anurag.
|
- Docs: add Render deployment guide. (#1975) Thanks @anurag.
|
||||||
- CI: increase Node heap size for macOS checks. (#1890) Thanks @realZachi.
|
- CI: increase Node heap size for macOS checks. (#1890) Thanks @realZachi.
|
||||||
- macOS: avoid crash when rendering code blocks by bumping Textual to 0.3.1. (#2033) Thanks @garricn.
|
- macOS: avoid crash when rendering code blocks by bumping Textual to 0.3.1. (#2033) Thanks @garricn.
|
||||||
|
- Browser: fall back to URL matching for extension relay target resolution. (#1999) Thanks @jonit-dev.
|
||||||
|
|
||||||
## 2026.1.24-3
|
## 2026.1.24-3
|
||||||
|
|
||||||
|
|||||||
@@ -337,12 +337,56 @@ async function pageTargetId(page: Page): Promise<string | null> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findPageByTargetId(browser: Browser, targetId: string): Promise<Page | null> {
|
async function findPageByTargetId(
|
||||||
|
browser: Browser,
|
||||||
|
targetId: string,
|
||||||
|
cdpUrl?: string,
|
||||||
|
): Promise<Page | null> {
|
||||||
const pages = await getAllPages(browser);
|
const pages = await getAllPages(browser);
|
||||||
|
// First, try the standard CDP session approach
|
||||||
for (const page of pages) {
|
for (const page of pages) {
|
||||||
const tid = await pageTargetId(page).catch(() => null);
|
const tid = await pageTargetId(page).catch(() => null);
|
||||||
if (tid && tid === targetId) return page;
|
if (tid && tid === targetId) return page;
|
||||||
}
|
}
|
||||||
|
// If CDP sessions fail (e.g., extension relay blocks Target.attachToBrowserTarget),
|
||||||
|
// fall back to URL-based matching using the /json/list endpoint
|
||||||
|
if (cdpUrl) {
|
||||||
|
try {
|
||||||
|
const baseUrl = cdpUrl
|
||||||
|
.replace(/\/+$/, "")
|
||||||
|
.replace(/^ws:/, "http:")
|
||||||
|
.replace(/\/cdp$/, "");
|
||||||
|
const response = await fetch(`${baseUrl}/json/list`);
|
||||||
|
if (response.ok) {
|
||||||
|
const targets = (await response.json()) as Array<{
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
title?: string;
|
||||||
|
}>;
|
||||||
|
const target = targets.find((t) => t.id === targetId);
|
||||||
|
if (target) {
|
||||||
|
// Try to find a page with matching URL
|
||||||
|
const urlMatch = pages.filter((p) => p.url() === target.url);
|
||||||
|
if (urlMatch.length === 1) {
|
||||||
|
return urlMatch[0];
|
||||||
|
}
|
||||||
|
// If multiple URL matches, use index-based matching as fallback
|
||||||
|
// This works when Playwright and the relay enumerate tabs in the same order
|
||||||
|
if (urlMatch.length > 1) {
|
||||||
|
const sameUrlTargets = targets.filter((t) => t.url === target.url);
|
||||||
|
if (sameUrlTargets.length === urlMatch.length) {
|
||||||
|
const idx = sameUrlTargets.findIndex((t) => t.id === targetId);
|
||||||
|
if (idx >= 0 && idx < urlMatch.length) {
|
||||||
|
return urlMatch[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore fetch errors and fall through to return null
|
||||||
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +399,7 @@ export async function getPageForTargetId(opts: {
|
|||||||
if (!pages.length) throw new Error("No pages available in the connected browser.");
|
if (!pages.length) throw new Error("No pages available in the connected browser.");
|
||||||
const first = pages[0];
|
const first = pages[0];
|
||||||
if (!opts.targetId) return first;
|
if (!opts.targetId) return first;
|
||||||
const found = await findPageByTargetId(browser, opts.targetId);
|
const found = await findPageByTargetId(browser, opts.targetId, opts.cdpUrl);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// Extension relays can block CDP attachment APIs (e.g. Target.attachToBrowserTarget),
|
// Extension relays can block CDP attachment APIs (e.g. Target.attachToBrowserTarget),
|
||||||
// which prevents us from resolving a page's targetId via newCDPSession(). If Playwright
|
// which prevents us from resolving a page's targetId via newCDPSession(). If Playwright
|
||||||
@@ -496,7 +540,7 @@ export async function closePageByTargetIdViaPlaywright(opts: {
|
|||||||
targetId: string;
|
targetId: string;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const { browser } = await connectBrowser(opts.cdpUrl);
|
const { browser } = await connectBrowser(opts.cdpUrl);
|
||||||
const page = await findPageByTargetId(browser, opts.targetId);
|
const page = await findPageByTargetId(browser, opts.targetId, opts.cdpUrl);
|
||||||
if (!page) {
|
if (!page) {
|
||||||
throw new Error("tab not found");
|
throw new Error("tab not found");
|
||||||
}
|
}
|
||||||
@@ -512,7 +556,7 @@ export async function focusPageByTargetIdViaPlaywright(opts: {
|
|||||||
targetId: string;
|
targetId: string;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const { browser } = await connectBrowser(opts.cdpUrl);
|
const { browser } = await connectBrowser(opts.cdpUrl);
|
||||||
const page = await findPageByTargetId(browser, opts.targetId);
|
const page = await findPageByTargetId(browser, opts.targetId, opts.cdpUrl);
|
||||||
if (!page) {
|
if (!page) {
|
||||||
throw new Error("tab not found");
|
throw new Error("tab not found");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user