#!/usr/bin/env tsx /** * Mint a public API key (CLAUDE.md §190-191). * * pnpm --filter @cancerindex/api create-key -- --label "Lab X" --email someone@example.org --tier research --rpm 600 * * The plaintext key is printed ONCE; only its sha256 hash and a display prefix are stored. */ import { randomBytes } from 'node:crypto'; import { sql } from 'drizzle-orm'; import { loadEnv } from '../src/lib/env.js'; import { hashApiKey } from '../src/plugins/auth.js'; loadEnv(); const args = process.argv.slice(2); const flag = (name: string, fallback?: string) => { const i = args.indexOf(`--${name}`); return i >= 0 && args[i + 1] && !args[i + 1]!.startsWith('--') ? args[i + 1] : fallback; }; const label = flag('label', 'unnamed'); const email = flag('email'); const tier = flag('tier', 'free')!; const rpm = Number(flag('rpm', tier === 'institutional' ? '3000' : tier === 'pro' ? '1200' : tier === 'research' ? '600' : '120')); const { getDb, closeDb } = await import('@cancerindex/database'); const db = getDb(); try { const key = `cix_${randomBytes(24).toString('base64url')}`; const prefix = key.slice(0, 12); const rows = await db.execute<{ id: number }>(sql` INSERT INTO api_keys (key_hash, prefix, label, owner_email, tier, rate_limit_per_minute, active) VALUES (${hashApiKey(key)}, ${prefix}, ${label}, ${email ?? null}, ${tier}, ${rpm}, true) RETURNING id`); console.log(`API key created (id=${rows[0]!.id}, prefix=${prefix}, tier=${tier}, ${rpm} req/min)`); console.log('Store it now — it will not be shown again:'); console.log(key); console.log(`Usage: curl -H "Authorization: Bearer ${key}" http://127.0.0.1:${process.env.API_PORT ?? 8251}/v1/stats`); } finally { await closeDb(); }