← back to Coming Soon Template
scripts/build.js
128 lines
#!/usr/bin/env node
/**
* Instantiates template.html per-domain from manifest.json → out/<domain>/index.html
*
* Usage:
* node scripts/build.js # build all
* node scripts/build.js abramsos.com # build one
* node scripts/build.js --deploy # also rsync to Kamatera /var/www/<domain>/
*
* Swap points (case-sensitive, double-curly):
* {{WORDMARK}} {{WORDMARK_INITIAL}} {{TAGLINE}} {{HERO_URL}} {{HERO_ALT}}
* {{DOMAIN}} {{PAGE_TITLE}} {{ACCENT_HEX}} {{YEAR}}
*/
'use strict';
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const ROOT = path.resolve(__dirname, '..');
const TEMPLATE = path.join(ROOT, 'template.html');
const MANIFEST = path.join(ROOT, 'manifest.json');
const OUT = path.join(ROOT, 'out');
const args = process.argv.slice(2);
const deploy = args.includes('--deploy');
const onlyDomain = args.find(a => !a.startsWith('--'));
if (!fs.existsSync(TEMPLATE)) { console.error('template.html missing'); process.exit(1); }
if (!fs.existsSync(MANIFEST)) { console.error('manifest.json missing'); process.exit(1); }
const tpl = fs.readFileSync(TEMPLATE, 'utf8');
const manifest = JSON.parse(fs.readFileSync(MANIFEST, 'utf8'));
const year = manifest.year || new Date().getFullYear();
// Per-domain /admin/ is just a redirect to the central admin portal at
// admin.agentabrams.com. One auth surface, one allowlist, one login.
const ADMIN_TPL = `<!doctype html>
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="robots" content="noindex,nofollow">
<meta http-equiv="refresh" content="0; url=https://admin.agentabrams.com/">
<title>redirecting to admin portal…</title>
<style>body{font:14px/1.6 system-ui;color:#57544c;background:#faf8f3;max-width:32em;margin:10em auto;padding:0 1.5em;text-align:center}a{color:#0f0e0c}</style>
</head><body>
<p>Redirecting to the admin portal…</p>
<p>If you are not redirected automatically, <a href="https://admin.agentabrams.com/">click here</a>.</p>
</body></html>
`;
function subsFor(entry) {
return {
WORDMARK: entry.wordmark,
WORDMARK_INITIAL: entry.wordmark_initial || entry.wordmark.slice(0, 1),
TAGLINE: entry.tagline,
HERO_URL: entry.hero_url,
HERO_ALT: entry.hero_alt || (entry.wordmark + ' coming soon'),
DOMAIN: entry.domain,
PAGE_TITLE: entry.page_title || (entry.wordmark + ' — coming soon'),
ACCENT_HEX: entry.accent_hex || '#3a3a3a',
YEAR: String(year),
};
}
function render(source, subs) {
let out = source;
for (const [k, v] of Object.entries(subs)) {
out = out.replaceAll('{{' + k + '}}', v);
}
return out;
}
function instantiate(entry) {
return render(tpl, subsFor(entry));
}
const targets = onlyDomain
? manifest.domains.filter(d => d.domain === onlyDomain)
: manifest.domains;
if (!targets.length) {
console.error(onlyDomain ? `no manifest entry for ${onlyDomain}` : 'no domains in manifest');
process.exit(1);
}
let built = 0;
for (const entry of targets) {
const subs = subsFor(entry);
const html = render(tpl, subs);
const adminHtml = render(ADMIN_TPL, subs);
const dir = path.join(OUT, entry.domain);
fs.mkdirSync(path.join(dir, 'admin'), { recursive: true });
fs.writeFileSync(path.join(dir, 'index.html'), html);
fs.writeFileSync(path.join(dir, 'admin', 'index.html'), adminHtml);
built++;
process.stdout.write(` built ${entry.domain.padEnd(28)} ${entry.tagline}\n`);
}
console.log(`\n✓ ${built} page${built === 1 ? '' : 's'} built into ${OUT}/`);
if (deploy) {
const REMOTE = 'root@45.61.58.125';
console.log(`\n→ rsync to ${REMOTE} (/var/www/<domain>/)…`);
// Pre-create remote dirs in one ssh call (BSD rsync on macOS lacks --mkpath).
const dirs = targets.map(t => '/var/www/' + t.domain).join(' ');
try {
execSync(`ssh -o StrictHostKeyChecking=no ${REMOTE} 'mkdir -p ${dirs}'`, { stdio: 'inherit' });
} catch (e) {
console.error(' ✗ remote mkdir failed:', e.message);
process.exit(1);
}
let ok = 0, fail = 0;
for (const entry of targets) {
const src = path.join(OUT, entry.domain, 'index.html');
const dest = REMOTE + ':/var/www/' + entry.domain + '/index.html';
try {
execSync(`rsync -az "${src}" "${dest}"`, { stdio: 'pipe' });
process.stdout.write(` deploy ${entry.domain}\n`);
ok++;
} catch (e) {
console.error(` ✗ ${entry.domain} — ${String(e.stderr || e.message).slice(0, 200)}`);
fail++;
}
}
console.log(`\n✓ deploy: ${ok} ok, ${fail} failed (vhosts must point at /var/www/<domain>/index.html)`);
}