feat: allow changing default relays
This commit is contained in:
parent
36959a1052
commit
53a67d8233
44 changed files with 356 additions and 92 deletions
109
src/components/DefaultRelaysSetting/index.tsx
Normal file
109
src/components/DefaultRelaysSetting/index.tsx
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { Input } from '@/components/ui/input'
|
||||||
|
import { Label } from '@/components/ui/label'
|
||||||
|
import { BIG_RELAY_URLS } from '@/constants'
|
||||||
|
import { isWebsocketUrl, normalizeUrl } from '@/lib/url'
|
||||||
|
import storage from '@/services/local-storage.service'
|
||||||
|
import { CircleX } from 'lucide-react'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import InfoCard from '../InfoCard'
|
||||||
|
import RelayIcon from '../RelayIcon'
|
||||||
|
|
||||||
|
export default function DefaultRelaysSetting() {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const [relayUrls, setRelayUrls] = useState<string[]>(storage.getDefaultRelayUrls())
|
||||||
|
const [newRelayUrl, setNewRelayUrl] = useState('')
|
||||||
|
const [newRelayUrlError, setNewRelayUrlError] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const removeRelayUrl = (url: string) => {
|
||||||
|
const normalizedUrl = normalizeUrl(url)
|
||||||
|
if (!normalizedUrl) return
|
||||||
|
const newUrls = relayUrls.filter((u) => u !== normalizedUrl)
|
||||||
|
setRelayUrls(newUrls)
|
||||||
|
storage.setDefaultRelayUrls(newUrls)
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveNewRelayUrl = () => {
|
||||||
|
if (newRelayUrl === '') return
|
||||||
|
const normalizedUrl = normalizeUrl(newRelayUrl)
|
||||||
|
if (!normalizedUrl) {
|
||||||
|
return setNewRelayUrlError(t('Invalid relay URL'))
|
||||||
|
}
|
||||||
|
if (relayUrls.includes(normalizedUrl)) {
|
||||||
|
return setNewRelayUrlError(t('Relay already exists'))
|
||||||
|
}
|
||||||
|
if (!isWebsocketUrl(normalizedUrl)) {
|
||||||
|
return setNewRelayUrlError(t('invalid relay URL'))
|
||||||
|
}
|
||||||
|
const newUrls = [...relayUrls, normalizedUrl]
|
||||||
|
setRelayUrls(newUrls)
|
||||||
|
storage.setDefaultRelayUrls(newUrls)
|
||||||
|
setNewRelayUrl('')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRelayUrlInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setNewRelayUrl(e.target.value)
|
||||||
|
setNewRelayUrlError(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRelayUrlInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
event.preventDefault()
|
||||||
|
saveNewRelayUrl()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetToDefault = () => {
|
||||||
|
setRelayUrls(BIG_RELAY_URLS)
|
||||||
|
storage.setDefaultRelayUrls(BIG_RELAY_URLS)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label className="text-base font-normal">{t('Default relays')}</Label>
|
||||||
|
<Button variant="outline" size="sm" onClick={resetToDefault}>
|
||||||
|
{t('Reset to default')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-muted-foreground">{t('Default relays description')}</div>
|
||||||
|
<InfoCard variant="alert" title={t('Default relays warning')} />
|
||||||
|
<div className="mt-1">
|
||||||
|
{relayUrls.map((url, index) => (
|
||||||
|
<RelayUrl key={index} url={url} onRemove={() => removeRelayUrl(url)} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 flex gap-2">
|
||||||
|
<Input
|
||||||
|
className={newRelayUrlError ? 'border-destructive' : ''}
|
||||||
|
placeholder={t('Add a new relay')}
|
||||||
|
value={newRelayUrl}
|
||||||
|
onKeyDown={handleRelayUrlInputKeyDown}
|
||||||
|
onChange={handleRelayUrlInputChange}
|
||||||
|
onBlur={saveNewRelayUrl}
|
||||||
|
/>
|
||||||
|
<Button onClick={saveNewRelayUrl}>{t('Add')}</Button>
|
||||||
|
</div>
|
||||||
|
{newRelayUrlError && <div className="text-xs text-destructive mt-1">{newRelayUrlError}</div>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function RelayUrl({ url, onRemove }: { url: string; onRemove: () => void }) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between pl-1 pr-3 py-1">
|
||||||
|
<div className="flex gap-3 items-center flex-1 w-0">
|
||||||
|
<RelayIcon url={url} className="w-4 h-4" />
|
||||||
|
<div className="text-muted-foreground text-sm truncate">{url}</div>
|
||||||
|
</div>
|
||||||
|
<div className="shrink-0">
|
||||||
|
<CircleX
|
||||||
|
size={16}
|
||||||
|
onClick={onRemove}
|
||||||
|
className="text-muted-foreground hover:text-destructive cursor-pointer"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -15,8 +15,9 @@ import {
|
||||||
DrawerTitle,
|
DrawerTitle,
|
||||||
DrawerTrigger
|
DrawerTrigger
|
||||||
} from '@/components/ui/drawer'
|
} from '@/components/ui/drawer'
|
||||||
import { BIG_RELAY_URLS } from '@/constants'
|
import { buildATag } from '@/lib/draft-event'
|
||||||
import { getReplaceableEventIdentifier } from '@/lib/event'
|
import { getReplaceableEventIdentifier } from '@/lib/event'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { tagNameEquals } from '@/lib/tag'
|
import { tagNameEquals } from '@/lib/tag'
|
||||||
import { isWebsocketUrl, simplifyUrl } from '@/lib/url'
|
import { isWebsocketUrl, simplifyUrl } from '@/lib/url'
|
||||||
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
|
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
|
||||||
|
|
@ -29,7 +30,6 @@ import { Event, kinds } from 'nostr-tools'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import RelaySetCard from '../RelaySetCard'
|
import RelaySetCard from '../RelaySetCard'
|
||||||
import { buildATag } from '@/lib/draft-event'
|
|
||||||
|
|
||||||
export default function PullRelaySetsButton() {
|
export default function PullRelaySetsButton() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
@ -94,7 +94,7 @@ function RemoteRelaySets({ close }: { close?: () => void }) {
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
setInitialed(false)
|
setInitialed(false)
|
||||||
const events = await client.fetchEvents(
|
const events = await client.fetchEvents(
|
||||||
(relayList?.write ?? []).concat(BIG_RELAY_URLS).slice(0, 4),
|
(relayList?.write ?? []).concat(getDefaultRelayUrls()).slice(0, 4),
|
||||||
{
|
{
|
||||||
kinds: [kinds.Relaysets],
|
kinds: [kinds.Relaysets],
|
||||||
authors: [pubkey],
|
authors: [pubkey],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { BIG_RELAY_URLS, ExtendedKind, NOTIFICATION_LIST_STYLE } from '@/constants'
|
import { ExtendedKind, NOTIFICATION_LIST_STYLE } from '@/constants'
|
||||||
import { useInfiniteScroll } from '@/hooks'
|
import { useInfiniteScroll } from '@/hooks'
|
||||||
import { compareEvents } from '@/lib/event'
|
import { compareEvents } from '@/lib/event'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { mergeTimelines } from '@/lib/timeline'
|
import { mergeTimelines } from '@/lib/timeline'
|
||||||
import { isTouchDevice } from '@/lib/utils'
|
import { isTouchDevice } from '@/lib/utils'
|
||||||
import { usePrimaryPage } from '@/PageManager'
|
import { usePrimaryPage } from '@/PageManager'
|
||||||
|
|
@ -137,7 +138,7 @@ const NotificationList = forwardRef((_, ref) => {
|
||||||
const { closer, timelineKey } = await client.subscribeTimeline(
|
const { closer, timelineKey } = await client.subscribeTimeline(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
urls: relayList.read.length > 0 ? relayList.read.slice(0, 5) : BIG_RELAY_URLS,
|
urls: relayList.read.length > 0 ? relayList.read.slice(0, 5) : getDefaultRelayUrls(),
|
||||||
filter
|
filter
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import Note from '@/components/Note'
|
import Note from '@/components/Note'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||||
import { BIG_RELAY_URLS } from '@/constants'
|
|
||||||
import {
|
import {
|
||||||
createCommentDraftEvent,
|
createCommentDraftEvent,
|
||||||
createHighlightDraftEvent,
|
createHighlightDraftEvent,
|
||||||
|
|
@ -9,6 +8,7 @@ import {
|
||||||
createShortTextNoteDraftEvent,
|
createShortTextNoteDraftEvent,
|
||||||
deleteDraftEventCache
|
deleteDraftEventCache
|
||||||
} from '@/lib/draft-event'
|
} from '@/lib/draft-event'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { isTouchDevice } from '@/lib/utils'
|
import { isTouchDevice } from '@/lib/utils'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import postEditorCache from '@/services/post-editor-cache.service'
|
import postEditorCache from '@/services/post-editor-cache.service'
|
||||||
|
|
@ -146,7 +146,7 @@ export default function PostContent({
|
||||||
|
|
||||||
const _additionalRelayUrls = [...additionalRelayUrls]
|
const _additionalRelayUrls = [...additionalRelayUrls]
|
||||||
if (parentStuff && typeof parentStuff === 'string') {
|
if (parentStuff && typeof parentStuff === 'string') {
|
||||||
_additionalRelayUrls.push(...BIG_RELAY_URLS)
|
_additionalRelayUrls.push(...getDefaultRelayUrls())
|
||||||
}
|
}
|
||||||
|
|
||||||
const newEvent = await publish(draftEvent, {
|
const newEvent = await publish(draftEvent, {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import KindFilter from '@/components/KindFilter'
|
import KindFilter from '@/components/KindFilter'
|
||||||
import NoteList, { TNoteListRef } from '@/components/NoteList'
|
import NoteList, { TNoteListRef } from '@/components/NoteList'
|
||||||
import Tabs from '@/components/Tabs'
|
import Tabs from '@/components/Tabs'
|
||||||
import { BIG_RELAY_URLS, MAX_PINNED_NOTES, SEARCHABLE_RELAY_URLS } from '@/constants'
|
import { MAX_PINNED_NOTES, SEARCHABLE_RELAY_URLS } from '@/constants'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { generateBech32IdFromETag } from '@/lib/tag'
|
import { generateBech32IdFromETag } from '@/lib/tag'
|
||||||
import { isTouchDevice } from '@/lib/utils'
|
import { isTouchDevice } from '@/lib/utils'
|
||||||
import { useKindFilter } from '@/providers/KindFilterProvider'
|
import { useKindFilter } from '@/providers/KindFilterProvider'
|
||||||
|
|
@ -100,14 +101,14 @@ export default function ProfileFeed({
|
||||||
|
|
||||||
setSubRequests([
|
setSubRequests([
|
||||||
{
|
{
|
||||||
urls: myRelayList.write.concat(BIG_RELAY_URLS).slice(0, 5),
|
urls: myRelayList.write.concat(getDefaultRelayUrls()).slice(0, 5),
|
||||||
filter: {
|
filter: {
|
||||||
authors: [myPubkey],
|
authors: [myPubkey],
|
||||||
'#p': [pubkey]
|
'#p': [pubkey]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
urls: relayList.write.concat(BIG_RELAY_URLS).slice(0, 5),
|
urls: relayList.write.concat(getDefaultRelayUrls()).slice(0, 5),
|
||||||
filter: {
|
filter: {
|
||||||
authors: [pubkey],
|
authors: [pubkey],
|
||||||
'#p': [myPubkey]
|
'#p': [myPubkey]
|
||||||
|
|
@ -134,7 +135,7 @@ export default function ProfileFeed({
|
||||||
} else {
|
} else {
|
||||||
setSubRequests([
|
setSubRequests([
|
||||||
{
|
{
|
||||||
urls: relayList.write.concat(BIG_RELAY_URLS).slice(0, 8),
|
urls: relayList.write.concat(getDefaultRelayUrls()).slice(0, 8),
|
||||||
filter: {
|
filter: {
|
||||||
authors: [pubkey]
|
authors: [pubkey]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants'
|
import { ExtendedKind } from '@/constants'
|
||||||
import { useStuff } from '@/hooks/useStuff'
|
import { useStuff } from '@/hooks/useStuff'
|
||||||
import { getReplaceableCoordinateFromEvent, isReplaceableEvent } from '@/lib/event'
|
import { getReplaceableCoordinateFromEvent, isReplaceableEvent } from '@/lib/event'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
import { TFeedSubRequest } from '@/types'
|
import { TFeedSubRequest } from '@/types'
|
||||||
import { Event, Filter, kinds } from 'nostr-tools'
|
import { Event, Filter, kinds } from 'nostr-tools'
|
||||||
|
|
@ -13,7 +14,7 @@ export default function QuoteList({ stuff }: { stuff: Event | string }) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function init() {
|
async function init() {
|
||||||
const relaySet = new Set(BIG_RELAY_URLS)
|
const relaySet = new Set(getDefaultRelayUrls())
|
||||||
const filters: Filter[] = []
|
const filters: Filter[] = []
|
||||||
if (event) {
|
if (event) {
|
||||||
const relayList = await client.fetchRelayList(event.pubkey)
|
const relayList = await client.fetchRelayList(event.pubkey)
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,11 @@ import {
|
||||||
CarouselNext,
|
CarouselNext,
|
||||||
CarouselPrevious
|
CarouselPrevious
|
||||||
} from '@/components/ui/carousel'
|
} from '@/components/ui/carousel'
|
||||||
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants'
|
import { ExtendedKind } from '@/constants'
|
||||||
import { compareEvents } from '@/lib/event'
|
import { compareEvents } from '@/lib/event'
|
||||||
import { getStarsFromRelayReviewEvent } from '@/lib/event-metadata'
|
import { getStarsFromRelayReviewEvent } from '@/lib/event-metadata'
|
||||||
import { toRelayReviews } from '@/lib/link'
|
import { toRelayReviews } from '@/lib/link'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { cn, isTouchDevice } from '@/lib/utils'
|
import { cn, isTouchDevice } from '@/lib/utils'
|
||||||
import { useMuteList } from '@/providers/MuteListProvider'
|
import { useMuteList } from '@/providers/MuteListProvider'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
|
|
@ -60,7 +61,7 @@ export default function RelayReviewsPreview({ relayUrl }: { relayUrl: string })
|
||||||
if (pubkey) {
|
if (pubkey) {
|
||||||
filters.push({ kinds: [ExtendedKind.RELAY_REVIEW], authors: [pubkey], '#d': [relayUrl] })
|
filters.push({ kinds: [ExtendedKind.RELAY_REVIEW], authors: [pubkey], '#d': [relayUrl] })
|
||||||
}
|
}
|
||||||
const events = await client.fetchEvents([relayUrl, ...BIG_RELAY_URLS], filters, {
|
const events = await client.fetchEvents([relayUrl, ...getDefaultRelayUrls()], filters, {
|
||||||
cache: true
|
cache: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { BIG_RELAY_URLS, SEARCHABLE_RELAY_URLS } from '@/constants'
|
import { SEARCHABLE_RELAY_URLS } from '@/constants'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { TSearchParams } from '@/types'
|
import { TSearchParams } from '@/types'
|
||||||
import NormalFeed from '../NormalFeed'
|
import NormalFeed from '../NormalFeed'
|
||||||
import Profile from '../Profile'
|
import Profile from '../Profile'
|
||||||
|
|
@ -27,7 +28,7 @@ export default function SearchResult({ searchParams }: { searchParams: TSearchPa
|
||||||
if (searchParams.type === 'hashtag') {
|
if (searchParams.type === 'hashtag') {
|
||||||
return (
|
return (
|
||||||
<NormalFeed
|
<NormalFeed
|
||||||
subRequests={[{ urls: BIG_RELAY_URLS, filter: { '#t': [searchParams.search] } }]}
|
subRequests={[{ urls: getDefaultRelayUrls(), filter: { '#t': [searchParams.search] } }]}
|
||||||
showRelayCloseReason
|
showRelayCloseReason
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import { Drawer, DrawerContent, DrawerOverlay } from '@/components/ui/drawer'
|
import { Drawer, DrawerContent, DrawerOverlay } from '@/components/ui/drawer'
|
||||||
import { Popover, PopoverAnchor, PopoverContent } from '@/components/ui/popover'
|
import { Popover, PopoverAnchor, PopoverContent } from '@/components/ui/popover'
|
||||||
import { BIG_RELAY_URLS, LONG_PRESS_THRESHOLD } from '@/constants'
|
import { LONG_PRESS_THRESHOLD } from '@/constants'
|
||||||
import { useStuff } from '@/hooks/useStuff'
|
import { useStuff } from '@/hooks/useStuff'
|
||||||
import { useStuffStatsById } from '@/hooks/useStuffStatsById'
|
import { useStuffStatsById } from '@/hooks/useStuffStatsById'
|
||||||
import {
|
import {
|
||||||
createExternalContentReactionDraftEvent,
|
createExternalContentReactionDraftEvent,
|
||||||
createReactionDraftEvent
|
createReactionDraftEvent
|
||||||
} from '@/lib/draft-event'
|
} from '@/lib/draft-event'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
||||||
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
|
|
@ -79,7 +80,7 @@ export default function LikeButton({ stuff }: { stuff: Event | string }) {
|
||||||
const reaction = event
|
const reaction = event
|
||||||
? createReactionDraftEvent(event, emoji)
|
? createReactionDraftEvent(event, emoji)
|
||||||
: createExternalContentReactionDraftEvent(externalContent, emoji)
|
: createExternalContentReactionDraftEvent(externalContent, emoji)
|
||||||
const seenOn = event ? client.getSeenEventRelayUrls(event.id) : BIG_RELAY_URLS
|
const seenOn = event ? client.getSeenEventRelayUrls(event.id) : getDefaultRelayUrls()
|
||||||
const evt = await publish(reaction, { additionalRelayUrls: seenOn })
|
const evt = await publish(reaction, { additionalRelayUrls: seenOn })
|
||||||
stuffStatsService.updateStuffStatsByEvents([evt])
|
stuffStatsService.updateStuffStatsByEvents([evt])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area'
|
import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area'
|
||||||
import { BIG_RELAY_URLS } from '@/constants'
|
|
||||||
import { useStuffStatsById } from '@/hooks/useStuffStatsById'
|
|
||||||
import { useStuff } from '@/hooks/useStuff'
|
import { useStuff } from '@/hooks/useStuff'
|
||||||
|
import { useStuffStatsById } from '@/hooks/useStuffStatsById'
|
||||||
import {
|
import {
|
||||||
createExternalContentReactionDraftEvent,
|
createExternalContentReactionDraftEvent,
|
||||||
createReactionDraftEvent
|
createReactionDraftEvent
|
||||||
} from '@/lib/draft-event'
|
} from '@/lib/draft-event'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
|
|
@ -53,7 +53,7 @@ export default function Likes({ stuff }: { stuff: Event | string }) {
|
||||||
const reaction = event
|
const reaction = event
|
||||||
? createReactionDraftEvent(event, emoji)
|
? createReactionDraftEvent(event, emoji)
|
||||||
: createExternalContentReactionDraftEvent(externalContent, emoji)
|
: createExternalContentReactionDraftEvent(externalContent, emoji)
|
||||||
const seenOn = event ? client.getSeenEventRelayUrls(event.id) : BIG_RELAY_URLS
|
const seenOn = event ? client.getSeenEventRelayUrls(event.id) : getDefaultRelayUrls()
|
||||||
const evt = await publish(reaction, { additionalRelayUrls: seenOn })
|
const evt = await publish(reaction, { additionalRelayUrls: seenOn })
|
||||||
stuffStatsService.updateStuffStatsByEvents([evt])
|
stuffStatsService.updateStuffStatsByEvents([evt])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ export const StorageKey = {
|
||||||
NSFW_DISPLAY_POLICY: 'nsfwDisplayPolicy',
|
NSFW_DISPLAY_POLICY: 'nsfwDisplayPolicy',
|
||||||
MIN_TRUST_SCORE: 'minTrustScore',
|
MIN_TRUST_SCORE: 'minTrustScore',
|
||||||
ENABLE_LIVE_FEED: 'enableLiveFeed',
|
ENABLE_LIVE_FEED: 'enableLiveFeed',
|
||||||
|
DEFAULT_RELAY_URLS: 'defaultRelayUrls',
|
||||||
HIDE_UNTRUSTED_NOTES: 'hideUntrustedNotes', // deprecated
|
HIDE_UNTRUSTED_NOTES: 'hideUntrustedNotes', // deprecated
|
||||||
HIDE_UNTRUSTED_INTERACTIONS: 'hideUntrustedInteractions', // deprecated
|
HIDE_UNTRUSTED_INTERACTIONS: 'hideUntrustedInteractions', // deprecated
|
||||||
HIDE_UNTRUSTED_NOTIFICATIONS: 'hideUntrustedNotifications', // deprecated
|
HIDE_UNTRUSTED_NOTIFICATIONS: 'hideUntrustedNotifications', // deprecated
|
||||||
|
|
|
||||||
|
|
@ -653,6 +653,11 @@ export default {
|
||||||
'trust-filter.trust-score-description': 'محسوبة بناءً على سمعة المستخدم والنسبة المئوية للشبكة الاجتماعية',
|
'trust-filter.trust-score-description': 'محسوبة بناءً على سمعة المستخدم والنسبة المئوية للشبكة الاجتماعية',
|
||||||
'Auto-load profile pictures': 'تحميل صور الملف الشخصي تلقائيًا',
|
'Auto-load profile pictures': 'تحميل صور الملف الشخصي تلقائيًا',
|
||||||
'Disable live feed': 'تعطيل التغذية المباشرة',
|
'Disable live feed': 'تعطيل التغذية المباشرة',
|
||||||
'Enable live feed': 'تفعيل التغذية المباشرة'
|
'Enable live feed': 'تفعيل التغذية المباشرة',
|
||||||
|
'Default relays': 'المرحلات الافتراضية',
|
||||||
|
'Reset to default': 'إعادة تعيين إلى الافتراضي',
|
||||||
|
'Default relays description': 'تُستخدم للاستعلام عن تكوينات المرحلات للمستخدمين الآخرين وكبديل احتياطي عندما لا يكون لدى المستخدمين مرحلات مكوّنة.',
|
||||||
|
'Default relays warning': 'تحذير: يرجى عدم تعديل هذه الإعدادات بشكل عشوائي، فقد يؤثر ذلك على تجربتك الأساسية.',
|
||||||
|
'Invalid relay URL': 'عنوان URL للمرحل غير صالح'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -675,6 +675,11 @@ export default {
|
||||||
'Berechnet basierend auf Benutzerreputation und sozialem Netzwerk-Perzentil',
|
'Berechnet basierend auf Benutzerreputation und sozialem Netzwerk-Perzentil',
|
||||||
'Auto-load profile pictures': 'Profilbilder automatisch laden',
|
'Auto-load profile pictures': 'Profilbilder automatisch laden',
|
||||||
'Disable live feed': 'Live-Feed deaktivieren',
|
'Disable live feed': 'Live-Feed deaktivieren',
|
||||||
'Enable live feed': 'Live-Feed aktivieren'
|
'Enable live feed': 'Live-Feed aktivieren',
|
||||||
|
'Default relays': 'Standard-Relays',
|
||||||
|
'Reset to default': 'Auf Standard zurücksetzen',
|
||||||
|
'Default relays description': 'Werden verwendet, um die Relay-Konfigurationen anderer Benutzer abzufragen und als Fallback, wenn Benutzer keine Relays konfiguriert haben.',
|
||||||
|
'Default relays warning': 'Warnung: Ändern Sie diese Einstellungen nicht leichtfertig, da dies Ihre grundlegende Erfahrung beeinträchtigen kann.',
|
||||||
|
'Invalid relay URL': 'Ungültige Relay-URL'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -658,6 +658,11 @@ export default {
|
||||||
'trust-filter.trust-score-description': 'Calculated based on user reputation and social network percentile',
|
'trust-filter.trust-score-description': 'Calculated based on user reputation and social network percentile',
|
||||||
'Auto-load profile pictures': 'Auto-load profile pictures',
|
'Auto-load profile pictures': 'Auto-load profile pictures',
|
||||||
'Disable live feed': 'Disable live feed',
|
'Disable live feed': 'Disable live feed',
|
||||||
'Enable live feed': 'Enable live feed'
|
'Enable live feed': 'Enable live feed',
|
||||||
|
'Default relays': 'Default relays',
|
||||||
|
'Reset to default': 'Reset to default',
|
||||||
|
'Default relays description': 'Used to query other users\' relay configurations and as a fallback when users have no relays configured.',
|
||||||
|
'Default relays warning': 'Warning: Please do not modify these settings casually, as it may affect your basic experience.',
|
||||||
|
'Invalid relay URL': 'Invalid relay URL'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -669,6 +669,11 @@ export default {
|
||||||
'Calculado según la reputación del usuario y el percentil de la red social',
|
'Calculado según la reputación del usuario y el percentil de la red social',
|
||||||
'Auto-load profile pictures': 'Cargar imágenes de perfil automáticamente',
|
'Auto-load profile pictures': 'Cargar imágenes de perfil automáticamente',
|
||||||
'Disable live feed': 'Desactivar feed en vivo',
|
'Disable live feed': 'Desactivar feed en vivo',
|
||||||
'Enable live feed': 'Activar feed en vivo'
|
'Enable live feed': 'Activar feed en vivo',
|
||||||
|
'Default relays': 'Relés predeterminados',
|
||||||
|
'Reset to default': 'Restablecer valores predeterminados',
|
||||||
|
'Default relays description': 'Se utilizan para consultar las configuraciones de relés de otros usuarios y como respaldo cuando los usuarios no tienen relés configurados.',
|
||||||
|
'Default relays warning': 'Advertencia: No modifiques estas configuraciones a la ligera, ya que puede afectar tu experiencia básica.',
|
||||||
|
'Invalid relay URL': 'URL de relé no válida'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -665,6 +665,11 @@ export default {
|
||||||
'بر اساس شهرت کاربر و صدک شبکه اجتماعی محاسبه میشود',
|
'بر اساس شهرت کاربر و صدک شبکه اجتماعی محاسبه میشود',
|
||||||
'Auto-load profile pictures': 'بارگذاری خودکار تصاویر پروفایل',
|
'Auto-load profile pictures': 'بارگذاری خودکار تصاویر پروفایل',
|
||||||
'Disable live feed': 'غیرفعال کردن فید زنده',
|
'Disable live feed': 'غیرفعال کردن فید زنده',
|
||||||
'Enable live feed': 'فعال کردن فید زنده'
|
'Enable live feed': 'فعال کردن فید زنده',
|
||||||
|
'Default relays': 'رلههای پیشفرض',
|
||||||
|
'Reset to default': 'بازنشانی به پیشفرض',
|
||||||
|
'Default relays description': 'برای پرسوجو از پیکربندیهای رله کاربران دیگر و به عنوان جایگزین زمانی که کاربران رله پیکربندی نکردهاند استفاده میشود.',
|
||||||
|
'Default relays warning': 'هشدار: لطفاً این تنظیمات را به صورت تصادفی تغییر ندهید، ممکن است بر تجربه اولیه شما تأثیر بگذارد.',
|
||||||
|
'Invalid relay URL': 'آدرس URL رله نامعتبر است'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -673,6 +673,11 @@ export default {
|
||||||
"Calculé en fonction de la réputation et du réseau social de l'utilisateur",
|
"Calculé en fonction de la réputation et du réseau social de l'utilisateur",
|
||||||
'Auto-load profile pictures': 'Charger les images de profil automatiquement',
|
'Auto-load profile pictures': 'Charger les images de profil automatiquement',
|
||||||
'Disable live feed': 'Désactiver le flux en direct',
|
'Disable live feed': 'Désactiver le flux en direct',
|
||||||
'Enable live feed': 'Activer le flux en direct'
|
'Enable live feed': 'Activer le flux en direct',
|
||||||
|
'Default relays': 'Relais par défaut',
|
||||||
|
'Reset to default': 'Réinitialiser par défaut',
|
||||||
|
'Default relays description': 'Utilisés pour interroger les configurations de relais d\'autres utilisateurs et comme solution de secours lorsque les utilisateurs n\'ont pas de relais configurés.',
|
||||||
|
'Default relays warning': 'Attention : Ne modifiez pas ces paramètres à la légère, car cela pourrait affecter votre expérience de base.',
|
||||||
|
'Invalid relay URL': 'URL de relais non valide'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -665,6 +665,11 @@ export default {
|
||||||
'उपयोगकर्ता की प्रतिष्ठा और सामाजिक नेटवर्क प्रतिशतक के आधार पर गणना की गई',
|
'उपयोगकर्ता की प्रतिष्ठा और सामाजिक नेटवर्क प्रतिशतक के आधार पर गणना की गई',
|
||||||
'Auto-load profile pictures': 'प्रोफ़ाइल चित्र स्वतः लोड करें',
|
'Auto-load profile pictures': 'प्रोफ़ाइल चित्र स्वतः लोड करें',
|
||||||
'Disable live feed': 'लाइव फ़ीड अक्षम करें',
|
'Disable live feed': 'लाइव फ़ीड अक्षम करें',
|
||||||
'Enable live feed': 'लाइव फ़ीड सक्षम करें'
|
'Enable live feed': 'लाइव फ़ीड सक्षम करें',
|
||||||
|
'Default relays': 'डिफ़ॉल्ट रिले',
|
||||||
|
'Reset to default': 'डिफ़ॉल्ट पर रीसेट करें',
|
||||||
|
'Default relays description': 'अन्य उपयोगकर्ताओं के रिले कॉन्फ़िगरेशन की जांच करने के लिए उपयोग किया जाता है और जब उपयोगकर्ताओं के पास रिले कॉन्फ़िगर नहीं है तो फ़ॉलबैक के रूप में।',
|
||||||
|
'Default relays warning': 'चेतावनी: कृपया इन सेटिंग्स को बेतरतीब ढंग से संशोधित न करें, क्योंकि यह आपके बुनियादी अनुभव को प्रभावित कर सकता है।',
|
||||||
|
'Invalid relay URL': 'अमान्य रिले URL'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -658,6 +658,11 @@ export default {
|
||||||
'A felhasználó hírneve és a közösségi hálózat percentilise alapján számítva',
|
'A felhasználó hírneve és a közösségi hálózat percentilise alapján számítva',
|
||||||
'Auto-load profile pictures': 'Profilképek automatikus betöltése',
|
'Auto-load profile pictures': 'Profilképek automatikus betöltése',
|
||||||
'Disable live feed': 'Élő hírfolyam letiltása',
|
'Disable live feed': 'Élő hírfolyam letiltása',
|
||||||
'Enable live feed': 'Élő hírfolyam engedélyezése'
|
'Enable live feed': 'Élő hírfolyam engedélyezése',
|
||||||
|
'Default relays': 'Alapértelmezett továbbítók',
|
||||||
|
'Reset to default': 'Visszaállítás alapértelmezettre',
|
||||||
|
'Default relays description': 'Más felhasználók továbbító konfigurációinak lekérdezésére használatos, és tartalékként szolgál, ha a felhasználóknak nincsenek továbbítóik beállítva.',
|
||||||
|
'Default relays warning': 'Figyelmeztetés: Ne módosítsa ezeket a beállításokat meggondolatlanul, mert ez befolyásolhatja az alapvető élményt.',
|
||||||
|
'Invalid relay URL': 'Érvénytelen továbbító URL'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -669,6 +669,11 @@ export default {
|
||||||
"Calcolato in base alla reputazione dell'utente e al percentile del social network",
|
"Calcolato in base alla reputazione dell'utente e al percentile del social network",
|
||||||
'Auto-load profile pictures': 'Caricamento automatico immagini di profilo',
|
'Auto-load profile pictures': 'Caricamento automatico immagini di profilo',
|
||||||
'Disable live feed': 'Disattiva feed live',
|
'Disable live feed': 'Disattiva feed live',
|
||||||
'Enable live feed': 'Attiva feed live'
|
'Enable live feed': 'Attiva feed live',
|
||||||
|
'Default relays': 'Relay predefiniti',
|
||||||
|
'Reset to default': 'Ripristina predefiniti',
|
||||||
|
'Default relays description': 'Utilizzati per interrogare le configurazioni dei relay di altri utenti e come fallback quando gli utenti non hanno relay configurati.',
|
||||||
|
'Default relays warning': 'Attenzione: Non modificare queste impostazioni alla leggera, potrebbe influire sull\'esperienza di base.',
|
||||||
|
'Invalid relay URL': 'URL relay non valido'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -663,6 +663,11 @@ export default {
|
||||||
'ユーザーの評判とソーシャルネットワークに基づいて信頼度パーセンタイルを計算',
|
'ユーザーの評判とソーシャルネットワークに基づいて信頼度パーセンタイルを計算',
|
||||||
'Auto-load profile pictures': 'プロフィール画像を自動読み込み',
|
'Auto-load profile pictures': 'プロフィール画像を自動読み込み',
|
||||||
'Disable live feed': 'ライブフィードを無効にする',
|
'Disable live feed': 'ライブフィードを無効にする',
|
||||||
'Enable live feed': 'ライブフィードを有効にする'
|
'Enable live feed': 'ライブフィードを有効にする',
|
||||||
|
'Default relays': 'デフォルトリレー',
|
||||||
|
'Reset to default': 'デフォルトにリセット',
|
||||||
|
'Default relays description': '他のユーザーのリレー設定を照会するために使用され、ユーザーがリレーを設定していない場合のフォールバックとして機能します。',
|
||||||
|
'Default relays warning': '警告:これらの設定を無闇に変更しないでください。基本的な体験に影響を与える可能性があります。',
|
||||||
|
'Invalid relay URL': '無効なリレーURL'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -658,6 +658,11 @@ export default {
|
||||||
'trust-filter.trust-score-description': '사용자의 평판과 소셜 네트워크를 기반으로 신뢰도 백분위수 계산',
|
'trust-filter.trust-score-description': '사용자의 평판과 소셜 네트워크를 기반으로 신뢰도 백분위수 계산',
|
||||||
'Auto-load profile pictures': '프로필 사진 자동 로드',
|
'Auto-load profile pictures': '프로필 사진 자동 로드',
|
||||||
'Disable live feed': '라이브 피드 비활성화',
|
'Disable live feed': '라이브 피드 비활성화',
|
||||||
'Enable live feed': '라이브 피드 활성화'
|
'Enable live feed': '라이브 피드 활성화',
|
||||||
|
'Default relays': '기본 릴레이',
|
||||||
|
'Reset to default': '기본값으로 재설정',
|
||||||
|
'Default relays description': '다른 사용자의 릴레이 구성을 조회하는 데 사용되며, 사용자가 릴레이를 구성하지 않은 경우 대체 수단으로 사용됩니다.',
|
||||||
|
'Default relays warning': '경고: 이러한 설정을 임의로 수정하지 마십시오. 기본 경험에 영향을 줄 수 있습니다.',
|
||||||
|
'Invalid relay URL': '유효하지 않은 릴레이 URL'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -670,6 +670,11 @@ export default {
|
||||||
'Obliczany na podstawie reputacji użytkownika i percentyla sieci społecznościowej',
|
'Obliczany na podstawie reputacji użytkownika i percentyla sieci społecznościowej',
|
||||||
'Auto-load profile pictures': 'Automatyczne ładowanie zdjęć profilowych',
|
'Auto-load profile pictures': 'Automatyczne ładowanie zdjęć profilowych',
|
||||||
'Disable live feed': 'Wyłącz kanał na żywo',
|
'Disable live feed': 'Wyłącz kanał na żywo',
|
||||||
'Enable live feed': 'Włącz kanał na żywo'
|
'Enable live feed': 'Włącz kanał na żywo',
|
||||||
|
'Default relays': 'Domyślne przekaźniki',
|
||||||
|
'Reset to default': 'Przywróć domyślne',
|
||||||
|
'Default relays description': 'Używane do odpytywania konfiguracji przekaźników innych użytkowników i jako rozwiązanie awaryjne, gdy użytkownicy nie mają skonfigurowanych przekaźników.',
|
||||||
|
'Default relays warning': 'Ostrzeżenie: Nie modyfikuj tych ustawień pochopnie, może to wpłynąć na podstawowe doświadczenie.',
|
||||||
|
'Invalid relay URL': 'Nieprawidłowy adres URL przekaźnika'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -666,6 +666,11 @@ export default {
|
||||||
'Calculado com base na reputação do usuário e no percentil da rede social',
|
'Calculado com base na reputação do usuário e no percentil da rede social',
|
||||||
'Auto-load profile pictures': 'Carregar fotos de perfil automaticamente',
|
'Auto-load profile pictures': 'Carregar fotos de perfil automaticamente',
|
||||||
'Disable live feed': 'Desativar feed ao vivo',
|
'Disable live feed': 'Desativar feed ao vivo',
|
||||||
'Enable live feed': 'Ativar feed ao vivo'
|
'Enable live feed': 'Ativar feed ao vivo',
|
||||||
|
'Default relays': 'Relays padrão',
|
||||||
|
'Reset to default': 'Redefinir para padrão',
|
||||||
|
'Default relays description': 'Usados para consultar as configurações de relays de outros usuários e como alternativa quando os usuários não têm relays configurados.',
|
||||||
|
'Default relays warning': 'Aviso: Não modifique essas configurações casualmente, pois pode afetar sua experiência básica.',
|
||||||
|
'Invalid relay URL': 'URL de relay inválida'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -669,6 +669,11 @@ export default {
|
||||||
'Calculado com base na reputação do utilizador e no percentil da rede social',
|
'Calculado com base na reputação do utilizador e no percentil da rede social',
|
||||||
'Auto-load profile pictures': 'Carregar fotos de perfil automaticamente',
|
'Auto-load profile pictures': 'Carregar fotos de perfil automaticamente',
|
||||||
'Disable live feed': 'Desativar feed ao vivo',
|
'Disable live feed': 'Desativar feed ao vivo',
|
||||||
'Enable live feed': 'Ativar feed ao vivo'
|
'Enable live feed': 'Ativar feed ao vivo',
|
||||||
|
'Default relays': 'Relays predefinidos',
|
||||||
|
'Reset to default': 'Repor predefinições',
|
||||||
|
'Default relays description': 'Utilizados para consultar as configurações de relays de outros utilizadores e como alternativa quando os utilizadores não têm relays configurados.',
|
||||||
|
'Default relays warning': 'Aviso: Não modifique estas configurações casualmente, pois pode afetar a sua experiência básica.',
|
||||||
|
'Invalid relay URL': 'URL de relay inválido'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -669,6 +669,11 @@ export default {
|
||||||
'Рассчитывается на основе репутации пользователя и процентиля социальной сети',
|
'Рассчитывается на основе репутации пользователя и процентиля социальной сети',
|
||||||
'Auto-load profile pictures': 'Автозагрузка аватаров',
|
'Auto-load profile pictures': 'Автозагрузка аватаров',
|
||||||
'Disable live feed': 'Отключить прямую трансляцию',
|
'Disable live feed': 'Отключить прямую трансляцию',
|
||||||
'Enable live feed': 'Включить прямую трансляцию'
|
'Enable live feed': 'Включить прямую трансляцию',
|
||||||
|
'Default relays': 'Реле по умолчанию',
|
||||||
|
'Reset to default': 'Сбросить по умолчанию',
|
||||||
|
'Default relays description': 'Используются для запроса конфигураций реле других пользователей и в качестве резервного варианта, когда у пользователей не настроены реле.',
|
||||||
|
'Default relays warning': 'Предупреждение: Не изменяйте эти настройки без необходимости, это может повлиять на базовый опыт использования.',
|
||||||
|
'Invalid relay URL': 'Неверный URL реле'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -655,6 +655,11 @@ export default {
|
||||||
'คำนวณจากชื่อเสียงของผู้ใช้และเปอร์เซ็นไทล์ของเครือข่ายสังคม',
|
'คำนวณจากชื่อเสียงของผู้ใช้และเปอร์เซ็นไทล์ของเครือข่ายสังคม',
|
||||||
'Auto-load profile pictures': 'โหลดรูปโปรไฟล์อัตโนมัติ',
|
'Auto-load profile pictures': 'โหลดรูปโปรไฟล์อัตโนมัติ',
|
||||||
'Disable live feed': 'ปิดฟีดสด',
|
'Disable live feed': 'ปิดฟีดสด',
|
||||||
'Enable live feed': 'เปิดฟีดสด'
|
'Enable live feed': 'เปิดฟีดสด',
|
||||||
|
'Default relays': 'รีเลย์เริ่มต้น',
|
||||||
|
'Reset to default': 'รีเซ็ตเป็นค่าเริ่มต้น',
|
||||||
|
'Default relays description': 'ใช้สำหรับสอบถามการกำหนดค่ารีเลย์ของผู้ใช้อื่นและเป็นทางเลือกสำรองเมื่อผู้ใช้ไม่ได้กำหนดค่ารีเลย์',
|
||||||
|
'Default relays warning': 'คำเตือน: กรุณาอย่าแก้ไขการตั้งค่าเหล่านี้โดยไม่ระมัดระวัง เพราะอาจส่งผลต่อประสบการณ์พื้นฐานของคุณ',
|
||||||
|
'Invalid relay URL': 'URL รีเลย์ไม่ถูกต้อง'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -638,6 +638,11 @@ export default {
|
||||||
'trust-filter.trust-score-description': '基於使用者的聲譽和社交網路計算信任度百分位',
|
'trust-filter.trust-score-description': '基於使用者的聲譽和社交網路計算信任度百分位',
|
||||||
'Auto-load profile pictures': '自動載入大頭照',
|
'Auto-load profile pictures': '自動載入大頭照',
|
||||||
'Disable live feed': '停用即時推送',
|
'Disable live feed': '停用即時推送',
|
||||||
'Enable live feed': '啟用即時推送'
|
'Enable live feed': '啟用即時推送',
|
||||||
|
'Default relays': '預設中繼',
|
||||||
|
'Reset to default': '重置為預設',
|
||||||
|
'Default relays description': '用於查詢其他使用者的中繼配置,並在使用者沒有配置中繼時作為回退策略。',
|
||||||
|
'Default relays warning': '警告:請不要隨意修改這些設定,可能會影響基礎體驗。',
|
||||||
|
'Invalid relay URL': '無效的中繼地址'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -643,6 +643,11 @@ export default {
|
||||||
'trust-filter.trust-score-description': '基于用户的声誉和社交网络计算信任度百分位',
|
'trust-filter.trust-score-description': '基于用户的声誉和社交网络计算信任度百分位',
|
||||||
'Auto-load profile pictures': '自动加载头像',
|
'Auto-load profile pictures': '自动加载头像',
|
||||||
'Disable live feed': '禁用实时推送',
|
'Disable live feed': '禁用实时推送',
|
||||||
'Enable live feed': '启用实时推送'
|
'Enable live feed': '启用实时推送',
|
||||||
|
'Default relays': '默认中继',
|
||||||
|
'Reset to default': '重置为默认',
|
||||||
|
'Default relays description': '用于查询其他用户的中继配置,并在用户没有配置中继时作为回退策略。',
|
||||||
|
'Default relays warning': '警告:请不要随意修改这些设置,可能会影响基础体验。',
|
||||||
|
'Invalid relay URL': '无效的中继地址'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { BIG_RELAY_URLS, MAX_PINNED_NOTES, POLL_TYPE } from '@/constants'
|
import { MAX_PINNED_NOTES, POLL_TYPE } from '@/constants'
|
||||||
import { TEmoji, TPollType, TRelayList, TRelaySet } from '@/types'
|
import { TEmoji, TPollType, TRelayList, TRelaySet } from '@/types'
|
||||||
import { Event, kinds } from 'nostr-tools'
|
import { Event, kinds } from 'nostr-tools'
|
||||||
import { buildATag } from './draft-event'
|
import { buildATag } from './draft-event'
|
||||||
import { getReplaceableEventIdentifier } from './event'
|
import { getReplaceableEventIdentifier } from './event'
|
||||||
import { getAmountFromInvoice, getLightningAddressFromProfile } from './lightning'
|
import { getAmountFromInvoice, getLightningAddressFromProfile } from './lightning'
|
||||||
import { formatPubkey, isValidPubkey, pubkeyToNpub } from './pubkey'
|
import { formatPubkey, isValidPubkey, pubkeyToNpub } from './pubkey'
|
||||||
|
import { getDefaultRelayUrls } from './relay'
|
||||||
import { generateBech32IdFromETag, getEmojiInfosFromEmojiTags, tagNameEquals } from './tag'
|
import { generateBech32IdFromETag, getEmojiInfosFromEmojiTags, tagNameEquals } from './tag'
|
||||||
import { isOnionUrl, isWebsocketUrl, normalizeHttpUrl, normalizeUrl } from './url'
|
import { isOnionUrl, isWebsocketUrl, normalizeHttpUrl, normalizeUrl } from './url'
|
||||||
|
|
||||||
|
|
@ -12,8 +13,10 @@ export function getRelayListFromEvent(
|
||||||
event?: Event | null,
|
event?: Event | null,
|
||||||
filterOutOnionRelays: boolean = true
|
filterOutOnionRelays: boolean = true
|
||||||
): TRelayList {
|
): TRelayList {
|
||||||
|
const defaultRelays = getDefaultRelayUrls()
|
||||||
|
|
||||||
if (!event) {
|
if (!event) {
|
||||||
return { write: BIG_RELAY_URLS, read: BIG_RELAY_URLS, originalRelays: [] }
|
return { write: defaultRelays, read: defaultRelays, originalRelays: [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
const relayList = { write: [], read: [], originalRelays: [] } as TRelayList
|
const relayList = { write: [], read: [], originalRelays: [] } as TRelayList
|
||||||
|
|
@ -38,11 +41,11 @@ export function getRelayListFromEvent(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// If there are too many relays, use the default BIG_RELAY_URLS
|
// If there are too many relays, use the default relays
|
||||||
// Because they don't know anything about relays, their settings cannot be trusted
|
// Because they don't know anything about relays, their settings cannot be trusted
|
||||||
return {
|
return {
|
||||||
write: relayList.write.length && relayList.write.length <= 8 ? relayList.write : BIG_RELAY_URLS,
|
write: relayList.write.length && relayList.write.length <= 8 ? relayList.write : defaultRelays,
|
||||||
read: relayList.read.length && relayList.write.length <= 8 ? relayList.read : BIG_RELAY_URLS,
|
read: relayList.read.length && relayList.write.length <= 8 ? relayList.read : defaultRelays,
|
||||||
originalRelays: relayList.originalRelays
|
originalRelays: relayList.originalRelays
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
import { BIG_RELAY_URLS } from '@/constants'
|
import storage from '@/services/local-storage.service'
|
||||||
import { TRelayInfo } from '@/types'
|
import { TRelayInfo } from '@/types'
|
||||||
|
|
||||||
|
export function getDefaultRelayUrls() {
|
||||||
|
return storage.getDefaultRelayUrls()
|
||||||
|
}
|
||||||
|
|
||||||
export function checkAlgoRelay(relayInfo: TRelayInfo | undefined) {
|
export function checkAlgoRelay(relayInfo: TRelayInfo | undefined) {
|
||||||
return relayInfo?.software === 'https://github.com/bitvora/algo-relay' // hardcode for now
|
return relayInfo?.software === 'https://github.com/bitvora/algo-relay' // hardcode for now
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +18,8 @@ export function checkNip43Support(relayInfo: TRelayInfo | undefined) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function filterOutBigRelays(relayUrls: string[]) {
|
export function filterOutBigRelays(relayUrls: string[]) {
|
||||||
return relayUrls.filter((url) => !BIG_RELAY_URLS.includes(url))
|
const defaultRelays = getDefaultRelayUrls()
|
||||||
|
return relayUrls.filter((url) => !defaultRelays.includes(url))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function recommendRelaysByLanguage(i18nLanguage: string) {
|
export function recommendRelaysByLanguage(i18nLanguage: string) {
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ import FollowingFavoriteRelayList from '@/components/FollowingFavoriteRelayList'
|
||||||
import NoteList from '@/components/NoteList'
|
import NoteList from '@/components/NoteList'
|
||||||
import Tabs from '@/components/Tabs'
|
import Tabs from '@/components/Tabs'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants'
|
import { ExtendedKind } from '@/constants'
|
||||||
import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
|
import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
|
||||||
import { getReplaceableEventIdentifier } from '@/lib/event'
|
import { getReplaceableEventIdentifier } from '@/lib/event'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { isLocalNetworkUrl, isOnionUrl, isWebsocketUrl } from '@/lib/url'
|
import { isLocalNetworkUrl, isOnionUrl, isWebsocketUrl } from '@/lib/url'
|
||||||
import storage from '@/services/local-storage.service'
|
import storage from '@/services/local-storage.service'
|
||||||
import { TPageRef } from '@/types'
|
import { TPageRef } from '@/types'
|
||||||
|
|
@ -42,7 +43,7 @@ const ExplorePage = forwardRef<TPageRef>((_, ref) => {
|
||||||
) : tab === 'reviews' ? (
|
) : tab === 'reviews' ? (
|
||||||
<NoteList
|
<NoteList
|
||||||
showKinds={[ExtendedKind.RELAY_REVIEW]}
|
showKinds={[ExtendedKind.RELAY_REVIEW]}
|
||||||
subRequests={[{ urls: BIG_RELAY_URLS, filter: {} }]}
|
subRequests={[{ urls: getDefaultRelayUrls(), filter: {} }]}
|
||||||
filterFn={relayReviewFilterFn}
|
filterFn={relayReviewFilterFn}
|
||||||
filterMutedNotes
|
filterMutedNotes
|
||||||
hideSpam
|
hideSpam
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import EmojiPackList from '@/components/EmojiPackList'
|
import EmojiPackList from '@/components/EmojiPackList'
|
||||||
import NoteList from '@/components/NoteList'
|
import NoteList from '@/components/NoteList'
|
||||||
import Tabs from '@/components/Tabs'
|
import Tabs from '@/components/Tabs'
|
||||||
import { BIG_RELAY_URLS } from '@/constants'
|
|
||||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { kinds } from 'nostr-tools'
|
import { kinds } from 'nostr-tools'
|
||||||
import { forwardRef, useState } from 'react'
|
import { forwardRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
@ -30,7 +30,7 @@ const EmojiPackSettingsPage = forwardRef(({ index }: { index?: number }, ref) =>
|
||||||
) : (
|
) : (
|
||||||
<NoteList
|
<NoteList
|
||||||
showKinds={[kinds.Emojisets]}
|
showKinds={[kinds.Emojisets]}
|
||||||
subRequests={[{ urls: BIG_RELAY_URLS, filter: {} }]}
|
subRequests={[{ urls: getDefaultRelayUrls(), filter: {} }]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</SecondaryPageLayout>
|
</SecondaryPageLayout>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { Favicon } from '@/components/Favicon'
|
import { Favicon } from '@/components/Favicon'
|
||||||
import NormalFeed from '@/components/NormalFeed'
|
import NormalFeed from '@/components/NormalFeed'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { BIG_RELAY_URLS, SEARCHABLE_RELAY_URLS } from '@/constants'
|
import { SEARCHABLE_RELAY_URLS } from '@/constants'
|
||||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||||
import { toProfileList } from '@/lib/link'
|
import { toProfileList } from '@/lib/link'
|
||||||
import { fetchPubkeysFromDomain, getWellKnownNip05Url } from '@/lib/nip05'
|
import { fetchPubkeysFromDomain, getWellKnownNip05Url } from '@/lib/nip05'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { useSecondaryPage } from '@/PageManager'
|
import { useSecondaryPage } from '@/PageManager'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
|
|
@ -47,7 +48,7 @@ const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||||
setSubRequests([
|
setSubRequests([
|
||||||
{
|
{
|
||||||
filter: { '#t': [hashtag], ...(kinds.length > 0 ? { kinds } : {}) },
|
filter: { '#t': [hashtag], ...(kinds.length > 0 ? { kinds } : {}) },
|
||||||
urls: BIG_RELAY_URLS
|
urls: getDefaultRelayUrls()
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import NoteList from '@/components/NoteList'
|
import NoteList from '@/components/NoteList'
|
||||||
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants'
|
import { ExtendedKind } from '@/constants'
|
||||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { normalizeUrl, simplifyUrl } from '@/lib/url'
|
import { normalizeUrl, simplifyUrl } from '@/lib/url'
|
||||||
import { forwardRef, useMemo } from 'react'
|
import { forwardRef, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
@ -24,7 +25,7 @@ const RelayReviewsPage = forwardRef(({ url, index }: { url?: string; index?: num
|
||||||
showKinds={[ExtendedKind.RELAY_REVIEW]}
|
showKinds={[ExtendedKind.RELAY_REVIEW]}
|
||||||
subRequests={[
|
subRequests={[
|
||||||
{
|
{
|
||||||
urls: [normalizedUrl, ...BIG_RELAY_URLS],
|
urls: [normalizedUrl, ...getDefaultRelayUrls()],
|
||||||
filter: { '#d': [normalizedUrl] }
|
filter: { '#d': [normalizedUrl] }
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import DefaultRelaysSetting from '@/components/DefaultRelaysSetting'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { Label } from '@/components/ui/label'
|
import { Label } from '@/components/ui/label'
|
||||||
import { Switch } from '@/components/ui/switch'
|
import { Switch } from '@/components/ui/switch'
|
||||||
|
|
@ -43,6 +44,9 @@ const SystemSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="px-4 space-y-2">
|
||||||
|
<DefaultRelaysSetting />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SecondaryPageLayout>
|
</SecondaryPageLayout>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { BIG_RELAY_URLS } from '@/constants'
|
|
||||||
import { createFavoriteRelaysDraftEvent, createRelaySetDraftEvent } from '@/lib/draft-event'
|
import { createFavoriteRelaysDraftEvent, createRelaySetDraftEvent } from '@/lib/draft-event'
|
||||||
import { getReplaceableEventIdentifier } from '@/lib/event'
|
import { getReplaceableEventIdentifier } from '@/lib/event'
|
||||||
import { getRelaySetFromEvent } from '@/lib/event-metadata'
|
import { getRelaySetFromEvent } from '@/lib/event-metadata'
|
||||||
import { randomString } from '@/lib/random'
|
import { randomString } from '@/lib/random'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { isWebsocketUrl, normalizeUrl } from '@/lib/url'
|
import { isWebsocketUrl, normalizeUrl } from '@/lib/url'
|
||||||
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'
|
||||||
|
|
@ -94,7 +94,7 @@ export function FavoriteRelaysProvider({ children }: { children: React.ReactNode
|
||||||
setRelaySetEvents(storedRelaySetEvents.filter(Boolean) as Event[])
|
setRelaySetEvents(storedRelaySetEvents.filter(Boolean) as Event[])
|
||||||
|
|
||||||
const newRelaySetEvents = await client.fetchEvents(
|
const newRelaySetEvents = await client.fetchEvents(
|
||||||
(relayList?.write ?? []).concat(BIG_RELAY_URLS).slice(0, 5),
|
(relayList?.write ?? []).concat(getDefaultRelayUrls()).slice(0, 5),
|
||||||
{
|
{
|
||||||
kinds: [kinds.Relaysets],
|
kinds: [kinds.Relaysets],
|
||||||
authors: [pubkey],
|
authors: [pubkey],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import LoginDialog from '@/components/LoginDialog'
|
import LoginDialog from '@/components/LoginDialog'
|
||||||
import PasswordInputDialog from '@/components/PasswordInputDialog'
|
import PasswordInputDialog from '@/components/PasswordInputDialog'
|
||||||
import { ApplicationDataKey, BIG_RELAY_URLS, ExtendedKind } from '@/constants'
|
import { ApplicationDataKey, ExtendedKind } from '@/constants'
|
||||||
import {
|
import {
|
||||||
createDeletionRequestDraftEvent,
|
createDeletionRequestDraftEvent,
|
||||||
createFollowListDraftEvent,
|
createFollowListDraftEvent,
|
||||||
|
|
@ -16,6 +16,7 @@ import {
|
||||||
} from '@/lib/event'
|
} from '@/lib/event'
|
||||||
import { getProfileFromEvent, getRelayListFromEvent } from '@/lib/event-metadata'
|
import { getProfileFromEvent, getRelayListFromEvent } from '@/lib/event-metadata'
|
||||||
import { formatPubkey, pubkeyToNpub } from '@/lib/pubkey'
|
import { formatPubkey, pubkeyToNpub } from '@/lib/pubkey'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
import customEmojiService from '@/services/custom-emoji.service'
|
import customEmojiService from '@/services/custom-emoji.service'
|
||||||
import indexedDb from '@/services/indexed-db.service'
|
import indexedDb from '@/services/indexed-db.service'
|
||||||
|
|
@ -246,7 +247,8 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
|
||||||
setPinnedUsersEvent(storedPinnedUsersEvent)
|
setPinnedUsersEvent(storedPinnedUsersEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
const relayListEvents = await client.fetchEvents(BIG_RELAY_URLS, {
|
const defaultRelays = getDefaultRelayUrls()
|
||||||
|
const relayListEvents = await client.fetchEvents(defaultRelays, {
|
||||||
kinds: [kinds.RelayList],
|
kinds: [kinds.RelayList],
|
||||||
authors: [account.pubkey]
|
authors: [account.pubkey]
|
||||||
})
|
})
|
||||||
|
|
@ -258,7 +260,7 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
|
||||||
}
|
}
|
||||||
setRelayList(relayList)
|
setRelayList(relayList)
|
||||||
|
|
||||||
const events = await client.fetchEvents(relayList.write.concat(BIG_RELAY_URLS).slice(0, 4), [
|
const events = await client.fetchEvents(relayList.write.concat(defaultRelays).slice(0, 4), [
|
||||||
{
|
{
|
||||||
kinds: [
|
kinds: [
|
||||||
kinds.Metadata,
|
kinds.Metadata,
|
||||||
|
|
@ -637,13 +639,14 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const setupNewUser = async (signer: ISigner) => {
|
const setupNewUser = async (signer: ISigner) => {
|
||||||
|
const defaultRelays = getDefaultRelayUrls()
|
||||||
await Promise.allSettled([
|
await Promise.allSettled([
|
||||||
client.publishEvent(BIG_RELAY_URLS, await signer.signEvent(createFollowListDraftEvent([]))),
|
client.publishEvent(defaultRelays, await signer.signEvent(createFollowListDraftEvent([]))),
|
||||||
client.publishEvent(BIG_RELAY_URLS, await signer.signEvent(createMuteListDraftEvent([]))),
|
client.publishEvent(defaultRelays, await signer.signEvent(createMuteListDraftEvent([]))),
|
||||||
client.publishEvent(
|
client.publishEvent(
|
||||||
BIG_RELAY_URLS,
|
defaultRelays,
|
||||||
await signer.signEvent(
|
await signer.signEvent(
|
||||||
createRelayListDraftEvent(BIG_RELAY_URLS.map((url) => ({ url, scope: 'both' })))
|
createRelayListDraftEvent(defaultRelays.map((url) => ({ url, scope: 'both' })))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants'
|
import { ExtendedKind } from '@/constants'
|
||||||
import { compareEvents } from '@/lib/event'
|
import { compareEvents } from '@/lib/event'
|
||||||
import { notificationFilter } from '@/lib/notification'
|
import { notificationFilter } from '@/lib/notification'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { usePrimaryPage } from '@/PageManager'
|
import { usePrimaryPage } from '@/PageManager'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
import storage from '@/services/local-storage.service'
|
import storage from '@/services/local-storage.service'
|
||||||
|
|
@ -103,7 +104,8 @@ export function NotificationProvider({ children }: { children: React.ReactNode }
|
||||||
try {
|
try {
|
||||||
let eosed = false
|
let eosed = false
|
||||||
const relayList = await client.fetchRelayList(pubkey)
|
const relayList = await client.fetchRelayList(pubkey)
|
||||||
const relays = relayList.read.length > 0 ? relayList.read.slice(0, 5) : BIG_RELAY_URLS
|
const relays =
|
||||||
|
relayList.read.length > 0 ? relayList.read.slice(0, 5) : getDefaultRelayUrls()
|
||||||
const subCloser = client.subscribe(
|
const subCloser = client.subscribe(
|
||||||
relays,
|
relays,
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { BIG_RELAY_URLS, ExtendedKind, SEARCHABLE_RELAY_URLS } from '@/constants'
|
import { ExtendedKind, SEARCHABLE_RELAY_URLS } from '@/constants'
|
||||||
import {
|
import {
|
||||||
compareEvents,
|
compareEvents,
|
||||||
getReplaceableCoordinate,
|
getReplaceableCoordinate,
|
||||||
|
|
@ -7,7 +7,7 @@ import {
|
||||||
} from '@/lib/event'
|
} from '@/lib/event'
|
||||||
import { getProfileFromEvent, getRelayListFromEvent } from '@/lib/event-metadata'
|
import { getProfileFromEvent, getRelayListFromEvent } from '@/lib/event-metadata'
|
||||||
import { formatPubkey, isValidPubkey, pubkeyToNpub, userIdToPubkey } from '@/lib/pubkey'
|
import { formatPubkey, isValidPubkey, pubkeyToNpub, userIdToPubkey } from '@/lib/pubkey'
|
||||||
import { filterOutBigRelays } from '@/lib/relay'
|
import { filterOutBigRelays, getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { getPubkeysFromPTags, getServersFromServerTags, tagNameEquals } from '@/lib/tag'
|
import { getPubkeysFromPTags, getServersFromServerTags, tagNameEquals } from '@/lib/tag'
|
||||||
import { mergeTimelines } from '@/lib/timeline'
|
import { mergeTimelines } from '@/lib/timeline'
|
||||||
import { isLocalNetworkUrl, isWebsocketUrl, normalizeUrl } from '@/lib/url'
|
import { isLocalNetworkUrl, isWebsocketUrl, normalizeUrl } from '@/lib/url'
|
||||||
|
|
@ -97,6 +97,7 @@ class ClientService extends EventTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultRelays = getDefaultRelayUrls()
|
||||||
const relaySet = new Set<string>()
|
const relaySet = new Set<string>()
|
||||||
if (specifiedRelayUrls?.length) {
|
if (specifiedRelayUrls?.length) {
|
||||||
specifiedRelayUrls.forEach((url) => relaySet.add(url))
|
specifiedRelayUrls.forEach((url) => relaySet.add(url))
|
||||||
|
|
@ -137,20 +138,20 @@ class ClientService extends EventTarget {
|
||||||
ExtendedKind.RELAY_REVIEW
|
ExtendedKind.RELAY_REVIEW
|
||||||
].includes(event.kind)
|
].includes(event.kind)
|
||||||
) {
|
) {
|
||||||
BIG_RELAY_URLS.forEach((url) => relaySet.add(url))
|
defaultRelays.forEach((url) => relaySet.add(url))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind === ExtendedKind.COMMENT) {
|
if (event.kind === ExtendedKind.COMMENT) {
|
||||||
const rootITag = event.tags.find(tagNameEquals('I'))
|
const rootITag = event.tags.find(tagNameEquals('I'))
|
||||||
if (rootITag) {
|
if (rootITag) {
|
||||||
// For external content comments, always publish to big relays
|
// For external content comments, always publish to default relays
|
||||||
BIG_RELAY_URLS.forEach((url) => relaySet.add(url))
|
defaultRelays.forEach((url) => relaySet.add(url))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!relaySet.size) {
|
if (!relaySet.size) {
|
||||||
BIG_RELAY_URLS.forEach((url) => relaySet.add(url))
|
defaultRelays.forEach((url) => relaySet.add(url))
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array.from(relaySet)
|
return Array.from(relaySet)
|
||||||
|
|
@ -166,7 +167,7 @@ class ClientService extends EventTarget {
|
||||||
const relayLists = await this.fetchRelayLists(filter['#p'])
|
const relayLists = await this.fetchRelayLists(filter['#p'])
|
||||||
return Array.from(new Set(relayLists.flatMap((list) => list.read.slice(0, 5))))
|
return Array.from(new Set(relayLists.flatMap((list) => list.read.slice(0, 5))))
|
||||||
}
|
}
|
||||||
return BIG_RELAY_URLS
|
return getDefaultRelayUrls()
|
||||||
}
|
}
|
||||||
|
|
||||||
async publishEvent(relayUrls: string[], event: NEvent) {
|
async publishEvent(relayUrls: string[], event: NEvent) {
|
||||||
|
|
@ -807,7 +808,11 @@ class ClientService extends EventTarget {
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
const relays = Array.from(new Set(urls))
|
const relays = Array.from(new Set(urls))
|
||||||
const events = await this.query(relays.length > 0 ? relays : BIG_RELAY_URLS, filter, onevent)
|
const events = await this.query(
|
||||||
|
relays.length > 0 ? relays : getDefaultRelayUrls(),
|
||||||
|
filter,
|
||||||
|
onevent
|
||||||
|
)
|
||||||
if (cache) {
|
if (cache) {
|
||||||
events.forEach((evt) => {
|
events.forEach((evt) => {
|
||||||
this.addEventToCache(evt)
|
this.addEventToCache(evt)
|
||||||
|
|
@ -935,7 +940,7 @@ class ClientService extends EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchEventsFromBigRelays(ids: readonly string[]) {
|
private async fetchEventsFromBigRelays(ids: readonly string[]) {
|
||||||
const events = await this.query(BIG_RELAY_URLS, {
|
const events = await this.query(getDefaultRelayUrls(), {
|
||||||
ids: Array.from(new Set(ids)),
|
ids: Array.from(new Set(ids)),
|
||||||
limit: ids.length
|
limit: ids.length
|
||||||
})
|
})
|
||||||
|
|
@ -961,7 +966,7 @@ class ClientService extends EventTarget {
|
||||||
private async _fetchFollowingFavoriteRelays(pubkey: string) {
|
private async _fetchFollowingFavoriteRelays(pubkey: string) {
|
||||||
const fetchNewData = async () => {
|
const fetchNewData = async () => {
|
||||||
const followings = await this.fetchFollowings(pubkey)
|
const followings = await this.fetchFollowings(pubkey)
|
||||||
const events = await this.fetchEvents(BIG_RELAY_URLS, {
|
const events = await this.fetchEvents(getDefaultRelayUrls(), {
|
||||||
authors: followings,
|
authors: followings,
|
||||||
kinds: [ExtendedKind.FAVORITE_RELAYS, kinds.Relaysets],
|
kinds: [ExtendedKind.FAVORITE_RELAYS, kinds.Relaysets],
|
||||||
limit: 1000
|
limit: 1000
|
||||||
|
|
@ -1182,9 +1187,10 @@ class ClientService extends EventTarget {
|
||||||
if (event) {
|
if (event) {
|
||||||
return getRelayListFromEvent(event, storage.getFilterOutOnionRelays())
|
return getRelayListFromEvent(event, storage.getFilterOutOnionRelays())
|
||||||
}
|
}
|
||||||
|
const defaultRelays = getDefaultRelayUrls()
|
||||||
return {
|
return {
|
||||||
write: BIG_RELAY_URLS,
|
write: defaultRelays,
|
||||||
read: BIG_RELAY_URLS,
|
read: defaultRelays,
|
||||||
originalRelays: []
|
originalRelays: []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1224,7 +1230,7 @@ class ClientService extends EventTarget {
|
||||||
const eventsMap = new Map<string, NEvent>()
|
const eventsMap = new Map<string, NEvent>()
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(
|
||||||
Array.from(groups.entries()).map(async ([kind, pubkeys]) => {
|
Array.from(groups.entries()).map(async ([kind, pubkeys]) => {
|
||||||
const events = await this.query(BIG_RELAY_URLS, {
|
const events = await this.query(getDefaultRelayUrls(), {
|
||||||
authors: pubkeys,
|
authors: pubkeys,
|
||||||
kinds: [kind]
|
kinds: [kind]
|
||||||
})
|
})
|
||||||
|
|
@ -1340,7 +1346,7 @@ class ClientService extends EventTarget {
|
||||||
: { authors: [pubkey], kinds: [kind] }) as Filter
|
: { authors: [pubkey], kinds: [kind] }) as Filter
|
||||||
)
|
)
|
||||||
const relayList = await this.fetchRelayList(pubkey)
|
const relayList = await this.fetchRelayList(pubkey)
|
||||||
const relays = relayList.write.concat(BIG_RELAY_URLS).slice(0, 5)
|
const relays = relayList.write.concat(getDefaultRelayUrls()).slice(0, 5)
|
||||||
const events = await this.query(relays, filters)
|
const events = await this.query(relays, filters)
|
||||||
|
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
|
|
@ -1471,10 +1477,10 @@ class ClientService extends EventTarget {
|
||||||
// If many websocket connections are initiated simultaneously, it will be
|
// If many websocket connections are initiated simultaneously, it will be
|
||||||
// very slow on Safari (for unknown reason)
|
// very slow on Safari (for unknown reason)
|
||||||
if (isSafari()) {
|
if (isSafari()) {
|
||||||
let urls = BIG_RELAY_URLS
|
let urls = getDefaultRelayUrls()
|
||||||
if (myPubkey) {
|
if (myPubkey) {
|
||||||
const relayList = await this.fetchRelayList(myPubkey)
|
const relayList = await this.fetchRelayList(myPubkey)
|
||||||
urls = relayList.read.concat(BIG_RELAY_URLS).slice(0, 5)
|
urls = relayList.read.concat(getDefaultRelayUrls()).slice(0, 5)
|
||||||
}
|
}
|
||||||
return [{ urls, filter: { authors: pubkeys } }]
|
return [{ urls, filter: { authors: pubkeys } }]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { BIG_RELAY_URLS, CODY_PUBKEY, JUMBLE_PUBKEY } from '@/constants'
|
import { CODY_PUBKEY, JUMBLE_PUBKEY } from '@/constants'
|
||||||
import { getZapInfoFromEvent } from '@/lib/event-metadata'
|
import { getZapInfoFromEvent } from '@/lib/event-metadata'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { TProfile } from '@/types'
|
import { TProfile } from '@/types'
|
||||||
import { init, launchPaymentModal } from '@getalby/bitcoin-connect-react'
|
import { init, launchPaymentModal } from '@getalby/bitcoin-connect-react'
|
||||||
import { Invoice } from '@getalby/lightning-tools'
|
import { Invoice } from '@getalby/lightning-tools'
|
||||||
|
|
@ -52,7 +53,7 @@ class LightningService {
|
||||||
client.fetchRelayList(recipient),
|
client.fetchRelayList(recipient),
|
||||||
sender
|
sender
|
||||||
? client.fetchRelayList(sender)
|
? client.fetchRelayList(sender)
|
||||||
: Promise.resolve({ read: BIG_RELAY_URLS, write: BIG_RELAY_URLS })
|
: Promise.resolve({ read: getDefaultRelayUrls(), write: getDefaultRelayUrls() })
|
||||||
])
|
])
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
throw new Error('Recipient not found')
|
throw new Error('Recipient not found')
|
||||||
|
|
@ -69,7 +70,7 @@ class LightningService {
|
||||||
relays: receiptRelayList.read
|
relays: receiptRelayList.read
|
||||||
.slice(0, 4)
|
.slice(0, 4)
|
||||||
.concat(senderRelayList.write.slice(0, 3))
|
.concat(senderRelayList.write.slice(0, 3))
|
||||||
.concat(BIG_RELAY_URLS),
|
.concat(getDefaultRelayUrls()),
|
||||||
comment
|
comment
|
||||||
})
|
})
|
||||||
const zapRequest = await client.signer.signEvent(zapRequestDraft)
|
const zapRequest = await client.signer.signEvent(zapRequestDraft)
|
||||||
|
|
@ -134,7 +135,7 @@ class LightningService {
|
||||||
filter['#e'] = [event.id]
|
filter['#e'] = [event.id]
|
||||||
}
|
}
|
||||||
subCloser = client.subscribe(
|
subCloser = client.subscribe(
|
||||||
senderRelayList.write.concat(BIG_RELAY_URLS).slice(0, 4),
|
senderRelayList.write.concat(getDefaultRelayUrls()).slice(0, 4),
|
||||||
filter,
|
filter,
|
||||||
{
|
{
|
||||||
onevent: (evt) => {
|
onevent: (evt) => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
ALLOWED_FILTER_KINDS,
|
ALLOWED_FILTER_KINDS,
|
||||||
|
BIG_RELAY_URLS,
|
||||||
DEFAULT_FAVICON_URL_TEMPLATE,
|
DEFAULT_FAVICON_URL_TEMPLATE,
|
||||||
DEFAULT_NIP_96_SERVICE,
|
DEFAULT_NIP_96_SERVICE,
|
||||||
ExtendedKind,
|
ExtendedKind,
|
||||||
|
|
@ -21,9 +22,9 @@ import {
|
||||||
TMediaAutoLoadPolicy,
|
TMediaAutoLoadPolicy,
|
||||||
TMediaUploadServiceConfig,
|
TMediaUploadServiceConfig,
|
||||||
TNoteListMode,
|
TNoteListMode,
|
||||||
TProfilePictureAutoLoadPolicy,
|
|
||||||
TNsfwDisplayPolicy,
|
|
||||||
TNotificationStyle,
|
TNotificationStyle,
|
||||||
|
TNsfwDisplayPolicy,
|
||||||
|
TProfilePictureAutoLoadPolicy,
|
||||||
TRelaySet,
|
TRelaySet,
|
||||||
TThemeSetting,
|
TThemeSetting,
|
||||||
TTranslationServiceConfig
|
TTranslationServiceConfig
|
||||||
|
|
@ -65,6 +66,7 @@ class LocalStorageService {
|
||||||
private nsfwDisplayPolicy: TNsfwDisplayPolicy = NSFW_DISPLAY_POLICY.HIDE_CONTENT
|
private nsfwDisplayPolicy: TNsfwDisplayPolicy = NSFW_DISPLAY_POLICY.HIDE_CONTENT
|
||||||
private minTrustScore: number = 40
|
private minTrustScore: number = 40
|
||||||
private enableLiveFeed: boolean = false
|
private enableLiveFeed: boolean = false
|
||||||
|
private defaultRelayUrls: string[] = BIG_RELAY_URLS
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (!LocalStorageService.instance) {
|
if (!LocalStorageService.instance) {
|
||||||
|
|
@ -278,6 +280,22 @@ class LocalStorageService {
|
||||||
|
|
||||||
this.enableLiveFeed = window.localStorage.getItem(StorageKey.ENABLE_LIVE_FEED) === 'true'
|
this.enableLiveFeed = window.localStorage.getItem(StorageKey.ENABLE_LIVE_FEED) === 'true'
|
||||||
|
|
||||||
|
const defaultRelayUrlsStr = window.localStorage.getItem(StorageKey.DEFAULT_RELAY_URLS)
|
||||||
|
if (defaultRelayUrlsStr) {
|
||||||
|
try {
|
||||||
|
const urls = JSON.parse(defaultRelayUrlsStr)
|
||||||
|
if (
|
||||||
|
Array.isArray(urls) &&
|
||||||
|
urls.length > 0 &&
|
||||||
|
urls.every((url) => typeof url === 'string')
|
||||||
|
) {
|
||||||
|
this.defaultRelayUrls = urls
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Invalid JSON, use default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up deprecated data
|
// Clean up deprecated data
|
||||||
window.localStorage.removeItem(StorageKey.PINNED_PUBKEYS)
|
window.localStorage.removeItem(StorageKey.PINNED_PUBKEYS)
|
||||||
window.localStorage.removeItem(StorageKey.ACCOUNT_PROFILE_EVENT_MAP)
|
window.localStorage.removeItem(StorageKey.ACCOUNT_PROFILE_EVENT_MAP)
|
||||||
|
|
@ -624,6 +642,15 @@ class LocalStorageService {
|
||||||
this.enableLiveFeed = enable
|
this.enableLiveFeed = enable
|
||||||
window.localStorage.setItem(StorageKey.ENABLE_LIVE_FEED, enable.toString())
|
window.localStorage.setItem(StorageKey.ENABLE_LIVE_FEED, enable.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDefaultRelayUrls() {
|
||||||
|
return this.defaultRelayUrls
|
||||||
|
}
|
||||||
|
|
||||||
|
setDefaultRelayUrls(urls: string[]) {
|
||||||
|
this.defaultRelayUrls = urls
|
||||||
|
window.localStorage.setItem(StorageKey.DEFAULT_RELAY_URLS, JSON.stringify(urls))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const instance = new LocalStorageService()
|
const instance = new LocalStorageService()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants'
|
import { ExtendedKind } from '@/constants'
|
||||||
import { getEventKey, getReplaceableCoordinateFromEvent, isReplaceableEvent } from '@/lib/event'
|
import { getEventKey, getReplaceableCoordinateFromEvent, isReplaceableEvent } from '@/lib/event'
|
||||||
import { getZapInfoFromEvent } from '@/lib/event-metadata'
|
import { getZapInfoFromEvent } from '@/lib/event-metadata'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { getEmojiInfosFromEmojiTags, tagNameEquals } from '@/lib/tag'
|
import { getEmojiInfosFromEmojiTags, tagNameEquals } from '@/lib/tag'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
import { TEmoji } from '@/types'
|
import { TEmoji } from '@/types'
|
||||||
|
|
@ -150,7 +151,9 @@ class StuffStatsService {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const relays = relayList ? relayList.read.concat(BIG_RELAY_URLS).slice(0, 5) : BIG_RELAY_URLS
|
const relays = relayList
|
||||||
|
? relayList.read.concat(getDefaultRelayUrls()).slice(0, 5)
|
||||||
|
: getDefaultRelayUrls()
|
||||||
|
|
||||||
const events: Event[] = []
|
const events: Event[] = []
|
||||||
await client.fetchEvents(relays, filters, {
|
await client.fetchEvents(relays, filters, {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants'
|
import { ExtendedKind } from '@/constants'
|
||||||
import {
|
import {
|
||||||
getEventKey,
|
getEventKey,
|
||||||
getKeyFromTag,
|
getKeyFromTag,
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
isReplaceableEvent,
|
isReplaceableEvent,
|
||||||
isReplyNoteEvent
|
isReplyNoteEvent
|
||||||
} from '@/lib/event'
|
} from '@/lib/event'
|
||||||
|
import { getDefaultRelayUrls } from '@/lib/relay'
|
||||||
import { generateBech32IdFromETag } from '@/lib/tag'
|
import { generateBech32IdFromETag } from '@/lib/tag'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
@ -69,7 +70,7 @@ class ThreadService {
|
||||||
const relayList = await client.fetchRelayList(rootPubkey)
|
const relayList = await client.fetchRelayList(rootPubkey)
|
||||||
relayUrls = relayList.read
|
relayUrls = relayList.read
|
||||||
}
|
}
|
||||||
relayUrls = relayUrls.concat(BIG_RELAY_URLS).slice(0, 4)
|
relayUrls = relayUrls.concat(getDefaultRelayUrls()).slice(0, 4)
|
||||||
|
|
||||||
// If current event is protected, we can assume its replies are also protected and stored on the same relays
|
// If current event is protected, we can assume its replies are also protected and stored on the same relays
|
||||||
if (event && isProtectedEvent(event)) {
|
if (event && isProtectedEvent(event)) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue