← 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); });