66 lines
3 KiB
JavaScript
66 lines
3 KiB
JavaScript
|
|
// Dev harness — exercise Theseus's `s3` content path (serveBns) WITHOUT Electron.
|
||
|
|
// Faithfully replicates what the browser triggers for a Sia site: resolve the
|
||
|
|
// name, fetch the index through the public gateway exactly as serveBns does,
|
||
|
|
// strip the gateway's <base>, then fetch every referenced same-origin asset the
|
||
|
|
// same way and report which load. This is the headless version of manual test
|
||
|
|
// #2 (Sia-via-gateway rendering).
|
||
|
|
//
|
||
|
|
// Usage: node dev/probe-site.mjs <name> e.g. coinspectrum.deviant.bch
|
||
|
|
import WebSocket from "ws";
|
||
|
|
import { resolveName } from "../../Argus/src/lib/resolver-web.js";
|
||
|
|
|
||
|
|
const GATEWAY = "https://navigate.st"; // must match main.js
|
||
|
|
const host = (process.argv[2] || "coinspectrum.deviant.bch").toLowerCase();
|
||
|
|
|
||
|
|
// mirror of serveBns's s3 fetch for one request path
|
||
|
|
async function gw(reqPath) {
|
||
|
|
const r = await fetch(`${GATEWAY}/bns/${host}${reqPath}`);
|
||
|
|
const ct = r.headers.get("content-type") || "";
|
||
|
|
const buf = Buffer.from(await r.arrayBuffer());
|
||
|
|
return { status: r.status, ct, buf };
|
||
|
|
}
|
||
|
|
const stripBase = (html) => html.replace(/<base\s+href="\/bns\/[^"]*">/i, "");
|
||
|
|
|
||
|
|
// same-origin STATIC asset refs a browser would request from bns://host/.
|
||
|
|
// Strip <script>/<style> bodies first so we don't match template literals or
|
||
|
|
// URLs built at runtime (those need a real render to verify — see selftest.js).
|
||
|
|
function assetPaths(html) {
|
||
|
|
const stripped = html
|
||
|
|
.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "")
|
||
|
|
.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "");
|
||
|
|
const out = new Set();
|
||
|
|
const re = /(?:href|src)\s*=\s*["']([^"']+)["']/gi;
|
||
|
|
let m;
|
||
|
|
while ((m = re.exec(stripped))) {
|
||
|
|
const u = m[1].trim();
|
||
|
|
if (!u || u.startsWith("#") || u.startsWith("data:") || u.startsWith("mailto:")) continue;
|
||
|
|
if (/^[a-z]+:\/\//i.test(u) || u.startsWith("//")) continue; // external
|
||
|
|
if (u.includes("${") || u.includes("{{")) continue; // runtime-built
|
||
|
|
out.add(u.startsWith("/") ? u : "/" + u.replace(/^\.?\//, ""));
|
||
|
|
}
|
||
|
|
return [...out];
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(`\n=== probe ${host} ===`);
|
||
|
|
const entry = await resolveName(host, { WebSocket });
|
||
|
|
if (!entry) { console.log("NXDOMAIN — not registered"); process.exit(1); }
|
||
|
|
console.log("records:", JSON.stringify(entry.records));
|
||
|
|
if (!entry.records.s3) { console.log("(not an s3 site — this harness targets s3)"); process.exit(0); }
|
||
|
|
|
||
|
|
const idx = await gw("/");
|
||
|
|
const wasBase = /<base\s+href="\/bns\//i.test(idx.buf.toString("utf8"));
|
||
|
|
const html = stripBase(idx.buf.toString("utf8"));
|
||
|
|
console.log(`index: HTTP ${idx.status} ${idx.ct} base-injected-by-gateway=${wasBase} (stripped)`);
|
||
|
|
|
||
|
|
const assets = assetPaths(html);
|
||
|
|
console.log(`\nassets referenced: ${assets.length}`);
|
||
|
|
let fail = 0;
|
||
|
|
for (const p of assets) {
|
||
|
|
const a = await gw(p);
|
||
|
|
const ok = a.status >= 200 && a.status < 300;
|
||
|
|
if (!ok) fail++;
|
||
|
|
console.log(` ${ok ? "OK " : "FAIL"} ${String(a.status).padEnd(3)} ${a.ct.split(";")[0].padEnd(24)} ${p}`);
|
||
|
|
}
|
||
|
|
console.log(`\nresult: ${assets.length - fail}/${assets.length} assets loaded, ${fail} failed`);
|
||
|
|
process.exit(fail ? 2 : 0);
|