Skip to content

Feed ​

The feed system provides a powerful way to compose and load complex Nostr queries. It supports user scopes, web of trust filtering, DVM integration, and thread construction.

Controller ​

The controller.load() function is the main interface for fetching events from a feed. It handles all the complexity of relay selection, subscription management, and event filtering.

typescript
import {createFeedController} from '@welshman/app'
import {scopeFeed, wotFeed} from '@welshman/feeds'

const controller = createFeedController({
  // Define what to load
  feed: scopeFeed("follows"),

  // Optional configurations
  closeOnEose: true,     // Close after getting all events
  onEvent: event => {},  // Handle events as they arrive
  onEose: url => {},     // Handle EOSE from each relay
  onComplete: () => {},  // Called when all relays complete
})

// Load first 20 events
const events = await controller.load(20)

// Load next 20 events
const moreEvents = await controller.load(20)

The controller maintains its state between loads, so subsequent calls will:

  • Continue from last position
  • Use appropriate time windows
  • Skip already seen events
  • Maintain relay connections

Paginated Feed ​

typescript
import {intersectionFeed, scopeFeed, wotFeed} from '@welshman/feeds'

const HomeFeed = {
  let events = []
  let loading = false
  let controller

  onMount(() => {
    // Create feed for home timeline
    controller = createFeedController({
      feed: intersectionFeed(
        // Content from follows
        scopeFeed("follows"),
        // Filtered by web of trust
        wotFeed({min: 0.1})
      ),

      // Handle events as they arrive
      onEvent: event => {
        events = [...events, event]
      },

      // Track loading state
      onComplete: () => {
        loading = false
      }
    })

    // Initial load
    loadMore()
  })

  const loadMore = async () => {
    if (loading) return
    loading = true

    // Load next batch
    await controller.load(20)
  }
}

Key points about controller.load():

  • Takes a limit parameter for batch size
  • Returns a promise of loaded events
  • Can be called repeatedly for pagination
  • Handles subscription lifecycle
  • Manages relay connections
  • Deduplicates events

The controller is stateful and maintains:

  • Current time window
  • Seen events
  • Active subscriptions
  • Relay connections

This makes it ideal for implementing infinite scroll feeds, thread loading, and other paginated content scenarios.