Add default feed loader to app

This commit is contained in:
Jon Staab
2024-10-09 09:48:08 -07:00
parent cabeba4533
commit 6e24f49384
9 changed files with 112 additions and 7 deletions
+2
View File
@@ -3639,6 +3639,8 @@
"version": "0.0.11",
"license": "MIT",
"dependencies": {
"@welshman/dvm": "~0.0.9",
"@welshman/feeds": "~0.0.19",
"@welshman/lib": "~0.0.19",
"@welshman/net": "~0.0.24",
"@welshman/signer": "~0.0.7",
+2
View File
@@ -32,6 +32,8 @@
},
"dependencies": {
"@welshman/lib": "~0.0.19",
"@welshman/feeds": "~0.0.19",
"@welshman/dvm": "~0.0.9",
"@welshman/net": "~0.0.24",
"@welshman/signer": "~0.0.7",
"@welshman/store": "~0.0.9",
+68
View File
@@ -0,0 +1,68 @@
import {ctx, now} from '@welshman/lib'
import {createEvent, getPubkeyTagValues} from '@welshman/util'
import {FeedLoader, Scope} from '@welshman/feeds'
import {makeDvmRequest} from '@welshman/dvm'
import {makeSecret, Nip01Signer} from '@welshman/signer'
import {pubkey, signer} from './session'
import {getFilterSelections} from './router'
import {wotGraph, maxWot, getFollows, getNetwork, getFollowers} from './wot'
import {load} from './core'
export const feedLoader = new FeedLoader({
request: async ({filters = [{}], relays = [], onEvent}) => {
if (relays.length > 0) {
await load({onEvent, filters, relays})
} else {
await Promise.all(
getFilterSelections(filters)
.map(opts => load({onEvent, ...opts}))
)
}
},
requestDVM: async ({kind, onEvent, ...request}) => {
const tags = [...request.tags || [], ["expiration", String(now() + 5)]]
const $signer = signer.get() || new Nip01Signer(makeSecret())
const event = await $signer.sign(createEvent(kind, {tags}))
const relays =
request.relays
? ctx.app.router.fromRelays(request.relays).getUrls()
: ctx.app.router.FromPubkeys(getPubkeyTagValues(tags)).getUrls()
const req = makeDvmRequest({event, relays})
await new Promise<void>(resolve => {
req.emitter.on("result", (url, event) => {
onEvent(event)
resolve()
})
})
},
getPubkeysForScope: (scope: string) => {
const $pubkey = pubkey.get()
if (!$pubkey) {
return []
}
switch (scope) {
case Scope.Self: return [$pubkey]
case Scope.Follows: return getFollows($pubkey)
case Scope.Network: return getNetwork($pubkey)
case Scope.Followers: return getFollowers($pubkey)
default: return []
}
},
getPubkeysForWOTRange: (min, max) => {
const pubkeys = []
const thresholdMin = maxWot.get() * min
const thresholdMax = maxWot.get() * max
for (const [tpk, score] of wotGraph.get().entries()) {
if (score >= thresholdMin && score <= thresholdMax) {
pubkeys.push(tpk)
}
}
return pubkeys
},
})
+4 -2
View File
@@ -108,5 +108,7 @@ export const deriveHandleForPubkey = (pubkey: string, request: Partial<Subscribe
}
)
export const displayHandle = (handle: Handle) =>
handle.nip05.startsWith("_@") ? last(handle.nip05.split("@")) : handle.nip05
export const displayNip05 = (nip05: string) =>
(nip05?.startsWith("_@") ? last(nip05.split("@")) : nip05)
export const displayHandle = (handle: Handle) => displayNip05(handle.nip05)
+1
View File
@@ -2,6 +2,7 @@ export * from './context'
export * from './core'
export * from './collection'
export * from './commands'
export * from './feeds'
export * from './freshness'
export * from './follows'
export * from './handles'
+19 -1
View File
@@ -1,6 +1,6 @@
import {throttle} from 'throttle-debounce'
import {derived, writable} from 'svelte/store'
import {addToMapKey, inc, dec} from '@welshman/lib'
import {max, addToMapKey, inc, dec} from '@welshman/lib'
import {getListTags, getPubkeyTagValues} from '@welshman/util'
import {throttled, withGetter} from '@welshman/store'
import {pubkey} from './session'
@@ -13,6 +13,22 @@ export const getFollows = (pubkey: string) =>
export const getMutes = (pubkey: string) =>
getPubkeyTagValues(getListTags(mutesByPubkey.get().get(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 = withGetter(
derived(
throttled(1000, follows),
@@ -61,6 +77,8 @@ export const getFollowsWhoMute = (pubkey: string, target: string) =>
export const wotGraph = withGetter(writable(new Map<string, number>()))
export const maxWot = withGetter(derived(wotGraph, $g => max(Array.from($g.values()))))
const buildGraph = throttle(1000, () => {
const $pubkey = pubkey.get()
const $graph = new Map<string, number>()
+3 -3
View File
@@ -1,4 +1,4 @@
import {inc, max, min, now} from '@welshman/lib'
import {inc, omitVals, max, min, now} from '@welshman/lib'
import type {TrustedEvent, Filter} from '@welshman/util'
import {EPOCH, trimFilters, guessFilterDelta} from '@welshman/util'
import type {Feed, RequestItem, FeedOptions} from './core'
@@ -98,7 +98,7 @@ export class FeedLoader {
let count = 0
await this.options.request({
await this.options.request(omitVals([undefined], {
relays,
filters: trimFilters(requestFilters),
onEvent: (event: TrustedEvent) => {
@@ -106,7 +106,7 @@ export class FeedLoader {
until = Math.min(until, event.created_at - 1)
onEvent?.(event)
},
})
}))
if (useWindowing) {
if (since === minSince) {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@welshman/lib",
"version": "0.0.19",
"version": "0.0.20",
"author": "hodlbod",
"license": "MIT",
"description": "A collection of utilities.",
+12
View File
@@ -47,6 +47,18 @@ export const omit = <T extends Record<string, any>>(ks: string[], x: T) => {
return r
}
export const omitVals = <T extends Record<string, any>>(xs: any[], x: T) => {
const r: Record<string, any> = {}
for (const [k, v] of Object.entries(x)) {
if (!xs.includes(v)) {
r[k] = v
}
}
return r as T
}
export const pick = <T extends Record<string, any>>(ks: string[], x: T) => {
const r: T = {...x}