Skip to content

Relay Management

How @snort/system manages relay connections, routing, and the outbox model.

ConnectionPool

The ConnectionPool manages all WebSocket connections to relays. Access it via System.pool.

Events

EventCallbackDescription
connected(address: string, wasReconnect: boolean) => voidRelay connected
connectFailed(address: string) => voidConnection failed
event(address: string, sub: string, e: TaggedNostrEvent) => voidEvent received
eose(address: string, sub: string) => voidEnd of stored events
disconnect(address: string, code: number) => voidRelay disconnected
auth(address: string, challenge: string, relay: string, cb) => voidAuth requested
notice(address: string, msg: string) => voidRelay notice

Methods

connect(address: string, options: RelaySettings, ephemeral: boolean): Promise<void>

Connect to a relay. If ephemeral is true, the connection will be closed after inactivity.

disconnect(address: string): void

Disconnect from a relay.

broadcast(ev: NostrEvent, cb?: (rsp: OkResponse) => void): Promise<OkResponse[]>

Broadcast an event to all connected write relays.

broadcastTo(address: string, ev: NostrEvent): Promise<OkResponse>

Broadcast to a specific relay.

Connection

Each relay connection is represented by a Connection instance.

Properties

PropertyTypeDescription
addressstringRelay WebSocket URL
settingsRelaySettingsRead/write settings
infoRelayInfoDocument | undefinedNIP-11 relay info
isOpenbooleanWhether WebSocket is open
isConnectingbooleanWhether currently connecting
isDownbooleanWhether connection has failed
ephemeralbooleanWhether this is a temporary connection
ActiveRequestsMap<string, ReqCommand>Currently active subscriptions
AuthedbooleanWhether NIP-42 auth completed
AwaitingAuthMap<string, boolean>Subscriptions awaiting auth

RelaySettings

typescript
interface RelaySettings {
  read: boolean   // Subscribe to events from this relay
  write: boolean  // Publish events to this relay
}

NIP-11 Relay Info

When a connection is established, the system automatically fetches the relay's NIP-11 document:

typescript
const conn = System.pool.getConnection('wss://relay.example.com')
console.log(conn.info?.name)
console.log(conn.info?.supported_nips)
console.log(conn.info?.limitation)

Outbox Model

When automaticOutboxModel is enabled (default), the system automatically:

  1. On query: Fetches kind 10002 relay lists for queried authors, then routes requests to their preferred relays
  2. On broadcast: Writes to inbox relays for all p-tagged users in addition to your own relays

OutboxModel

The OutboxModel class implements the RequestRouter interface:

typescript
// Access via System
if (System.requestRouter) {
  // Pick 2 relays per author for optimal delivery
  const split = System.requestRouter.forRequest(filter, 2)
}

RelayMetadataLoader

Loads and caches relay metadata (kind 10002) for pubkeys:

typescript
// Automatically used by OutboxModel
// But can be used directly:
await System.relayLoader.loadForPubkeys(['pubkey1', 'pubkey2'])

FullRelaySettings

typescript
interface FullRelaySettings {
  url: string
  settings: RelaySettings
}

Relay Tag Helpers

typescript
import { settingsToRelayTag, parseRelayTags, parseRelaysFromKind } from '@snort/system'

// Convert settings to relay tag
const tag = settingsToRelayTag({ url: 'wss://relay.example.com', settings: { read: true, write: true } })
// ["r", "wss://relay.example.com", "read", "write"]

// Parse relay tags from kind 10002 event
const relays = parseRelayTags(event.tags)

// Parse relays from kind 3 content
const relays = parseRelaysFromKind(event)

Best Practices

Choosing Relays

typescript
// Connect to a mix of relays
await System.ConnectToRelay('wss://relay.snort.social', { read: true, write: true })
await System.ConnectToRelay('wss://nos.lol', { read: true, write: false })
await System.ConnectToRelay('wss://relay.damus.io', { read: true, write: false })

Outbox Model Configuration

typescript
// Enable outbox model (default)
const System = new NostrSystem({ automaticOutboxModel: true })

// Customize relay pick count per request
const rb = new RequestBuilder('feed')
  .withOptions({ outboxPickN: 3 }) // Pick 3 relays per author
  .withFilter().authors(['pubkey1', 'pubkey2']).kinds([1])

Monitoring Connections

typescript
System.pool.on('connected', (addr, wasReconnect) => {
  console.log(`Connected to ${addr}${wasReconnect ? ' (reconnect)' : ''}`)
})

System.pool.on('disconnect', (addr, code) => {
  console.log(`Disconnected from ${addr} (code: ${code})`)
})

System.pool.on('notice', (addr, msg) => {
  console.warn(`Notice from ${addr}: ${msg}`)
})