/** * In-memory token blacklist with SQLite persistence. * Tokens are blacklisted on logout and expire automatically based on JWT expiry. */ import { getDb } from '../db/database.js' const memoryCache = new Set() let initialized = false function initCache(): void { if (initialized) return const db = getDb() db.exec(` CREATE TABLE IF NOT EXISTS token_blacklist ( token_hash TEXT PRIMARY KEY, expires_at INTEGER NOT NULL ); CREATE INDEX IF NOT EXISTS idx_token_blacklist_expires ON token_blacklist(expires_at); `) // Load recent blacklisted tokens into memory const rows = db.prepare('SELECT token_hash FROM token_blacklist WHERE expires_at > ?') .all(Date.now()) as { token_hash: string }[] for (const row of rows) { memoryCache.add(row.token_hash) } initialized = true } export function isTokenBlacklisted(tokenHash: string): boolean { initCache() return memoryCache.has(tokenHash) } export function blacklistToken(tokenHash: string, expiresAt: number): void { initCache() memoryCache.add(tokenHash) const db = getDb() db.prepare('INSERT OR IGNORE INTO token_blacklist (token_hash, expires_at) VALUES (?, ?)') .run(tokenHash, expiresAt) } export function cleanupExpiredTokens(): void { const db = getDb() db.prepare('DELETE FROM token_blacklist WHERE expires_at <= ?').run(Date.now()) }