UNPKG

lightning-auth-and-payment

Version:

Lightning Network authentication and payment processing library for modern web applications

194 lines 7.09 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useLightningPayment = useLightningPayment; const react_1 = require("react"); function useLightningPayment(options = {}) { const { onPaymentSuccess, onPaymentError, onPaymentExpired, pollInterval = 2000, useSSE = true, } = options; const [invoice, setInvoice] = (0, react_1.useState)(null); const [isLoading, setIsLoading] = (0, react_1.useState)(false); const [error, setError] = (0, react_1.useState)(null); const [paymentState, setPaymentState] = (0, react_1.useState)('idle'); const [timeLeft, setTimeLeft] = (0, react_1.useState)(0); const [copied, setCopied] = (0, react_1.useState)(false); const pollingRef = (0, react_1.useRef)(null); const sseRef = (0, react_1.useRef)(null); const timeLeftRef = (0, react_1.useRef)(null); const createInvoice = (0, react_1.useCallback)(async (amount, description) => { try { setIsLoading(true); setError(null); setPaymentState('idle'); const response = await fetch('/api/payment/create-invoice', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ amount, description, }), }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || 'Failed to create invoice'); } setInvoice(data); setPaymentState('waiting'); // Calculate time left const expiresAt = new Date(data.expiresAt).getTime(); const now = Date.now(); const timeLeftMs = expiresAt - now; if (timeLeftMs > 0) { setTimeLeft(Math.floor(timeLeftMs / 1000)); // Start countdown timeLeftRef.current = setInterval(() => { setTimeLeft(prev => { if (prev <= 1) { setPaymentState('expired'); onPaymentExpired?.(); return 0; } return prev - 1; }); }, 1000); } else { setPaymentState('expired'); onPaymentExpired?.(); } // Start monitoring payment if (useSSE && data.invoiceId) { startSSEMonitoring(data.invoiceId); } else { startPolling(data.invoiceId); } } catch (err) { const errorMessage = err instanceof Error ? err.message : 'Payment failed'; setError(errorMessage); onPaymentError?.(errorMessage); } finally { setIsLoading(false); } }, [onPaymentSuccess, onPaymentError, onPaymentExpired, useSSE]); const startSSEMonitoring = (0, react_1.useCallback)((invoiceId) => { if (sseRef.current) { sseRef.current.close(); } const eventSource = new EventSource(`/api/invoices/${invoiceId}/events`); sseRef.current = eventSource; eventSource.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.status === 'settled') { setPaymentState('settled'); onPaymentSuccess?.(invoiceId); eventSource.close(); } else if (data.status === 'expired') { setPaymentState('expired'); onPaymentExpired?.(); eventSource.close(); } } catch (err) { console.error('SSE parsing error:', err); } }; eventSource.onerror = () => { console.error('SSE connection error'); eventSource.close(); // Fallback to polling startPolling(invoiceId); }; }, [onPaymentSuccess, onPaymentExpired]); const startPolling = (0, react_1.useCallback)((invoiceId) => { if (pollingRef.current) { clearInterval(pollingRef.current); } pollingRef.current = setInterval(async () => { try { const response = await fetch(`/api/payment/status?id=${invoiceId}`); const data = await response.json(); if (data.status === 'settled') { setPaymentState('settled'); onPaymentSuccess?.(invoiceId); if (pollingRef.current) { clearInterval(pollingRef.current); pollingRef.current = null; } } else if (data.status === 'expired') { setPaymentState('expired'); onPaymentExpired?.(); if (pollingRef.current) { clearInterval(pollingRef.current); pollingRef.current = null; } } } catch (err) { console.error('Polling error:', err); } }, pollInterval); }, [onPaymentSuccess, onPaymentExpired, pollInterval]); const cancelPayment = (0, react_1.useCallback)(() => { setInvoice(null); setPaymentState('idle'); setError(null); setTimeLeft(0); setCopied(false); if (pollingRef.current) { clearInterval(pollingRef.current); pollingRef.current = null; } if (sseRef.current) { sseRef.current.close(); sseRef.current = null; } if (timeLeftRef.current) { clearInterval(timeLeftRef.current); timeLeftRef.current = null; } }, []); const copyBolt11 = (0, react_1.useCallback)(async () => { if (!invoice?.bolt11) return; try { await navigator.clipboard.writeText(invoice.bolt11); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch (err) { console.error('Failed to copy BOLT11:', err); } }, [invoice?.bolt11]); // Cleanup on unmount (0, react_1.useEffect)(() => { return () => { if (pollingRef.current) { clearInterval(pollingRef.current); } if (sseRef.current) { sseRef.current.close(); } if (timeLeftRef.current) { clearInterval(timeLeftRef.current); } }; }, []); return { invoice, isLoading, error, paymentState, timeLeft, createInvoice, cancelPayment, copyBolt11, copied, }; } //# sourceMappingURL=use-lightning-payment.js.map