import { ensurePageState, getPageForTargetId } from "./pw-session.js"; import { normalizeTimeoutMs } from "./pw-tools-core.shared.js"; function matchUrlPattern(pattern: string, url: string): boolean { const p = pattern.trim(); if (!p) return false; if (p === url) return true; if (p.includes("*")) { const escaped = p.replace(/[|\\{}()[\]^$+?.]/g, "\\$&"); const regex = new RegExp(`^${escaped.replace(/\*\*/g, ".*").replace(/\*/g, ".*")}$`); return regex.test(url); } return url.includes(p); } export async function responseBodyViaPlaywright(opts: { cdpUrl: string; targetId?: string; url: string; timeoutMs?: number; maxChars?: number; }): Promise<{ url: string; status?: number; headers?: Record; body: string; truncated?: boolean; }> { const pattern = String(opts.url ?? "").trim(); if (!pattern) throw new Error("url is required"); const maxChars = typeof opts.maxChars === "number" && Number.isFinite(opts.maxChars) ? Math.max(1, Math.min(5_000_000, Math.floor(opts.maxChars))) : 200_000; const timeout = normalizeTimeoutMs(opts.timeoutMs, 20_000); const page = await getPageForTargetId(opts); ensurePageState(page); const promise = new Promise((resolve, reject) => { let done = false; let timer: NodeJS.Timeout | undefined; let handler: ((resp: unknown) => void) | undefined; const cleanup = () => { if (timer) clearTimeout(timer); timer = undefined; if (handler) page.off("response", handler as never); }; handler = (resp: unknown) => { if (done) return; const r = resp as { url?: () => string }; const u = r.url?.() || ""; if (!matchUrlPattern(pattern, u)) return; done = true; cleanup(); resolve(resp); }; page.on("response", handler as never); timer = setTimeout(() => { if (done) return; done = true; cleanup(); reject( new Error( `Response not found for url pattern "${pattern}". Run 'clawdbot browser requests' to inspect recent network activity.`, ), ); }, timeout); }); const resp = (await promise) as { url?: () => string; status?: () => number; headers?: () => Record; body?: () => Promise; text?: () => Promise; }; const url = resp.url?.() || ""; const status = resp.status?.(); const headers = resp.headers?.(); let bodyText = ""; try { if (typeof resp.text === "function") { bodyText = await resp.text(); } else if (typeof resp.body === "function") { const buf = await resp.body(); bodyText = new TextDecoder("utf-8").decode(buf); } } catch (err) { throw new Error(`Failed to read response body for "${url}": ${String(err)}`); } const trimmed = bodyText.length > maxChars ? bodyText.slice(0, maxChars) : bodyText; return { url, status, headers, body: trimmed, truncated: bodyText.length > maxChars ? true : undefined, }; }