The Buzz relay authenticates via NIP-42 but does not send EndOfStoredEvents
after the second subscription. Waiting for EOSE caused a 15s timeout and
channel startup failure.
After auth, wait a short grace period (3s) for either EOSE or a rejection.
If neither arrives, the subscription was accepted — the relay simply doesn
not send EOSE, which is valid per NIP-01 (EOSE is optional for live-only
subscriptions).
Add ReactToMessage method that publishes a NIP-25 kind:7 reaction event
with content 👀, scoped to the same channel via the h tag and pointing at
the inbound message via the e tag. The undo function is a no-op since
NIP-25 does not define a standard way to remove a reaction.
This enables the BaseChannel auto-reaction pipeline: when a message
arrives on a Buzz channel, the bot reacts with 👀 before processing,
giving the Emperor visual confirmation that the message was received.
Calling relay.Auth() immediately after RelayConnect signed an auth event
with an empty challenge tag. go-nostr keeps the relay's challenge on an
unexported field populated by its reader goroutine when the AUTH envelope
arrives, so the value is not yet set at connect time, and relays reject
the resulting event.
Subscribe first and run the handshake only once the relay answers
"auth-required". That guarantees the challenge has been read: the CLOSED
envelope is processed after AUTH on the relay's single reader goroutine,
and receiving it over a channel establishes the happens-before edge that
makes the read safe.
A second rejection after authenticating is a permissions failure rather
than a mistimed handshake, so it fails instead of retrying. Both waits
are bounded by a 15s timeout, and relays that accept without auth still
work via EndOfStoredEvents.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implements a Buzz channel backed by a Nostr relay:
- kind:9 events scoped by "h" tag, "p" tags for mentions
- NIP-42 (kind:22242) auth before subscription
- optional threaded replies via "e" tag
- registered as config.ChannelBuzz with BuzzSettings