publishEventToRelay expected the old nostr-tools publish handle (.on/.then), but
nostr-tools 2.17 SimplePool.publish(relays, event) returns an ARRAY of per-relay
promises. The array has neither .on nor .then, so the code (a) fell through to
the "optimistic success" path (publishes were never truly confirmed) and (b)
never attached a .catch to the inner promise — so every relay that rejected
("blocked", "auth-required", "publish timed out", websocket error, …) leaked an
unhandled promise rejection. With a large/flaky relay list (e.g. a 35-relay
account hitting many paid/restricted relays) that floods the event loop and can
freeze the tab — observed when republishing the relay list and when publishing a
video.
Fix: detect the array return and Promise.allSettled it — any fulfilled = success,
otherwise a failure result; every rejection is consumed. Confirmed publishes now
resolve from real acks instead of the optimistic fallback.
New tests assert a rejecting array-promise becomes a failure result with NO
unhandled rejection leak, a fulfilling one succeeds, and an all-rejecting publish
still resolves. Mutation-verified; existing publish tests pass under the suite.
Co-Authored-By: Claude Opus 4.8 <[email protected]>