fix: ensure events are sent to mentioned users' read relays

This commit is contained in:
codytseng
2025-03-13 12:03:38 +08:00
parent 24a18e4d7a
commit 78caabeafc
7 changed files with 45 additions and 55 deletions

View File

@@ -2,7 +2,6 @@ import { createReactionDraftEvent } from '@/lib/draft-event'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { useNoteStats } from '@/providers/NoteStatsProvider' import { useNoteStats } from '@/providers/NoteStatsProvider'
import client from '@/services/client.service'
import { Heart, Loader } from 'lucide-react' import { Heart, Loader } from 'lucide-react'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
@@ -37,11 +36,8 @@ export default function LikeButton({ event }: { event: Event }) {
if (stats?.likes?.has(pubkey)) return if (stats?.likes?.has(pubkey)) return
} }
const targetRelayList = await client.fetchRelayList(event.pubkey)
const reaction = createReactionDraftEvent(event) const reaction = createReactionDraftEvent(event)
const evt = await publish(reaction, { const evt = await publish(reaction)
additionalRelayUrls: targetRelayList.read.slice(0, 4)
})
updateNoteStatsByEvents([evt]) updateNoteStatsByEvents([evt])
} catch (error) { } catch (error) {
console.error('like failed', error) console.error('like failed', error)

View File

@@ -12,7 +12,6 @@ import { cn } from '@/lib/utils'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { useNoteStats } from '@/providers/NoteStatsProvider' import { useNoteStats } from '@/providers/NoteStatsProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider'
import client from '@/services/client.service'
import { Loader, PencilLine, Repeat } from 'lucide-react' import { Loader, PencilLine, Repeat } from 'lucide-react'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
@@ -53,9 +52,8 @@ export default function RepostButton({ event }: { event: Event }) {
if (stats?.reposts?.has(pubkey)) return if (stats?.reposts?.has(pubkey)) return
} }
const targetRelayList = await client.fetchRelayList(event.pubkey)
const repost = createRepostDraftEvent(event) const repost = createRepostDraftEvent(event)
const evt = await publish(repost, { additionalRelayUrls: targetRelayList.read.slice(0, 5) }) const evt = await publish(repost)
updateNoteStatsByEvents([evt]) updateNoteStatsByEvents([evt])
} catch (error) { } catch (error) {
console.error('repost failed', error) console.error('repost failed', error)

View File

@@ -1,20 +1,17 @@
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { useToast } from '@/hooks/use-toast' import { useToast } from '@/hooks/use-toast'
import { createCommentDraftEvent, createShortTextNoteDraftEvent } from '@/lib/draft-event' import { createCommentDraftEvent, createShortTextNoteDraftEvent } from '@/lib/draft-event'
import { getRootEventTag } from '@/lib/event.ts'
import { generateEventIdFromETag } from '@/lib/tag.ts'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import client from '@/services/client.service'
import postContentCache from '@/services/post-content-cache.service' import postContentCache from '@/services/post-content-cache.service'
import { ChevronDown, ImageUp, LoaderCircle } from 'lucide-react' import { ChevronDown, ImageUp, LoaderCircle } from 'lucide-react'
import { Event, kinds } from 'nostr-tools' import { Event, kinds } from 'nostr-tools'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import TextareaWithMentions from '../TextareaWithMentions.tsx' import TextareaWithMentions from '../TextareaWithMentions'
import Mentions from './Mentions' import Mentions from './Mentions'
import PostOptions from './PostOptions.tsx' import PostOptions from './PostOptions'
import Preview from './Preview' import Preview from './Preview'
import SendOnlyToSwitch from './SendOnlyToSwitch.tsx' import SendOnlyToSwitch from './SendOnlyToSwitch'
import Uploader from './Uploader' import Uploader from './Uploader'
export default function NormalPostContent({ export default function NormalPostContent({
@@ -69,31 +66,6 @@ export default function NormalPostContent({
setPosting(true) setPosting(true)
try { try {
const additionalRelayUrls: string[] = []
if (parentEvent && !specifiedRelayUrls) {
const rootEventTag = getRootEventTag(parentEvent)
if (rootEventTag) {
const [, , , , rootAuthor] = rootEventTag
if (rootAuthor) {
if (rootAuthor !== parentEvent.pubkey) {
const rootAuthorRelayList = await client.fetchRelayList(rootAuthor)
additionalRelayUrls.push(...rootAuthorRelayList.read.slice(0, 4))
}
} else {
const rootEventId = generateEventIdFromETag(rootEventTag)
if (rootEventId) {
const rootEvent = await client.fetchEvent(rootEventId)
if (rootEvent && rootEvent.pubkey !== parentEvent.pubkey) {
const rootAuthorRelayList = await client.fetchRelayList(rootEvent.pubkey)
additionalRelayUrls.push(...rootAuthorRelayList.read.slice(0, 4))
}
}
}
}
const relayList = await client.fetchRelayList(parentEvent.pubkey)
additionalRelayUrls.push(...relayList.read.slice(0, 4))
}
const draftEvent = const draftEvent =
parentEvent && parentEvent.kind !== kinds.ShortTextNote parentEvent && parentEvent.kind !== kinds.ShortTextNote
? await createCommentDraftEvent(content, parentEvent, pictureInfos, mentions, { ? await createCommentDraftEvent(content, parentEvent, pictureInfos, mentions, {
@@ -105,10 +77,7 @@ export default function NormalPostContent({
addClientTag, addClientTag,
protectedEvent: !!specifiedRelayUrls protectedEvent: !!specifiedRelayUrls
}) })
await publish(draftEvent, { await publish(draftEvent, { specifiedRelayUrls })
additionalRelayUrls,
specifiedRelayUrls
})
setContent('') setContent('')
close() close()
} catch (error) { } catch (error) {

View File

@@ -8,10 +8,10 @@ import { ChevronDown, Loader, LoaderCircle, Plus, X } from 'lucide-react'
import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react' import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Image from '../Image' import Image from '../Image'
import TextareaWithMentions from '../TextareaWithMentions.tsx' import TextareaWithMentions from '../TextareaWithMentions'
import Mentions from './Mentions' import Mentions from './Mentions'
import PostOptions from './PostOptions.tsx' import PostOptions from './PostOptions'
import SendOnlyToSwitch from './SendOnlyToSwitch.tsx' import SendOnlyToSwitch from './SendOnlyToSwitch'
import Uploader from './Uploader' import Uploader from './Uploader'
export default function PicturePostContent({ close }: { close: () => void }) { export default function PicturePostContent({ close }: { close: () => void }) {

View File

@@ -1,11 +1,12 @@
import LoginDialog from '@/components/LoginDialog' import LoginDialog from '@/components/LoginDialog'
import { BIG_RELAY_URLS } from '@/constants' import { BIG_RELAY_URLS, COMMENT_EVENT_KIND, PICTURE_EVENT_KIND } from '@/constants'
import { useToast } from '@/hooks' import { useToast } from '@/hooks'
import { import {
getLatestEvent, getLatestEvent,
getProfileFromProfileEvent, getProfileFromProfileEvent,
getRelayListFromRelayListEvent getRelayListFromRelayListEvent
} from '@/lib/event' } from '@/lib/event'
import { isValidPubkey } from '@/lib/pubkey'
import client from '@/services/client.service' import client from '@/services/client.service'
import indexedDb from '@/services/indexed-db.service' import indexedDb from '@/services/indexed-db.service'
import storage from '@/services/local-storage.service' import storage from '@/services/local-storage.service'
@@ -40,10 +41,7 @@ type TNostrContext = {
/** /**
* Default publish the event to current relays, user's write relays and additional relays * Default publish the event to current relays, user's write relays and additional relays
*/ */
publish: ( publish: (draftEvent: TDraftEvent, options?: { specifiedRelayUrls?: string[] }) => Promise<Event>
draftEvent: TDraftEvent,
options?: { additionalRelayUrls?: string[]; specifiedRelayUrls?: string[] }
) => Promise<Event>
signHttpAuth: (url: string, method: string) => Promise<string> signHttpAuth: (url: string, method: string) => Promise<string>
signEvent: (draftEvent: TDraftEvent) => Promise<VerifiedEvent> signEvent: (draftEvent: TDraftEvent) => Promise<VerifiedEvent>
nip04Encrypt: (pubkey: string, plainText: string) => Promise<string> nip04Encrypt: (pubkey: string, plainText: string) => Promise<string>
@@ -372,11 +370,40 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
const publish = async ( const publish = async (
draftEvent: TDraftEvent, draftEvent: TDraftEvent,
{ { specifiedRelayUrls }: { specifiedRelayUrls?: string[] } = {}
additionalRelayUrls,
specifiedRelayUrls
}: { additionalRelayUrls?: string[]; specifiedRelayUrls?: string[] } = {}
) => { ) => {
const additionalRelayUrls: string[] = []
if (
!specifiedRelayUrls?.length &&
[
kinds.ShortTextNote,
kinds.Reaction,
kinds.Repost,
COMMENT_EVENT_KIND,
PICTURE_EVENT_KIND
].includes(draftEvent.kind)
) {
const mentions: string[] = []
draftEvent.tags.forEach(([tagName, tagValue]) => {
if (
['p', 'P'].includes(tagName) &&
!!tagValue &&
isValidPubkey(tagValue) &&
!mentions.includes(tagValue)
) {
mentions.push(tagValue)
}
})
if (mentions.length > 0) {
const relayLists = await Promise.all(
mentions.map((pubkey) => client.fetchRelayList(pubkey))
)
relayLists.forEach((relayList) => {
additionalRelayUrls.push(...relayList.read.slice(0, 4))
})
}
}
const event = await signEvent(draftEvent) const event = await signEvent(draftEvent)
const relays = specifiedRelayUrls?.length const relays = specifiedRelayUrls?.length
? specifiedRelayUrls ? specifiedRelayUrls