Skip to content

Commit

Permalink
Merge branch 'next'
Browse files Browse the repository at this point in the history
  • Loading branch information
hzrd149 committed Feb 5, 2024
2 parents a38710e + 1c8f68f commit dccd259
Show file tree
Hide file tree
Showing 21 changed files with 449 additions and 178 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-impalas-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostrudel": patch
---

Add explanations to relay views
12 changes: 8 additions & 4 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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"));
Expand Down Expand Up @@ -267,6 +269,8 @@ const router = createHashRouter([
{ path: "app", element: <AppRelays /> },
{ path: "cache", element: <CacheRelayView /> },
{ path: "mailboxes", element: <MailboxesView /> },
{ path: "nip05", element: <NIP05RelaysView /> },
{ path: "contacts", element: <ContactListRelaysView /> },
{ path: "sets", element: <BrowseRelaySetsView /> },
{ path: ":id", element: <RelaySetView /> },
],
Expand Down
10 changes: 10 additions & 0 deletions src/classes/relay-set.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -39,4 +41,12 @@ export default class RelaySet extends Set<string> {
.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),
);
}
}
4 changes: 3 additions & 1 deletion src/components/keyboard-shortcut.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
19 changes: 19 additions & 0 deletions src/helpers/nip07.ts
Original file line number Diff line number Diff line change
@@ -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 };
}
21 changes: 21 additions & 0 deletions src/helpers/nostr/contacts.ts
Original file line number Diff line number Diff line change
@@ -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<string, { read: boolean; write: boolean }>;
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;
}
25 changes: 25 additions & 0 deletions src/hooks/use-user-contact-relays.ts
Original file line number Diff line number Diff line change
@@ -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<string>,
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]);
}
7 changes: 7 additions & 0 deletions src/hooks/use-user-dns-identity.ts
Original file line number Diff line number Diff line change
@@ -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);
}
21 changes: 18 additions & 3 deletions src/providers/route/require-read-relays.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -52,7 +53,14 @@ export default function RequireReadRelays({ children }: PropsWithChildren) {
if (readRelays.size === 0 && !offline && !location.pathname.startsWith("/relays"))
return (
<Flex direction="column" maxW="md" mx="auto" h="full" alignItems="center" justifyContent="center" gap="4">
<Heading size="md">Looks like you don't have any relays setup</Heading>
<Box w="full">
<Heading size="md" textAlign="center">
Setup App Relays
</Heading>
<Text fontStyle="italic">
App Relays are stored locally and are used to fetch your timeline and other users notes
</Text>
</Box>
<RelaySetCard label="Recommended Relays" read={recommendedReadRelays} write={recommendedWriteRelays} />
<RelaySetCard label="Japanese relays" read={JapaneseRelays} write={JapaneseRelays} />
<Card w="full" variant="outline">
Expand All @@ -63,7 +71,14 @@ export default function RequireReadRelays({ children }: PropsWithChildren) {
<AddRelayForm onSubmit={(url) => clientRelaysService.addRelay(url, RelayMode.ALL)} w="full" />
</CardBody>
</Card>
<Button onClick={() => offlineMode.next(true)}>Offline mode</Button>
<ButtonGroup>
<Button as={RouterLink} to="/relays/app" variant="outline" colorScheme="primary">
Custom Relays
</Button>
<Button onClick={() => offlineMode.next(true)} variant="outline">
Offline mode
</Button>
</ButtonGroup>
</Flex>
);

Expand Down
3 changes: 2 additions & 1 deletion src/services/client-relays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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() {
Expand Down
87 changes: 0 additions & 87 deletions src/services/user-contacts.ts

This file was deleted.

15 changes: 11 additions & 4 deletions src/services/user-event-sync.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -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() {
Expand Down
19 changes: 10 additions & 9 deletions src/services/user-mailboxes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
});
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/views/launchpad/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function LaunchpadPage() {
<Flex gap="4" w="full">
<Button colorScheme="primary" size="lg" onClick={() => openModal()} variant="outline">
New Note
<KeyboardShortcut letter="n" ml="auto" onPress={(e) => openModal()} />
<KeyboardShortcut letter="n" ml="2" onPress={(e) => openModal()} />
</Button>
<SearchForm flex={1} />
</Flex>
Expand Down
Loading

0 comments on commit dccd259

Please sign in to comment.