Browse Source

bug-fixes

imwald
Silberengel 2 weeks ago
parent
commit
38e428020e
  1. 12
      src/components/PostEditor/PostTextarea/Mention/suggestion.ts
  2. 8
      src/hooks/useSearchProfiles.tsx
  3. 107
      src/services/client.service.ts

12
src/components/PostEditor/PostTextarea/Mention/suggestion.ts

@ -22,6 +22,7 @@ export const OPEN_NEVENT_PICKER_EVENT = 'open-nevent-picker'
// Shared state for incremental updates // Shared state for incremental updates
let currentComponent: ReactRenderer<MentionListHandle, MentionListProps> | undefined let currentComponent: ReactRenderer<MentionListHandle, MentionListProps> | undefined
let currentQuery = '' let currentQuery = ''
let pendingMentionItems: MentionListItem[] | null = null
let backgroundSearchController: AbortController | null = null let backgroundSearchController: AbortController | null = null
let mentionSearchDebounceTimer: ReturnType<typeof setTimeout> | null = null let mentionSearchDebounceTimer: ReturnType<typeof setTimeout> | null = null
let mentionSearchGeneration = 0 let mentionSearchGeneration = 0
@ -100,8 +101,11 @@ const suggestion = {
currentQuery = q currentQuery = q
const updateComponent = (npubs: string[]) => { const updateComponent = (npubs: string[]) => {
if (currentComponent && currentQuery === q && generation === mentionSearchGeneration) { if (generation !== mentionSearchGeneration || currentQuery !== q) return
pendingMentionItems = npubs
if (currentComponent) {
currentComponent.updateProps({ items: npubs }) currentComponent.updateProps({ items: npubs })
pendingMentionItems = null
} }
} }
@ -151,6 +155,11 @@ const suggestion = {
// Store component reference for incremental updates // Store component reference for incremental updates
currentComponent = component currentComponent = component
if (pendingMentionItems) {
component.updateProps({ items: pendingMentionItems })
pendingMentionItems = null
}
if (!props.clientRect) { if (!props.clientRect) {
return return
} }
@ -206,6 +215,7 @@ const suggestion = {
} }
currentComponent = undefined currentComponent = undefined
currentQuery = '' currentQuery = ''
pendingMentionItems = null
if (popup[0]) { if (popup[0]) {
popup[0].destroy() popup[0].destroy()

8
src/hooks/useSearchProfiles.tsx

@ -64,7 +64,13 @@ export function useSearchProfiles(
} }
} }
void run() const wallTimeout = window.setTimeout(() => {
if (!cancelled && !ac.signal.aborted) setIsFetching(false)
}, 20_000)
void run().finally(() => {
window.clearTimeout(wallTimeout)
})
return () => { return () => {
cancelled = true cancelled = true
if (partialTimerRef.current) clearTimeout(partialTimerRef.current) if (partialTimerRef.current) clearTimeout(partialTimerRef.current)

107
src/services/client.service.ts

@ -4214,48 +4214,54 @@ class ClientService extends EventTarget {
? AbortSignal.any([runAbort.signal, externalSignal]) ? AbortSignal.any([runAbort.signal, externalSignal])
: runAbort.signal : runAbort.signal
merge(await this.searchProfilesFromLocal(q, limit)) const relayUrls = this.profileRelaySearchUrls()
if (isStale()) return out.slice(0, limit) const indexUrls = this.nip50ProfileIndexRelayUrls()
emit()
if (out.length >= limit) return out.slice(0, limit)
if (q.length >= 2 && nostrArchivesApi.isAvailable()) { const localPromise = this.searchProfilesFromLocal(q, limit)
const suggestRes = await nostrArchivesApi.searchSuggest(q, Math.min(limit, 10)) const profileRelayPromise = this.searchProfiles(
if (!isStale() && suggestRes.ok) { relayUrls,
merge(archivesMetadataListToProfiles(suggestRes.data.suggestions)) { search: q, limit },
{
relaysOnly: true,
includeTagFilters: false,
signal: relaySignal,
eoseTimeout: 6_000,
globalTimeout: 9_000
} }
} ).catch(() => [] as TProfile[])
if (isStale()) return out.slice(0, limit) const archivesPromise =
emit() q.length >= 2 && nostrArchivesApi.isAvailable()
if (out.length >= limit) return out.slice(0, limit) ? nostrArchivesApi.searchSuggest(q, Math.min(limit, 10))
: Promise.resolve({ ok: false as const, reason: 'disabled' as const })
const [localProfiles, profileRelayProfiles, archivesRes] = await Promise.all([
localPromise,
profileRelayPromise,
archivesPromise
])
const needAfterLocal = limit - out.length merge(localProfiles)
merge( if (!isStale() && archivesRes.ok) {
await this.searchProfiles( merge(archivesMetadataListToProfiles(archivesRes.data.suggestions))
this.profileRelaySearchUrls(), }
{ search: q, limit: needAfterLocal }, merge(profileRelayProfiles)
{
relaysOnly: true,
includeTagFilters: false,
signal: relaySignal,
eoseTimeout: 6_000,
globalTimeout: 9_000
}
)
)
if (isStale()) return out.slice(0, limit) if (isStale()) return out.slice(0, limit)
emit() emit()
if (out.length >= limit) return out.slice(0, limit) if (out.length >= limit) return out.slice(0, limit)
if (out.length > 0) return out.slice(0, limit) if (out.length > 0) return out.slice(0, limit)
const indexUrls = this.nip50ProfileIndexRelayUrls()
if (indexUrls.length > 0) { if (indexUrls.length > 0) {
merge( merge(
await this.searchProfiles( await this.searchProfiles(
indexUrls, indexUrls,
{ search: q, limit }, { search: q, limit },
{ signal: relaySignal, includeTagFilters: true } {
) signal: relaySignal,
includeTagFilters: true,
eoseTimeout: 5_000,
globalTimeout: 12_000
}
).catch(() => [] as TProfile[])
) )
if (!isStale()) emit() if (!isStale()) emit()
} }
@ -4407,11 +4413,18 @@ class ClientService extends EventTarget {
} }
const updateIfNeeded = () => { const updateIfNeeded = () => {
if (onUpdate && out.length > 0) { if (onUpdate) onUpdate([...out])
onUpdate([...out])
}
} }
const profileRelayPromise =
q.length >= 1
? this.searchProfiles(
this.profileRelaySearchUrls(),
{ search: q, limit },
{ relaysOnly: true, includeTagFilters: false, eoseTimeout: 6_000, globalTimeout: 9_000 }
).catch(() => [] as TProfile[])
: Promise.resolve([] as TProfile[])
const matchProfileText = (p: TProfile) => const matchProfileText = (p: TProfile) =>
((p.username ?? '') + ' ' + (p.original_username ?? '') + ' ' + (p.nip05 ?? '')).toLowerCase() ((p.username ?? '') + ' ' + (p.original_username ?? '') + ' ' + (p.nip05 ?? '')).toLowerCase()
@ -4507,14 +4520,10 @@ class ClientService extends EventTarget {
return out return out
} }
// 3. Profile relays only (purplepag.es, profiles.nostr1.com, …) — not NIP-50 index relays. // 3. Profile relays (started in parallel with local + follow merge above).
if (q.length >= 1 && out.length < limit) { if (q.length >= 1 && out.length < limit) {
try { try {
const relayProfiles = await this.searchProfiles( const relayProfiles = await profileRelayPromise
this.profileRelaySearchUrls(),
{ search: q, limit: limit - out.length },
{ relaysOnly: true, includeTagFilters: false, eoseTimeout: 6_000, globalTimeout: 9_000 }
)
for (const p of relayProfiles) { for (const p of relayProfiles) {
const npub = pubkeyToNpub(p.pubkey) const npub = pubkeyToNpub(p.pubkey)
if (!npub) continue if (!npub) continue
@ -4531,7 +4540,10 @@ class ClientService extends EventTarget {
const indexUrls = this.nip50ProfileIndexRelayUrls() const indexUrls = this.nip50ProfileIndexRelayUrls()
if (indexUrls.length > 0) { if (indexUrls.length > 0) {
try { try {
const indexProfiles = await this.searchProfiles(indexUrls, { search: q, limit }) const indexProfiles = await this.searchProfiles(indexUrls, { search: q, limit }, {
eoseTimeout: 5_000,
globalTimeout: 12_000
})
for (const p of indexProfiles) { for (const p of indexProfiles) {
const npub = pubkeyToNpub(p.pubkey) const npub = pubkeyToNpub(p.pubkey)
if (!npub) continue if (!npub) continue
@ -4594,17 +4606,22 @@ class ClientService extends EventTarget {
if (remaining <= 0) return out if (remaining <= 0) return out
const npubs = await this.searchNpubsFromLocal(q, remaining) const npubs = await this.searchNpubsFromLocal(q, remaining)
const pkBatch: string[] = []
for (const npub of npubs) { for (const npub of npubs) {
let pkHex: string
try { try {
pkHex = userIdToPubkey(npub).toLowerCase() const pkHex = userIdToPubkey(npub).toLowerCase()
if (!seen.has(pkHex)) pkBatch.push(pkHex)
} catch { } catch {
continue continue
} }
if (seen.has(pkHex)) continue }
const p = await this.replaceableEventService.fetchProfile(npub) if (pkBatch.length === 0) return out
if (!p) continue
seen.add(pkHex) const profiles = await this.fetchProfilesForPubkeys(pkBatch.slice(0, remaining))
for (const p of profiles) {
const pk = p.pubkey.toLowerCase()
if (seen.has(pk)) continue
seen.add(pk)
out.push(p) out.push(p)
if (out.length >= limit) break if (out.length >= limit) break
} }

Loading…
Cancel
Save