diff --git a/packages/app/src/follows.ts b/packages/app/src/follows.ts index 4549d7f..837b25d 100644 --- a/packages/app/src/follows.ts +++ b/packages/app/src/follows.ts @@ -1,6 +1,6 @@ import {FOLLOWS, asDecryptedEvent, readList} from '@welshman/util' import {type TrustedEvent, type PublishedList} from '@welshman/util' -import {type SubscribeRequest} from "@welshman/net" +import {type SubscribeRequestWithHandlers} from "@welshman/net" import {deriveEventsMapped, withGetter} from '@welshman/store' import {repository, load} from './core' import {collection} from './collection' @@ -28,7 +28,7 @@ export const { name: "follows", store: follows, getKey: follows => follows.event.pubkey, - load: async (pubkey: string, request: Partial = {}) => { + load: async (pubkey: string, request: Partial = {}) => { await loadRelaySelections(pubkey, request) await load({...request, filters: [{kinds: [FOLLOWS], authors: [pubkey]}]}) }, diff --git a/packages/app/src/handles.ts b/packages/app/src/handles.ts index cbe6882..4a77170 100644 --- a/packages/app/src/handles.ts +++ b/packages/app/src/handles.ts @@ -1,6 +1,6 @@ import {writable, derived} from 'svelte/store' import {withGetter} from '@welshman/store' -import {type SubscribeRequest} from "@welshman/net" +import {type SubscribeRequestWithHandlers} from "@welshman/net" import {ctx, tryCatch, fetchJson, uniq, batcher, postJson, last} from '@welshman/lib' import {collection} from './collection' import {deriveProfile} from './profiles' @@ -97,7 +97,7 @@ export const { }), }) -export const deriveHandleForPubkey = (pubkey: string, request: Partial = {}) => +export const deriveHandleForPubkey = (pubkey: string, request: Partial = {}) => derived( [handlesByNip05, deriveProfile(pubkey, request)], ([$handlesByNip05, $profile]) => { diff --git a/packages/app/src/mutes.ts b/packages/app/src/mutes.ts index ed0cb88..575a420 100644 --- a/packages/app/src/mutes.ts +++ b/packages/app/src/mutes.ts @@ -1,6 +1,6 @@ import {MUTES, asDecryptedEvent, readList} from '@welshman/util' import {type TrustedEvent, type PublishedList} from '@welshman/util' -import {type SubscribeRequest} from "@welshman/net" +import {type SubscribeRequestWithHandlers} from "@welshman/net" import {deriveEventsMapped, withGetter} from '@welshman/store' import {repository, load} from './core' import {collection} from './collection' @@ -28,7 +28,7 @@ export const { name: "mutes", store: mutes, getKey: mute => mute.event.pubkey, - load: async (pubkey: string, request: Partial = {}) => { + load: async (pubkey: string, request: Partial = {}) => { await loadRelaySelections(pubkey, request) await load({...request, filters: [{kinds: [MUTES], authors: [pubkey]}]}) }, diff --git a/packages/app/src/profiles.ts b/packages/app/src/profiles.ts index 97648e6..598219d 100644 --- a/packages/app/src/profiles.ts +++ b/packages/app/src/profiles.ts @@ -1,7 +1,7 @@ import {derived, readable} from 'svelte/store' import {readProfile, displayProfile, displayPubkey, PROFILE} from '@welshman/util' -import {type SubscribeRequest} from "@welshman/net" -import {type PublishedProfile} from "@welshman/util" +import type {SubscribeRequestWithHandlers} from "@welshman/net" +import type {PublishedProfile, TrustedEvent} from "@welshman/util" import {deriveEventsMapped, withGetter} from '@welshman/store' import {repository, load} from './core' import {createSearch} from './util' @@ -24,9 +24,24 @@ export const { name: "profiles", store: profiles, getKey: profile => profile.event.pubkey, - load: async (pubkey: string, request: Partial = {}) => { - await loadRelaySelections(pubkey, request) - await load({...request, filters: [{kinds: [PROFILE], authors: [pubkey]}]}) + load: async (pubkey: string, request: Partial = {}) => { + const filters = [{kinds: [PROFILE], authors: [pubkey]}] + + // Attempt to load the user profile right away, regardless of whether we have relays, + // since profiles are crucial to UX + load({...request, filters}) + + // Load relay selections as quickly as possible, moving on to retrying profiles with + // better selections the moment we have a result, even if it's outdated + await new Promise(resolve => { + loadRelaySelections(pubkey, { + onEvent: (event: TrustedEvent) => { + resolve() + } + }) + }) + + await load({...request, filters}) }, }) diff --git a/packages/app/src/relaySelections.ts b/packages/app/src/relaySelections.ts index f49e451..d0b2c63 100644 --- a/packages/app/src/relaySelections.ts +++ b/packages/app/src/relaySelections.ts @@ -1,5 +1,5 @@ import {INBOX_RELAYS, RELAYS, getRelayTags, normalizeRelayUrl, type TrustedEvent} from '@welshman/util' -import {type SubscribeRequest} from "@welshman/net" +import {type SubscribeRequestWithHandlers} from "@welshman/net" import {deriveEvents, withGetter} from '@welshman/store' import {load, repository} from './core' import {collection} from './collection' @@ -28,7 +28,7 @@ export const { name: "relaySelections", store: relaySelections, getKey: relaySelections => relaySelections.pubkey, - load: (pubkey: string, request: Partial = {}) => + load: (pubkey: string, request: Partial = {}) => load({...request, filters: [{kinds: [RELAYS], authors: [pubkey]}]}), }) @@ -42,6 +42,6 @@ export const { name: "inboxRelaySelections", store: inboxRelaySelections, getKey: inboxRelaySelections => inboxRelaySelections.pubkey, - load: (pubkey: string, request: Partial = {}) => + load: (pubkey: string, request: Partial = {}) => load({...request, filters: [{kinds: [INBOX_RELAYS], authors: [pubkey]}]}), }) diff --git a/packages/app/src/zappers.ts b/packages/app/src/zappers.ts index 2ab61ef..19fea74 100644 --- a/packages/app/src/zappers.ts +++ b/packages/app/src/zappers.ts @@ -1,7 +1,7 @@ import {writable, derived} from 'svelte/store' import {withGetter} from '@welshman/store' import {type Zapper} from '@welshman/util' -import {type SubscribeRequest} from "@welshman/net" +import {type SubscribeRequestWithHandlers} from "@welshman/net" import {ctx, identity, fetchJson, uniq, bech32ToHex, hexToBech32, tryCatch, batcher, postJson} from '@welshman/lib' import {collection} from './collection' import {deriveProfile} from './profiles' @@ -15,10 +15,13 @@ 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 = lnurls.map(lnurl => tryCatch(() => bech32ToHex(lnurl))).filter(identity) - const res: any = await tryCatch(async () => await postJson(`${base}/zapper/info`, {lnurls: hexUrls})) - for (const {lnurl, info} of res?.data || []) { - tryCatch(() => zappersByLnurl.set(hexToBech32("lnurl", lnurl), info)) + if (hexUrls.length > 0) { + const res: any = await tryCatch(async () => await postJson(`${base}/zapper/info`, {lnurls: hexUrls})) + + for (const {lnurl, info} of res?.data || []) { + tryCatch(() => zappersByLnurl.set(hexToBech32("lnurl", lnurl), info)) + } } } else { const results = await Promise.all( @@ -68,7 +71,7 @@ export const { }), }) -export const deriveZapperForPubkey = (pubkey: string, request: Partial = {}) => +export const deriveZapperForPubkey = (pubkey: string, request: Partial = {}) => derived( [zappersByLnurl, deriveProfile(pubkey, request)], ([$zappersByLnurl, $profile]) => { diff --git a/packages/net/src/Subscribe.ts b/packages/net/src/Subscribe.ts index 9394539..a23e44a 100644 --- a/packages/net/src/Subscribe.ts +++ b/packages/net/src/Subscribe.ts @@ -139,7 +139,8 @@ export const optimizeSubscriptions = (subs: Subscription[]) => { const mergedSubs = [] for (const {relays, filters} of ctx.net.optimizeSubscriptions(group)) { - const mergedSub = makeSubscription({filters, + const mergedSub = makeSubscription({ + filters, relays, timeout, authTimeout, @@ -211,7 +212,7 @@ export const optimizeSubscriptions = (subs: Subscription[]) => { }) } -export const executeSubscription = (sub: Subscription) => { +const _executeSubscription = (sub: Subscription) => { const {request, emitter, tracker, controller} = sub const {filters, closeOnEose, relays, signal, timeout, authTimeout = 0} = request const executor = ctx.net.getExecutor(relays) @@ -305,8 +306,11 @@ export const executeSubscription = (sub: Subscription) => { } } +export const executeSubscription = (sub: Subscription) => + optimizeSubscriptions([sub]).forEach(_executeSubscription) + export const executeSubscriptions = (subs: Subscription[]) => - optimizeSubscriptions(subs).forEach(executeSubscription) + optimizeSubscriptions(subs).forEach(_executeSubscription) export const executeSubscriptionBatched = (() => { const subs: Subscription[] = []