#!/usr/bin/env node // ───────────────────────────────────────────────────────────── // bin/joins.js — read the Bifrost join-click log. // // Every press of the final "Join Project Bifrost" CTA is recorded // as its own row in the `bifrost_joins` table (who, when, session). // // Usage: // node bin/joins.js list # every click, newest first // node bin/joins.js summary # one row per user, with click count // node bin/joins.js for # full click history for one user // node bin/joins.js stats # totals (clicks + unique users) // ───────────────────────────────────────────────────────────── import { q } from '../src/db.js'; const [, , cmd, arg] = process.argv; const EMAIL_RE = /^[^@\s]+@[^@\s]+\.[^@\s]+$/; function help() { console.log('Usage:'); console.log(' joins list # every click, newest first'); console.log(' joins summary # one row per user'); console.log(' joins for # click history for a user'); console.log(' joins stats # totals'); process.exit(1); } function iso(t) { return new Date(t).toISOString(); } function shortSid(s) { return s ? `[${s.slice(0, 8)}…]` : ''; } switch (cmd) { case 'list': { const rows = q.listJoins.all(); if (rows.length === 0) { console.log('(no clicks yet)'); break; } for (const r of rows) { console.log(` ${iso(r.clicked_at)} ${r.email.padEnd(32)} ${shortSid(r.session_id)}`); } console.log(`\n${rows.length} click${rows.length === 1 ? '' : 's'} total.`); break; } case 'summary': { const rows = q.summariseJoins.all(); if (rows.length === 0) { console.log('(no clicks yet)'); break; } console.log(' CLICKS FIRST LAST EMAIL'); for (const r of rows) { const n = String(r.click_count).padStart(6); console.log(` ${n} ${iso(r.first_clicked_at)} ${iso(r.last_clicked_at)} ${r.email}`); } console.log(`\n${rows.length} unique user${rows.length === 1 ? '' : 's'}.`); break; } case 'for': { if (!arg || !EMAIL_RE.test(arg)) help(); const email = arg.trim().toLowerCase(); const rows = q.listJoinsForEmail.all(email); if (rows.length === 0) { console.log(`(no clicks for ${email})`); break; } console.log(`Clicks by ${email}:`); for (const r of rows) { console.log(` ${iso(r.clicked_at)} ${shortSid(r.session_id)}`); } console.log(`\n${rows.length} click${rows.length === 1 ? '' : 's'}.`); break; } case 'stats': { const total = q.countJoins.get().n; const unique = q.countUniqueJoiners.get().n; console.log(` total clicks: ${total}`); console.log(` unique users: ${unique}`); break; } default: help(); }