spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1#!/usr/bin/env tsx2/**3 * Mint a public API key (CLAUDE.md §190-191).4 *5 * pnpm --filter @cancerindex/api create-key -- --label "Lab X" --email someone@example.org --tier research --rpm 6006 *7 * The plaintext key is printed ONCE; only its sha256 hash and a display prefix are stored.8 */9import { randomBytes } from 'node:crypto';10import { sql } from 'drizzle-orm';11import { loadEnv } from '../src/lib/env.js';12import { hashApiKey } from '../src/plugins/auth.js';1314loadEnv();1516const args = process.argv.slice(2);17const flag = (name: string, fallback?: string) => {18 const i = args.indexOf(`--${name}`);19 return i >= 0 && args[i + 1] && !args[i + 1]!.startsWith('--') ? args[i + 1] : fallback;20};2122const label = flag('label', 'unnamed');23const email = flag('email');24const tier = flag('tier', 'free')!;25const rpm = Number(flag('rpm', tier === 'institutional' ? '3000' : tier === 'pro' ? '1200' : tier === 'research' ? '600' : '120'));2627const { getDb, closeDb } = await import('@cancerindex/database');28const db = getDb();29try {30 const key = `cix_${randomBytes(24).toString('base64url')}`;31 const prefix = key.slice(0, 12);32 const rows = await db.execute<{ id: number }>(sql`33 INSERT INTO api_keys (key_hash, prefix, label, owner_email, tier, rate_limit_per_minute, active)34 VALUES (${hashApiKey(key)}, ${prefix}, ${label}, ${email ?? null}, ${tier}, ${rpm}, true) RETURNING id`);35 console.log(`API key created (id=${rows[0]!.id}, prefix=${prefix}, tier=${tier}, ${rpm} req/min)`);36 console.log('Store it now — it will not be shown again:');37 console.log(key);38 console.log(`Usage: curl -H "Authorization: Bearer ${key}" http://127.0.0.1:${process.env.API_PORT ?? 8251}/v1/stats`);39} finally {40 await closeDb();41}42