1#!/usr/bin/env node2// Serve a mirror made by mirror-site.mjs, offline.3//4// node scripts/copy/serve-mirror.mjs <outDir> [--port 8732] [--volatile name,name]5//6// Use a port of your own per site: 8732 may already be served by another agent's mirror, and7// a failed listen (EADDRINUSE) leaves that other server answering. GET /__mirror-site returns8// the host this server mirrors.9//10// Dynamic pages: a head shim maps hosts that page scripts build at runtime, a request that11// misses by exact URL falls back to path + stable query params (timestamps, visitor ids and the12// JSONP callback are ignored, the callback is renamed in the answer), and a rewritten local URL13// echoed back inside a query value is mapped back to the recorded one.14
15// The source site's own URLs map to the server root (https://site/?page_id=5 -> /?page_id=5);
16// every other host maps to /_/<host>/... . URLs inside HTML, CSS, JS, JSON and SVG are
17// rewritten to those local paths as they are served, so the browser never leaves the
18// server. Third-party iframes saved as snapshots (index.embeds) are replaced by an <img> of the
19// same size and style, marked data-embed-src (snapshots are the iframe's content box; iframes sit
20// on the baseline, where themes often set img { vertical-align: bottom }). Requests the mirror does not hold get a 404 and are logged to <outDir>/misses.log.
86 let body = fs.readFileSync(`${outDir}/bodies/${r.body}`);
87 if (textual(r.type)) {
88 const origin = `http://${req.headers.host}`;
89 body = body.toString('utf8');
90 if (r.recordedUrl) { // JSONP: answer with the callback name this load asked for
91 const was = new URL(r.recordedUrl).searchParams.get('callback'), want = new URL(original).searchParams.get('callback');
92 if (was && want && was !== want) body = body.split(was).join(want);
93 }
94 if (/html/.test(r.type)) body = injectShim(swapEmbeds(body), origin); // swapEmbeds runs before the URL rewrite, so the src still matches; the shim is added last of the HTML edits
95 body = body.replace(hostRe, (all, slash, host) => {
96 const base = host === site ? origin : `${origin}/_/${host}`;