diff --git a/js/nostr.js b/js/nostr.js index 1aa43fd5..f8750e1d 100644 --- a/js/nostr.js +++ b/js/nostr.js @@ -1139,23 +1139,46 @@ function publishEventToRelay(pool, url, event) { const pub = pool.publish([url], event); if (pub && typeof pub.on === "function") { - pub.on("ok", () => { + const registerHandler = (eventName, handler) => { + try { + pub.on(eventName, handler); + return true; + } catch (error) { + if (isDevMode) { + console.warn( + `[nostr] Relay publish handle rejected ${eventName} listener:`, + error + ); + } + return false; + } + }; + + const handleSuccess = () => { clearTimeout(timeoutId); finalize(true); - }); - pub.on("seen", () => { - clearTimeout(timeoutId); - finalize(true); - }); - pub.on("failed", (reason) => { + }; + + const handleFailure = (reason) => { clearTimeout(timeoutId); const err = reason instanceof Error ? reason : new Error(String(reason || "publish failed")); finalize(false, err); - }); - return; + }; + + let handlerRegistered = false; + handlerRegistered = + registerHandler("ok", handleSuccess) || handlerRegistered; + handlerRegistered = + registerHandler("seen", handleSuccess) || handlerRegistered; + handlerRegistered = + registerHandler("failed", handleFailure) || handlerRegistered; + + if (handlerRegistered) { + return; + } } if (pub && typeof pub.then === "function") { diff --git a/tests/watch-history.test.mjs b/tests/watch-history.test.mjs index fb365ee3..7198d55f 100644 --- a/tests/watch-history.test.mjs +++ b/tests/watch-history.test.mjs @@ -507,6 +507,43 @@ assert.deepEqual( "republish scheduler should receive the remaining items" ); +const NO_SEEN_ACTOR = `${ACTOR}-no-seen`; +const { + client: noSeenClient, + publishedEvents: noSeenPublishedEvents, +} = createPublishingClient(NO_SEEN_ACTOR); + +noSeenClient.pool.publish = (_urls, event) => { + noSeenPublishedEvents.push(event); + return { + on(eventName, handler) { + if (eventName === "seen") { + throw new TypeError("seen unsupported"); + } + if (eventName === "ok") { + setTimeout(handler, 0); + } else if (eventName === "failed") { + // Never invoke failed handlers in this mock; they should remain idle. + } + }, + }; +}; + +const noSeenResult = await noSeenClient.publishWatchHistorySnapshot( + NO_SEEN_ACTOR, + [{ type: "e", value: "no-seen-pointer", relay: null }] +); + +assert.equal( + noSeenResult.ok, + true, + "publish should succeed when relay handle rejects seen handlers" +); +assert( + noSeenResult.events.length > 0, + "publish should still return the emitted events when seen is unsupported" +); + delete globalThis.window.nostr; if (!globalThis.window.NostrTools.nip04) {