/** * Development-only routes. Not mounted in production. */ import { Router, type Request, type Response } from "express"; import { eq, or } from "drizzle-orm"; import { db, invoices, sessions, bootstrapJobs } from "@workspace/db"; import { lnbitsService } from "../lib/lnbits.js"; const router = Router(); /** * POST /dev/stub/pay/:paymentHash * Simulates an invoice being paid. * - In LNbits stub mode: marks the invoice as paid in the in-memory store. * - In real LNbits mode (FakeWallet): looks up the BOLT11 from DB and pays it via LNbits. * Searches the invoices, sessions, and bootstrapJobs tables. */ router.post("/dev/stub/pay/:paymentHash", async (req: Request, res: Response) => { const { paymentHash } = req.params as { paymentHash: string }; if (lnbitsService.stubMode) { lnbitsService.stubMarkPaid(paymentHash); res.json({ ok: true, paymentHash, mode: "stub" }); return; } // Real LNbits mode — look up the BOLT11 in all tables that store invoices let bolt11: string | null = null; // 1. Check job eval/work invoices table const jobInvoiceRows = await db.select().from(invoices).where(eq(invoices.paymentHash, paymentHash)).limit(1); if (jobInvoiceRows.length > 0) { bolt11 = jobInvoiceRows[0]!.paymentRequest; } // 2. Check sessions table (deposit + topup invoices) if (!bolt11) { const sessionRows = await db.select().from(sessions).where( or(eq(sessions.depositPaymentHash, paymentHash), eq(sessions.topupPaymentHash, paymentHash)) ).limit(1); if (sessionRows.length > 0) { const s = sessionRows[0]!; bolt11 = s.depositPaymentHash === paymentHash ? s.depositPaymentRequest : (s.topupPaymentRequest ?? null); } } // 3. Check bootstrapJobs table if (!bolt11) { const bjRows = await db.select().from(bootstrapJobs).where(eq(bootstrapJobs.paymentHash, paymentHash)).limit(1); if (bjRows.length > 0) { bolt11 = bjRows[0]!.paymentRequest; } } if (!bolt11) { res.status(404).json({ error: "Invoice not found for paymentHash" }); return; } try { await lnbitsService.payInvoice(bolt11); res.json({ ok: true, paymentHash, mode: "real" }); } catch (err) { res.status(500).json({ error: err instanceof Error ? err.message : "Failed to pay invoice" }); } }); export default router;