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