Files
welshman/docs/app/feeds-and-search.md
T
hodlbod fe5c11b00f
tests / tests (push) Failing after 5m4s
rename client, update docs/skills
2026-06-18 19:31:14 +00:00

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 user
  • Scope.FollowsWot.follows(pubkey)
  • Scope.NetworkWot.network(pubkey)
  • Scope.FollowersWot.followers(pubkey)

WoT-range feeds resolve to the pubkeys whose trust score falls within a fraction of the maximum score in the graph.

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.

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