From d147e04d1b52f1359507a6f9d88e0227cf6bb250 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 22 Jan 2026 18:48:07 -0800 Subject: read payments from archive --- lib/db.ts | 37 +++++++++++++++++++++++++++++++++++++ lib/utils.ts | 10 +++++----- routes/payments.ts | 23 ++++++++++++++++++----- routes/users.ts | 12 ++++++------ 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/lib/db.ts b/lib/db.ts index 56921adb..12e89757 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -152,6 +152,43 @@ export const sa = (k, v) => { archive.set(k, JSON.stringify(v)); }; +// Get with fallback to archive +export const gf = async (k) => { + let v = await db.get(k); + if (v === null) v = await archive.get(k); + try { + return JSON.parse(v); + } catch (e) { + return v; + } +}; + +// lRange with fallback to archive for missing items +export const lRangeWithArchive = async (k, start, end) => { + const items = await db.lRange(k, start, end); + return items || []; +}; + +// Get payment/invoice with archive fallback - for individual lookups +export const getWithArchive = async (prefix, id) => { + let v = await db.get(`${prefix}:${id}`); + if (v === null) v = await archive.get(`${prefix}:${id}`); + if (v === null) return null; + try { + const parsed = JSON.parse(v); + // If it's a reference to another key, follow it + if (typeof parsed === "string") { + let ref = await db.get(`${prefix}:${parsed}`); + if (ref === null) ref = await archive.get(`${prefix}:${parsed}`); + if (ref === null) return null; + return JSON.parse(ref); + } + return parsed; + } catch (e) { + return v; + } +}; + const retries = {}; export const t = async (k, f) => { try { diff --git a/lib/utils.ts b/lib/utils.ts index 018dc92e..add09782 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,5 +1,5 @@ import config from "$config"; -import { g } from "$lib/db"; +import { g, gf } from "$lib/db"; import locales from "$lib/locales/index"; const { URL } = process.env; @@ -57,15 +57,15 @@ export const getUser = async (username, fields = undefined) => { }; export const getInvoice = async (hash) => { - let iid = await g(`invoice:${hash}`); + let iid = await gf(`invoice:${hash}`); if (iid?.id) iid = iid.id; else if (iid?.hash) iid = iid.hash; - return await g(`invoice:${iid}`); + return await gf(`invoice:${iid}`); }; export const getPayment = async (id) => { - let p = await g(`payment:${id}`); - if (typeof p === "string") p = await g(`payment:${p}`); + let p = await gf(`payment:${id}`); + if (typeof p === "string") p = await gf(`payment:${p}`); return p; }; diff --git a/routes/payments.ts b/routes/payments.ts index d4d83bd2..a61c4c3c 100644 --- a/routes/payments.ts +++ b/routes/payments.ts @@ -1,7 +1,7 @@ import config from "$config"; import api from "$lib/api"; import { requirePin } from "$lib/auth"; -import { db, g, s } from "$lib/db"; +import { archive, db, g, gf, s } from "$lib/db"; import { generate } from "$lib/invoices"; import { replay } from "$lib/lightning"; import ln from "$lib/ln"; @@ -112,15 +112,28 @@ export default { offset = Number.parseInt(offset) || 0; const range = !limit || received || start || end ? -1 : limit - 1; - let payments = (await db.lRange(`${aid || id}:payments`, 0, range)) || []; + const listKey = `${aid || id}:payments`; + let payments = (await db.lRange(listKey, 0, range)) || []; + + if (range === -1) { + const archived = (await archive.lRange(listKey, 0, -1)) || []; + payments = [...new Set([...payments, ...archived])]; + } else if (limit) { + const needed = Math.max(0, limit + offset - payments.length); + if (needed > 0) { + const archived = + (await archive.lRange(listKey, 0, limit + offset - 1)) || []; + payments = [...new Set([...payments, ...archived])]; + } + } payments = ( await Promise.all( payments.map(async (pid) => { - const p = await g(`payment:${pid}`); + const p = await gf(`payment:${pid}`); if (!p) { warn("user", id, "missing payment", pid); - await db.lRem(`${aid || id}:payments`, 0, pid); + await db.lRem(listKey, 0, pid); return p; } if (received && p.amount < 0) return; @@ -237,7 +250,7 @@ export default { if (typeof amount === "undefined" || amount === null) return bail(res, "fund not found"); let payments = (await db.lRange(`fund:${id}:payments`, 0, -1)) || []; - payments = await Promise.all(payments.map((hash) => g(`payment:${hash}`))); + payments = await Promise.all(payments.map((hash) => gf(`payment:${hash}`))); await Promise.all( payments.map(async (p: any) => (p.user = await getUser(p.uid, fields))), diff --git a/routes/users.ts b/routes/users.ts index 91928503..8cb24870 100644 --- a/routes/users.ts +++ b/routes/users.ts @@ -2,7 +2,7 @@ import { createReadStream } from "node:fs"; import { appendFile, unlink, writeFile } from "node:fs/promises"; import config from "$config"; import { requirePin } from "$lib/auth"; -import { db, g, ga, s } from "$lib/db"; +import { db, g, ga, gf, s } from "$lib/db"; import { err, l, warn } from "$lib/logging"; import { mail, templates } from "$lib/mail"; import { getNostrUser, getProfile, serverPubkey2 } from "$lib/nostr"; @@ -109,7 +109,7 @@ export default { let total = 0; for (const pid of payments) { - const p = await g(`payment:${pid}`); + const p = await gf(`payment:${pid}`); if (!p) continue; total += p.amount; if (p.amount < 0) @@ -571,7 +571,7 @@ export default { for (const { ref } of ( await Promise.all( - payments.reverse().map(async (id) => await g(`payment:${id}`)), + payments.reverse().map(async (id) => await gf(`payment:${id}`)), ) ).filter((p) => p && p.type === PaymentType.internal && p.ref)) { if (ref === id) continue; @@ -950,8 +950,8 @@ export default { const payments = await Promise.all( pids.map(async (pid) => { - const p = await g(`payment:${pid}`); - p.user = await g(`user:${p.uid}`); + const p = await gf(`payment:${pid}`); + if (p) p.user = await g(`user:${p.uid}`); return p; }), ); @@ -976,7 +976,7 @@ export default { const pids = await db.lRange(`${a.pubkey}:payments`, 0, -1); let payments = await Promise.all( - pids.map((pid) => g(`payment:${pid}`)), + pids.map((pid) => gf(`payment:${pid}`)), ); payments = payments.filter((p) => p); a.spent = payments.reduce( -- cgit v1.2.3