Files
welshman/docs/feeds/controller.md
T
2026-06-10 14:12:47 -07:00

106 lines
3.0 KiB
Markdown

# Feed Controller
The `FeedController` class manages feed execution with advanced loading strategies including pagination, windowing, and set operations. It compiles feeds into requests and handles event streaming with deduplication.
## Types
```typescript
export type FeedControllerOptions = FeedCompilerOptions & {
feed: Feed
tracker?: Tracker
onEvent?: (event: TrustedEvent) => void
onExhausted?: () => void
useWindowing?: boolean
}
```
## FeedController Class
```typescript
export class FeedController {
compiler: FeedCompiler
constructor(readonly options: FeedControllerOptions)
// Get compiled request items (memoized)
getRequestItems(): Promise<RequestItem[] | undefined>
// Get loader function (memoized)
getLoader(): Promise<(limit: number) => Promise<void>>
// Load events with specified limit
load(limit: number): Promise<void>
// Get listener function (memoized)
getListener(): Promise<() => () => void>
// Listen for new events in the feed; returns an unsubscribe function
listen(): () => Promise<void>
}
```
## Loading Strategies
### Request-based Loading
For feeds that can be compiled to `RequestItem[]`:
- **Pagination**: Automatically handles `since`/`until` windowing
- **Deduplication**: Prevents duplicate events across multiple requests
- **Exhaustion tracking**: Detects when all requests are exhausted
### Set Operation Loading
For feeds requiring special handling:
#### Union Feeds
- Loads events from all sub-feeds in parallel
- Deduplicates events by ID across sub-feeds
- Signals exhaustion when all sub-feeds are exhausted
#### Intersection Feeds
- Loads events from all sub-feeds in parallel
- Only emits events that appear in ALL sub-feeds
- Uses count tracking to determine intersection
#### Difference Feeds
- Loads events from first feed (included) and remaining feeds (excluded)
- Emits events from first feed that don't appear in other feeds
- Maintains skip set for excluded events
## Windowing Strategy
When `useWindowing: true`:
- **Initial window**: Starts from recent events with estimated delta
- **Exponential backoff**: Increases window size when few events found
- **Timeline traversal**: Moves backward through time systematically
- **Performance optimization**: Gets recent events first
Windowing is best used when you don't trust relays to give you results ordered by `created_at` descending. Windowing should not be used when treating relays as algorithm feeds.
## Usage
```typescript
import { FeedController, makeAuthorFeed } from '@welshman/feeds'
const controller = new FeedController({
feed: makeAuthorFeed("pubkey1", "pubkey2"),
useWindowing: true,
onEvent: (event) => console.log('New event:', event.id),
onExhausted: () => console.log('No more events'),
getPubkeysForScope: (scope) => [...],
getPubkeysForWOTRange: (min, max) => [...]
})
// Load first batch of events
await controller.load(50)
// Load more events
await controller.load(50)
// Listen for new events
const unlisten = controller.listen()
// Unsubscribe from listener
unlisten()
```