/** * Middleware to check subscription status for protected routes */ export function requireActiveSubscription(req, res, next) { // Check if user has subscription info attached if (!req.subscription) { return res.status(403).json({ error: 'Active subscription required', code: 'NO_SUBSCRIPTION' }); } // Check if subscription is active (not cancelled or past due) if (req.subscription.status !== 'active' && req.subscription.status !== 'trialing') { return res.status(403).json({ error: 'Subscription not active', code: 'SUBSCRIPTION_INACTIVE', status: req.subscription.status }); } // Check if trial has expired (if trialing) if (req.subscription.status === 'trialing' && req.subscription.trial_end) { const trialEnd = new Date(req.subscription.trial_end); if (new Date() > trialEnd) { return res.status(403).json({ error: 'Trial period expired', code: 'TRIAL_EXPIRED' }); } } next(); } /** * Middleware to attach subscription info to request * Must be placed after verifyToken middleware */ export function attachSubscription(pool) { return async (req, res, next) => { if (!req.user) { return next(); } try { const result = await pool.query( 'SELECT * FROM subscriptions WHERE user_id = $1', [req.user.id] ); if (result.rows.length > 0) { req.subscription = result.rows[0]; } } catch (error) { console.error('Error fetching subscription:', error); } next(); }; } /** * Middleware to check if user is on free tier or has active subscription */ export function requireFreeOrSubscription(req, res, next) { // Free tier is always allowed if (req.user && req.user.tier === 'free') { return next(); } // Otherwise, require active subscription return requireActiveSubscription(req, res, next); } export default { requireActiveSubscription, attachSubscription, requireFreeOrSubscription };