← back to Slack To Steve

preflight.mjs

55 lines

// preflight.mjs — is the two-way pipe ready to go live?
// Checks: token valid, channel resolvable, and whether the READ scope
// (channels:history) has been granted yet. Prints READY / BLOCKED with the gap.
// $0 — hits Slack Web API only (auth.test + one conversations.history probe).
import fs from 'fs';
import path from 'path';

const ENV = loadEnv(path.join(process.cwd(), '.env'));
const TOKEN = ENV.SLACK_BOT_TOKEN || process.env.SLACK_BOT_TOKEN;
const CHANNEL = ENV.SLACK_CHANNEL_ID || process.env.SLACK_CHANNEL_ID || '';

function loadEnv(p) {
  const o = {};
  try {
    for (const line of fs.readFileSync(p, 'utf8').split('\n')) {
      const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
      if (m) o[m[1]] = m[2].replace(/^['"]|['"]$/g, '');
    }
  } catch {}
  return o;
}
async function slack(method, params = {}) {
  const url = 'https://slack.com/api/' + method + '?' + new URLSearchParams(params);
  const r = await fetch(url, { headers: { Authorization: 'Bearer ' + TOKEN } });
  return r.json();
}

(async () => {
  if (!TOKEN) { console.log('BLOCKED — no SLACK_BOT_TOKEN (copy .env.example → .env)'); process.exit(1); }
  const auth = await slack('auth.test');
  if (!auth.ok) { console.log('BLOCKED — token invalid: ' + auth.error); process.exit(1); }
  console.log(`token OK — bot @${auth.user} on team ${auth.team} (${auth.team_id})`);

  // WRITE check is implicit (chat:write present). READ check = probe history.
  let readOK = false, readErr = null;
  if (CHANNEL) {
    const h = await slack('conversations.history', { channel: CHANNEL, limit: 1 });
    readOK = !!h.ok;
    readErr = h.error || null;
  } else {
    readErr = 'no SLACK_CHANNEL_ID set';
  }

  if (readOK) {
    console.log('READ OK — channels:history is granted and the channel is readable.');
    console.log('\n✅ READY — run `node ingest.mjs` (or install the launchd plist) to go live.');
  } else if (readErr === 'missing_scope') {
    console.log('READ BLOCKED — token still lacks channels:history.');
    console.log('\n⛔ NOT READY — Steve must add channels:history to the Slack app + reinstall (see README).');
  } else {
    console.log('READ BLOCKED — ' + readErr + (readErr === 'not_in_channel' ? ' (invite the bot to the channel)' : ''));
    console.log('\n⛔ NOT READY — resolve the above, then re-run preflight.');
  }
})();