This commit is contained in:
Ren Amamiya
2023-06-09 18:26:24 +07:00
parent 0ba9877785
commit 61ab719a2f
7 changed files with 75 additions and 163 deletions

View File

@@ -15,7 +15,7 @@
"dependencies": { "dependencies": {
"@floating-ui/react": "^0.23.1", "@floating-ui/react": "^0.23.1",
"@headlessui/react": "^1.7.15", "@headlessui/react": "^1.7.15",
"@nostr-dev-kit/ndk": "^0.4.4", "@nostr-dev-kit/ndk": "^0.4.5",
"@tanstack/react-virtual": "3.0.0-beta.54", "@tanstack/react-virtual": "3.0.0-beta.54",
"@tauri-apps/api": "^1.3.0", "@tauri-apps/api": "^1.3.0",
"@vidstack/react": "^0.4.5", "@vidstack/react": "^0.4.5",
@@ -24,7 +24,7 @@
"immer": "^10.0.2", "immer": "^10.0.2",
"light-bolt11-decoder": "^3.0.0", "light-bolt11-decoder": "^3.0.0",
"nostr-relaypool": "^0.6.28", "nostr-relaypool": "^0.6.28",
"nostr-tools": "^1.11.1", "nostr-tools": "^1.11.2",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.44.3", "react-hook-form": "^7.44.3",
@@ -36,7 +36,7 @@
"slate-history": "^0.93.0", "slate-history": "^0.93.0",
"slate-react": "^0.94.2", "slate-react": "^0.94.2",
"swr": "^2.1.5", "swr": "^2.1.5",
"tailwind-merge": "^1.13.0", "tailwind-merge": "^1.13.1",
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql", "tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql",
"vidstack": "^0.4.5", "vidstack": "^0.4.5",
"zustand": "^4.3.8" "zustand": "^4.3.8"

46
pnpm-lock.yaml generated
View File

@@ -8,8 +8,8 @@ dependencies:
specifier: ^1.7.15 specifier: ^1.7.15
version: 1.7.15(react-dom@18.2.0)(react@18.2.0) version: 1.7.15(react-dom@18.2.0)(react@18.2.0)
'@nostr-dev-kit/ndk': '@nostr-dev-kit/ndk':
specifier: ^0.4.4 specifier: ^0.4.5
version: 0.4.4(typescript@4.9.5) version: 0.4.5(typescript@4.9.5)
'@tanstack/react-virtual': '@tanstack/react-virtual':
specifier: 3.0.0-beta.54 specifier: 3.0.0-beta.54
version: 3.0.0-beta.54(react@18.2.0) version: 3.0.0-beta.54(react@18.2.0)
@@ -35,8 +35,8 @@ dependencies:
specifier: ^0.6.28 specifier: ^0.6.28
version: 0.6.28(ws@8.13.0) version: 0.6.28(ws@8.13.0)
nostr-tools: nostr-tools:
specifier: ^1.11.1 specifier: ^1.11.2
version: 1.11.1 version: 1.11.2
react: react:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.2.0 version: 18.2.0
@@ -71,8 +71,8 @@ dependencies:
specifier: ^2.1.5 specifier: ^2.1.5
version: 2.1.5(react@18.2.0) version: 2.1.5(react@18.2.0)
tailwind-merge: tailwind-merge:
specifier: ^1.13.0 specifier: ^1.13.1
version: 1.13.0 version: 1.13.1
tauri-plugin-sql-api: tauri-plugin-sql-api:
specifier: github:tauri-apps/tauri-plugin-sql specifier: github:tauri-apps/tauri-plugin-sql
version: github.com/tauri-apps/tauri-plugin-sql/312c4d39ac5eb1c6c75e8ecee1c4bc89ed799675 version: github.com/tauri-apps/tauri-plugin-sql/312c4d39ac5eb1c6c75e8ecee1c4bc89ed799675
@@ -161,23 +161,23 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true dev: true
/@babel/code-frame@7.21.4: /@babel/code-frame@7.22.5:
resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/highlight': 7.18.6 '@babel/highlight': 7.22.5
dev: false dev: false
/@babel/helper-validator-identifier@7.19.1: /@babel/helper-validator-identifier@7.22.5:
resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: false dev: false
/@babel/highlight@7.18.6: /@babel/highlight@7.22.5:
resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/helper-validator-identifier': 7.19.1 '@babel/helper-validator-identifier': 7.22.5
chalk: 2.4.2 chalk: 2.4.2
js-tokens: 4.0.0 js-tokens: 4.0.0
dev: false dev: false
@@ -566,8 +566,8 @@ packages:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0 fastq: 1.15.0
/@nostr-dev-kit/ndk@0.4.4(typescript@4.9.5): /@nostr-dev-kit/ndk@0.4.5(typescript@4.9.5):
resolution: {integrity: sha512-hzXWAlUO1LEmHv3W0Nj0gLmbpZ0gC4WmtDFKdOMnKkFMno0bMobGk8S4hrHHTThigA+OHtkjkPl1vr8fx+a03w==} resolution: {integrity: sha512-iiWWOHjejt5uBKh0q38hN/jBM2rJsgZn3T0fe9AwQCRTm2PkXYDbfT5uYz+VHaovkJx8WLYeV4Ol9nz4p7b8aA==}
dependencies: dependencies:
'@noble/secp256k1': 2.0.0 '@noble/secp256k1': 2.0.0
'@scure/base': 1.1.1 '@scure/base': 1.1.1
@@ -583,7 +583,7 @@ packages:
eventemitter3: 5.0.1 eventemitter3: 5.0.1
light-bolt11-decoder: 3.0.0 light-bolt11-decoder: 3.0.0
node-fetch: 3.3.1 node-fetch: 3.3.1
nostr-tools: 1.11.1 nostr-tools: 1.11.2
tsd: 0.28.1 tsd: 0.28.1
typedoc: 0.24.8(typescript@4.9.5) typedoc: 0.24.8(typescript@4.9.5)
utf8-buffer: 1.0.0 utf8-buffer: 1.0.0
@@ -3507,14 +3507,14 @@ packages:
dependencies: dependencies:
'@jest/source-map': 29.4.3 '@jest/source-map': 29.4.3
isomorphic-ws: 5.0.0(ws@8.13.0) isomorphic-ws: 5.0.0(ws@8.13.0)
nostr-tools: 1.11.1 nostr-tools: 1.11.2
safe-stable-stringify: 2.4.3 safe-stable-stringify: 2.4.3
transitivePeerDependencies: transitivePeerDependencies:
- ws - ws
dev: false dev: false
/nostr-tools@1.11.1: /nostr-tools@1.11.2:
resolution: {integrity: sha512-b8BpCiD3wxjBZwrn0wc+CkVj6/7s4sQxp+Az7UkCG80mJu7xTspZsOoUP/geBNwZVYETzEwj+CPBvW8WIP8mBQ==} resolution: {integrity: sha512-ezN+QwPlFTRZLjstUJw9xacI7/rKKOn18bRitKcArj5YFLaxA2xDIvkryapYZ1IBsJzFYcODmygKIrHdZXsJjw==}
dependencies: dependencies:
'@noble/curves': 1.0.0 '@noble/curves': 1.0.0
'@noble/hashes': 1.3.0 '@noble/hashes': 1.3.0
@@ -3672,7 +3672,7 @@ packages:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'} engines: {node: '>=8'}
dependencies: dependencies:
'@babel/code-frame': 7.21.4 '@babel/code-frame': 7.22.5
error-ex: 1.3.2 error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1 json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4 lines-and-columns: 1.2.4
@@ -4472,8 +4472,8 @@ packages:
resolution: {integrity: sha512-qCN98uP7i9z0fIS4amQ5zbGBOq+OSigYeGvPy7NDk8Y9yncqDZ9pRPgfsc2PJIVM9RrJj7GIfuRgmjoUU9zTHQ==} resolution: {integrity: sha512-qCN98uP7i9z0fIS4amQ5zbGBOq+OSigYeGvPy7NDk8Y9yncqDZ9pRPgfsc2PJIVM9RrJj7GIfuRgmjoUU9zTHQ==}
dev: false dev: false
/tailwind-merge@1.13.0: /tailwind-merge@1.13.1:
resolution: {integrity: sha512-mUTmDbcU+IhOvJ0c42eLQ/nRkvolTqfpVaVQRSxfJAv9TabS6Y2zW/1wKpKLdKzyL3Gh8j6NTLl6MWNmvOM6kA==} resolution: {integrity: sha512-tRtRN22TDokGi2TuYSvuHQuuW6BJ/zlUEG+iYpAQ9i66msc/0eU/+HPccbPnNNH0mCPp0Ob8thaC8Uy9CxHitQ==}
dev: false dev: false
/tailwindcss@3.3.2: /tailwindcss@3.3.2:

View File

@@ -1,9 +1,5 @@
import { RelayContext } from "@shared/relayProvider"; import { RelayContext } from "@shared/relayProvider";
import { READONLY_RELAYS } from "@stores/constants";
import { getChannel, updateChannelMetadata } from "@utils/storage"; import { getChannel, updateChannelMetadata } from "@utils/storage";
import { useContext } from "react"; import { useContext } from "react";
import useSWR, { useSWRConfig } from "swr"; import useSWR, { useSWRConfig } from "swr";
import useSWRSubscription from "swr/subscription"; import useSWRSubscription from "swr/subscription";
@@ -18,7 +14,7 @@ const fetcher = async ([, id]) => {
}; };
export function useChannelProfile(id: string, channelPubkey: string) { export function useChannelProfile(id: string, channelPubkey: string) {
const pool: any = useContext(RelayContext); const ndk = useContext(RelayContext);
const { mutate } = useSWRConfig(); const { mutate } = useSWRConfig();
const { data, isLoading } = useSWR(["channel-metadata", id], fetcher); const { data, isLoading } = useSWR(["channel-metadata", id], fetcher);
@@ -27,30 +23,26 @@ export function useChannelProfile(id: string, channelPubkey: string) {
!isLoading && data ? ["channel-metadata", id] : null, !isLoading && data ? ["channel-metadata", id] : null,
([, key]) => { ([, key]) => {
// subscribe to channel // subscribe to channel
const unsubscribe = pool.subscribe( const sub = ndk.subscribe(
[
{ {
"#e": [key], "#e": [key],
authors: [channelPubkey], authors: [channelPubkey],
kinds: [41], kinds: [41],
}, },
], {
READONLY_RELAYS, closeOnEose: true,
(event: { content: string }) => { },
);
sub.addListener("event", (event: { content: string }) => {
// update in local database // update in local database
updateChannelMetadata(key, event.content); updateChannelMetadata(key, event.content);
// revaildate // revaildate
mutate(["channel-metadata", key]); mutate(["channel-metadata", key]);
}, });
undefined,
undefined,
{
unsubscribeOnEose: true,
},
);
return () => { return () => {
unsubscribe(); sub.stop();
}; };
}, },
); );

View File

@@ -8,7 +8,7 @@ export function LinkPreview({ urls }: { urls: string[] }) {
return ( return (
<div className="mt-3 overflow-hidden rounded-lg bg-zinc-800"> <div className="mt-3 overflow-hidden rounded-lg bg-zinc-800">
{error && <p>failed to load</p>} {error && <p>failed to load</p>}
{isLoading && !data ? ( {isLoading || !data ? (
<p>Loading...</p> <p>Loading...</p>
) : ( ) : (
<a <a

View File

@@ -1,14 +1,10 @@
import { prefetchEvents } from "@libs/ndk";
import { NDKFilter } from "@nostr-dev-kit/ndk"; import { NDKFilter } from "@nostr-dev-kit/ndk";
import { LumeIcon } from "@shared/icons"; import { LumeIcon } from "@shared/icons";
import { RelayContext } from "@shared/relayProvider"; import { RelayContext } from "@shared/relayProvider";
import { useActiveAccount } from "@stores/accounts"; import { useActiveAccount } from "@stores/accounts";
import { dateToUnix, getHourAgo } from "@utils/date"; import { dateToUnix, getHourAgo } from "@utils/date";
import { import { countTotalNotes, createNote } from "@utils/storage";
addToBlacklist,
countTotalNotes,
createChat,
createNote,
} from "@utils/storage";
import { useContext, useEffect, useRef } from "react"; import { useContext, useEffect, useRef } from "react";
import { navigate } from "vite-plugin-ssr/client/router"; import { navigate } from "vite-plugin-ssr/client/router";
@@ -48,7 +44,7 @@ export function Page() {
since: queryNoteSince, since: queryNoteSince,
}; };
const events = await ndk.fetchEvents(filter); const events = await prefetchEvents(ndk, filter);
events.forEach((event) => { events.forEach((event) => {
createNote( createNote(
event.id, event.id,
@@ -66,91 +62,6 @@ export function Page() {
} }
} }
async function fetchChannelBlacklist() {
try {
const filter: NDKFilter = {
authors: [account.pubkey],
kinds: [43, 44],
since: lastLogin,
};
const events = await ndk.fetchEvents(filter);
events.forEach((event) => {
switch (event.kind) {
case 43:
if (event.tags[0][0] === "e") {
addToBlacklist(account.id, event.tags[0][1], 43, 1);
}
break;
case 44:
if (event.tags[0][0] === "p") {
addToBlacklist(account.id, event.tags[0][1], 44, 1);
}
break;
default:
break;
}
});
return true;
} catch (e) {
console.log("error: ", e);
}
}
async function fetchReceiveMessages() {
try {
const filter: NDKFilter = {
kinds: [4],
"#p": [account.pubkey],
since: lastLogin,
};
const events = await ndk.fetchEvents(filter);
events.forEach((event) => {
createChat(
event.id,
account.pubkey,
event.pubkey,
event.content,
event.tags,
event.created_at,
);
});
return true;
} catch (e) {
console.log("error: ", e);
}
}
async function fetchSendMessages() {
try {
const filter: NDKFilter = {
kinds: [4],
authors: [account.pubkey],
since: lastLogin,
};
const events = await ndk.fetchEvents(filter);
events.forEach((event) => {
const receiver = event.tags.find((t) => t[0] === "p")[1];
createChat(
event.id,
receiver,
account.pubkey,
event.content,
event.tags,
event.created_at,
);
});
return true;
} catch (e) {
console.log("error: ", e);
}
}
useEffect(() => { useEffect(() => {
async function prefetch() { async function prefetch() {
const notes = await fetchNotes(); const notes = await fetchNotes();
@@ -158,7 +69,6 @@ export function Page() {
navigate("/app/space", { overwriteLastHistoryEntry: true }); navigate("/app/space", { overwriteLastHistoryEntry: true });
} }
} }
prefetch(); prefetch();
}, []); }, []);

View File

@@ -1,4 +1,10 @@
import NDK, { NDKConstructorParams } from "@nostr-dev-kit/ndk"; import NDK, {
NDKConstructorParams,
NDKEvent,
NDKFilter,
NDKFilterOptions,
NDKRelaySet,
} from "@nostr-dev-kit/ndk";
import { FULL_RELAYS } from "@stores/constants"; import { FULL_RELAYS } from "@stores/constants";
export async function initNDK( export async function initNDK(
@@ -13,3 +19,25 @@ export async function initNDK(
return ndk; return ndk;
} }
export async function prefetchEvents(
ndk: NDK,
filter: NDKFilter,
): Promise<Set<NDKEvent>> {
return new Promise((resolve) => {
const events: Map<string, NDKEvent> = new Map();
const relaySetSubscription = ndk.subscribe(filter, {
closeOnEose: true,
});
relaySetSubscription.on("event", (event: NDKEvent) => {
event.ndk = ndk;
events.set(event.tagId(), event);
});
relaySetSubscription.on("eose", () => {
setTimeout(() => resolve(new Set(events.values())), 2000);
});
});
}

View File

@@ -7,28 +7,10 @@ export const DEFAULT_CHANNEL_BANNER =
export const OPENGRAPH_KEY = "9EJG4SY-19Q4M5J-H8R29C9-091XPCC"; export const OPENGRAPH_KEY = "9EJG4SY-19Q4M5J-H8R29C9-091XPCC";
// read-only relay list
export const READONLY_RELAYS = [
"wss://welcome.nostr.wine",
"wss://relay.nostr.band",
"wss://relay.damus.io",
];
// write-only relay list
export const WRITEONLY_RELAYS = [
"wss://relay.damus.io",
"wss://relay.nostr.band",
];
// metadata relay
export const METADATA_RELAY = ["wss://relay.nostr.band"];
// full-relay list
export const FULL_RELAYS = [ export const FULL_RELAYS = [
"wss://welcome.nostr.wine", "wss://welcome.nostr.wine",
"wss://relay.nostr.band", "wss://relay.nostr.band",
"wss://relay.damus.io", "wss://relay.damus.io",
"wss://relay.snort.social",
"wss://relayable.org", "wss://relayable.org",
"wss://nostr.mutinywallet.com", "wss://nostr.mutinywallet.com",
]; ];