Theseus: light/dark theme, redesigned search box, trimmed engines, WebRTC modes

- Light/dark/system theme (Settings > General) via nativeTheme.themeSource
  driving prefers-color-scheme across chrome, settings, popover, and home.
- Search box redesigned: a magnifier icon opens the engine dropdown, the rest
  is a wider typing field; styled to match the browser (was a raw <select>).
- Trimmed built-in engines to DuckDuckGo/Google/Brave/Bing/Startpage/Yandex;
  custom engines still add/remove via "Add / edit engines…".
- WebRTC: the "WebRTC Network Limiter" extension can't run in Electron
  (chrome.privacy API is unavailable), so its function is now a native
  4-mode WebRTC IP policy in Settings > Privacy.
- Address-bar placeholder: "Ask a search engine or enter web address".
This commit is contained in:
Local Dev 2026-07-30 22:00:01 +02:00
parent eb18108fb1
commit 83bff76960

View file

@ -0,0 +1,98 @@
// Electrum-sourced BNS indexer — NO node, NO Fulcrum, NO disk, NO sync.
//
// Instead of scanning blocks from a BCHN node (see RpcSource in bns-indexer.js),
// this polls PUBLIC electrum/Fulcrum servers for just the two calls BNS needs —
// blockchain.scripthash.get_history (the beacon) + blockchain.transaction.get —
// caches the beacon set, and serves the same BNS electrum-over-WebSocket endpoint.
//
// Result: a featherweight, pinned-IP, DNS-independent caching relay you can run on
// a tiny VPS. Tradeoff vs. RpcSource: it trusts the upstream public servers (no own
// chain), but it needs no node, no Fulcrum, no storage.
//
// BNS_ELECTRUM_SERVERS=wss://a:50004,wss://b:50004 (comma-separated, tried in order)
// BNS_WS_BIND=127.0.0.1 BNS_WS_PORT=50010 BNS_POLL_MS=30000
// node electrum-source.js
import WebSocket from "ws";
import { pathToFileURL } from "node:url";
import { BeaconIndex, startElectrumWS } from "./bns-indexer.js";
const CONFIG = {
servers: (process.env.BNS_ELECTRUM_SERVERS ||
"wss://chipnet.bch.ninja:50004,wss://chipnet.imaginary.cash:50004,wss://chipnet.c3-soft.com:64004")
.split(",").map((s) => s.trim()).filter(Boolean),
wsBind: process.env.BNS_WS_BIND || "127.0.0.1",
wsPort: Number(process.env.BNS_WS_PORT || 50010),
beacon: process.env.BNS_BEACON_SCRIPTHASH ||
"e1cdbba719436f49acb4bf245b44df875c6d6b405eda46a9d3e736d138102f3b",
pollMs: Number(process.env.BNS_POLL_MS || 30000),
};
const log = (...a) => console.log(new Date().toISOString(), ...a);
// minimal newline-delimited electrum WS client (tolerates a missing trailing newline).
function elClient(url) {
return new Promise((resolve, reject) => {
const ws = new WebSocket(url);
let id = 0, buf = ""; const pending = new Map();
const t = setTimeout(() => { try { ws.close(); } catch {} reject(new Error("connect timeout " + url)); }, 15000);
ws.on("open", () => { clearTimeout(t); resolve({
call(method, params = []) {
return new Promise((res, rej) => {
const i = ++id; pending.set(i, { res, rej });
ws.send(JSON.stringify({ id: i, method, params }) + "\n");
setTimeout(() => { if (pending.has(i)) { pending.delete(i); rej(new Error("timeout " + method)); } }, 20000);
});
},
close() { try { ws.close(); } catch {} },
}); });
ws.on("error", (e) => { clearTimeout(t); reject(e); });
const settle = (line) => { try { const m = JSON.parse(line); const p = pending.get(m.id); if (p) { pending.delete(m.id); m.error ? p.rej(new Error(JSON.stringify(m.error))) : p.res(m.result); } } catch {} };
ws.on("message", (d) => {
buf += d.toString(); let nl;
while ((nl = buf.indexOf("\n")) >= 0) { const line = buf.slice(0, nl).trim(); buf = buf.slice(nl + 1); if (line) settle(line); }
const rest = buf.trim();
if (rest) { try { JSON.parse(rest); settle(rest); buf = ""; } catch {} }
});
});
}
async function connectAny(servers) {
let lastErr;
for (const url of servers) {
try { const cl = await elClient(url); await cl.call("server.version", ["BNS-Relay/0.1", "1.4.3"]); return { cl, url }; }
catch (e) { lastErr = e; log("upstream unavailable:", url, "-", e.message); }
}
throw lastErr || new Error("no upstream servers configured");
}
// Pull the beacon history + any not-yet-cached txs from an upstream, into the index.
async function sync(index, servers) {
const { cl, url } = await connectAny(servers);
try {
const history = await cl.call("blockchain.scripthash.get_history", [CONFIG.beacon]);
if (!Array.isArray(history)) throw new Error("bad get_history response");
let fetched = 0;
for (const { tx_hash, height } of history) {
index.history.set(tx_hash, height);
if (!index.txCache.has(tx_hash)) {
index.txCache.set(tx_hash, await cl.call("blockchain.transaction.get", [tx_hash, true]));
fetched++;
}
}
log(`synced via ${url}: ${index.history.size} beacon txs (${fetched} new)`);
} finally { cl.close(); }
}
async function main() {
log("electrum-sourced BNS indexer starting — upstreams:", CONFIG.servers.join(", "));
const index = new BeaconIndex(CONFIG.beacon);
startElectrumWS(index, { bind: CONFIG.wsBind, port: CONFIG.wsPort }, null); // cache-only: beacon txs are all cached
for (;;) {
try { await sync(index, CONFIG.servers); }
catch (e) { log("sync error (will retry):", e.message); }
await new Promise((r) => setTimeout(r, CONFIG.pollMs));
}
}
if (import.meta.url === pathToFileURL(process.argv[1] || "").href) {
main().catch((e) => { console.error("fatal:", e.message); process.exit(1); });
}