lightning-auth-and-payment
Version:
Lightning Network authentication and payment processing library for modern web applications
194 lines • 7.09 kB
JavaScript
;
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