2.9 KiB
Feeds & Search
Feeds
app.use(Feeds) builds @welshman/feeds FeedControllers wired to this app — its router, web-of-trust graph, signer, and net context are all injected for you, so the controller can resolve scopes (Self, Follows, Network, Followers) and WoT ranges to real pubkeys and fetch through the app's repository and pool.
import {makeIntersectionFeed, makeScopeFeed, makeKindFeed, Scope} from "@welshman/feeds"
const controller = app.use(Feeds).makeFeedController({
feed: makeIntersectionFeed(
makeScopeFeed(Scope.Follows),
makeKindFeed(1),
),
onEvent: event => {
// render the event
},
})
await controller.load(50) // load a page of 50
MakeFeedControllerOptions
type MakeFeedControllerOptions = Partial<Omit<FeedControllerOptions, "feed">> & {feed: Feed}
You provide the feed (and typically onEvent); the app injects router, signer, context, and the scope/WoT-range resolvers. The scope resolvers map @welshman/feeds Scope values to pubkeys via Wot:
Scope.Self→ the current userScope.Follows→Wot.follows(pubkey)Scope.Network→Wot.network(pubkey)Scope.Followers→Wot.followers(pubkey)
WoT-range feeds resolve to the pubkeys whose trust score falls within a fraction of the maximum score in the graph.
Search
app.use(Searches) provides fuzzy (Fuse.js) search over profiles, topics, and relays. Profile search additionally triggers a NIP-50 network search and ranks results by web of trust.
import {get} from "svelte/store"
const searches = app.use(Searches)
// Each of these is a Readable<Search<...>> that stays up to date
const profileSearch = get(searches.profileSearch)
const topicSearch = get(searches.topicSearch)
const relaySearch = get(searches.relaySearch)
// A Search exposes both option objects and their values
profileSearch.searchValues("alice") // string[] — pubkeys; also fires a NIP-50 network search
profileSearch.searchOptions("alice") // PublishedProfile[]
profileSearch.getOption(pubkey) // PublishedProfile | undefined
Profile results are ranked by blending the Fuse score with the WoT score, so well-trusted matches surface first. An empty search term returns all options.
Building your own search
The generic createSearch helper underlies the built-in searches and is exported for custom indexes:
import {createSearch} from "@welshman/app"
const search = createSearch(items, {
getValue: item => item.id, // map an item to its identifier
fuseOptions: {keys: ["name", "about"], threshold: 0.3},
onSearch: term => {/* e.g. trigger a network fetch */},
sortFn: results => results, // optional custom result ordering
})
search.searchOptions("query") // T[]
search.searchValues("query") // V[]
search.getOption(value) // T | undefined