import { Router } from 'express'; import { paywallService } from '../services/paywall.js'; import { authenticate, requireCreator } from '../middleware/auth.js'; import { validateBody, createPaywallSchema, updatePaywallSchema } from '../utils/validation.js'; import { prisma } from '../config/database.js'; const router = Router(); // All routes require authentication router.use(authenticate); router.use(requireCreator); // Create paywall router.post('/', validateBody(createPaywallSchema), async (req, res, next) => { try { const paywall = await paywallService.create(req.user.id, req.body); res.status(201).json({ paywall }); } catch (error) { next(error); } }); // List paywalls router.get('/', async (req, res, next) => { try { const { status, page = 1, limit = 20 } = req.query; const result = await paywallService.listByCreator(req.user.id, { status, page: parseInt(page), limit: parseInt(limit), }); res.json(result); } catch (error) { next(error); } }); // Get paywall stats router.get('/stats', async (req, res, next) => { try { const stats = await paywallService.getStats(req.user.id); res.json(stats); } catch (error) { next(error); } }); // Fetch URL metadata router.post('/fetch-metadata', async (req, res, next) => { try { const { url } = req.body; if (!url) { return res.status(400).json({ error: 'URL is required' }); } const metadata = await paywallService.fetchUrlMetadata(url); res.json(metadata); } catch (error) { next(error); } }); // Get single paywall router.get('/:id', async (req, res, next) => { try { const paywall = await paywallService.findByIdAndCreator(req.params.id, req.user.id); // Get additional stats const [salesCount, totalRevenue] = await Promise.all([ prisma.sale.count({ where: { paywallId: paywall.id } }), prisma.sale.aggregate({ where: { paywallId: paywall.id }, _sum: { netSats: true }, }), ]); res.json({ paywall, stats: { salesCount, totalRevenue: totalRevenue._sum.netSats || 0, }, }); } catch (error) { next(error); } }); // Update paywall router.patch('/:id', validateBody(updatePaywallSchema), async (req, res, next) => { try { const paywall = await paywallService.update(req.user.id, req.params.id, req.body); res.json({ paywall }); } catch (error) { next(error); } }); // Archive paywall router.post('/:id/archive', async (req, res, next) => { try { const paywall = await paywallService.archive(req.user.id, req.params.id); res.json({ paywall }); } catch (error) { next(error); } }); // Activate paywall router.post('/:id/activate', async (req, res, next) => { try { await paywallService.findByIdAndCreator(req.params.id, req.user.id); const paywall = await prisma.paywall.update({ where: { id: req.params.id }, data: { status: 'ACTIVE' }, }); res.json({ paywall }); } catch (error) { next(error); } }); // Get paywall sales router.get('/:id/sales', async (req, res, next) => { try { await paywallService.findByIdAndCreator(req.params.id, req.user.id); const { page = 1, limit = 20 } = req.query; const skip = (parseInt(page) - 1) * parseInt(limit); const [sales, total] = await Promise.all([ prisma.sale.findMany({ where: { paywallId: req.params.id }, orderBy: { createdAt: 'desc' }, skip, take: parseInt(limit), }), prisma.sale.count({ where: { paywallId: req.params.id } }), ]); res.json({ sales, total, page: parseInt(page), totalPages: Math.ceil(total / parseInt(limit)), }); } catch (error) { next(error); } }); // Get embed code router.get('/:id/embed', async (req, res, next) => { try { const paywall = await paywallService.findByIdAndCreator(req.params.id, req.user.id); const baseUrl = process.env.FRONTEND_URL || 'http://localhost:5173'; const apiUrl = process.env.API_URL || 'http://localhost:3001'; const embedCode = { iframe: ``, button: ``, link: `${baseUrl}/p/${paywall.slug || paywall.id}`, }; res.json(embedCode); } catch (error) { next(error); } }); export default router;