3.1 KiB
Routing & Tags
The Router
app.use(Router) is a per-app Router (from @welshman/router) wired to this app's data. It is the single source for relay selection — there is no global Router.get() anymore; one router belongs to each app.
The app wires it up with:
- user pubkey from
app.user - read/write relays per pubkey from
RelayLists - relay quality from
RelayStats - default / indexer / search relays from
AppConfig
Relay-selection scenes
The router exposes composable "scenes" (inherited from the base router) that resolve to a relay set:
const router = app.use(Router)
router.FromUser() // the current user's relays
router.FromPubkey(pubkey) // another user's relays
router.FromRelays(urls) // explicit relays
router.Event(event) // relays where an event is likely found
router.EventRoots(event) // relays for an event's thread roots
router.Search() // search relays
Scenes are chainable and terminate in getUrls() / getUrl():
import {addMinimalFallbacks} from "@welshman/router"
const relays = router.FromUser().policy(addMinimalFallbacks).limit(8).getUrls()
const hint = router.Event(event).getUrl()
Relay quality
app.use(RelayStats) collects per-relay connection statistics (open/close/publish/request/event counts, timestamps, recent errors) and exposes a quality score the router uses to rank relays.
const stats = app.use(RelayStats)
stats.one(url) // Readable<Maybe<RelayStatsItem>>
stats.getQuality(url) // number in [0, 1] — 0 for blocked/error-prone relays
Stats are populated automatically by the appPolicyRelayStats default policy. getQuality returns 0 for non-relay URLs, relays in the user's blocked list, or error-prone relays, and higher scores for relays that are connected or have been seen before.
Tag utilities
app.use(Tags) builds nostr tags using the router for relay hints, Profiles for display names, and the current user to avoid self-tagging.
const tags = app.use(Tags)
tags.tagPubkey(pubkey) // ["p", pubkey, hint, name]
tags.tagEvent(event, url?, mark?) // [["e", id, hint, mark, pubkey], ("a", ...)? ]
tags.tagEventPubkeys(event) // de-duped p-tags (author + mentions, minus self)
tags.tagZapSplit(pubkey, split?) // ["zap", pubkey, hint, split]
tags.tagEventForReply(event, relay?) // reply tag set (root/reply e/a + p tags)
tags.tagEventForComment(event, relay?) // NIP-22 comment tags (K/E/A/I/P + k/p/e)
tags.tagEventForQuote(event, relay?) // ["q", id, hint, pubkey]
tags.tagEventForReaction(event, relay?) // p, ["k", kind], ["e", id, hint], ("a", ...)?
A typical reply:
import {makeEvent, NOTE} from "@welshman/util"
const replyTags = app.use(Tags).tagEventForReply(parentEvent)
app.use(Thunks).publishToOutbox({
event: makeEvent(NOTE, {content: "well said", tags: replyTags}),
})