2 Commits
Author SHA1 Message Date
thePR0M3TH3ANandClaude Opus 4.8 47f2a9a865 [nostr] Fix spurious "failed" errors on unconfirmed list publishes across the board
Same class of bug as the subscription fix, applied everywhere an idempotent,
replaceable list is published with an optimistic UI: when no relay ACKs within the
10s window (slow/flaky relays), the event was still sent and almost always
persists (it shows up after a refresh), but assertAnyRelayAccepted threw -> the UI
showed a scary error / reverted, even though it worked.

- nostrPublish.js: add shared helpers relayPublishFailuresAreAllTimeouts() and
  assertAnyRelayAcceptedOrUnconfirmed() — the latter returns a summary flagged
  { unconfirmed: true } on all-timeout instead of throwing; explicit relay
  rejections (and pre-publish signer/encryption errors) still throw.
- Applied to the replaceable-list publishes: subscriptions (kind 30000, refactored
  to the shared helper), user mute/block list (10000), relay list (10002), DM
  relay hints (10050), hashtag preferences (30015).

Left as-is for now (higher-stakes, separate follow-up): the generic content
publish path (video/edit/delete/revert/rebroadcast) in publishHelpers/client.js —
same latent issue but the video outcome-describer needs careful handling.

Tests: tests/subscription-publish-timeout.test.mjs (8) now cover both the
classifier and assertAnyRelayAcceptedOrUnconfirmed (confirmed->summary,
all-timeout->soft, rejection->throws). hashtag-preferences suite green (14).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-01 15:20:58 -04:00
thePR0M3TH3ANandClaude Opus 4.8 a9271fd0e6 [subscriptions] Stop spurious "Failed to update subscriptions" on unconfirmed publish
Subscribe/unsubscribe intermittently showed an error but "worked after refresh":
the kind-30000 list event WAS sent and persisted, but when no relay ACKed it
within the 10s window, assertAnyRelayAccepted threw -> toggleChannel threw -> the
button handler reverted the optimistic UI and showed "Failed to update your
subscriptions." The event was on the relays the whole time (hence the refresh).

Fix: in publishSubscriptionList, distinguish an all-timeout (unconfirmed) result
from an explicit rejection. The list is an idempotent, replaceable event that was
already sent + locally cached, so an all-timeout is treated as a SOFT SUCCESS
(record the event id, no throw, reconciles on next load) instead of a hard error.
Only an explicit relay rejection (or a pre-publish signer/encryption error, thrown
earlier) still fails loudly. New exported classifier
subscriptionPublishFailuresAreAllTimeouts().

Tests: tests/subscription-publish-timeout.test.mjs (5 — all-timeout=soft,
any-rejection=hard, empty=hard, case-insensitive).

Note: assertAnyRelayAccepted is used the same way by userBlocks/app list publishes
— they likely have the same false-negative and could get the same treatment later.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-01 14:08:33 -04:00