← back to Small Business Builder
scripts/rerender-url-mockups.mjs
71 lines
// Re-render the preview_html of URL-driven website_analyses entries (the ones
// NOT created by build-all-analyses.mjs) using their enriched copy_pack. The
// 11 entries created via the /website-analysis form have copy_pack saved in
// summary_json but their stored preview_html was rendered before enrichment.
//
// node scripts/rerender-url-mockups.mjs # do it
// node scripts/rerender-url-mockups.mjs --dry-run # preview
import 'dotenv/config';
import { renderTheme } from '../src/render/website-analysis-themes.js';
import { many, query } from '../src/lib/db.js';
const DRY = process.argv.includes('--dry-run');
function isPublicUrl(u) {
try {
const p = new URL(u);
if (p.protocol !== 'http:' && p.protocol !== 'https:') return false;
const h = p.hostname;
if (/^(127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|100\.)/.test(h)) return false;
if (h === 'localhost' || h.endsWith('.local')) return false;
return true;
} catch { return false; }
}
async function main() {
const rows = await many(`
SELECT a.id, a.slug, a.url, a.vertical, a.summary_json, a.meta_json
FROM website_analyses a
WHERE (a.meta_json->>'source') IS DISTINCT FROM 'build-all-analyses'
AND a.summary_json ? 'copy_pack'
ORDER BY a.id
`);
console.log(`Re-rendering ${rows.length} URL-driven analyses with enriched copy_pack${DRY ? ' (DRY)' : ''}`);
let touched = 0, skipped = 0;
for (const row of rows) {
const cp = row.summary_json?.copy_pack;
const meta = row.meta_json || {};
const ctx = {
title: cp?.headline || meta.title || row.slug,
tagline: cp?.tagline || meta.tagline || '',
cta_primary: cp?.cta_primary,
cta_secondary: cp?.cta_secondary,
cards: cp?.cards,
palette: meta.palette || [],
hero_image: meta.hero_image || null,
vertical: row.vertical || 'generic',
ig_handle: meta.ig_handle || null,
url: isPublicUrl(row.url) ? row.url : `https://${row.slug}.example`,
};
const mockups = await many('SELECT id, theme, mockup_id FROM website_analysis_mockups WHERE analysis_id=$1 ORDER BY mockup_id', [row.id]);
if (!mockups.length) { skipped += 1; continue; }
for (const m of mockups) {
const html = renderTheme(m.theme, ctx);
if (DRY) {
console.log(` ${row.slug} ${m.mockup_id} would re-render (${html.length} chars, headline="${ctx.title.slice(0,60)}")`);
} else {
await query('UPDATE website_analysis_mockups SET preview_html=$1 WHERE id=$2', [html, m.id]);
}
}
touched += 1;
console.log(`[${touched}/${rows.length}] ${row.slug} → "${ctx.title.slice(0, 60)}"`);
}
console.log(`\nDONE — touched:${touched} skipped:${skipped}`);
process.exit(0);
}
main().catch(e => { console.error(e); process.exit(1); });