When a name exists on both BCNR and ICANN, which one wins? Applies machine-wide — every browser sees the same answer. Change is picked up within 5 seconds; no daemon restart, no UAC.
+
+
+
+
+
+
Sources
+
Each index source can be toggled independently to isolate a path or measure without it. Changes hot-reload every 5 s via C:\ProgramData\Ariadne\policy.json — no restart. State column shows the last attempt result for each.
+
+
SourceEnabledState
+
+
+
+
Status report
+
Full snapshot of what the daemon currently sees — daemon version, permitted TLDs, index size, last fetch per source. Paste into a support conversation.
+
+
+
+
+
Loading…
+
Remove
Uninstall the resolver from this machine. Theseus itself keeps working — its built-in resolver isn't affected.
@@ -1547,6 +1585,96 @@
arRefreshSub.onclick = refreshAriadne;
refreshAriadne();
+ // ---- Ariadne 0.1.13+ sub-page: policy + sources + status report -----
+ // All read/write against the daemon's /api/status (over 127.0.0.1) and
+ // C:\ProgramData\Ariadne\policy.json (user-writable ACL) -- no UAC.
+ const arPolicyRadios = document.querySelectorAll('input[name="ariadnePolicy"]');
+ const arSourcesBody = q("ariadneSourcesBody");
+ const arStatusJson = q("ariadneStatusJson");
+ const arStatusCopy = q("ariadneStatusCopy");
+ const arStatusRefr = q("ariadneStatusRefresh");
+ const SOURCE_DESCRIPTIONS = {
+ snapshotHttps: { label: "HTTPS snapshot (VPS + Sia)", hint: "dl.silentmode.st + s3.silentmode.st, polled every 30 s with ETag" },
+ electrumWss: { label: "Electrum WSS (chipnet)", hint: "direct chain read via WebSocket; secondary refresh" },
+ perQueryLookup: { label: "Per-query indexer fallback", hint: "navigate.st/api/name/<host> on index miss, 30-s LRU" },
+ diskCache: { label: "Disk cache", hint: "C:\\ProgramData\\Ariadne\\bns-name-snapshot.json — read at boot, written on any HTTPS win" },
+ localApi: { label: "Local BNS indexer API", hint: "http://127.0.0.1/api/tlds, /api/name/:n, /api/registry, /api/status" },
+ };
+ function fmtTime(iso) {
+ if (!iso) return "never";
+ try { const d = new Date(iso); const s = Math.round((Date.now() - d.getTime()) / 1000); return s < 60 ? `${s} s ago` : s < 3600 ? `${Math.round(s/60)} m ago` : d.toLocaleString(); } catch { return String(iso); }
+ }
+ function sourceState(name, st) {
+ if (!st) return { text: "no state yet", ok: false, err: false };
+ if (name === "diskCache") return { text: st.exists ? `${(st.size||0).toLocaleString()} B · ${fmtTime(st.mtime)}` : "no file yet", ok: !!st.exists, err: false };
+ if (name === "localApi") return { text: st.enabled ? "listening" : "disabled", ok: !!st.enabled, err: false };
+ if (name === "perQueryLookup") return { text: `${st.hits||0} hit · ${st.misses||0} miss · ${st.errors||0} err · last ${fmtTime(st.lastAttempt)}`, ok: (st.hits||0) > 0 || !st.lastAttempt, err: (st.errors||0) > 0 };
+ if (st.lastError) return { text: `error: ${st.lastError.slice(0, 80)} · last ${fmtTime(st.lastAttempt)}`, ok: false, err: true };
+ if (st.lastSuccess) return { text: `ok · last success ${fmtTime(st.lastSuccess)}` + (st.refreshes ? ` · ${st.refreshes} refresh${st.refreshes>1?"es":""}` : ""), ok: true, err: false };
+ return { text: `waiting · last try ${fmtTime(st.lastAttempt)}`, ok: false, err: false };
+ }
+ let arLastStatus = null;
+ async function refreshAriadneStatus() {
+ arStatusJson.textContent = "Loading…";
+ arSourcesBody.innerHTML = "";
+ const r = await C.ariadneGetStatus();
+ if (!r || !r.ok) {
+ arStatusJson.textContent = `Cannot reach the daemon: ${r?.error || "unknown error"}\n\nIs Ariadne's Thread running? Turn it on from the Status section above.`;
+ arSourcesBody.innerHTML = '
Daemon unreachable — start it from Status above.
';
+ return;
+ }
+ arLastStatus = r.status;
+ arStatusJson.textContent = JSON.stringify(r.status, null, 2);
+ const sources = r.status.sources || {};
+ arSourcesBody.innerHTML = "";
+ for (const name of Object.keys(SOURCE_DESCRIPTIONS)) {
+ const d = SOURCE_DESCRIPTIONS[name];
+ const st = sources[name] || {};
+ const s = sourceState(name, st);
+ const row = document.createElement("div");
+ row.className = "asrc-row";
+ row.innerHTML = `${d.label}${d.hint}` +
+ `` +
+ `${s.text}`;
+ arSourcesBody.appendChild(row);
+ }
+ // Wire the enable checkboxes AFTER they're in the DOM.
+ arSourcesBody.querySelectorAll('input[type="checkbox"][data-src]').forEach((cb) => {
+ cb.addEventListener("change", async () => {
+ cb.disabled = true;
+ const w = await C.ariadneSetSource(cb.dataset.src, cb.checked);
+ cb.disabled = false;
+ if (!w?.ok) { alert(`Could not save: ${w?.error || "unknown error"}`); cb.checked = !cb.checked; return; }
+ // Poll again after the daemon's 5-s hot-reload tick so state text catches up.
+ setTimeout(refreshAriadneStatus, 6000);
+ });
+ });
+ }
+ async function loadAriadnePolicy() {
+ const r = await C.ariadneGetPolicy();
+ const p = (r?.policy?.policy || "bcnr-first").toLowerCase();
+ arPolicyRadios.forEach((rb) => { rb.checked = (rb.value === p); });
+ }
+ arPolicyRadios.forEach((rb) => {
+ rb.addEventListener("change", async () => {
+ if (!rb.checked) return;
+ const w = await C.ariadneSetPolicy(rb.value);
+ if (!w?.ok) alert(`Could not save policy: ${w?.error || "unknown error"}`);
+ });
+ });
+ arStatusRefr.onclick = refreshAriadneStatus;
+ arStatusCopy.onclick = async () => {
+ if (!arLastStatus) return;
+ try { await navigator.clipboard.writeText(JSON.stringify(arLastStatus, null, 2)); arStatusCopy.textContent = "Copied"; setTimeout(() => (arStatusCopy.textContent = "Copy report"), 1500); }
+ catch { arStatusCopy.textContent = "Copy failed"; setTimeout(() => (arStatusCopy.textContent = "Copy report"), 1500); }
+ };
+ // Load once on script boot; also every time the user navigates INTO the
+ // Ariadne sub-page (fresh state, no cached-stale JSON on re-entry).
+ loadAriadnePolicy(); refreshAriadneStatus();
+ document.addEventListener("section", (e) => {
+ if (e.detail === "plugins/ariadne") { loadAriadnePolicy(); refreshAriadneStatus(); }
+ });
+
// AEGIS ——————————————————————————————————————————————————————————
// Bundled add-on shipped OTA. Same addons-check-updates IPC the
// Extensions page uses, filtered for the aegis id. Legacy id