diff --git a/src/components/ChatViewer.tsx b/src/components/ChatViewer.tsx index b915946..c5737db 100644 --- a/src/components/ChatViewer.tsx +++ b/src/components/ChatViewer.tsx @@ -31,7 +31,7 @@ import { Nip10Adapter } from "@/lib/chat/adapters/nip-10-adapter"; import { Nip29Adapter } from "@/lib/chat/adapters/nip-29-adapter"; import { Nip53Adapter } from "@/lib/chat/adapters/nip-53-adapter"; import type { ChatProtocolAdapter } from "@/lib/chat/adapters/base-adapter"; -import type { Message, ParticipantRole } from "@/types/chat"; +import type { Message } from "@/types/chat"; import type { ChatAction } from "@/types/chat-actions"; import { parseSlashCommand } from "@/lib/chat/slash-command-parser"; import { @@ -895,29 +895,6 @@ export function ChatViewer({ return participants; } - // NIP-29 groups: use static participants but fallback to message authors if empty - // Some relays may not provide kind 39001/39002 member list events - if (protocol === "nip-29" && messages) { - const staticParticipants = conversation?.participants || []; - - // If we have static participants from member list events, use them as base - // and augment with message authors - const participants: { pubkey: string; role?: ParticipantRole }[] = [ - ...staticParticipants, - ]; - const seen = new Set(staticParticipants.map((p) => p.pubkey)); - - // Add message authors who aren't already in the list as members - for (const msg of messages) { - if (msg.type !== "system" && !seen.has(msg.author)) { - seen.add(msg.author); - participants.push({ pubkey: msg.author, role: "member" }); - } - } - - return participants; - } - // Other protocols: use static participants from conversation return conversation?.participants || []; }, [ diff --git a/src/lib/chat/adapters/nip-29-adapter.ts b/src/lib/chat/adapters/nip-29-adapter.ts index c2c9a99..9cffa60 100644 --- a/src/lib/chat/adapters/nip-29-adapter.ts +++ b/src/lib/chat/adapters/nip-29-adapter.ts @@ -269,11 +269,46 @@ export class Nip29Adapter extends ChatProtocolAdapter { } } - const participants = Array.from(participantsMap.values()); + let participants = Array.from(participantsMap.values()); console.log( `[NIP-29] Found ${participants.length} participants (${adminEvents.length} admin events, ${memberEvents.length} member events)`, ); + + // Fallback: if no member list found, derive participants from recent messages + if (participants.length === 0) { + console.log( + `[NIP-29] No member list found, fetching recent messages for participant fallback`, + ); + + const messagesFilter: Filter = { + kinds: [9], + "#h": [groupId], + limit: 50, + }; + + const recentMessages = await firstValueFrom( + pool + .request([relayUrl], [messagesFilter], { eventStore }) + .pipe(toArray()), + ); + + // Extract unique authors from messages + const messageAuthors = new Set(); + for (const event of recentMessages) { + messageAuthors.add(event.pubkey); + } + + participants = Array.from(messageAuthors).map((pubkey) => ({ + pubkey, + role: "member" as const, + })); + + console.log( + `[NIP-29] Derived ${participants.length} participants from ${recentMessages.length} messages`, + ); + } + console.log( `[NIP-29] Metadata - title: ${title}, icon: ${icon}, description: ${description}`, );