From 37989576d91d21b4f727a67470eef9e07e85dd07 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sat, 1 Aug 2026 12:30:57 -0700 Subject: Pass a single filter to subscribeMany — arrays are rejected by relays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nostr-tools ≥2.23 changed subscribeMany to take one filter object; the old array form now serializes as ["REQ",id,[{...}]], which every relay answers with CLOSED "provided filter is not an object". That killed the NWC request subscription (the Amethyst forever-spinner), the device-sync live subscription, and the push notifier's relay watch — all silently. Co-Authored-By: Claude Fable 5 --- nwcpush/server.js | 6 ++++-- src/nostr.js | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/nwcpush/server.js b/nwcpush/server.js index feca109..a2164d6 100644 --- a/nwcpush/server.js +++ b/nwcpush/server.js @@ -79,8 +79,10 @@ function resubscribe() { lastResub = Date.now(); sub = pool.subscribeMany( RELAYS, - // only live traffic: a replayed old request must not wake devices - [{ kinds: [REQ_KIND], '#p': pks, since: Math.floor(Date.now() / 1000) }], + // only live traffic: a replayed old request must not wake devices. + // NOTE: nostr-tools ≥2.23 wants a single filter object, NOT an array — + // an array serializes as an invalid REQ that relays reject with CLOSED. + { kinds: [REQ_KIND], '#p': pks, since: Math.floor(Date.now() / 1000) }, { onevent: (ev) => { const target = ev.tags?.find((t) => t[0] === 'p')?.[1]; diff --git a/src/nostr.js b/src/nostr.js index 0b902e1..e1f1c14 100644 --- a/src/nostr.js +++ b/src/nostr.js @@ -29,7 +29,10 @@ const pool = new SimplePool(); // request lands somewhere the wallet isn't and it waits forever. export function subscribeOn(relays, filter, onEvent, extra = {}) { try { - const sub = pool.subscribeMany(relays, [filter], { onevent: onEvent, ...extra }); + // nostr-tools ≥2.23 takes a single filter object here; wrapping it in an + // array serializes as ["REQ",id,[{...}]] which every relay rejects with + // "provided filter is not an object" — and the subscription dies silently. + const sub = pool.subscribeMany(relays, filter, { onevent: onEvent, ...extra }); return () => { try { sub.close(); } catch {} }; } catch { return () => {}; } } @@ -247,7 +250,8 @@ export class NostrSync { // Live subscription; returns an unsubscribe function. subscribeEvents(filter, onEvent) { try { - const sub = pool.subscribeMany(this.relays, [filter], { onevent: onEvent }); + // single filter object — see subscribeOn for the array-wrapping trap + const sub = pool.subscribeMany(this.relays, filter, { onevent: onEvent }); return () => { try { sub.close(); } catch {} }; } catch { return () => {}; } } -- cgit v1.2.3