← back to Marketing Command Center

scripts/follow-counts-snapshot.js

38 lines

#!/usr/bin/env node
// Once-daily Followers/Following snapshot capture for the DW Marketing Command
// Center. Calls the follow-counts module's captureSnapshot() directly (no HTTP /
// no auth needed — same process boundary as the module) so a launchd job can run
// it headlessly. Reuses Norma's IG token/plumbing via the module; honors Norma's
// simulation mode (records the real Graph shape, labeled simulated, until creds
// are live). Idempotent per UTC day.
//
// Wire as a daily launchd job (staged in deploy/com.steve.dw-follow-counts.plist).
// Run manually:  node scripts/follow-counts-snapshot.js
const path = require('path');

// Load .env so NORMA_IG_* overrides (if any) and any future creds are visible.
const fs = require('fs');
try {
  for (const line of fs.readFileSync(path.join(__dirname, '..', '.env'), 'utf8').split('\n')) {
    const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
    if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, '');
  }
} catch { /* no .env */ }

const mod = require('../modules/follow-counts');

(async () => {
  try {
    const r = await mod.captureSnapshot();
    const tag = r.simulated ? 'SIMULATED (awaiting live IG creds)' : 'LIVE';
    console.log(`[follow-counts] ${new Date().toISOString()} snapshot ${r.ok ? 'ok' : 'FAILED'} · ${tag} · date=${r.date}`);
    for (const c of (r.captured || [])) {
      console.log(`  @${c.handle}: followers=${c.followers} following=${c.following} media=${c.media} (${c.source})`);
    }
    if (!r.ok) { console.error(`  error: ${r.error}`); process.exit(2); }
  } catch (e) {
    console.error(`[follow-counts] snapshot crashed: ${e.message}`);
    process.exit(1);
  }
})();