Browse Source

bug-fixes

imwald
Silberengel 1 month ago
parent
commit
8f4b50dff9
  1. 96
      src/components/ReplyNoteList/index.tsx
  2. 7
      src/constants.ts
  3. 18
      src/services/client-query.service.ts

96
src/components/ReplyNoteList/index.tsx

@ -78,6 +78,8 @@ type TRootInfo = @@ -78,6 +78,8 @@ type TRootInfo =
const LIMIT = 200
const SHOW_COUNT = 10
const MAX_KINDS_PER_THREAD_REQ_FILTER = 4
/** Some relays cap `#e` array length; chunk parent-id batches for nested-thread REQs. */
const MAX_PARENT_IDS_PER_NESTED_REQ = 64
function chunkKindsForThreadReq(list: readonly number[], size = MAX_KINDS_PER_THREAD_REQ_FILTER): number[][] {
const out: number[][] = []
@ -1294,19 +1296,24 @@ function ReplyNoteList({ @@ -1294,19 +1296,24 @@ function ReplyNoteList({
.filter((evt) => commentKinds.includes(evt.kind))
.map((evt) => evt.id)
if (parentIds.length > 0) {
const nestedFilters: Filter[] = [
{ '#e': parentIds, kinds: commentKinds, limit: LIMIT }
]
const nestedReplies = await queryService.fetchEvents(finalRelayUrls, nestedFilters, {
onevent: (evt: NEvent) => {
if (fetchGeneration !== replyFetchGenRef.current) return
if (shouldHideThreadResponseEvent(evt, mutePubkeySet, hideContentMentioningMutedUsers))
return
addReplies([evt])
}
})
if (fetchGeneration !== replyFetchGenRef.current) return
const validNested = nestedReplies.filter(
const nestedAccum: NEvent[] = []
for (let off = 0; off < parentIds.length; off += MAX_PARENT_IDS_PER_NESTED_REQ) {
const idChunk = parentIds.slice(off, off + MAX_PARENT_IDS_PER_NESTED_REQ)
const nestedFilters: Filter[] = [
{ '#e': idChunk, kinds: commentKinds, limit: LIMIT }
]
const nestedReplies = await queryService.fetchEvents(finalRelayUrls, nestedFilters, {
onevent: (evt: NEvent) => {
if (fetchGeneration !== replyFetchGenRef.current) return
if (shouldHideThreadResponseEvent(evt, mutePubkeySet, hideContentMentioningMutedUsers))
return
addReplies([evt])
}
})
if (fetchGeneration !== replyFetchGenRef.current) return
nestedAccum.push(...nestedReplies)
}
const validNested = nestedAccum.filter(
(evt) =>
!shouldHideThreadResponseEvent(evt, mutePubkeySet, hideContentMentioningMutedUsers)
)
@ -1318,41 +1325,48 @@ function ReplyNoteList({ @@ -1318,41 +1325,48 @@ function ReplyNoteList({
}
}
// Second pass for kind-11 discussions: nested 1111/1 chains are keyed under parent ids in
// ReplyProvider; fetching #e:[comment-id] fills gaps the root-scoped REQ can miss.
// Second pass for discussions, plain kind-1 threads, and replaceable (longform/wiki) roots:
// nested 1 / 1111 / 1244 often tag only the parent's #e; root-scoped REQ misses them (same
// idea as URL-thread #I follow-up above).
if (
event.kind === ExtendedKind.DISCUSSION &&
rootInfo.type === 'E' &&
regularReplies.length > 0
regularReplies.length > 0 &&
((rootInfo.type === 'E' &&
(event.kind === ExtendedKind.DISCUSSION || event.kind === kinds.ShortTextNote)) ||
rootInfo.type === 'A')
) {
const commentKinds = [
const commentKindsNested = [
ExtendedKind.COMMENT,
ExtendedKind.VOICE_COMMENT,
kinds.ShortTextNote
]
const parentIds = regularReplies
.filter((evt) => commentKinds.includes(evt.kind))
const parentIdsNested = regularReplies
.filter((evt) => commentKindsNested.includes(evt.kind))
.map((evt) => evt.id)
if (parentIds.length > 0) {
const nestedFilters: Filter[] = [
{ '#e': parentIds, kinds: commentKinds, limit: LIMIT },
{
'#E': parentIds,
kinds: [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT],
limit: LIMIT
}
]
const nestedReplies = await queryService.fetchEvents(finalRelayUrls, nestedFilters, {
onevent: (evt: NEvent) => {
if (fetchGeneration !== replyFetchGenRef.current) return
if (shouldHideThreadResponseEvent(evt, mutePubkeySet, hideContentMentioningMutedUsers))
return
if (!replyMatchesThreadForList(evt, event, rootInfo, isDiscussionRoot)) return
addReplies([evt])
}
})
if (fetchGeneration !== replyFetchGenRef.current) return
const validNested = nestedReplies.filter(
if (parentIdsNested.length > 0) {
const nestedAccum: NEvent[] = []
for (let off = 0; off < parentIdsNested.length; off += MAX_PARENT_IDS_PER_NESTED_REQ) {
const idChunk = parentIdsNested.slice(off, off + MAX_PARENT_IDS_PER_NESTED_REQ)
const nestedFilters: Filter[] = [
{ '#e': idChunk, kinds: commentKindsNested, limit: LIMIT },
{
'#E': idChunk,
kinds: [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT],
limit: LIMIT
}
]
const nestedReplies = await queryService.fetchEvents(finalRelayUrls, nestedFilters, {
onevent: (evt: NEvent) => {
if (fetchGeneration !== replyFetchGenRef.current) return
if (shouldHideThreadResponseEvent(evt, mutePubkeySet, hideContentMentioningMutedUsers))
return
if (!replyMatchesThreadForList(evt, event, rootInfo, isDiscussionRoot)) return
addReplies([evt])
}
})
if (fetchGeneration !== replyFetchGenRef.current) return
nestedAccum.push(...nestedReplies)
}
const validNested = nestedAccum.filter(
(evt) =>
!shouldHideThreadResponseEvent(evt, mutePubkeySet, hideContentMentioningMutedUsers) &&
replyMatchesThreadForList(evt, event, rootInfo, isDiscussionRoot)

7
src/constants.ts

@ -145,6 +145,13 @@ export const MAX_REQ_RELAY_URLS = MAX_CONCURRENT_RELAY_CONNECTIONS @@ -145,6 +145,13 @@ export const MAX_REQ_RELAY_URLS = MAX_CONCURRENT_RELAY_CONNECTIONS
*/
export const RELAY_FILTER_MAX_KINDS_PER_OBJECT = 10
/**
* Maximum NIP-01 filters per REQ (`["REQ", subId, …filters]`). Primal, damus.io, and others return
* NOTICE `bad req: arr too big` when the filter list is long (e.g. replaceable threads with #a + #e
* snapshot + many kind-chunked op-reference filters).
*/
export const RELAY_REQ_MAX_FILTERS_PER_MESSAGE = 10
/** `SimplePool.ensureRelay` WebSocket handshake timeout (parallel multi-relay + slow TLS). */
export const RELAY_POOL_CONNECTION_TIMEOUT_MS = 20_000

18
src/services/client-query.service.ts

@ -8,6 +8,7 @@ import { @@ -8,6 +8,7 @@ import {
MAX_CONCURRENT_RELAY_CONNECTIONS,
MAX_CONCURRENT_SUBS_PER_RELAY,
RELAY_FILTER_MAX_KINDS_PER_OBJECT,
RELAY_REQ_MAX_FILTERS_PER_MESSAGE,
RELAY_POOL_CONNECTION_TIMEOUT_MS,
SEARCHABLE_RELAY_URLS
} from '@/constants'
@ -293,6 +294,23 @@ export class QueryService { @@ -293,6 +294,23 @@ export class QueryService {
): Promise<NEvent[]> {
const sanitizedFilters = sanitizeFiltersBeforeReq(filter)
if (sanitizedFilters.length === 0) return []
const maxFilters = RELAY_REQ_MAX_FILTERS_PER_MESSAGE
if (sanitizedFilters.length > maxFilters) {
const merged: NEvent[] = []
const seen = new Set<string>()
for (let i = 0; i < sanitizedFilters.length; i += maxFilters) {
const slice = sanitizedFilters.slice(i, i + maxFilters)
const part = await this.query(urls, slice, onevent, options)
for (const e of part) {
if (seen.has(e.id)) continue
seen.add(e.id)
merged.push(e)
}
}
return merged
}
/** One chunk → pass a single Filter (compat); several (e.g. kinds split) → full array for WS + HTTP. */
const effectiveFilter: Filter | Filter[] =
sanitizedFilters.length === 1 ? sanitizedFilters[0]! : sanitizedFilters

Loading…
Cancel
Save