diff options
| author | Adam Soltys <[email protected]> | 2026-08-18 12:16:36 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-18 12:16:36 -0700 |
| commit | 1d21e3b9546496a4eccf8ec9ec45934999e07fd8 (patch) | |
| tree | f1d556b6964d58eac18d2350ff0ec4f7d4306d2e /src/nostr.js | |
| parent | 1731b035ebdb4e09b2578300345ac2c3480b5735 (diff) | |
| download | coinosv3-1d21e3b9546496a4eccf8ec9ec45934999e07fd8.tar.gz coinosv3-1d21e3b9546496a4eccf8ec9ec45934999e07fd8.zip | |
Delivery moves at the speed of the best relay, not the worst: publish resolves on the first acceptance, DMs stop idling on the peer's inbox lookup, and the dimming departs — a sent message simply appears
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012u4oe1KPx9faCsDBLfZYqi
Diffstat (limited to 'src/nostr.js')
| -rw-r--r-- | src/nostr.js | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/src/nostr.js b/src/nostr.js index 2166880..753d4a8 100644 --- a/src/nostr.js +++ b/src/nostr.js @@ -83,20 +83,27 @@ export async function queryOn(relays, filter, maxWait = 1500) { export async function publishOn(relays, evt) { try { const live = liveRelays(relays); - const results = await Promise.allSettled(pool.publish(live, evt)); // A rejected publish is a relay refusing the event (policy, rate limit, // ban). Swallowing that silently once hid a relay-side rejection behind // what looked like a client bug — always say which relay refused and why. - results.forEach((r, i) => { - if (r.status === 'rejected') { - const msg = r.reason?.message || String(r.reason || ''); + const pubs = pool.publish(live, evt).map((p, i) => + Promise.resolve(p).then(() => true, (reason) => { + const msg = reason?.message || String(reason || ''); // "relay connection errored/closed" means the socket never came up — // that's a sick relay, not a rejected event. if (/connect|closed|errored|timeout|network/i.test(msg)) markRelaySick(live[i], msg); else console.warn(`nostr: publish kind ${evt.kind} refused by ${live[i]}:`, msg); - } + return false; + })); + // The first acceptance IS delivery — one durable copy is enough, and + // waiting on allSettled meant every send moved at the pace of the + // slowest relay in the set. The stragglers keep settling in the + // background so the sick-list still learns from them. + return await new Promise((resolve) => { + let left = pubs.length; + if (!left) return resolve(false); + for (const p of pubs) p.then((ok) => { if (ok) resolve(true); else if (!--left) resolve(false); }); }); - return results.some((r) => r.status === 'fulfilled'); } catch { return false; } } |
