aboutsummaryrefslogtreecommitdiffstats
path: root/src/nostr.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-18 12:16:36 -0700
committerAdam Soltys <[email protected]>2026-08-18 12:16:36 -0700
commit1d21e3b9546496a4eccf8ec9ec45934999e07fd8 (patch)
treef1d556b6964d58eac18d2350ff0ec4f7d4306d2e /src/nostr.js
parent1731b035ebdb4e09b2578300345ac2c3480b5735 (diff)
downloadcoinosv3-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.js19
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; }
}