fix(lnbits): normalize invoice response (fallback to bolt11) and update payment status check; chore: add .gitignore

This commit is contained in:
Noderunners
2025-11-10 20:47:58 +01:00
parent bb3b5604a1
commit 4afe3f6d3e
2 changed files with 105 additions and 20 deletions

64
.gitignore vendored Normal file
View File

@@ -0,0 +1,64 @@
# Dependencies
node_modules/
# Production builds
dist/
dist-ssr/
build/
# Vite and tooling caches
.vite/
.esbuild/
.rollup.cache/
.parcel-cache/
.turbo/
# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Environment files
.env
.env.local
.env.*.local
.env.production.local
.env.development.local
.env.test.local
!.env.example
# Coverage
coverage/
# TypeScript build info
*.tsbuildinfo
# Editor directories and files
.vscode/
.idea/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*~
# OS metadata
.DS_Store
Thumbs.db
# Misc secrets/keys (if present)
*.pem
*.key
*.crt
*.p12
*.pfx
# Package tarballs
*.tgz

View File

@@ -8,6 +8,7 @@ const api = axios.create({
headers: { headers: {
'X-Api-Key': API_KEY, 'X-Api-Key': API_KEY,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
Accept: 'application/json',
}, },
}); });
@@ -62,16 +63,26 @@ export const lnbitsService = {
extra = {}, extra = {},
}: CreateInvoiceParams): Promise<Invoice> { }: CreateInvoiceParams): Promise<Invoice> {
try { try {
const response = await api.post('/api/v1/payments', { // Build a V1-safe payload: only include known/supported fields when defined
const payload: Record<string, any> = {
out: false, out: false,
amount, amount,
memo, memo,
unit, };
webhook, if (unit) payload.unit = unit;
internal, if (webhook) payload.webhook = webhook;
extra, if (typeof internal === 'boolean') payload.internal = internal;
}); if (extra && Object.keys(extra).length > 0) payload.extra = extra;
return response.data;
const response = await api.post('/api/v1/payments', payload);
const data = response.data ?? {};
// Normalize response to ensure payment_request is always populated for the UI
const normalized: Invoice = {
...data,
payment_request: data.payment_request || data.bolt11,
bolt11: data.bolt11 || data.payment_request,
};
return normalized;
} catch (error) { } catch (error) {
console.error('Error creating invoice:', error); console.error('Error creating invoice:', error);
throw error; throw error;
@@ -82,10 +93,13 @@ export const lnbitsService = {
async checkPayment(paymentHash: string): Promise<PaymentStatus> { async checkPayment(paymentHash: string): Promise<PaymentStatus> {
try { try {
const response = await api.get(`/api/v1/payments/${paymentHash}`); const response = await api.get(`/api/v1/payments/${paymentHash}`);
const data = response.data || {};
// Normalize potential V1 shapes
const paid: boolean = (data.paid === true) || (data.status === 'paid') || (data.settled === true);
return { return {
paid: response.data.paid, paid,
preimage: response.data.preimage, preimage: data.preimage,
details: response.data.details, details: data.details,
}; };
} catch (error) { } catch (error) {
console.error('Error checking payment:', error); console.error('Error checking payment:', error);
@@ -150,17 +164,24 @@ export const lnbitsService = {
// Long poll payment status // Long poll payment status
async longPollPayment(paymentHash: string, timeout = 60000): Promise<boolean> { async longPollPayment(paymentHash: string, timeout = 60000): Promise<boolean> {
// Fallback to authenticated polling against V1 status endpoint to ensure compatibility
const start = Date.now();
const pollIntervalMs = 2000;
while (Date.now() - start < timeout) {
try { try {
const response = await api.get(`/public/v1/payment/${paymentHash}`, { const status = await this.checkPayment(paymentHash);
timeout, if (status.paid) return true;
});
return response.data.paid;
} catch (error) { } catch (error) {
if (axios.isAxiosError(error) && error.code === 'ECONNABORTED') { // If transient error, keep polling until timeout
return false; // Timeout reached if (axios.isAxiosError(error) && (error.response?.status ?? 0) >= 500) {
} // continue
} else {
console.error('Error polling payment:', error); console.error('Error polling payment:', error);
throw error; throw error;
} }
}
await new Promise((r) => setTimeout(r, pollIntervalMs));
}
return false;
}, },
}; };