diff --git a/src/cdn-name-index.mjs b/src/cdn-name-index.mjs new file mode 100644 index 0000000..4e1e148 --- /dev/null +++ b/src/cdn-name-index.mjs @@ -0,0 +1,48 @@ +// Keep the CDN's interpreted name index fresh from the gateway's own index. +// +// Ariadne for Android (and Theseus, via NETWORKS.cdnIndexUrl) pull +// https://dl.silentmode.st/bns-name-index.json on cold start: a snapshot of +// every registered name with its records, so the first page loads before +// the electrum walk finishes. It was produced by publish-name-mirror.mjs, +// which needs the operator wallet and ran by hand — the CDN copy went stale +// for weeks (seven names behind on 2026-09-28). The gateway already holds +// the same index in memory and serves it as /api/registry, so this script +// simply reshapes that into the snapshot format and writes the CDN file. +// Runs on the VPS from a systemd timer (VPS/SilentMode/cdn-name-index.*). +// +// node cdn-name-index.mjs [--gateway http://127.0.0.1:8700] [--out /opt/silent-mode/dl/bns-name-index.json] +// +// Snapshot shape (what Bns.java's loadDisk / pullSiaIndex parse): +// [{ name, category, records, txid, height, updatedTxid }, …] +import { readFileSync, writeFileSync, renameSync, existsSync } from "node:fs"; + +const args = process.argv.slice(2); +const opt = (k, d) => { const i = args.indexOf(k); return i >= 0 && args[i + 1] ? args[i + 1] : d; }; +const GATEWAY = opt("--gateway", "http://127.0.0.1:8700"); +const OUT = opt("--out", "/opt/silent-mode/dl/bns-name-index.json"); +const MIN_NAMES = 10; // a shorter answer is a gateway still warming up, not the registry + +const r = await fetch(`${GATEWAY}/api/registry`, { signal: AbortSignal.timeout(20_000) }); +if (!r.ok) throw new Error(`gateway ${r.status}`); +const reg = await r.json(); +const names = Array.isArray(reg.names) ? reg.names : []; +if (names.length < MIN_NAMES) throw new Error(`only ${names.length} names — not writing`); + +const snapshot = names + .filter((e) => e && typeof e.name === "string" && e.records && typeof e.records === "object") + .map((e) => ({ + name: e.name, + category: e.category || "", + records: e.records, + txid: e.txid || "", + height: Number(e.height) || 0, + updatedTxid: e.updated_txid ?? e.updatedTxid ?? null, + })) + .sort((a, b) => (a.height || 0) - (b.height || 0) || a.name.localeCompare(b.name)); + +const next = JSON.stringify(snapshot); +const prev = existsSync(OUT) ? readFileSync(OUT, "utf8") : ""; +if (prev === next) { console.log(`unchanged (${snapshot.length} names)`); process.exit(0); } +writeFileSync(OUT + ".tmp", next); +renameSync(OUT + ".tmp", OUT); +console.log(`wrote ${OUT}: ${snapshot.length} names, height hint ${reg.height_hint ?? "?"}`);