From e582d46afddbed74bde9fdaa04b2d48be794360d Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Tue, 11 Nov 2025 14:05:30 -0800 Subject: [PATCH] Break down relay utils, replace removeNil with removeUndefined --- docs/editor/index.md | 4 +- docs/lib/tools.md | 2 +- packages/app/src/commands.ts | 4 +- packages/app/src/relays.ts | 76 ++++++++++++++++++++++---------- packages/app/src/zappers.ts | 10 ++--- packages/feeds/src/controller.ts | 9 ++-- packages/lib/src/Tools.ts | 2 +- packages/store/src/repository.ts | 16 +++++-- 8 files changed, 81 insertions(+), 42 deletions(-) diff --git a/docs/editor/index.md b/docs/editor/index.md index 99afa8b..33141c4 100644 --- a/docs/editor/index.md +++ b/docs/editor/index.md @@ -19,14 +19,14 @@ import {get} from "svelte/store" import type {Writable} from "svelte/store" import type {NodeViewProps} from "@tiptap/core" import {Router} from "@welshman/router" -import {removeNil} from "@welshman/lib" +import {removeUndefined} from "@welshman/lib" import type {FileAttributes} from "@welshman/editor" import {Editor, MentionSuggestion, WelshmanExtension} from "@welshman/editor" import {profileSearch, deriveProfileDisplay} from "@welshman/app" export const MentionNodeView = ({node}: NodeViewProps) => { 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") diff --git a/docs/lib/tools.md b/docs/lib/tools.md index ad03c27..b5a9175 100644 --- a/docs/lib/tools.md +++ b/docs/lib/tools.md @@ -324,7 +324,7 @@ export declare const toIterable: (x: any) => any; export declare const ensurePlural: (x: T | T[]) => T[]; // Ensures values are not undefined -export declare const removeNil: (xs: T[]) => (T & {})[]; +export declare const removeUndefined: (xs: T[]) => (T & {})[]; // Returns a list of overlapping pairs of elements in xs export declare const overlappingPairs: (xs: T[]) => T[][]; diff --git a/packages/app/src/commands.ts b/packages/app/src/commands.ts index cb668ee..a43c7b5 100644 --- a/packages/app/src/commands.ts +++ b/packages/app/src/commands.ts @@ -1,5 +1,5 @@ import {get} from "svelte/store" -import {uniq, nthNe, removeNil, nthEq} from "@welshman/lib" +import {uniq, nthNe, removeUndefined, nthEq} from "@welshman/lib" import { sendManagementRequest, ManagementRequest, @@ -75,7 +75,7 @@ export const addRelay = async (url: string, mode: RelayMode) => { const list = get(userRelaySelections) || makeList({kind: RELAYS}) 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 event = {kind: list.kind, content: list.event?.content || "", tags} const relays = Router.get().FromUser().policy(addMaximalFallbacks).getUrls() diff --git a/packages/app/src/relays.ts b/packages/app/src/relays.ts index 0849953..229c51a 100644 --- a/packages/app/src/relays.ts +++ b/packages/app/src/relays.ts @@ -1,6 +1,15 @@ import {writable, derived} from "svelte/store" +import { + uniq, + removeUndefined, + prop, + indexBy, + batcher, + fetchJson, + postJson, + Maybe, +} from "@welshman/lib" import {withGetter} from "@welshman/store" -import {uniq, batcher, postJson} from "@welshman/lib" import {RelayProfile} from "@welshman/util" import {normalizeRelayUrl, displayRelayUrl, displayRelayProfile, isRelayUrl} from "@welshman/util" import {collection} from "@welshman/store" @@ -8,36 +17,55 @@ import {appContext} from "./context.js" export const relays = withGetter(writable([])) -export const fetchRelayProfiles = async (urls: string[]) => { +export const fetchRelayProfileDirectly = async (url: string): Promise> => { + try { + return fetchJson(url.replace(/^ws/, "http"), { + headers: { + Accept: "application/nostr+json", + }, + }) + } catch (e) { + // pass + } +} + +export const fetchRelayProfilesDirectly = async ( + urls: string[], +): Promise> => + 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> => { const profilesByUrl = new Map() + const res: any = await postJson(`${proxy}/relay/info`, {urls}) - if (appContext.dufflepudUrl) { - const res: any = await postJson(`${appContext.dufflepudUrl}/relay/info`, {urls}) - - 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 - } - }), - ) + for (const {url, info} of res?.data || []) { + profilesByUrl.set(url, info) } return profilesByUrl } +export const fetchRelayProfiles = (urls: string[]) => + appContext.dufflepudUrl + ? fetchRelayProfilesUsingProxy(appContext.dufflepudUrl, urls) + : fetchRelayProfilesDirectly(urls) + export const { indexStore: relaysByUrl, deriveItem: deriveRelay, diff --git a/packages/app/src/zappers.ts b/packages/app/src/zappers.ts index c6602ce..3f5a5b4 100644 --- a/packages/app/src/zappers.ts +++ b/packages/app/src/zappers.ts @@ -1,7 +1,7 @@ import {writable, derived} from "svelte/store" import {Zapper, TrustedEvent, Zap, getTagValues, getLnUrl, zapFromEvent} from "@welshman/util" import { - removeNil, + removeUndefined, fetchJson, uniq, 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 if (base) { - const hexUrls = removeNil(lnurls.map(lnurl => tryCatch(() => bech32ToHex(lnurl)))) + const hexUrls = removeUndefined(lnurls.map(lnurl => tryCatch(() => bech32ToHex(lnurl)))) if (hexUrls.length > 0) { const res: any = await tryCatch( @@ -102,7 +102,7 @@ export const deriveZapperForPubkey = (pubkey: string, relays: string[] = []) => }) 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) { return lnurls @@ -110,7 +110,7 @@ export const getLnUrlsForEvent = async (event: TrustedEvent) => { const profile = await loadProfile(event.pubkey) - return removeNil([profile?.lnurl]) + return removeUndefined([profile?.lnurl]) } 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) => - 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) => { const store = writable([]) diff --git a/packages/feeds/src/controller.ts b/packages/feeds/src/controller.ts index 2eb3ef1..c6949e2 100644 --- a/packages/feeds/src/controller.ts +++ b/packages/feeds/src/controller.ts @@ -1,6 +1,6 @@ import { inc, - removeNil, + removeUndefined, call, defer, Deferred, @@ -130,9 +130,10 @@ export class FeedController { let delta = initialDelta let since = this.options.useWindowing ? maxUntil - delta : 0 let until = maxUntil + let exhausted = false return async (limit: number) => { - if (promise) { + if (promise || exhausted) { return promise } @@ -173,6 +174,7 @@ export class FeedController { if (this.options.useWindowing) { if (since === minSince) { + exhausted = true onExhausted?.() } @@ -185,6 +187,7 @@ export class FeedController { since = Math.max(minSince, until - delta) } else if (count === 0) { + exhausted = true onExhausted?.() } @@ -351,7 +354,7 @@ export class FeedController { return () => { 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})) requestPage( diff --git a/packages/lib/src/Tools.ts b/packages/lib/src/Tools.ts index 9fda88d..0166738 100644 --- a/packages/lib/src/Tools.ts +++ b/packages/lib/src/Tools.ts @@ -776,7 +776,7 @@ export const toIterable = (x: any) => (isIterable(x) ? x : [x]) export const ensurePlural = (x: T | T[]) => (x instanceof Array ? x : [x]) /** Ensures values are not undefined */ -export const removeNil = (xs: T[]) => xs.filter(isDefined).map(assertDefined) +export const removeUndefined = (xs: T[]) => xs.filter(isDefined).map(assertDefined) /** Returns a list of overlapping pairs of elements in xs */ export const overlappingPairs = (xs: T[]): T[][] => { diff --git a/packages/store/src/repository.ts b/packages/store/src/repository.ts index d0bff0b..4714a86 100644 --- a/packages/store/src/repository.ts +++ b/packages/store/src/repository.ts @@ -1,5 +1,13 @@ 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 {Repository} from "@welshman/net" import {custom} from "./custom.js" @@ -34,7 +42,7 @@ export const deriveEventsMapped = ( if (deferred.has(event.id)) { deferred.delete(event.id) - for (const item of removeNil(ensurePlural(items))) { + for (const item of removeUndefined(ensurePlural(items))) { data.push(item) } @@ -53,7 +61,7 @@ export const deriveEventsMapped = ( if (items instanceof Promise) { defer(event, items) } else { - for (const item of removeNil(ensurePlural(items))) { + for (const item of removeUndefined(ensurePlural(items))) { data.push(item) } } @@ -89,7 +97,7 @@ export const deriveEventsMapped = ( } else if (items) { dirty = true - for (const item of removeNil(ensurePlural(items))) { + for (const item of removeUndefined(ensurePlural(items))) { data.push(item as T) } }