diff --git a/package.json b/package.json index d4b5a48..55d7e34 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@welshman", "private": true, - "version": "0.8.0", + "version": "0.8.1", "workspaces": [ "packages/*" ], diff --git a/packages/app/package.json b/packages/app/package.json index aa1ecd6..b1cde6b 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/app", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "A collection of svelte stores for use in building nostr client applications.", diff --git a/packages/app/src/blockedRelayLists.ts b/packages/app/src/blockedRelayLists.ts new file mode 100644 index 0000000..8bc49b8 --- /dev/null +++ b/packages/app/src/blockedRelayLists.ts @@ -0,0 +1,42 @@ +import {BLOCKED_RELAYS, asDecryptedEvent, readList} from "@welshman/util" +import {TrustedEvent} from "@welshman/util" +import { + deriveItemsByKey, + deriveItems, + makeForceLoadItem, + makeLoadItem, + makeDeriveItem, + getter, +} from "@welshman/store" +import {repository} from "./core.js" +import {makeOutboxLoader} from "./relayLists.js" + +export const blockedRelayListsByPubkey = deriveItemsByKey({ + repository, + eventToItem: (event: TrustedEvent) => readList(asDecryptedEvent(event)), + filters: [{kinds: [BLOCKED_RELAYS]}], + getKey: blockedRelayLists => blockedRelayLists.event.pubkey, +}) + +export const blockedRelayLists = deriveItems(blockedRelayListsByPubkey) + +export const getBlockedRelayListsByPubkey = getter(blockedRelayListsByPubkey) + +export const getBlockedRelayLists = getter(blockedRelayLists) + +export const getBlockedRelayList = (pubkey: string) => getBlockedRelayListsByPubkey().get(pubkey) + +export const forceLoadBlockedRelayList = makeForceLoadItem( + makeOutboxLoader(BLOCKED_RELAYS), + getBlockedRelayList, +) + +export const loadBlockedRelayList = makeLoadItem( + makeOutboxLoader(BLOCKED_RELAYS), + getBlockedRelayList, +) + +export const deriveBlockedRelayList = makeDeriveItem( + blockedRelayListsByPubkey, + loadBlockedRelayList, +) diff --git a/packages/app/src/commands.ts b/packages/app/src/commands.ts index 153feb1..fa50990 100644 --- a/packages/app/src/commands.ts +++ b/packages/app/src/commands.ts @@ -24,6 +24,7 @@ import { editProfile, RelayMode, MESSAGING_RELAYS, + BLOCKED_RELAYS, FOLLOWS, RELAYS, MUTES, @@ -36,6 +37,8 @@ import { forceLoadUserRelayList, userMessagingRelayList, forceLoadUserMessagingRelayList, + userBlockedRelayList, + forceLoadUserBlockedRelayList, userFollowList, forceLoadUserFollowList, userMuteList, @@ -105,6 +108,28 @@ export const addMessagingRelay = async (url: string) => { return publishThunk({event, relays}) } +// NIP 51 + +export const removeBlockedRelay = async (url: string) => { + await forceLoadUserBlockedRelayList([]) + + const list = get(userBlockedRelayList) || makeList({kind: BLOCKED_RELAYS}) + const event = await removeFromList(list, url).reconcile(nip44EncryptToSelf) + const relays = Router.get().FromUser().policy(addMaximalFallbacks).getUrls() + + return publishThunk({event, relays}) +} + +export const addBlockedRelay = async (url: string) => { + await forceLoadUserBlockedRelayList([]) + + const list = get(userBlockedRelayList) || makeList({kind: BLOCKED_RELAYS}) + const event = await addToListPublicly(list, ["relay", url]).reconcile(nip44EncryptToSelf) + const relays = Router.get().FromUser().policy(addMaximalFallbacks).getUrls() + + return publishThunk({event, relays}) +} + // NIP 01 export const setProfile = (profile: Profile) => { diff --git a/packages/app/src/index.ts b/packages/app/src/index.ts index 6238810..d9d8b35 100644 --- a/packages/app/src/index.ts +++ b/packages/app/src/index.ts @@ -12,6 +12,7 @@ export * from "./pins.js" export * from "./relays.js" export * from "./relayStats.js" export * from "./relayLists.js" +export * from "./blockedRelayLists.js" export * from "./messagingRelayLists.js" export * from "./search.js" export * from "./session.js" @@ -40,6 +41,7 @@ import {repository, tracker} from "./core.js" import {getRelays, loadRelay} from "./relays.js" import {trackRelayStats, getRelayQuality} from "./relayStats.js" import {deriveRelayList, getRelayList} from "./relayLists.js" +import {deriveBlockedRelayList, getBlockedRelayList} from "./blockedRelayLists.js" import {deriveMessagingRelayList, getMessagingRelayList} from "./messagingRelayLists.js" // Sync relays with our database @@ -84,15 +86,19 @@ const _relayGetter = (fn?: (relay: RelayProfile) => any) => .map(r => r.url) }) -export const getPubkeyRelays = (pubkey: string, mode?: RelayMode) => - mode === RelayMode.Messaging - ? getRelaysFromList(getMessagingRelayList(pubkey)) - : getRelaysFromList(getRelayList(pubkey), mode) +export const getPubkeyRelays = (pubkey: string, mode?: RelayMode) => { + if (mode === RelayMode.Blocked) return getRelaysFromList(getBlockedRelayList(pubkey)) + if (mode === RelayMode.Messaging) return getRelaysFromList(getMessagingRelayList(pubkey)) + return getRelaysFromList(getRelayList(pubkey), mode) +} -export const derivePubkeyRelays = (pubkey: string, mode?: RelayMode) => - mode === RelayMode.Messaging - ? derived(deriveMessagingRelayList(pubkey), list => getRelaysFromList(list)) - : derived(deriveRelayList(pubkey), list => getRelaysFromList(list, mode)) +export const derivePubkeyRelays = (pubkey: string, mode?: RelayMode) => { + if (mode === RelayMode.Blocked) + return derived(deriveBlockedRelayList(pubkey), list => getRelaysFromList(list)) + if (mode === RelayMode.Messaging) + return derived(deriveMessagingRelayList(pubkey), list => getRelaysFromList(list)) + return derived(deriveRelayList(pubkey), list => getRelaysFromList(list, mode)) +} routerContext.getUserPubkey = () => pubkey.get() routerContext.getPubkeyRelays = getPubkeyRelays diff --git a/packages/app/src/relayStats.ts b/packages/app/src/relayStats.ts index a5e26f5..f3d8ef4 100644 --- a/packages/app/src/relayStats.ts +++ b/packages/app/src/relayStats.ts @@ -1,8 +1,10 @@ import {writable, Subscriber} from "svelte/store" import {getter, makeDeriveItem} from "@welshman/store" import {groupBy, batch, now, uniq, ago, DAY, HOUR, MINUTE} from "@welshman/lib" -import {isOnionUrl, isLocalUrl, isIPAddress, isRelayUrl} from "@welshman/util" +import {isOnionUrl, isLocalUrl, isIPAddress, isRelayUrl, getRelaysFromList} from "@welshman/util" import {Pool, Socket, SocketStatus, SocketEvent, ClientMessage, RelayMessage} from "@welshman/net" +import {getBlockedRelayList} from "./blockedRelayLists.js" +import {pubkey} from "./session.js" export type RelayStats = { url: string @@ -75,6 +77,10 @@ export const getRelayQuality = (url: string) => { // Skip non-relays entirely if (!isRelayUrl(url)) return 0 + const $pubkey = pubkey.get() + + if ($pubkey && getRelaysFromList(getBlockedRelayList($pubkey)).includes(url)) return 0 + const relayStats = getRelayStats(url) // If we have recent errors, skip it diff --git a/packages/app/src/user.ts b/packages/app/src/user.ts index ad52525..29dc891 100644 --- a/packages/app/src/user.ts +++ b/packages/app/src/user.ts @@ -16,6 +16,11 @@ import { forceLoadMessagingRelayList, loadMessagingRelayList, } from "./messagingRelayLists.js" +import { + blockedRelayListsByPubkey, + forceLoadBlockedRelayList, + loadBlockedRelayList, +} from "./blockedRelayLists.js" import {wotGraph, getWotGraph} from "./wot.js" export const makeUserData = ( @@ -67,6 +72,10 @@ export const userMessagingRelayList = makeUserData( export const forceLoadUserMessagingRelayList = makeUserLoader(forceLoadMessagingRelayList) export const loadUserMessagingRelayList = makeUserLoader(loadMessagingRelayList) +export const userBlockedRelayList = makeUserData(blockedRelayListsByPubkey, loadBlockedRelayList) +export const forceLoadUserBlockedRelayList = makeUserLoader(forceLoadBlockedRelayList) +export const loadUserBlockedRelayList = makeUserLoader(loadBlockedRelayList) + export const userBlossomServerList = makeUserData(blossomServerListsByPubkey, loadBlossomServerList) export const forceLoadUserBlossomServerList = makeUserLoader(forceLoadBlossomServerList) export const loadUserBlossomServerList = makeUserLoader(loadBlossomServerList) diff --git a/packages/content/package.json b/packages/content/package.json index 30aee30..98e9734 100644 --- a/packages/content/package.json +++ b/packages/content/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/content", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "A collection of utilities for parsing nostr note content.", diff --git a/packages/editor/package.json b/packages/editor/package.json index b3635c1..d4f57d7 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/editor", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "A batteries-included nostr editor.", diff --git a/packages/feeds/package.json b/packages/feeds/package.json index 7cf3822..a6c879a 100644 --- a/packages/feeds/package.json +++ b/packages/feeds/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/feeds", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "Utilities for building dynamic nostr feeds.", diff --git a/packages/lib/package.json b/packages/lib/package.json index e3e3512..7b09505 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/lib", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "A collection of utilities.", diff --git a/packages/net/package.json b/packages/net/package.json index 64f0bd3..2500bb5 100644 --- a/packages/net/package.json +++ b/packages/net/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/net", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "Utilities for connecting with nostr relays.", diff --git a/packages/router/package.json b/packages/router/package.json index 24e064a..d2d554e 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/router", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "A collection of utilities for nostr relay selection.", diff --git a/packages/signer/package.json b/packages/signer/package.json index e80009f..cc3b9d8 100644 --- a/packages/signer/package.json +++ b/packages/signer/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/signer", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "A nostr signer implemenation supporting several login methods.", diff --git a/packages/store/package.json b/packages/store/package.json index 19bb914..def464b 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/store", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "A collection of utilities based on svelte/store for use with welshman", diff --git a/packages/util/package.json b/packages/util/package.json index 5f6d7b4..04d2a28 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@welshman/util", - "version": "0.8.0", + "version": "0.8.1", "author": "hodlbod", "license": "MIT", "description": "A collection of nostr-related utilities.", diff --git a/packages/util/src/Relay.ts b/packages/util/src/Relay.ts index fb8f94a..e6775a5 100644 --- a/packages/util/src/Relay.ts +++ b/packages/util/src/Relay.ts @@ -5,6 +5,8 @@ import {last, normalizeUrl, stripProtocol} from "@welshman/lib" export enum RelayMode { Read = "read", Write = "write", + Search = "search", + Blocked = "blocked", Messaging = "messaging", }