Break down relay utils, replace removeNil with removeUndefined

This commit is contained in:
Jon Staab
2025-11-11 14:05:30 -08:00
parent 4c1c138329
commit e582d46afd
8 changed files with 81 additions and 42 deletions
+2 -2
View File
@@ -19,14 +19,14 @@ import {get} from "svelte/store"
import type {Writable} from "svelte/store" import type {Writable} from "svelte/store"
import type {NodeViewProps} from "@tiptap/core" import type {NodeViewProps} from "@tiptap/core"
import {Router} from "@welshman/router" import {Router} from "@welshman/router"
import {removeNil} from "@welshman/lib" import {removeUndefined} from "@welshman/lib"
import type {FileAttributes} from "@welshman/editor" import type {FileAttributes} from "@welshman/editor"
import {Editor, MentionSuggestion, WelshmanExtension} from "@welshman/editor" import {Editor, MentionSuggestion, WelshmanExtension} from "@welshman/editor"
import {profileSearch, deriveProfileDisplay} from "@welshman/app" import {profileSearch, deriveProfileDisplay} from "@welshman/app"
export const MentionNodeView = ({node}: NodeViewProps) => { export const MentionNodeView = ({node}: NodeViewProps) => {
const dom = document.createElement("span") const dom = document.createElement("span")
const display = deriveProfileDisplay(node.attrs.pubkey, removeNil([url])) const display = deriveProfileDisplay(node.attrs.pubkey, removeUndefined([url]))
dom.classList.add("tiptap-object") dom.classList.add("tiptap-object")
+1 -1
View File
@@ -324,7 +324,7 @@ export declare const toIterable: (x: any) => any;
export declare const ensurePlural: <T>(x: T | T[]) => T[]; export declare const ensurePlural: <T>(x: T | T[]) => T[];
// Ensures values are not undefined // Ensures values are not undefined
export declare const removeNil: <T>(xs: T[]) => (T & {})[]; export declare const removeUndefined: <T>(xs: T[]) => (T & {})[];
// Returns a list of overlapping pairs of elements in xs // Returns a list of overlapping pairs of elements in xs
export declare const overlappingPairs: <T>(xs: T[]) => T[][]; export declare const overlappingPairs: <T>(xs: T[]) => T[][];
+2 -2
View File
@@ -1,5 +1,5 @@
import {get} from "svelte/store" import {get} from "svelte/store"
import {uniq, nthNe, removeNil, nthEq} from "@welshman/lib" import {uniq, nthNe, removeUndefined, nthEq} from "@welshman/lib"
import { import {
sendManagementRequest, sendManagementRequest,
ManagementRequest, ManagementRequest,
@@ -75,7 +75,7 @@ export const addRelay = async (url: string, mode: RelayMode) => {
const list = get(userRelaySelections) || makeList({kind: RELAYS}) const list = get(userRelaySelections) || makeList({kind: RELAYS})
const dup = getRelayTags(getListTags(list)).find(nthEq(1, url)) const dup = getRelayTags(getListTags(list)).find(nthEq(1, url))
const tag = removeNil(["r", url, dup && dup[2] !== mode ? undefined : mode]) const tag = removeUndefined(["r", url, dup && dup[2] !== mode ? undefined : mode])
const tags = [...list.publicTags.filter(nthNe(1, url)), tag] const tags = [...list.publicTags.filter(nthNe(1, url)), tag]
const event = {kind: list.kind, content: list.event?.content || "", tags} const event = {kind: list.kind, content: list.event?.content || "", tags}
const relays = Router.get().FromUser().policy(addMaximalFallbacks).getUrls() const relays = Router.get().FromUser().policy(addMaximalFallbacks).getUrls()
+52 -24
View File
@@ -1,6 +1,15 @@
import {writable, derived} from "svelte/store" import {writable, derived} from "svelte/store"
import {
uniq,
removeUndefined,
prop,
indexBy,
batcher,
fetchJson,
postJson,
Maybe,
} from "@welshman/lib"
import {withGetter} from "@welshman/store" import {withGetter} from "@welshman/store"
import {uniq, batcher, postJson} from "@welshman/lib"
import {RelayProfile} from "@welshman/util" import {RelayProfile} from "@welshman/util"
import {normalizeRelayUrl, displayRelayUrl, displayRelayProfile, isRelayUrl} from "@welshman/util" import {normalizeRelayUrl, displayRelayUrl, displayRelayProfile, isRelayUrl} from "@welshman/util"
import {collection} from "@welshman/store" import {collection} from "@welshman/store"
@@ -8,36 +17,55 @@ import {appContext} from "./context.js"
export const relays = withGetter(writable<RelayProfile[]>([])) export const relays = withGetter(writable<RelayProfile[]>([]))
export const fetchRelayProfiles = async (urls: string[]) => { export const fetchRelayProfileDirectly = async (url: string): Promise<Maybe<RelayProfile>> => {
try {
return fetchJson(url.replace(/^ws/, "http"), {
headers: {
Accept: "application/nostr+json",
},
})
} catch (e) {
// pass
}
}
export const fetchRelayProfilesDirectly = async (
urls: string[],
): Promise<Map<string, RelayProfile>> =>
indexBy(
prop("url"),
removeUndefined(
await Promise.all(
urls.map(async url => {
const profile = await fetchRelayProfileDirectly(url)
if (profile) {
return {...profile, url}
}
}),
),
),
)
export const fetchRelayProfilesUsingProxy = async (
proxy: string,
urls: string[],
): Promise<Map<string, RelayProfile>> => {
const profilesByUrl = new Map<string, RelayProfile>() const profilesByUrl = new Map<string, RelayProfile>()
const res: any = await postJson(`${proxy}/relay/info`, {urls})
if (appContext.dufflepudUrl) { for (const {url, info} of res?.data || []) {
const res: any = await postJson(`${appContext.dufflepudUrl}/relay/info`, {urls}) profilesByUrl.set(url, info)
for (const {url, info} of res?.data || []) {
profilesByUrl.set(url, info)
}
} else {
await Promise.all(
urls.map(async url => {
try {
const res = await fetch(url.replace(/^ws/, "http"), {
headers: {
Accept: "application/nostr+json",
},
})
profilesByUrl.set(url, await res.json())
} catch (e) {
// pass
}
}),
)
} }
return profilesByUrl return profilesByUrl
} }
export const fetchRelayProfiles = (urls: string[]) =>
appContext.dufflepudUrl
? fetchRelayProfilesUsingProxy(appContext.dufflepudUrl, urls)
: fetchRelayProfilesDirectly(urls)
export const { export const {
indexStore: relaysByUrl, indexStore: relaysByUrl,
deriveItem: deriveRelay, deriveItem: deriveRelay,
+5 -5
View File
@@ -1,7 +1,7 @@
import {writable, derived} from "svelte/store" import {writable, derived} from "svelte/store"
import {Zapper, TrustedEvent, Zap, getTagValues, getLnUrl, zapFromEvent} from "@welshman/util" import {Zapper, TrustedEvent, Zap, getTagValues, getLnUrl, zapFromEvent} from "@welshman/util"
import { import {
removeNil, removeUndefined,
fetchJson, fetchJson,
uniq, uniq,
bech32ToHex, bech32ToHex,
@@ -22,7 +22,7 @@ export const fetchZappers = async (lnurls: string[]) => {
// Use dufflepud if we it's set up to protect user privacy, otherwise fetch directly // Use dufflepud if we it's set up to protect user privacy, otherwise fetch directly
if (base) { if (base) {
const hexUrls = removeNil(lnurls.map(lnurl => tryCatch(() => bech32ToHex(lnurl)))) const hexUrls = removeUndefined(lnurls.map(lnurl => tryCatch(() => bech32ToHex(lnurl))))
if (hexUrls.length > 0) { if (hexUrls.length > 0) {
const res: any = await tryCatch( const res: any = await tryCatch(
@@ -102,7 +102,7 @@ export const deriveZapperForPubkey = (pubkey: string, relays: string[] = []) =>
}) })
export const getLnUrlsForEvent = async (event: TrustedEvent) => { export const getLnUrlsForEvent = async (event: TrustedEvent) => {
const lnurls = removeNil(getTagValues("zap", event.tags).map(getLnUrl)) const lnurls = removeUndefined(getTagValues("zap", event.tags).map(getLnUrl))
if (lnurls.length > 0) { if (lnurls.length > 0) {
return lnurls return lnurls
@@ -110,7 +110,7 @@ export const getLnUrlsForEvent = async (event: TrustedEvent) => {
const profile = await loadProfile(event.pubkey) const profile = await loadProfile(event.pubkey)
return removeNil([profile?.lnurl]) return removeUndefined([profile?.lnurl])
} }
export const getZapperForZap = async (zap: TrustedEvent, parent: TrustedEvent) => { export const getZapperForZap = async (zap: TrustedEvent, parent: TrustedEvent) => {
@@ -126,7 +126,7 @@ export const getValidZap = async (zap: TrustedEvent, parent: TrustedEvent) => {
} }
export const getValidZaps = async (zaps: TrustedEvent[], parent: TrustedEvent) => export const getValidZaps = async (zaps: TrustedEvent[], parent: TrustedEvent) =>
removeNil(await Promise.all(zaps.map(zap => getValidZap(zap, parent)))) removeUndefined(await Promise.all(zaps.map(zap => getValidZap(zap, parent))))
export const deriveValidZaps = (zaps: TrustedEvent[], parent: TrustedEvent) => { export const deriveValidZaps = (zaps: TrustedEvent[], parent: TrustedEvent) => {
const store = writable<Zap[]>([]) const store = writable<Zap[]>([])
+6 -3
View File
@@ -1,6 +1,6 @@
import { import {
inc, inc,
removeNil, removeUndefined,
call, call,
defer, defer,
Deferred, Deferred,
@@ -130,9 +130,10 @@ export class FeedController {
let delta = initialDelta let delta = initialDelta
let since = this.options.useWindowing ? maxUntil - delta : 0 let since = this.options.useWindowing ? maxUntil - delta : 0
let until = maxUntil let until = maxUntil
let exhausted = false
return async (limit: number) => { return async (limit: number) => {
if (promise) { if (promise || exhausted) {
return promise return promise
} }
@@ -173,6 +174,7 @@ export class FeedController {
if (this.options.useWindowing) { if (this.options.useWindowing) {
if (since === minSince) { if (since === minSince) {
exhausted = true
onExhausted?.() onExhausted?.()
} }
@@ -185,6 +187,7 @@ export class FeedController {
since = Math.max(minSince, until - delta) since = Math.max(minSince, until - delta)
} else if (count === 0) { } else if (count === 0) {
exhausted = true
onExhausted?.() onExhausted?.()
} }
@@ -351,7 +354,7 @@ export class FeedController {
return () => { return () => {
const controller = new AbortController() const controller = new AbortController()
const signal = AbortSignal.any(removeNil([controller.signal, this.options.signal])) const signal = AbortSignal.any(removeUndefined([controller.signal, this.options.signal]))
const requestFilters = filters!.map((filter: Filter) => ({...filter, limit: 0})) const requestFilters = filters!.map((filter: Filter) => ({...filter, limit: 0}))
requestPage( requestPage(
+1 -1
View File
@@ -776,7 +776,7 @@ export const toIterable = (x: any) => (isIterable(x) ? x : [x])
export const ensurePlural = <T>(x: T | T[]) => (x instanceof Array ? x : [x]) export const ensurePlural = <T>(x: T | T[]) => (x instanceof Array ? x : [x])
/** Ensures values are not undefined */ /** Ensures values are not undefined */
export const removeNil = <T>(xs: T[]) => xs.filter(isDefined).map(assertDefined) export const removeUndefined = <T>(xs: T[]) => xs.filter(isDefined).map(assertDefined)
/** Returns a list of overlapping pairs of elements in xs */ /** Returns a list of overlapping pairs of elements in xs */
export const overlappingPairs = <T>(xs: T[]): T[][] => { export const overlappingPairs = <T>(xs: T[]): T[][] => {
+12 -4
View File
@@ -1,5 +1,13 @@
import {derived} from "svelte/store" import {derived} from "svelte/store"
import {sortBy, identity, ensurePlural, removeNil, batch, partition, first} from "@welshman/lib" import {
sortBy,
identity,
ensurePlural,
removeUndefined,
batch,
partition,
first,
} from "@welshman/lib"
import {matchFilters, getIdAndAddress, getIdFilters, Filter, TrustedEvent} from "@welshman/util" import {matchFilters, getIdAndAddress, getIdFilters, Filter, TrustedEvent} from "@welshman/util"
import {Repository} from "@welshman/net" import {Repository} from "@welshman/net"
import {custom} from "./custom.js" import {custom} from "./custom.js"
@@ -34,7 +42,7 @@ export const deriveEventsMapped = <T>(
if (deferred.has(event.id)) { if (deferred.has(event.id)) {
deferred.delete(event.id) deferred.delete(event.id)
for (const item of removeNil(ensurePlural(items))) { for (const item of removeUndefined(ensurePlural(items))) {
data.push(item) data.push(item)
} }
@@ -53,7 +61,7 @@ export const deriveEventsMapped = <T>(
if (items instanceof Promise) { if (items instanceof Promise) {
defer(event, items) defer(event, items)
} else { } else {
for (const item of removeNil(ensurePlural(items))) { for (const item of removeUndefined(ensurePlural(items))) {
data.push(item) data.push(item)
} }
} }
@@ -89,7 +97,7 @@ export const deriveEventsMapped = <T>(
} else if (items) { } else if (items) {
dirty = true dirty = true
for (const item of removeNil(ensurePlural(items))) { for (const item of removeUndefined(ensurePlural(items))) {
data.push(item as T) data.push(item as T)
} }
} }