diff --git a/main.js b/main.js index 8426a2e..fbfb09d 100644 --- a/main.js +++ b/main.js @@ -532,34 +532,8 @@ async function serveBns(request) { const host = url.hostname.toLowerCase(); const reqPath = decodeURIComponent(url.pathname) || "/"; - // Special host: apply a soft-mode "Open with…" choice submitted by - // collision.html, then redirect the tab to the actual target. Persistent - // memory (byName/byTld) is written HERE; the one-shot BCDN choice rides - // along via a ?_collision=bcnr param that loadBns consumes. - if (host === "collision-choose") { - const p = url.searchParams; - const target = String(p.get("host") || "").toLowerCase(); - const cTld = String(p.get("tld") || "").toLowerCase(); - const cChoice = p.get("choice"); - const cRem = p.get("remember") || "no"; - const rest = p.get("resturl") || "/"; - if (cChoice === "bcnr" || cChoice === "icann") { - rememberCollision(target, cTld, cChoice, cRem); - } - let dest; - if (cChoice === "icann") { - dest = "https://" + target + rest; - } else { - // BCNR/BCDN: bounce back through the bns:// resolver with a one-shot - // marker so loadBns won't re-prompt for this specific load. - const sep = rest.includes("?") ? "&" : "?"; - dest = "bns://" + target + rest + sep + "_collision=bcnr"; - } - const html = `Opening…` + - `` + - `Opening ${target}…`; - return new Response(html, { headers: { "content-type": "text/html; charset=utf-8" } }); - } + // (bns://collision-choose/ is handled by the will-navigate listener attached + // to each tab — it fires BEFORE the request reaches this protocol handler.) let rec = entries.get(host); if (!rec) { try { await resolveHost(host); } catch {} rec = entries.get(host); } @@ -778,7 +752,30 @@ function createTab(initial, opts = {}) { wc.on("did-stop-loading", () => setLoading(tab, false)); wc.on("will-navigate", (e, u) => { try { + // Skip our own programmatic loads. fallbackToWeb calls loadURL("https:///") + // and that host is often a BCNR-registered dotted name — without this guard, + // isBnsHost() would send us right back into navigateTab, canceling the + // fallback (blank-page bug 2026-08-02). + if (tab.internalNav) return; const parsed = new URL(u); + // Intercept the collision-choose posted by the in-tab "Open with…" page, + // apply the remember flag, set a one-shot transient override so loadBns + // doesn't re-prompt, and route via navigateTab so chrome/prov stay in sync. + if (parsed.protocol === "bns:" && parsed.hostname === "collision-choose") { + e.preventDefault(); + const p = parsed.searchParams; + const target = String(p.get("host") || "").toLowerCase(); + const cTld = String(p.get("tld") || "").toLowerCase(); + const cChoice = p.get("choice"); + const cRem = p.get("remember") || "no"; + const rest = p.get("resturl") || "/"; + if (!target) return; + if (cChoice === "bcnr" || cChoice === "icann") { + rememberCollision(target, cTld, cChoice, cRem); + tab.collisionOverride = cChoice; // one-shot, consumed by loadBns + } + return navigateTab(id, target + rest); + } if (parsed.protocol === "bns:") return; if (isBnsHost(parsed.hostname)) { e.preventDefault(); navigateTab(id, parsed.hostname + parsed.pathname); } } catch {} @@ -901,7 +898,10 @@ async function loadBns(t, id, host, rest, tld) { if (id === activeId) pushNav({ host, kind: "resolving", tld, registry }); const fallbackToWeb = async (reason) => { t.url = "https://" + host + (rest === "/" ? "" : rest); - try { await t.view.webContents.loadURL(t.url); } catch {} + t.internalNav = true; + try { await t.view.webContents.loadURL(t.url); } + catch (e) { console.warn("fallback loadURL failed:", e?.message); } + finally { t.internalNav = false; } t.prov = { host, kind: "web", note: `fallback: ${reason}`, tld, registry }; if (id === activeId) pushNav(t.prov); emitTabs();