diff --git a/packages/app/src/collection.ts b/packages/app/src/collection.ts index b950773..05a9b80 100644 --- a/packages/app/src/collection.ts +++ b/packages/app/src/collection.ts @@ -15,12 +15,11 @@ export const collection = ({ load: (key: string, ...args: LoadArgs) => Promise }) => { const indexStore = withGetter(derived(store, $items => indexBy(getKey, $items))) - const getItem = (key: string) => indexStore.get().get(key) const pending = new Map>>() const loadAttempts = new Map() const loadItem = async (key: string, ...args: LoadArgs) => { - const stale = getItem(key) + const stale = indexStore.get().get(key) const freshness = getFreshness(name, key) // If we have an item, reload if it's stale @@ -30,7 +29,7 @@ export const collection = ({ // If we already are loading, await and return if (pending.has(key)) { - return pending.get(key)!.then(() => getItem(key)) + return pending.get(key)!.then(() => indexStore.get().get(key)) } const attempt = loadAttempts.get(key) || 0 @@ -52,7 +51,7 @@ export const collection = ({ pending.delete(key) - const fresh = getItem(key) + const fresh = indexStore.get().get(key) if (fresh) { loadAttempts.delete(key) @@ -73,5 +72,5 @@ export const collection = ({ return derived(indexStore, $index => $index.get(key)) } - return {indexStore, deriveItem, loadItem, getItem} + return {indexStore, deriveItem, loadItem} } diff --git a/packages/app/src/follows.ts b/packages/app/src/follows.ts index 494dd1d..1201ce5 100644 --- a/packages/app/src/follows.ts +++ b/packages/app/src/follows.ts @@ -1,24 +1,17 @@ -import {FOLLOWS, getListValues, asDecryptedEvent, readList} from '@welshman/util' +import {FOLLOWS, asDecryptedEvent, readList} from '@welshman/util' import {type TrustedEvent, type PublishedList} from '@welshman/util' import {type SubscribeRequestWithHandlers} from "@welshman/net" -import {deriveEventsMapped, withGetter} from '@welshman/store' +import {deriveEventsMapped} from '@welshman/store' import {repository, load} from './core' import {collection} from './collection' -import {ensurePlaintext} from './plaintext' import {loadRelaySelections} from './relaySelections' -export const follows = withGetter( - deriveEventsMapped(repository, { - filters: [{kinds: [FOLLOWS]}], - itemToEvent: item => item.event, - eventToItem: async (event: TrustedEvent) => - readList( - asDecryptedEvent(event, { - content: await ensurePlaintext(event), - }), - ), - }) -) +export const follows = deriveEventsMapped(repository, { + filters: [{kinds: [FOLLOWS]}], + itemToEvent: item => item.event, + eventToItem: (event: TrustedEvent) => + readList(asDecryptedEvent(event)), +}) export const { indexStore: followsByPubkey, @@ -33,6 +26,3 @@ export const { await load({...request, filters: [{kinds: [FOLLOWS], authors: [pubkey]}]}) }, }) - -export const getFollows = (pubkey: string) => - getListValues("p", followsByPubkey.get().get(pubkey)) diff --git a/packages/app/src/handles.ts b/packages/app/src/handles.ts index a1d70db..dee6087 100644 --- a/packages/app/src/handles.ts +++ b/packages/app/src/handles.ts @@ -1,5 +1,4 @@ import {writable, derived} from 'svelte/store' -import {withGetter} from '@welshman/store' import {type SubscribeRequestWithHandlers} from "@welshman/net" import {ctx, tryCatch, fetchJson, uniq, batcher, postJson, last} from '@welshman/lib' import {collection} from './collection' @@ -41,7 +40,7 @@ export async function queryProfile(nip05: string) { } } -export const handles = withGetter(writable([])) +export const handles = writable([]) export const fetchHandles = async (nip05s: string[]) => { const base = ctx.app.dufflepudUrl! diff --git a/packages/app/src/mutes.ts b/packages/app/src/mutes.ts index 0ee77af..69f7587 100644 --- a/packages/app/src/mutes.ts +++ b/packages/app/src/mutes.ts @@ -1,24 +1,22 @@ -import {MUTES, getListValues, asDecryptedEvent, readList} from '@welshman/util' +import {MUTES, asDecryptedEvent, readList} from '@welshman/util' import {type TrustedEvent, type PublishedList} from '@welshman/util' import {type SubscribeRequestWithHandlers} from "@welshman/net" -import {deriveEventsMapped, withGetter} from '@welshman/store' +import {deriveEventsMapped} from '@welshman/store' import {repository, load} from './core' import {collection} from './collection' import {ensurePlaintext} from './plaintext' import {loadRelaySelections} from './relaySelections' -export const mutes = withGetter( - deriveEventsMapped(repository, { - filters: [{kinds: [MUTES]}], - itemToEvent: item => item.event, - eventToItem: async (event: TrustedEvent) => - readList( - asDecryptedEvent(event, { - content: await ensurePlaintext(event), - }), - ), - }) -) +export const mutes = deriveEventsMapped(repository, { + filters: [{kinds: [MUTES]}], + itemToEvent: item => item.event, + eventToItem: async (event: TrustedEvent) => + readList( + asDecryptedEvent(event, { + content: await ensurePlaintext(event), + }), + ), +}) export const { indexStore: mutesByPubkey, @@ -34,7 +32,3 @@ export const { }, }) - -export const getMutes = (pubkey: string) => - getListValues("p", mutesByPubkey.get().get(pubkey)) - diff --git a/packages/app/src/profiles.ts b/packages/app/src/profiles.ts index a563daf..27cead9 100644 --- a/packages/app/src/profiles.ts +++ b/packages/app/src/profiles.ts @@ -19,7 +19,6 @@ export const { indexStore: profilesByPubkey, deriveItem: deriveProfile, loadItem: loadProfile, - getItem: getProfile, } = collection({ name: "profiles", store: profiles, diff --git a/packages/app/src/relaySelections.ts b/packages/app/src/relaySelections.ts index b0f7530..fb5015d 100644 --- a/packages/app/src/relaySelections.ts +++ b/packages/app/src/relaySelections.ts @@ -1,56 +1,62 @@ import {uniq} from '@welshman/lib' -import {INBOX_RELAYS, RELAYS, getRelayTags, normalizeRelayUrl, type TrustedEvent} from '@welshman/util' -import {type SubscribeRequestWithHandlers} from "@welshman/net" -import {deriveEvents, withGetter} from '@welshman/store' +import {INBOX_RELAYS, RELAYS, normalizeRelayUrl, asDecryptedEvent, readList, getListTags, getRelayTags, getRelayTagValues} from '@welshman/util' +import type {TrustedEvent, PublishedList, List} from '@welshman/util' +import type {SubscribeRequestWithHandlers} from "@welshman/net" +import {deriveEventsMapped} from '@welshman/store' import {load, repository} from './core' import {collection} from './collection' -export const getRelayUrls = (event?: TrustedEvent): string[] => - uniq( - getRelayTags(event?.tags || []) - .map((t: string[]) => normalizeRelayUrl(t[1])) - ) +export const getRelayUrls = (list?: List): string[] => + uniq(getRelayTagValues(getListTags(list)).map(normalizeRelayUrl)) -export const getReadRelayUrls = (event?: TrustedEvent): string[] => +export const getReadRelayUrls = (list?: List): string[] => uniq( - getRelayTags(event?.tags || []) + getRelayTags(getListTags(list)) .filter((t: string[]) => !t[2] || t[2] === "read") .map((t: string[]) => normalizeRelayUrl(t[1])) ) -export const getWriteRelayUrls = (event?: TrustedEvent): string[] => +export const getWriteRelayUrls = (list?: List): string[] => uniq( - getRelayTags(event?.tags || []) + getRelayTags(getListTags(list)) .filter((t: string[]) => !t[2] || t[2] === "write") .map((t: string[]) => normalizeRelayUrl(t[1])) ) -export const relaySelections = withGetter(deriveEvents(repository, {filters: [{kinds: [RELAYS]}]})) +export const relaySelections = deriveEventsMapped(repository, { + filters: [{kinds: [RELAYS]}], + itemToEvent: item => item.event, + eventToItem: (event: TrustedEvent) => + readList(asDecryptedEvent(event)), +}) export const { indexStore: relaySelectionsByPubkey, deriveItem: deriveRelaySelections, loadItem: loadRelaySelections, - getItem: getRelaySelections, } = collection({ name: "relaySelections", store: relaySelections, - getKey: relaySelections => relaySelections.pubkey, + getKey: relaySelections => relaySelections.event.pubkey, load: (pubkey: string, request: Partial = {}) => load({...request, filters: [{kinds: [RELAYS], authors: [pubkey]}]}), }) -export const inboxRelaySelections = withGetter(deriveEvents(repository, {filters: [{kinds: [INBOX_RELAYS]}]})) +export const inboxRelaySelections = deriveEventsMapped(repository, { + filters: [{kinds: [INBOX_RELAYS]}], + itemToEvent: item => item.event, + eventToItem: (event: TrustedEvent) => + readList(asDecryptedEvent(event)), +}) export const { indexStore: inboxRelaySelectionsByPubkey, deriveItem: deriveInboxRelaySelections, loadItem: loadInboxRelaySelections, - getItem: getInboxRelaySelections, } = collection({ name: "inboxRelaySelections", store: inboxRelaySelections, - getKey: inboxRelaySelections => inboxRelaySelections.pubkey, + getKey: inboxRelaySelections => inboxRelaySelections.event.pubkey, load: (pubkey: string, request: Partial = {}) => load({...request, filters: [{kinds: [INBOX_RELAYS], authors: [pubkey]}]}), }) diff --git a/packages/app/src/wot.ts b/packages/app/src/wot.ts index 736d998..84757aa 100644 --- a/packages/app/src/wot.ts +++ b/packages/app/src/wot.ts @@ -1,11 +1,17 @@ import {throttle} from 'throttle-debounce' import {derived, writable} from 'svelte/store' import {addToMapKey, inc, dec} from '@welshman/lib' -import {getListValues} from '@welshman/util' +import {getListTags, getPubkeyTagValues} from '@welshman/util' import {throttled, withGetter} from '@welshman/store' import {pubkey} from './session' -import {follows, getFollows, followsByPubkey} from './follows' -import {mutes, getMutes} from './mutes' +import {follows, followsByPubkey} from './follows' +import {mutes, mutesByPubkey} from './mutes' + +export const getFollows = (pubkey: string) => + getPubkeyTagValues(getListTags(followsByPubkey.get().get(pubkey))) + +export const getMutes = (pubkey: string) => + getPubkeyTagValues(getListTags(mutesByPubkey.get().get(pubkey))) export const followersByPubkey = withGetter( derived( @@ -14,7 +20,7 @@ export const followersByPubkey = withGetter( const $followersByPubkey = new Map>() for (const list of lists) { - for (const pubkey of getListValues("p", list)) { + for (const pubkey of getPubkeyTagValues(getListTags(list))) { addToMapKey($followersByPubkey, pubkey, list.event.pubkey) } } @@ -31,7 +37,7 @@ export const mutersByPubkey = withGetter( const $mutersByPubkey = new Map>() for (const list of lists) { - for (const pubkey of getListValues("p", list)) { + for (const pubkey of getPubkeyTagValues(getListTags(list))) { addToMapKey($mutersByPubkey, pubkey, list.event.pubkey) } } diff --git a/packages/app/src/zappers.ts b/packages/app/src/zappers.ts index c74d988..7c30f4f 100644 --- a/packages/app/src/zappers.ts +++ b/packages/app/src/zappers.ts @@ -1,12 +1,11 @@ import {writable, derived} from 'svelte/store' -import {withGetter} from '@welshman/store' import {type Zapper} from '@welshman/util' import {type SubscribeRequestWithHandlers} from "@welshman/net" import {ctx, identity, fetchJson, uniq, bech32ToHex, hexToBech32, tryCatch, batcher, postJson} from '@welshman/lib' import {collection} from './collection' import {deriveProfile} from './profiles' -export const zappers = withGetter(writable([])) +export const zappers = writable([]) export const fetchZappers = async (lnurls: string[]) => { const base = ctx.app.dufflepudUrl! diff --git a/packages/util/src/Encryptable.ts b/packages/util/src/Encryptable.ts index 14706b8..c46dc88 100644 --- a/packages/util/src/Encryptable.ts +++ b/packages/util/src/Encryptable.ts @@ -18,7 +18,7 @@ export type DecryptedEvent = TrustedEvent & { plaintext: Partial } -export const asDecryptedEvent = (event: TrustedEvent, plaintext: Partial) => +export const asDecryptedEvent = (event: TrustedEvent, plaintext: Partial = {}) => ({...event, plaintext}) as DecryptedEvent export class Encryptable { diff --git a/packages/util/src/List.ts b/packages/util/src/List.ts index 476f3f4..69364bb 100644 --- a/packages/util/src/List.ts +++ b/packages/util/src/List.ts @@ -1,7 +1,7 @@ -import {parseJson, ensurePlural, nth} from "@welshman/lib" +import {parseJson} from "@welshman/lib" import {Address} from "./Address" import {isShareableRelayUrl} from "./Relay" -import {Encryptable, DecryptedEvent} from "./Encryptable" +import {DecryptedEvent} from "./Encryptable" export type ListParams = { kind: number @@ -39,16 +39,5 @@ export const readList = (event: DecryptedEvent): PublishedList => { return {event, kind: event.kind, publicTags, privateTags} } -export const createList = ({kind, publicTags = [], privateTags = []}: List) => - new Encryptable({kind, tags: publicTags}, {content: JSON.stringify(privateTags)}) - -export const editList = ({kind, publicTags = [], privateTags = []}: PublishedList) => - new Encryptable({kind, tags: publicTags}, {content: JSON.stringify(privateTags)}) - -export const getListValues = (tagName: string | string[], list: List | undefined) => { - const tagNames = ensurePlural(tagName) - const allTags = [...list?.publicTags || [], ...list?.privateTags || []] - const filteredTags = allTags.filter(t => tagNames.includes(t[0])).map(nth(1)) - - return filteredTags -} +export const getListTags = (list: List | undefined) => + [...list?.publicTags || [], ...list?.privateTags || []] diff --git a/packages/util/src/Tags.ts b/packages/util/src/Tags.ts index 78250d4..b3f5bd8 100644 --- a/packages/util/src/Tags.ts +++ b/packages/util/src/Tags.ts @@ -177,6 +177,15 @@ export class Tags extends (Fluent as OmitStatics, 'from' // New, simpler version +export const getTags = (types: string | string[], tags: string[][]) => { + types = ensurePlural(types) + + return tags.filter(t => types.includes(t[0])) +} + +export const getTagValues = (types: string | string[], tags: string[][]) => + getTags(types, tags).map(nth(1)) + export const getEventTags = (tags: string[][]) => tags.filter(t => ["e"].includes(t[0]) && t[1].length === 64)