diff --git a/packages/app/src/Components/Tasks/BackupKey.tsx b/packages/app/src/Components/Tasks/BackupKey.tsx
index 2464daf0..7c194bd8 100644
--- a/packages/app/src/Components/Tasks/BackupKey.tsx
+++ b/packages/app/src/Components/Tasks/BackupKey.tsx
@@ -1,4 +1,4 @@
-import { MetadataCache } from "@snort/system";
+import { CachedMetadata } from "@snort/system";
import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom";
@@ -10,7 +10,7 @@ export class BackupKeyTask extends BaseUITask {
id = "backup-key";
noBaseStyle = true;
- check(_: MetadataCache, session: LoginSession): boolean {
+ check(_: CachedMetadata, session: LoginSession): boolean {
return !this.state.muted && session.type == "private_key";
}
diff --git a/packages/app/src/Components/Tasks/Nip5Task.tsx b/packages/app/src/Components/Tasks/Nip5Task.tsx
index 44dd5f22..da874fc6 100644
--- a/packages/app/src/Components/Tasks/Nip5Task.tsx
+++ b/packages/app/src/Components/Tasks/Nip5Task.tsx
@@ -1,4 +1,4 @@
-import { MetadataCache } from "@snort/system";
+import { CachedMetadata } from "@snort/system";
import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom";
@@ -7,7 +7,7 @@ import { BaseUITask } from "@/Components/Tasks/index";
export class Nip5Task extends BaseUITask {
id = "buy-nip5";
- check(user: MetadataCache): boolean {
+ check(user: CachedMetadata): boolean {
return !this.state.muted && !user.nip05;
}
diff --git a/packages/app/src/Components/Tasks/RenewSubscription.tsx b/packages/app/src/Components/Tasks/RenewSubscription.tsx
index e07e6f2d..1ad43270 100644
--- a/packages/app/src/Components/Tasks/RenewSubscription.tsx
+++ b/packages/app/src/Components/Tasks/RenewSubscription.tsx
@@ -1,4 +1,4 @@
-import { MetadataCache } from "@snort/system";
+import { CachedMetadata } from "@snort/system";
import { FormattedMessage } from "react-intl";
import { BaseUITask } from "@/Components/Tasks/index";
@@ -9,7 +9,7 @@ import { getCurrentSubscription } from "@/Utils/Subscription";
export class RenewSubTask extends BaseUITask {
id = "renew-sub";
- check(user: MetadataCache, session: LoginSession): boolean {
+ check(user: CachedMetadata, session: LoginSession): boolean {
const sub = getCurrentSubscription(session.subscriptions);
return !sub && session.subscriptions.length > 0;
}
diff --git a/packages/app/src/Components/Tasks/index.ts b/packages/app/src/Components/Tasks/index.ts
index 476f3fb8..a09c10d4 100644
--- a/packages/app/src/Components/Tasks/index.ts
+++ b/packages/app/src/Components/Tasks/index.ts
@@ -1,4 +1,4 @@
-import { MetadataCache } from "@snort/system";
+import { CachedMetadata } from "@snort/system";
import { LoginSession } from "@/Utils/Login";
@@ -8,7 +8,7 @@ export interface UITask {
/**
* Run checks to determine if this Task should be triggered for this user
*/
- check(user: MetadataCache, session: LoginSession): boolean;
+ check(user: CachedMetadata, session: LoginSession): boolean;
mute(): void;
load(cb: () => void): void;
render(): JSX.Element;
@@ -26,7 +26,7 @@ export abstract class BaseUITask implements UITask {
abstract id: string;
noBaseStyle = false;
- abstract check(user: MetadataCache, session: LoginSession): boolean;
+ abstract check(user: CachedMetadata, session: LoginSession): boolean;
abstract render(): JSX.Element;
constructor() {
diff --git a/packages/app/src/Components/Textarea/Textarea.tsx b/packages/app/src/Components/Textarea/Textarea.tsx
index 749237ad..43f1a131 100644
--- a/packages/app/src/Components/Textarea/Textarea.tsx
+++ b/packages/app/src/Components/Textarea/Textarea.tsx
@@ -1,7 +1,7 @@
import "@webscopeio/react-textarea-autocomplete/style.css";
import "./Textarea.css";
-import { MetadataCache, NostrPrefix } from "@snort/system";
+import { CachedMetadata, NostrPrefix } from "@snort/system";
import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete";
import { useIntl } from "react-intl";
import TextareaAutosize from "react-textarea-autosize";
@@ -28,7 +28,7 @@ const EmojiItem = ({ entity: { name, char } }: { entity: EmojiItemProps }) => {
);
};
-const UserItem = (metadata: MetadataCache) => {
+const UserItem = (metadata: CachedMetadata) => {
const { pubkey, display_name, nip05, ...rest } = metadata;
return (
@@ -84,7 +84,7 @@ const Textarea = (props: TextareaProps) => {
"@": {
afterWhitespace: true,
dataProvider: userDataProvider,
- component: (props: { entity: MetadataCache }) =>
,
+ component: (props: { entity: CachedMetadata }) =>
,
output: (item: { pubkey: string }) => `@${hexToBech32(NostrPrefix.PublicKey, item.pubkey)}`,
},
}}
diff --git a/packages/app/src/Components/User/ProfileLink.tsx b/packages/app/src/Components/User/ProfileLink.tsx
index 42ad992d..98feee1c 100644
--- a/packages/app/src/Components/User/ProfileLink.tsx
+++ b/packages/app/src/Components/User/ProfileLink.tsx
@@ -1,4 +1,4 @@
-import { MetadataCache, NostrLink, NostrPrefix, UserMetadata } from "@snort/system";
+import { CachedMetadata, NostrLink, NostrPrefix, UserMetadata } from "@snort/system";
import { SnortContext } from "@snort/system-react";
import { ReactNode, useContext } from "react";
import { Link, LinkProps } from "react-router-dom";
@@ -13,7 +13,7 @@ export function ProfileLink({
...others
}: {
pubkey: string;
- user?: UserMetadata | MetadataCache;
+ user?: UserMetadata | CachedMetadata;
explicitLink?: string;
children?: ReactNode;
} & Omit
) {
diff --git a/packages/app/src/Components/User/UserWebsiteLink.tsx b/packages/app/src/Components/User/UserWebsiteLink.tsx
index e35d1e5c..8d3173ed 100644
--- a/packages/app/src/Components/User/UserWebsiteLink.tsx
+++ b/packages/app/src/Components/User/UserWebsiteLink.tsx
@@ -1,10 +1,10 @@
import "./UserWebsiteLink.css";
-import { MetadataCache, UserMetadata } from "@snort/system";
+import { CachedMetadata, UserMetadata } from "@snort/system";
import Icon from "@/Components/Icons/Icon";
-export function UserWebsiteLink({ user }: { user?: MetadataCache | UserMetadata }) {
+export function UserWebsiteLink({ user }: { user?: CachedMetadata | UserMetadata }) {
const website_url =
user?.website && !user.website.startsWith("http") ? "https://" + user.website : user?.website || "";
diff --git a/packages/app/src/Db/FuzzySearch.ts b/packages/app/src/Db/FuzzySearch.ts
index c40f2154..0210cfac 100644
--- a/packages/app/src/Db/FuzzySearch.ts
+++ b/packages/app/src/Db/FuzzySearch.ts
@@ -1,4 +1,5 @@
import Fuse from "fuse.js";
+import {CachedMetadata} from "@snort/system";
export type FuzzySearchResult = {
pubkey: string;
@@ -19,23 +20,43 @@ export const addEventToFuzzySearch = ev => {
if (ev.kind !== 0) {
return;
}
- const existing = profileTimestamps.get(ev.pubkey);
- if (existing) {
- if (existing > ev.created_at) {
- return;
+ requestAnimationFrame(() => {
+ const existing = profileTimestamps.get(ev.pubkey);
+ if (existing) {
+ if (existing > ev.created_at) {
+ return;
+ }
+ fuzzySearch.remove(doc => doc.pubkey === ev.pubkey);
}
- fuzzySearch.remove(doc => doc.pubkey === ev.pubkey);
- }
- profileTimestamps.set(ev.pubkey, ev.created_at);
- try {
- const data = JSON.parse(ev.content);
- if (ev.pubkey && (data.name || data.display_name || data.nip05)) {
- data.pubkey = ev.pubkey;
- fuzzySearch.add(data);
+ profileTimestamps.set(ev.pubkey, ev.created_at);
+ try {
+ const data = JSON.parse(ev.content);
+ if (ev.pubkey && (data.name || data.display_name || data.nip05)) {
+ data.pubkey = ev.pubkey;
+ fuzzySearch.add(data);
+ }
+ } catch (e) {
+ console.error(e);
}
- } catch (e) {
- console.error(e);
- }
+ });
};
+export const addCachedMetadataToFuzzySearch = (profile: CachedMetadata) => {
+ // TODO add profiles from Cache
+ requestAnimationFrame(() => {
+ const existing = profileTimestamps.get(profile.pubkey);
+ if (existing) {
+ if (existing > profile.created) {
+ return;
+ }
+ fuzzySearch.remove(doc => doc.pubkey === profile.pubkey);
+ }
+ profileTimestamps.set(profile.pubkey, profile.created);
+ if (profile.pubkey && (profile.name || profile.display_name || profile.nip05)) {
+ fuzzySearch.add(profile);
+ console.log('added profile to fuzzy search', profile);
+ }
+ });
+}
+
export default fuzzySearch;
diff --git a/packages/app/src/Pages/Messages/ChatParticipant.tsx b/packages/app/src/Pages/Messages/ChatParticipant.tsx
index d09535c2..226a1e89 100644
--- a/packages/app/src/Pages/Messages/ChatParticipant.tsx
+++ b/packages/app/src/Pages/Messages/ChatParticipant.tsx
@@ -1,4 +1,4 @@
-import { MetadataCache } from "@snort/system";
+import { CachedMetadata } from "@snort/system";
import { ChatParticipant } from "@/chat";
import NoteToSelf from "@/Components/User/NoteToSelf";
@@ -10,5 +10,5 @@ export function ChatParticipantProfile({ participant }: { participant: ChatParti
if (participant.id === publicKey) {
return ;
}
- return ;
+ return ;
}
diff --git a/packages/app/src/Pages/NetworkGraph.tsx b/packages/app/src/Pages/NetworkGraph.tsx
index 1728cbe1..20645daa 100644
--- a/packages/app/src/Pages/NetworkGraph.tsx
+++ b/packages/app/src/Pages/NetworkGraph.tsx
@@ -1,4 +1,4 @@
-import { MetadataCache, socialGraphInstance, STR, UID } from "@snort/system";
+import { CachedMetadata, socialGraphInstance, STR, UID } from "@snort/system";
import { SnortContext } from "@snort/system-react";
import { useContext, useEffect, useState } from "react";
import { NodeObject } from "react-force-graph-3d";
@@ -12,7 +12,7 @@ import { defaultAvatar } from "../Utils";
interface GraphNode {
id: UID;
- profile?: MetadataCache;
+ profile?: CachedMetadata;
distance: number;
val: number;
inboundCount: number;
diff --git a/packages/app/src/Pages/Profile/ProfilePage.tsx b/packages/app/src/Pages/Profile/ProfilePage.tsx
index 96e32ef3..6c4efe93 100644
--- a/packages/app/src/Pages/Profile/ProfilePage.tsx
+++ b/packages/app/src/Pages/Profile/ProfilePage.tsx
@@ -4,7 +4,7 @@ import { fetchNip05Pubkey, LNURL } from "@snort/shared";
import {
encodeTLVEntries,
EventKind,
- MetadataCache,
+ CachedMetadata,
NostrPrefix,
TLVEntryType,
tryParseNostrLink,
@@ -59,13 +59,13 @@ import { ZapTarget } from "@/Utils/Zapper";
interface ProfilePageProps {
id?: string;
- state?: MetadataCache;
+ state?: CachedMetadata;
}
export default function ProfilePage({ id: propId, state }: ProfilePageProps) {
const params = useParams();
const location = useLocation();
- const profileState = (location.state as MetadataCache | undefined) || state;
+ const profileState = (location.state as CachedMetadata | undefined) || state;
const navigate = useNavigate();
const [id, setId] = useState(profileState?.pubkey);
const [relays, setRelays] = useState>();
diff --git a/packages/app/src/Utils/Notifications.ts b/packages/app/src/Utils/Notifications.ts
index 16f7cbe5..30999541 100644
--- a/packages/app/src/Utils/Notifications.ts
+++ b/packages/app/src/Utils/Notifications.ts
@@ -1,6 +1,6 @@
import { base64 } from "@scure/base";
import { removeUndefined, unwrap } from "@snort/shared";
-import { EventKind, EventPublisher, MetadataCache, TaggedNostrEvent } from "@snort/system";
+import { EventKind, EventPublisher, CachedMetadata, TaggedNostrEvent } from "@snort/system";
import { UserCache } from "@/Cache";
import SnortApi from "@/External/SnortApi";
@@ -38,7 +38,7 @@ export async function makeNotification(ev: TaggedNostrEvent): Promise {
diff --git a/packages/app/src/Utils/index.ts b/packages/app/src/Utils/index.ts
index 3db6487d..812d6e21 100644
--- a/packages/app/src/Utils/index.ts
+++ b/packages/app/src/Utils/index.ts
@@ -9,7 +9,7 @@ import {
encodeTLV,
EventKind,
HexKey,
- MetadataCache,
+ CachedMetadata,
NostrEvent,
NostrLink,
NostrPrefix,
@@ -214,8 +214,8 @@ export function getLatestByPubkey(events: TaggedNostrEvent[]): Map {
- const deduped = profiles.reduce((results: Map, ev) => {
+export function getLatestProfileByPubkey(profiles: CachedMetadata[]): Map {
+ const deduped = profiles.reduce((results: Map, ev) => {
if (!results.has(ev.pubkey)) {
const latest = getNewestProfile(profiles.filter(a => a.pubkey === ev.pubkey));
if (latest) {
@@ -223,7 +223,7 @@ export function getLatestProfileByPubkey(profiles: MetadataCache[]): Map());
+ }, new Map());
return deduped;
}
@@ -255,7 +255,7 @@ export function getNewest(rawNotes: readonly TaggedNostrEvent[]) {
}
}
-export function getNewestProfile(rawNotes: MetadataCache[]) {
+export function getNewestProfile(rawNotes: CachedMetadata[]) {
const notes = [...rawNotes];
notes.sort((a, b) => b.created - a.created);
if (notes.length > 0) {
@@ -279,7 +279,7 @@ export function tagFilterOfTextRepost(note: TaggedNostrEvent, id?: u256): (tag:
tag[0] === "e" && tag[3] === "mention" && note.content === `#[${i}]` && (id ? tag[1] === id : true);
}
-export function groupByPubkey(acc: Record, user: MetadataCache) {
+export function groupByPubkey(acc: Record, user: CachedMetadata) {
return { ...acc, [user.pubkey]: user };
}
diff --git a/packages/app/src/system.ts b/packages/app/src/system.ts
index e8552673..8552a47f 100644
--- a/packages/app/src/system.ts
+++ b/packages/app/src/system.ts
@@ -2,7 +2,7 @@ import { removeUndefined, throwIfOffline } from "@snort/shared";
import { mapEventToProfile, NostrEvent, NostrSystem, ProfileLoaderService, socialGraphInstance } from "@snort/system";
import { RelayMetrics, SystemDb, UserCache, UserRelays } from "@/Cache";
-import { addEventToFuzzySearch } from "@/Db/FuzzySearch";
+import { addEventToFuzzySearch, addProfileToFuzzySearch } from "@/Db/FuzzySearch";
import { LoginStore } from "@/Utils/Login";
import { hasWasm, WasmOptimizer } from "@/Utils/wasm";
diff --git a/packages/system-react/src/useUserProfile.ts b/packages/system-react/src/useUserProfile.ts
index 95dd0a6c..4410e6e6 100644
--- a/packages/system-react/src/useUserProfile.ts
+++ b/packages/system-react/src/useUserProfile.ts
@@ -1,13 +1,13 @@
import { useContext, useSyncExternalStore } from "react";
-import { HexKey, MetadataCache } from "@snort/system";
+import { HexKey, CachedMetadata } from "@snort/system";
import { SnortContext } from "./context";
/**
* Gets a profile from cache or requests it from the relays
*/
-export function useUserProfile(pubKey?: HexKey): MetadataCache | undefined {
+export function useUserProfile(pubKey?: HexKey): CachedMetadata | undefined {
const system = useContext(SnortContext);
- return useSyncExternalStore(
+ return useSyncExternalStore(
h => {
if (pubKey) {
system.ProfileLoader.TrackKeys(pubKey);
diff --git a/packages/system-web/src/index.ts b/packages/system-web/src/index.ts
index 1f3366d2..9e53455a 100644
--- a/packages/system-web/src/index.ts
+++ b/packages/system-web/src/index.ts
@@ -1,4 +1,4 @@
-import { NostrEvent, MetadataCache, RelayMetrics, UsersRelays } from "@snort/system";
+import { NostrEvent, CachedMetadata, RelayMetrics, UsersRelays } from "@snort/system";
import Dexie, { Table } from "dexie";
const NAME = "snort-system";
@@ -13,7 +13,7 @@ const STORES = {
export class SnortSystemDb extends Dexie {
ready = false;
- users!: Table;
+ users!: Table;
relayMetrics!: Table;
userRelays!: Table;
events!: Table;
diff --git a/packages/system/src/cache/index.ts b/packages/system/src/cache/index.ts
index e1315b75..f7e327cb 100644
--- a/packages/system/src/cache/index.ts
+++ b/packages/system/src/cache/index.ts
@@ -1,7 +1,7 @@
import { FullRelaySettings, HexKey, NostrEvent, UserMetadata } from "..";
import { hexToBech32, unixNowMs, DexieTableLike } from "@snort/shared";
-export interface MetadataCache extends UserMetadata {
+export interface CachedMetadata extends UserMetadata {
/**
* When the object was saved in cache
*/
@@ -58,7 +58,7 @@ export function mapEventToProfile(ev: NostrEvent) {
npub: hexToBech32("npub", ev.pubkey),
created: ev.created_at,
loaded: unixNowMs(),
- } as MetadataCache;
+ } as CachedMetadata;
// sanitize non-string/number
for (const [k, v] of Object.entries(ret)) {
@@ -73,7 +73,7 @@ export function mapEventToProfile(ev: NostrEvent) {
}
export interface SnortSystemDb {
- users: DexieTableLike;
+ users: DexieTableLike;
relayMetrics: DexieTableLike;
userRelays: DexieTableLike;
events: DexieTableLike;
diff --git a/packages/system/src/cache/user-metadata.ts b/packages/system/src/cache/user-metadata.ts
index b3485b17..0895697c 100644
--- a/packages/system/src/cache/user-metadata.ts
+++ b/packages/system/src/cache/user-metadata.ts
@@ -1,17 +1,17 @@
-import { MetadataCache } from ".";
+import { CachedMetadata } from ".";
import { fetchNip05Pubkey, FeedCache, LNURL, DexieTableLike } from "@snort/shared";
-export class UserProfileCache extends FeedCache {
+export class UserProfileCache extends FeedCache {
#zapperQueue: Array<{ pubkey: string; lnurl: string }> = [];
#nip5Queue: Array<{ pubkey: string; nip05: string }> = [];
- constructor(table?: DexieTableLike) {
+ constructor(table?: DexieTableLike) {
super("UserCache", table);
this.#processZapperQueue();
this.#processNip5Queue();
}
- key(of: MetadataCache): string {
+ key(of: CachedMetadata): string {
return of.pubkey;
}
@@ -23,7 +23,7 @@ export class UserProfileCache extends FeedCache {
}
}
- async search(q: string): Promise> {
+ async search(q: string): Promise> {
if (this.table) {
// on-disk cache will always have more data
return (
@@ -41,7 +41,7 @@ export class UserProfileCache extends FeedCache {
} else {
return [...this.cache.values()]
.filter(user => {
- const profile = user as MetadataCache;
+ const profile = user as CachedMetadata;
return (
profile.name?.includes(q) ||
profile.npub?.includes(q) ||
@@ -58,7 +58,7 @@ export class UserProfileCache extends FeedCache {
* @param m Profile metadata
* @returns
*/
- override async update(m: MetadataCache) {
+ override async update(m: CachedMetadata) {
const updateType = await super.update(m);
if (updateType !== "refresh") {
const lnurl = m.lud16 ?? m.lud06;
@@ -78,7 +78,7 @@ export class UserProfileCache extends FeedCache {
return updateType;
}
- takeSnapshot(): MetadataCache[] {
+ takeSnapshot(): CachedMetadata[] {
return [...this.cache.values()];
}
diff --git a/packages/system/src/nostr-system.ts b/packages/system/src/nostr-system.ts
index 7e5272ef..8ad13e36 100644
--- a/packages/system/src/nostr-system.ts
+++ b/packages/system/src/nostr-system.ts
@@ -9,7 +9,7 @@ import { NoteStore } from "./note-collection";
import { BuiltRawReqFilter, RequestBuilder } from "./request-builder";
import { RelayMetricHandler } from "./relay-metric-handler";
import {
- MetadataCache,
+ CachedMetadata,
ProfileLoaderService,
RelayMetrics,
SystemInterface,
@@ -38,7 +38,7 @@ export interface NostrSystemEvents {
export interface NostrsystemProps {
relayCache?: FeedCache;
- profileCache?: FeedCache;
+ profileCache?: FeedCache;
relayMetrics?: FeedCache;
eventsCache?: FeedCache;
optimizer?: Optimizer;
@@ -62,7 +62,7 @@ export class NostrSystem extends EventEmitter implements Syst
/**
* Storage class for user profiles
*/
- #profileCache: FeedCache;
+ #profileCache: FeedCache;
/**
* Storage class for relay metrics (connects/disconnects)
diff --git a/packages/system/src/profile-cache.ts b/packages/system/src/profile-cache.ts
index 84d2e511..377d61ac 100644
--- a/packages/system/src/profile-cache.ts
+++ b/packages/system/src/profile-cache.ts
@@ -1,16 +1,16 @@
import { unixNowMs } from "@snort/shared";
import { EventKind, TaggedNostrEvent, RequestBuilder } from ".";
import { ProfileCacheExpire } from "./const";
-import { mapEventToProfile, MetadataCache } from "./cache";
+import { mapEventToProfile, CachedMetadata } from "./cache";
import { v4 as uuid } from "uuid";
import { BackgroundLoader } from "./background-loader";
-export class ProfileLoaderService extends BackgroundLoader {
+export class ProfileLoaderService extends BackgroundLoader {
override name(): string {
return "ProfileLoaderService";
}
- override onEvent(e: Readonly): MetadataCache | undefined {
+ override onEvent(e: Readonly): CachedMetadata | undefined {
return mapEventToProfile(e);
}
@@ -30,11 +30,11 @@ export class ProfileLoaderService extends BackgroundLoader {
return sub;
}
- protected override makePlaceholder(key: string): MetadataCache | undefined {
+ protected override makePlaceholder(key: string): CachedMetadata | undefined {
return {
pubkey: key,
loaded: unixNowMs() - ProfileCacheExpire + 30_000,
created: 0,
- } as MetadataCache;
+ } as CachedMetadata;
}
}