Files
welshman/packages/app/src/wot.ts
T
2025-11-25 14:19:11 -08:00

102 lines
3.2 KiB
TypeScript

import {derived, writable} from "svelte/store"
import {max, throttle, addToMapKey, inc, dec} from "@welshman/lib"
import {getListTags, getPubkeyTagValues} from "@welshman/util"
import {throttled, getter} from "@welshman/store"
import {pubkey} from "./session.js"
import {followLists, getFollowListsByPubkey, getFollowList} from "./follows.js"
import {muteLists, getMuteList} from "./mutes.js"
export const getFollows = (pubkey: string) => getPubkeyTagValues(getListTags(getFollowList(pubkey)))
export const getMutes = (pubkey: string) => getPubkeyTagValues(getListTags(getMuteList(pubkey)))
export const getNetwork = (pubkey: string) => {
const pubkeys = new Set(getFollows(pubkey))
const network = new Set<string>()
for (const follow of pubkeys) {
for (const tpk of getFollows(follow)) {
if (!pubkeys.has(tpk)) {
network.add(tpk)
}
}
}
return Array.from(network)
}
export const followersByPubkey = derived(throttled(1000, followLists), lists => {
const $followersByPubkey = new Map<string, Set<string>>()
for (const list of lists) {
for (const pubkey of getPubkeyTagValues(getListTags(list))) {
addToMapKey($followersByPubkey, pubkey, list.event.pubkey)
}
}
return $followersByPubkey
})
export const getFollowersByPubkey = getter(followersByPubkey)
export const mutersByPubkey = derived(throttled(1000, muteLists), lists => {
const $mutersByPubkey = new Map<string, Set<string>>()
for (const list of lists) {
for (const pubkey of getPubkeyTagValues(getListTags(list))) {
addToMapKey($mutersByPubkey, pubkey, list.event.pubkey)
}
}
return $mutersByPubkey
})
export const getMutersByPubkey = getter(mutersByPubkey)
export const getFollowers = (pubkey: string) => Array.from(getFollowersByPubkey().get(pubkey) || [])
export const getMuters = (pubkey: string) => Array.from(getMutersByPubkey().get(pubkey) || [])
export const getFollowsWhoFollow = (pubkey: string, target: string) =>
getFollows(pubkey).filter(other => getFollows(other).includes(target))
export const getFollowsWhoMute = (pubkey: string, target: string) =>
getFollows(pubkey).filter(other => getMutes(other).includes(target))
export const wotGraph = writable(new Map<string, number>())
export const getWotGraph = getter(wotGraph)
export const maxWot = derived(wotGraph, $g => max(Array.from($g.values())))
export const getMaxWot = getter(maxWot)
const buildGraph = throttle(1000, () => {
const $pubkey = pubkey.get()
const $graph = new Map<string, number>()
const $follows = $pubkey ? getFollows($pubkey) : getFollowListsByPubkey().keys()
for (const follow of $follows) {
for (const pubkey of getFollows(follow)) {
$graph.set(pubkey, inc($graph.get(pubkey)))
}
for (const pubkey of getMutes(follow)) {
$graph.set(pubkey, dec($graph.get(pubkey)))
}
}
wotGraph.set($graph)
})
pubkey.subscribe(buildGraph)
followLists.subscribe(buildGraph)
muteLists.subscribe(buildGraph)
export const getWotScore = (pubkey: string, target: string) => {
const follows = pubkey ? getFollowsWhoFollow(pubkey, target) : getFollowers(target)
const mutes = pubkey ? getFollowsWhoMute(pubkey, target) : getMuters(target)
return follows.length - mutes.length
}