From 290acb73beff82762572d6eb69c6297bf7d88af7 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 18 Jun 2026 07:37:04 -0700 Subject: invoices: don't re-list an invoice id on update (dedupe :invoices) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit generate() unconditionally lPush'd the invoice id to `${aid}:invoices`, but it's also called from the update() handler (tip/webhook changes, and repeated bolt12 offer creation) re-using the existing id — so each update re-appended the same id and the user's :invoices accumulated duplicate entries, rendering the same offer/invoice multiple times. Only push when the id isn't already in the list (LPOS guard). Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/invoices.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/invoices.ts b/lib/invoices.ts index ad0b604e..79bf6f19 100644 --- a/lib/invoices.ts +++ b/lib/invoices.ts @@ -159,7 +159,13 @@ export const generate = async ({ invoice, user }) => { await s(`invoice:${hash}`, id); await s(`invoice:${id}`, invoice); - await db.lPush(`${aid}:invoices`, id); + // generate() is also called on UPDATE (re-using an existing invoice id, e.g. + // a tip/webhook change or a repeated bolt12 offer create), which must NOT + // re-append the id to the list. Only add it the first time — otherwise the + // user's :invoices accumulates duplicate entries and the same offer/invoice + // renders multiple times (see kaliyi's OCEAN offer, listed 2-6x). + if ((await db.lPos(`${aid}:invoices`, id)) === null) + await db.lPush(`${aid}:invoices`, id); if (request_id) { const request = await g(`request:${request_id}`); -- cgit v1.2.3