diff --git a/.changeset/calm-impalas-battle.md b/.changeset/calm-impalas-battle.md
new file mode 100644
index 000000000..08d27f5d1
--- /dev/null
+++ b/.changeset/calm-impalas-battle.md
@@ -0,0 +1,5 @@
+---
+"nostrudel": patch
+---
+
+Add explanations to relay views
diff --git a/src/app.tsx b/src/app.tsx
index 9dae6c00a..9c8c0cc8d 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -69,6 +69,12 @@ import CommunityTrendingView from "./views/community/views/trending";
import RelaysView from "./views/relays";
import RelayView from "./views/relays/relay";
import BrowseRelaySetsView from "./views/relays/browse-sets";
+import CacheRelayView from "./views/relays/cache";
+import RelaySetView from "./views/relays/relay-set";
+import AppRelays from "./views/relays/app";
+import MailboxesView from "./views/relays/mailboxes";
+import NIP05RelaysView from "./views/relays/nip05";
+import ContactListRelaysView from "./views/relays/contact-list";
import UserDMsTab from "./views/user/dms";
import DMTimelineView from "./views/tools/dm-timeline";
import LoginNostrConnectView from "./views/signin/nostr-connect";
@@ -82,10 +88,6 @@ import LaunchpadView from "./views/launchpad";
import VideosView from "./views/videos";
import VideoDetailsView from "./views/videos/video";
import BookmarksView from "./views/bookmarks";
-import CacheRelayView from "./views/relays/cache";
-import RelaySetView from "./views/relays/relay-set";
-import AppRelays from "./views/relays/app";
-import MailboxesView from "./views/relays/mailboxes";
import LoginNostrAddressView from "./views/signin/address";
import LoginNostrAddressCreate from "./views/signin/address/create";
const TracksView = lazy(() => import("./views/tracks"));
@@ -267,6 +269,8 @@ const router = createHashRouter([
{ path: "app", element: },
{ path: "cache", element: },
{ path: "mailboxes", element: },
+ { path: "nip05", element: },
+ { path: "contacts", element: },
{ path: "sets", element: },
{ path: ":id", element: },
],
diff --git a/src/classes/relay-set.ts b/src/classes/relay-set.ts
index 751b52b11..0f1d9914f 100644
--- a/src/classes/relay-set.ts
+++ b/src/classes/relay-set.ts
@@ -1,4 +1,6 @@
+import { relaysFromContactsEvent } from "../helpers/nostr/contacts";
import { getRelaysFromMailbox } from "../helpers/nostr/mailbox";
+import { safeJson } from "../helpers/parse";
import { safeRelayUrl } from "../helpers/relay";
import relayPoolService from "../services/relay-pool";
import { NostrEvent } from "../types/nostr-event";
@@ -39,4 +41,12 @@ export default class RelaySet extends Set {
.map((r) => r.url),
);
}
+
+ static fromContactsEvent(contacts: NostrEvent, mode: RelayMode = RelayMode.ALL) {
+ return new RelaySet(
+ relaysFromContactsEvent(contacts)
+ .filter((r) => r.mode & mode)
+ .map((r) => r.url),
+ );
+ }
}
diff --git a/src/components/keyboard-shortcut.tsx b/src/components/keyboard-shortcut.tsx
index 269380652..22445a35c 100644
--- a/src/components/keyboard-shortcut.tsx
+++ b/src/components/keyboard-shortcut.tsx
@@ -17,7 +17,9 @@ export default function KeyboardShortcut({
(e) => (requireMeta ? e.ctrlKey || e.metaKey : true) && e.key === letter,
(e) => {
// ignore if the user is focused on an input
- if (document.activeElement instanceof HTMLInputElement) return;
+ if (document.activeElement instanceof HTMLInputElement || document.activeElement instanceof HTMLTextAreaElement) {
+ return;
+ }
if (onPress) {
e.preventDefault();
diff --git a/src/helpers/nip07.ts b/src/helpers/nip07.ts
new file mode 100644
index 000000000..c7f8aa0aa
--- /dev/null
+++ b/src/helpers/nip07.ts
@@ -0,0 +1,19 @@
+import RelaySet from "../classes/relay-set";
+import { safeRelayUrls } from "./relay";
+
+export async function getRelaysFromExt() {
+ if (!window.nostr) throw new Error("Missing extension");
+ const read = new RelaySet();
+ const write = new RelaySet();
+ const extRelays = (await window.nostr.getRelays?.()) ?? [];
+ if (Array.isArray(extRelays)) {
+ const safeUrls = safeRelayUrls(extRelays);
+ read.merge(safeUrls);
+ write.merge(safeUrls);
+ } else {
+ read.merge(safeRelayUrls(Object.keys(extRelays).filter((url) => extRelays[url].read)));
+ write.merge(safeRelayUrls(Object.keys(extRelays).filter((url) => extRelays[url].write)));
+ }
+
+ return { read, write };
+}
diff --git a/src/helpers/nostr/contacts.ts b/src/helpers/nostr/contacts.ts
new file mode 100644
index 000000000..aba924e1e
--- /dev/null
+++ b/src/helpers/nostr/contacts.ts
@@ -0,0 +1,21 @@
+import { NostrEvent } from "nostr-tools";
+import { RelayMode } from "../../classes/relay";
+import { safeJson } from "../parse";
+import { safeRelayUrl } from "../relay";
+
+type RelayJson = Record;
+export function relaysFromContactsEvent(event: NostrEvent) {
+ const relayJson = safeJson(event.content, {}) as RelayJson;
+
+ const relays: { url: string; mode: RelayMode }[] = [];
+ for (const [url, opts] of Object.entries(relayJson)) {
+ const safeUrl = safeRelayUrl(url);
+ if (!safeUrl) continue;
+ let mode = RelayMode.NONE;
+ if (opts.write) mode = mode | RelayMode.WRITE;
+ if (opts.read) mode = mode | RelayMode.READ;
+ if (mode === RelayMode.NONE) mode = RelayMode.ALL;
+ relays.push({ url: safeUrl, mode });
+ }
+ return relays;
+}
diff --git a/src/hooks/use-user-contact-relays.ts b/src/hooks/use-user-contact-relays.ts
new file mode 100644
index 000000000..a3d731139
--- /dev/null
+++ b/src/hooks/use-user-contact-relays.ts
@@ -0,0 +1,25 @@
+import { useMemo } from "react";
+import { RequestOptions } from "../services/replaceable-event-requester";
+import RelaySet from "../classes/relay-set";
+import useUserContactList from "./use-user-contact-list";
+import { RelayMode } from "../classes/relay";
+import { relaysFromContactsEvent } from "../helpers/nostr/contacts";
+
+export default function useUserContactRelays(
+ pubkey?: string,
+ additionalRelays?: Iterable,
+ opts: RequestOptions = {},
+) {
+ const contacts = useUserContactList(pubkey, additionalRelays, opts);
+
+ return useMemo(() => {
+ if (!contacts) return undefined;
+ if (contacts.content.length === 0) return null;
+
+ const relays = relaysFromContactsEvent(contacts);
+ const inbox = new RelaySet(relays.filter((r) => r.mode & RelayMode.READ).map((r) => r.url));
+ const outbox = new RelaySet(relays.filter((r) => r.mode & RelayMode.WRITE).map((r) => r.url));
+
+ return { inbox, outbox };
+ }, [contacts]);
+}
diff --git a/src/hooks/use-user-dns-identity.ts b/src/hooks/use-user-dns-identity.ts
new file mode 100644
index 000000000..fcbf90a9a
--- /dev/null
+++ b/src/hooks/use-user-dns-identity.ts
@@ -0,0 +1,7 @@
+import { useDnsIdentity } from "./use-dns-identity";
+import { useUserMetadata } from "./use-user-metadata";
+
+export function useUserDNSIdentity(pubkey?: string) {
+ const metadata = useUserMetadata(pubkey);
+ return useDnsIdentity(metadata?.nip05);
+}
diff --git a/src/providers/route/require-read-relays.tsx b/src/providers/route/require-read-relays.tsx
index 655a330a2..41d6aa8c6 100644
--- a/src/providers/route/require-read-relays.tsx
+++ b/src/providers/route/require-read-relays.tsx
@@ -1,5 +1,6 @@
import { MouseEventHandler, PropsWithChildren, useCallback } from "react";
-import { Button, Card, CardBody, CardHeader, Flex, Heading } from "@chakra-ui/react";
+import { Box, Button, ButtonGroup, Card, CardBody, CardHeader, Flex, Heading, Text } from "@chakra-ui/react";
+import { Link as RouterLink } from "react-router-dom";
import { useReadRelays } from "../../hooks/use-client-relays";
import clientRelaysService, { recommendedReadRelays, recommendedWriteRelays } from "../../services/client-relays";
@@ -52,7 +53,14 @@ export default function RequireReadRelays({ children }: PropsWithChildren) {
if (readRelays.size === 0 && !offline && !location.pathname.startsWith("/relays"))
return (
- Looks like you don't have any relays setup
+
+
+ Setup App Relays
+
+
+ App Relays are stored locally and are used to fetch your timeline and other users notes
+
+
@@ -63,7 +71,14 @@ export default function RequireReadRelays({ children }: PropsWithChildren) {
clientRelaysService.addRelay(url, RelayMode.ALL)} w="full" />
-
+
+
+
+
);
diff --git a/src/services/client-relays.ts b/src/services/client-relays.ts
index 48c412851..a44fba0a5 100644
--- a/src/services/client-relays.ts
+++ b/src/services/client-relays.ts
@@ -16,7 +16,7 @@ export const recommendedReadRelays = new RelaySet(
"wss://relay.snort.social/",
"wss://nos.lol/",
"wss://purplerelay.com/",
- "wss://eden.nostr.land/",
+ "wss://nostr.land/",
]),
);
export const recommendedWriteRelays = new RelaySet(
@@ -63,6 +63,7 @@ class ClientRelayService {
setRelaysFromRelaySet(event: NostrEvent) {
this.writeRelays.next(RelaySet.fromNIP65Event(event, RelayMode.WRITE));
this.readRelays.next(RelaySet.fromNIP65Event(event, RelayMode.READ));
+ this.saveRelays();
}
saveRelays() {
diff --git a/src/services/user-contacts.ts b/src/services/user-contacts.ts
deleted file mode 100644
index 2b8c714a0..000000000
--- a/src/services/user-contacts.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import { kinds } from "nostr-tools";
-
-import { isPTag, NostrEvent } from "../types/nostr-event";
-import { safeJson } from "../helpers/parse";
-import SuperMap from "../classes/super-map";
-import Subject from "../classes/subject";
-import replaceableEventLoaderService, { RequestOptions } from "./replaceable-event-requester";
-import RelaySet from "../classes/relay-set";
-
-export type UserContacts = {
- pubkey: string;
- relays: RelaySet;
- inbox: RelaySet;
- outbox: RelaySet;
- contacts: string[];
- contactRelay: Record;
- created_at: number;
-};
-
-type RelayJson = Record;
-function relayJsonToMailboxes(relayJson: RelayJson) {
- const relays = new RelaySet();
- const inbox = new RelaySet();
- const outbox = new RelaySet();
- for (const [url, opts] of Object.entries(relayJson)) {
- relays.add(url);
- if (opts.write) outbox.add(url);
- if (opts.read) inbox.add(url);
- }
- return { relays, inbox, outbox };
-}
-
-function parseContacts(event: NostrEvent): UserContacts {
- const relayJson = safeJson(event.content, {}) as RelayJson;
- const { relays, inbox, outbox } = relayJsonToMailboxes(relayJson);
-
- const pubkeys = event.tags.filter(isPTag).map((tag) => tag[1]);
- const contactRelay = event.tags.filter(isPTag).reduce(
- (dir, tag) => {
- if (tag[2]) {
- dir[tag[1]] = tag[2];
- }
- return dir;
- },
- {} as Record,
- );
-
- return {
- pubkey: event.pubkey,
- relays,
- inbox,
- outbox,
- contacts: pubkeys,
- contactRelay,
- created_at: event.created_at,
- };
-}
-
-class UserContactsService {
- private subjects = new SuperMap>(() => new Subject());
- getSubject(pubkey: string) {
- return this.subjects.get(pubkey);
- }
- requestContacts(pubkey: string, relays: Iterable, opts?: RequestOptions) {
- const sub = this.subjects.get(pubkey);
-
- const requestSub = replaceableEventLoaderService.requestEvent(relays, kinds.Contacts, pubkey, undefined, opts);
-
- sub.connectWithHandler(requestSub, (event, next) => next(parseContacts(event)));
-
- return sub;
- }
-
- /** @deprecated */
- receiveEvent(event: NostrEvent) {
- replaceableEventLoaderService.handleEvent(event);
- }
-}
-
-const userContactsService = new UserContactsService();
-
-if (import.meta.env.DEV) {
- // @ts-ignore
- window.userContactsService = userContactsService;
-}
-
-export default userContactsService;
diff --git a/src/services/user-event-sync.ts b/src/services/user-event-sync.ts
index 466af89c9..3debdfa36 100644
--- a/src/services/user-event-sync.ts
+++ b/src/services/user-event-sync.ts
@@ -1,10 +1,11 @@
+import { kinds } from "nostr-tools";
import { COMMON_CONTACT_RELAY } from "../const";
import { logger } from "../helpers/debug";
import accountService from "./account";
import clientRelaysService from "./client-relays";
import { offlineMode } from "./offline-mode";
+import replaceableEventLoaderService from "./replaceable-event-requester";
import userAppSettings from "./settings/user-app-settings";
-import userContactsService from "./user-contacts";
import userMailboxesService from "./user-mailboxes";
import userMetadataService from "./user-metadata";
@@ -14,9 +15,15 @@ function loadContactsList() {
const account = accountService.current.value!;
log("Loading contacts list");
- userContactsService.requestContacts(account.pubkey, [...clientRelaysService.readRelays.value, COMMON_CONTACT_RELAY], {
- alwaysRequest: true,
- });
+ replaceableEventLoaderService.requestEvent(
+ [...clientRelaysService.readRelays.value, COMMON_CONTACT_RELAY],
+ kinds.Contacts,
+ account.pubkey,
+ undefined,
+ {
+ alwaysRequest: true,
+ },
+ );
}
function downloadEvents() {
diff --git a/src/services/user-mailboxes.ts b/src/services/user-mailboxes.ts
index 3e31becc0..61c99174d 100644
--- a/src/services/user-mailboxes.ts
+++ b/src/services/user-mailboxes.ts
@@ -3,10 +3,10 @@ import { kinds } from "nostr-tools";
import { NostrEvent } from "../types/nostr-event";
import SuperMap from "../classes/super-map";
import Subject from "../classes/subject";
-import userContactsService from "./user-contacts";
import replaceableEventLoaderService, { createCoordinate, RequestOptions } from "./replaceable-event-requester";
import RelaySet from "../classes/relay-set";
import { RelayMode } from "../classes/relay";
+import { relaysFromContactsEvent } from "../helpers/nostr/contacts";
export type UserMailboxes = {
pubkey: string;
@@ -39,17 +39,18 @@ class UserMailboxesService {
sub.connectWithHandler(requestSub, (event, next) => next(nip65ToUserMailboxes(event)));
// also fetch the relays from the users contacts
- const contactsSub = userContactsService.requestContacts(pubkey, relays, opts);
- sub.connectWithHandler(contactsSub, (contacts, next, value) => {
+ const contactsSub = replaceableEventLoaderService.requestEvent(relays, kinds.Contacts, pubkey, undefined, opts);
+ sub.connectWithHandler(contactsSub, (event, next, value) => {
// NOTE: only use relays from contact list if the user dose not have a NIP-65 relay list
- if (contacts.relays.size > 0 && !value) {
+ const relays = relaysFromContactsEvent(event);
+ if (relays.length > 0 && !value) {
next({
- pubkey: contacts.pubkey,
+ pubkey: event.pubkey,
event: null,
- relays: contacts.relays,
- inbox: contacts.inbox,
- outbox: contacts.outbox,
- created_at: contacts.created_at,
+ relays: RelaySet.fromContactsEvent(event),
+ inbox: RelaySet.fromContactsEvent(event, RelayMode.READ),
+ outbox: RelaySet.fromContactsEvent(event, RelayMode.WRITE),
+ created_at: event.created_at,
});
}
});
diff --git a/src/views/launchpad/index.tsx b/src/views/launchpad/index.tsx
index a6b7caef7..0b942fe05 100644
--- a/src/views/launchpad/index.tsx
+++ b/src/views/launchpad/index.tsx
@@ -34,7 +34,7 @@ function LaunchpadPage() {
diff --git a/src/views/relays/app/index.tsx b/src/views/relays/app/index.tsx
index 0c6fb5c32..e7f1ad8b9 100644
--- a/src/views/relays/app/index.tsx
+++ b/src/views/relays/app/index.tsx
@@ -1,6 +1,6 @@
-import { useMemo } from "react";
+import { useCallback, useMemo } from "react";
-import { Button, Flex, Heading } from "@chakra-ui/react";
+import { Button, ButtonGroup, Flex, Heading, Text } from "@chakra-ui/react";
import useSubject from "../../../hooks/use-subject";
import { offlineMode } from "../../../services/offline-mode";
import WifiOff from "../../../components/icons/wifi-off";
@@ -14,12 +14,20 @@ import { useReadRelays, useWriteRelays } from "../../../hooks/use-client-relays"
import useCurrentAccount from "../../../hooks/use-current-account";
import RelayControl from "./relay-control";
import SelectRelaySet from "./select-relay-set";
+import useUserMailboxes from "../../../hooks/use-user-mailboxes";
+import { getRelaysFromExt } from "../../../helpers/nip07";
+import { useUserDNSIdentity } from "../../../hooks/use-user-dns-identity";
+import useUserContactRelays from "../../../hooks/use-user-contact-relays";
+import { WarningIcon } from "@chakra-ui/icons";
export default function AppRelays() {
const account = useCurrentAccount();
const readRelays = useReadRelays();
const writeRelays = useWriteRelays();
const offline = useSubject(offlineMode);
+ const { event: nip65 } = useUserMailboxes(account?.pubkey) ?? {};
+ const nip05 = useUserDNSIdentity(account?.pubkey);
+ const contactRelays = useUserContactRelays(account?.pubkey);
const sorted = useMemo(() => RelaySet.from(readRelays, writeRelays).urls.sort(), [readRelays, writeRelays]);
@@ -27,7 +35,9 @@ export default function AppRelays() {
- App Relays
+
+ App Relays
+
+
+ These relays are stored locally and are used for everything in the app
+
+
{sorted.map((url) => (
))}
@@ -47,6 +61,60 @@ export default function AppRelays() {
}}
/>
+ {writeRelays.size === 0 && (
+
+ There are write relays set, any note you create might not be saved
+
+ )}
+
+
+ Import from:
+
+
+ {window.nostr && (
+
+ )}
+ {nip65 && (
+
+ )}
+ {nip05 && (
+
+ )}
+ {contactRelays && (
+
+ )}
+
{/* {account && (
<>
diff --git a/src/views/relays/cache/index.tsx b/src/views/relays/cache/index.tsx
index 6d9b1c63c..3cc885e01 100644
--- a/src/views/relays/cache/index.tsx
+++ b/src/views/relays/cache/index.tsx
@@ -100,6 +100,9 @@ export default function CacheRelayView() {
Cache Relay
+
+ The cache relay is used to cache event locally so they can be loaded quickly
+
{window.CACHE_RELAY_ENABLED && }
diff --git a/src/views/relays/contact-list/index.tsx b/src/views/relays/contact-list/index.tsx
new file mode 100644
index 000000000..077e7de12
--- /dev/null
+++ b/src/views/relays/contact-list/index.tsx
@@ -0,0 +1,114 @@
+import { Button, Code, Flex, Heading, Link, Spinner, Text } from "@chakra-ui/react";
+import BackButton from "../../../components/back-button";
+import useCurrentAccount from "../../../hooks/use-current-account";
+import { Link as RouterLink } from "react-router-dom";
+
+import { RelayFavicon } from "../../../components/relay-favicon";
+import useUserContactRelays from "../../../hooks/use-user-contact-relays";
+import { CheckIcon, InboxIcon, OutboxIcon } from "../../../components/icons";
+import { useCallback, useState } from "react";
+import useCacheForm from "../../../hooks/use-cache-form";
+import useUserContactList from "../../../hooks/use-user-contact-list";
+import { cloneEvent } from "../../../helpers/nostr/events";
+import { EventTemplate } from "nostr-tools";
+import dayjs from "dayjs";
+import { usePublishEvent } from "../../../providers/global/publish-provider";
+
+function RelayItem({ url }: { url: string }) {
+ return (
+
+
+
+ {url}
+
+
+ );
+}
+
+export default function ContactListRelaysView() {
+ const account = useCurrentAccount();
+ const contacts = useUserContactList(account?.pubkey);
+ const relays = useUserContactRelays(account?.pubkey);
+ const publish = usePublishEvent();
+
+ const [loading, setLoading] = useState(false);
+ const clearRelays = useCallback(async () => {
+ if (!contacts) return;
+ if (confirm("Are you use you want to remove these relays? Other nostr apps might be effected") !== true) return;
+
+ const draft: EventTemplate = {
+ kind: contacts.kind,
+ content: "",
+ tags: contacts.tags,
+ created_at: dayjs().unix(),
+ };
+
+ setLoading(true);
+ await publish("Clear Relays", draft);
+ setLoading(false);
+ }, [setLoading, contacts, publish]);
+
+ if (relays === undefined) return ;
+
+ return (
+
+
+
+ Contact List Relays
+ {relays && (
+
+ )}
+
+
+
+ Some apps store relays in your contacts list (kind-3)
+
+ noStrudel dose not use these relays, instead it uses your{" "}
+
+ Mailbox Relays
+
+
+
+ {relays === null ? (
+
+ You don't have any relays stored in your contact list
+
+ ) : (
+ <>
+
+ Read Relays
+
+ {relays.inbox.urls.map((relay) => (
+
+
+
+ {relay}
+
+
+ ))}
+
+
+ Write Relays
+
+ {relays.outbox.urls.map((relay) => (
+
+
+
+ {relay}
+
+
+ ))}
+ >
+ )}
+
+ );
+}
diff --git a/src/views/relays/index.tsx b/src/views/relays/index.tsx
index 8f5d3eacc..5451e0df5 100644
--- a/src/views/relays/index.tsx
+++ b/src/views/relays/index.tsx
@@ -8,13 +8,18 @@ import { getListName } from "../../helpers/nostr/lists";
import { getEventCoordinate } from "../../helpers/nostr/events";
import { useBreakpointValue } from "../../providers/global/breakpoint-provider";
import Database01 from "../../components/icons/database-01";
-import { RelayIcon } from "../../components/icons";
+import { AtIcon, RelayIcon } from "../../components/icons";
import Mail02 from "../../components/icons/mail-02";
+import { useUserDNSIdentity } from "../../hooks/use-user-dns-identity";
+import useUserContactRelays from "../../hooks/use-user-contact-relays";
+import UserSquare from "../../components/icons/user-square";
export default function RelaysView() {
const account = useCurrentAccount();
const relaySets = useUserRelaySets(account?.pubkey, undefined);
const vertical = useBreakpointValue({ base: true, lg: false });
+ const nip05 = useUserDNSIdentity(account?.pubkey);
+ const kind3Relays = useUserContactRelays(account?.pubkey);
const location = useLocation();
@@ -54,6 +59,26 @@ export default function RelaysView() {
Mailboxes
)}
+ {nip05 && (
+ }
+ colorScheme={location.pathname === "/relays/nip05" ? "primary" : undefined}
+ >
+ NIP-05 Relays
+
+ )}
+ }
+ colorScheme={location.pathname === "/relays/contacts" ? "primary" : undefined}
+ >
+ Contact List Relays
+
{/* {account && (
<>
diff --git a/src/views/relays/mailboxes/index.tsx b/src/views/relays/mailboxes/index.tsx
index aa185c6c4..e788f527a 100644
--- a/src/views/relays/mailboxes/index.tsx
+++ b/src/views/relays/mailboxes/index.tsx
@@ -17,7 +17,7 @@ import VerticalPageLayout from "../../../components/vertical-page-layout";
import RequireCurrentAccount from "../../../providers/route/require-current-account";
import useUserMailboxes from "../../../hooks/use-user-mailboxes";
import useCurrentAccount from "../../../hooks/use-current-account";
-import { InboxIcon } from "../../../components/icons";
+import { InboxIcon, OutboxIcon } from "../../../components/icons";
import { RelayUrlInput } from "../../../components/relay-url-input";
import { RelayFavicon } from "../../../components/relay-favicon";
import { RelayMode } from "../../../classes/relay";
@@ -30,6 +30,7 @@ import { safeRelayUrl } from "../../../helpers/relay";
import { usePublishEvent } from "../../../providers/global/publish-provider";
import { COMMON_CONTACT_RELAY } from "../../../const";
import BackButton from "../../../components/back-button";
+import AddRelayForm from "../app/add-relay-form";
function RelayLine({ relay, mode, list }: { relay: string; mode: RelayMode; list?: NostrEvent }) {
const publish = usePublishEvent();
@@ -57,30 +58,6 @@ function RelayLine({ relay, mode, list }: { relay: string; mode: RelayMode; list
);
}
-function AddRelayForm({ onSubmit }: { onSubmit: (url: string) => void }) {
- const { register, handleSubmit, reset } = useForm({
- defaultValues: {
- url: "",
- },
- });
-
- const submit = handleSubmit(async (values) => {
- const url = safeRelayUrl(values.url);
- if (!url) return;
- await onSubmit(url);
- reset();
- });
-
- return (
-
-
-
-
- );
-}
-
function MailboxesPage() {
const account = useCurrentAccount()!;
const publish = usePublishEvent();
@@ -95,41 +72,46 @@ function MailboxesPage() {
);
return (
-
+
Mailboxes
-
-
-
- Inbox
-
-
- Other users will send DMs and notes to these relays to notify you
- {inbox?.urls
- .sort()
- .map((url) => )}
-
-
- addRelay(r, RelayMode.READ)} />
-
-
-
-
-
- Outbox
-
-
- Always publish to these relays so your followers can find your notes
- {outbox?.urls
- .sort()
- .map((url) => )}
-
-
- addRelay(r, RelayMode.WRITE)} />
-
-
+
+ Mailbox relays are a way for other users to find your events, or send you events. they are defined in{" "}
+
+ NIP-65
+
+
+
+
+
+ Inbox
+
+
+ These relays are used by other users to send DMs and notes to you
+
+ {inbox?.urls
+ .sort()
+ .map((url) => )}
+ addRelay(r, RelayMode.READ)} />
+
+
+
+ Outbox
+
+
+ noStrudel will always publish to these relays so other users can find your notes
+
+ {outbox?.urls
+ .sort()
+ .map((url) => )}
+ addRelay(r, RelayMode.WRITE)} />
);
}
diff --git a/src/views/relays/nip05/index.tsx b/src/views/relays/nip05/index.tsx
new file mode 100644
index 000000000..aee931a5f
--- /dev/null
+++ b/src/views/relays/nip05/index.tsx
@@ -0,0 +1,48 @@
+import { Code, Flex, Heading, Link, Text } from "@chakra-ui/react";
+import BackButton from "../../../components/back-button";
+import useCurrentAccount from "../../../hooks/use-current-account";
+import { useUserDNSIdentity } from "../../../hooks/use-user-dns-identity";
+import { Link as RouterLink } from "react-router-dom";
+
+import { RelayFavicon } from "../../../components/relay-favicon";
+
+function RelayItem({ url }: { url: string }) {
+ return (
+
+
+
+ {url}
+
+
+ );
+}
+
+export default function NIP05RelaysView() {
+ const account = useCurrentAccount();
+ const nip05 = useUserDNSIdentity(account?.pubkey);
+
+ return (
+
+
+
+ NIP-05 Relays
+
+
+
+ These relays cant be modified by noStrudel, they must be set manually on your{" "}
+ /.well-known/nostr.json
file or by your identity provider
+
+
+ Read more about nip-05
+
+
+
+ {nip05?.relays.map((url) => )}
+
+ );
+}
diff --git a/src/views/signin/start.tsx b/src/views/signin/start.tsx
index a57ba14f8..4ebaa9cd8 100644
--- a/src/views/signin/start.tsx
+++ b/src/views/signin/start.tsx
@@ -25,6 +25,8 @@ import accountService from "../../services/account";
import serialPortService from "../../services/serial-port";
import amberSignerService from "../../services/amber-signer";
import { AtIcon } from "../../components/icons";
+import { getRelaysFromExt } from "../../helpers/nip07";
+import { safeRelayUrls } from "../../helpers/relay";
export default function LoginStartView() {
const location = useLocation();
@@ -40,16 +42,15 @@ export default function LoginStartView() {
const pubkey = await window.nostr.getPublicKey();
if (!accountService.hasAccount(pubkey)) {
- let relays: string[] = [];
- const extRelays = (await window.nostr.getRelays?.()) ?? [];
- if (Array.isArray(extRelays)) {
- relays = extRelays;
- } else {
- relays = Object.keys(extRelays).filter((url) => extRelays[url].read);
- }
+ let relays = (await getRelaysFromExt()).read.urls;
if (relays.length === 0) {
- relays = ["wss://relay.damus.io", "wss://relay.snort.social", "wss://nostr.wine", COMMON_CONTACT_RELAY];
+ relays = safeRelayUrls([
+ "wss://relay.damus.io/",
+ "wss://relay.snort.social/",
+ "wss://nostr.wine/",
+ COMMON_CONTACT_RELAY,
+ ]);
}
accountService.addAccount({ pubkey, relays, type: "extension", readonly: false });