aboutsummaryrefslogtreecommitdiffstats
path: root/src/nostr.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-01 17:49:50 -0700
committerAdam Soltys <[email protected]>2026-08-01 17:49:50 -0700
commit4ca5dd0afa7848d100f0b99be7b53f5dcb2fd061 (patch)
treef174344ded20ad4cef4315bed5c5f8f9d3bb9708 /src/nostr.js
parenta64611377c646415bc0c21a8bb96b9a079c4ce2b (diff)
downloadcoinosv3-4ca5dd0afa7848d100f0b99be7b53f5dcb2fd061.tar.gz
coinosv3-4ca5dd0afa7848d100f0b99be7b53f5dcb2fd061.zip
Never let a losing device's error shout over a paid zap
Loose leader election for pay_invoice across a user's open tabs: before handling, defer a beat and stay silent if any reply for the request already exists on the relays; and before sending an ERROR reply, re-check — a device that lost the race (mid-init, stale state) was replying 'superseded' after another device's success, and clients trusted the later error, marking paid zaps as failed. Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src/nostr.js')
-rw-r--r--src/nostr.js3
1 files changed, 3 insertions, 0 deletions
diff --git a/src/nostr.js b/src/nostr.js
index 2c458af..37bd62d 100644
--- a/src/nostr.js
+++ b/src/nostr.js
@@ -40,6 +40,9 @@ export function subscribeOn(relays, filter, onEvent, extra = {}) {
return () => { try { sub.close(); } catch {} };
} catch { return () => {}; }
}
+export async function queryOn(relays, filter, maxWait = 1500) {
+ try { return await pool.querySync(relays, filter, { maxWait }); } catch { return []; }
+}
export async function publishOn(relays, evt) {
try {
const results = await Promise.allSettled(pool.publish(relays, evt));