/**
* Tiny relay content script present on every http(s) page. Two jobs:
* - let the BugTrail web panel talk to the extension through window messages
* (the panel can't use runtime.sendMessage directly — it would need the
* extension id in externally_connectable, which differs per installation);
* - forward the MAIN-world console tap's events into the extension (the tap
* itself has no access to extension messaging).
* The overlay is still injected on demand; this relay holds no UI.
*/
import browser from "webextension-polyfill";
const PANEL_SOURCE = "bugtrail-panel";
const EXT_SOURCE = "bugtrail-ext";
const TAP_SOURCE = "bugtrail-tap";
window.addEventListener("message", (event) => {
// only accept messages from this same window (the page itself)
if (event.source !== window) return;
const data = event.data as { source?: string; type?: string; token?: string; level?: string; text?: string; at?: number } | null;
if (!data) return;
// console tap (MAIN world) → background recorder buffer; the background
// drops the event when no recording is running on this tab
if (data.source === TAP_SOURCE && data.type === "console" && typeof data.text === "string") {
void browser.runtime
.sendMessage({ type: "recorder_console", level: data.level === "warning" ? "warning" : "error", text: data.text, at: data.at })
.catch(() => {});
return;
}
if (data.source !== PANEL_SOURCE) return;
if (data.type === "ping") {
window.postMessage({ source: EXT_SOURCE, type: "pong", ok: true }, window.location.origin);
return;
}
if (data.type === "replay_report" && typeof data.token === "string" && /^https?:$/.test(window.location.protocol)) {
void browser.runtime
.sendMessage({ type: "replay_report", token: data.token })
.then((response) => {
const r = response as { ok: boolean; data?: unknown; error?: string } | undefined;
window.postMessage(
{ source: EXT_SOURCE, type: "replay_result", ok: r?.ok ?? false, data: r?.data ?? null, error: r?.error },
window.location.origin
);
})
.catch((error) => {
// e.g. the extension context is gone after an update
window.postMessage(
{ source: EXT_SOURCE, type: "replay_result", ok: false, data: null, error: String(error) },
window.location.origin
);
});
}
});