diff --git a/src/components/NewNote/EditBox/EditBox.tsx b/src/components/NewNote/EditBox/EditBox.tsx index 953a8a9..14928f8 100644 --- a/src/components/NewNote/EditBox/EditBox.tsx +++ b/src/components/NewNote/EditBox/EditBox.tsx @@ -632,17 +632,21 @@ const EditBox: Component<{ const rep = props.replyToNote; if (rep) { - const rootTag = rep.post.tags.find(t => t[0] === 'e' && t[3] === 'root'); + let rootTag = rep.post.tags.find(t => t[0] === 'e' && t[3] === 'root'); // If the note has a root tag, that meens it is not a root note itself // So we need to copy the `root` tag and add a `reply` tag if (rootTag) { - tags.push([...rootTag]); - tags.push(['e', rep.post.id, '', 'reply']); + const tagWithHint = rootTag.map((v, i) => i === 2 ? + (rep.post.relayHints && rep.post.relayHints[rep.post.id]) || '' : + v, + ); + tags.push([...tagWithHint]); + tags.push(['e', rep.post.id, (rep.post.relayHints && rep.post.relayHints[rep.post.id]) || '', 'reply']); } // Otherwise, add the note as the root tag for this reply else { - tags.push(['e', rep.post.id, '', 'root']); + tags.push(['e', rep.post.id, (rep.post.relayHints && rep.post.relayHints[rep.post.id]) || '', 'root']); } // Copy all `p` tags from the note we are repling to diff --git a/src/constants.ts b/src/constants.ts index 8b4f140..1424dcd 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -138,6 +138,7 @@ export enum Kind { SuggestedUsersByCategory = 10_000_134, UploadChunk = 10_000_135, UserRelays=10_000_139, + RelayHint=10_000_141, WALLET_OPERATION = 10_000_300, } diff --git a/src/contexts/ThreadContext.tsx b/src/contexts/ThreadContext.tsx index 9b64bd2..9e42432 100644 --- a/src/contexts/ThreadContext.tsx +++ b/src/contexts/ThreadContext.tsx @@ -206,6 +206,11 @@ export const ThreadProvider = (props: { children: ContextChildren }) => { setLinkPreviews(() => ({ [data.url]: preview })); return; } + + if (content.kind === Kind.RelayHint) { + const hints = JSON.parse(content.content); + updateStore('page', 'relayHints', (rh) => ({ ...rh, ...hints })); + } }; const savePage = (page: FeedPage) => { diff --git a/src/lib/notes.tsx b/src/lib/notes.tsx index 26c4a1e..8685ef4 100644 --- a/src/lib/notes.tsx +++ b/src/lib/notes.tsx @@ -1,6 +1,6 @@ import { A } from "@solidjs/router"; // @ts-ignore Bad types in nostr-tools -import { Relay } from "nostr-tools"; +import { Relay, relayInit } from "nostr-tools"; import { createStore } from "solid-js/store"; import LinkPreview from "../components/LinkPreview/LinkPreview"; import { appleMusicRegex, emojiRegex, hashtagRegex, interpunctionRegex, Kind, linebreakRegex, lnRegex, mixCloudRegex, nostrNestsRegex, noteRegex, noteRegexLocal, profileRegex, profileRegexG, soundCloudRegex, spotifyRegex, tagMentionRegex, twitchRegex, urlRegex, urlRegexG, wavlakeRegex, youtubeRegex } from "../constants"; @@ -440,7 +440,21 @@ export const sendEvent = async (event: NostrEvent, relays: Relay[], relaySetting let responses = []; let reasons: string[] = []; + // Relay hints fromm `e` tags + const hintRelayUrls = event.tags.reduce((acc, t) => { + if ( + t[0] === 'e' && + t[2].length > 0 && + !relays.find(r => r.url === t[2]) + ) { + return [ ...acc, t[2] ]; + } + + return [...acc]; + }, []); + for (let i = 0;i < relays.length;i++) { + const relay = relays[i]; const settings = (relaySettings && relaySettings[relay.url]) || { read: true, write: true }; @@ -474,6 +488,30 @@ export const sendEvent = async (event: NostrEvent, relays: Relay[], relaySetting })); } + for (let i = 0;i < hintRelayUrls.length;i++) { + const url = hintRelayUrls[i]; + + new Promise(async (resolve, reject) => { + const relay = relayInit(url); + await relay.connect(); + + try { + logInfo('publishing to relay: ', relay) + + await relay.publish(signedNote); + + logInfo(`${relay.url} has accepted our event`); + resolve('success'); + + } catch (e) { + logError(`Failed publishing note to ${relay.url}: `, e); + reject('success'); + } + + relay.close(); + }); + } + try { await Promise.any(responses); diff --git a/src/stores/note.ts b/src/stores/note.ts index 6352909..4a293d6 100644 --- a/src/stores/note.ts +++ b/src/stores/note.ts @@ -1,3 +1,4 @@ +import { propTraps } from "@solid-primitives/props"; import { nip19 } from "nostr-tools"; import { Kind } from "../constants"; import { hexToNpub } from "../lib/keys"; @@ -55,6 +56,7 @@ export const getRepostInfo: RepostInfo = (page, message) => { satszapped: stat?.satszapped || 0, noteId: nip19.noteEncode(message.id), noteActions: (page.noteActions && page.noteActions[message.id]) || noActions, + relayHints: page.relayHints, }, } }; @@ -299,6 +301,7 @@ export const convertToNotes: ConvertToNotes = (page) => { satszapped: stat?.satszapped || 0, noteId: nip19.noteEncode(msg.id), noteActions: (page.noteActions && page.noteActions[msg.id]) ?? noActions, + relayHints: page.relayHints, }, repost, msg, diff --git a/src/types/primal.d.ts b/src/types/primal.d.ts index 075ce9c..c8eb515 100644 --- a/src/types/primal.d.ts +++ b/src/types/primal.d.ts @@ -207,6 +207,13 @@ export type NostrBookmarks = { tags: string[][], }; +export type NostrRelayHint = { + kind: Kind.RelayHint, + content: string, + created_at?: number, + tags: string[][], +}; + export type NostrEventContent = NostrNoteContent | NostrUserContent | @@ -235,7 +242,8 @@ export type NostrEventContent = NostrUserZaps | NostrSuggestedUsers | PrimalUserRelays | - NostrBookmarks; + NostrBookmarks | + NostrRelayHint; export type NostrEvent = [ type: "EVENT", @@ -293,6 +301,7 @@ export type FeedPage = { postStats: NostrPostStats, mentions?: Record, noteActions: Record, + relayHints?: Record, since?: number, until?: number, }; @@ -437,6 +446,7 @@ export type PrimalNoteData = { satszapped: number, noteId: string, noteActions: NoteActions, + relayHints?: Record, } export type PrimalNote = {