From 8cb89f362c4244ae89759ee17e23845cb2cd9dd8 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Mon, 31 Aug 2026 10:31:58 -0700 Subject: [PATCH] Add deriveLatestEvent for ProfileBadges --- src/app/components/ProfileBadges.svelte | 26 +++------ src/app/repository.ts | 76 ++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/src/app/components/ProfileBadges.svelte b/src/app/components/ProfileBadges.svelte index 45cac751..13a96b0e 100644 --- a/src/app/components/ProfileBadges.svelte +++ b/src/app/components/ProfileBadges.svelte @@ -1,11 +1,11 @@
- {#if $events.length > 0} + {#if $latest} {/if} {#if $spaceUrls.length > 0} diff --git a/src/app/repository.ts b/src/app/repository.ts index 8c2ef850..35ea1202 100644 --- a/src/app/repository.ts +++ b/src/app/repository.ts @@ -1,5 +1,8 @@ -import {derived} from "svelte/store" -import {filter, spec} from "@welshman/lib" +import {derived, readable} from "svelte/store" +import type {Unsubscriber} from "svelte/store" +import {filter, first, on, spec} from "@welshman/lib" +import type {Maybe} from "@welshman/lib" +import {sortEventsDesc} from "@welshman/util" import type {Filter, TrustedEvent} from "@welshman/util" import * as store from "@welshman/store" import {Network, Relays} from "@welshman/app" @@ -61,3 +64,72 @@ export const deriveRelaySignedEvents = (url: string, filters: Filter[] = [{}]) = [fromApp($app => $app.use(Relays).one(url)), deriveEventsForUrl(url, filters)], ([$relay, $events]) => filter(spec({pubkey: $relay?.self}), $events as TrustedEvent[]), ) + +// The most recent event held from one author. + +const latestByPubkey = new Map>() + +const latestSubscribers = new Map) => void>>() + +let latestUnsubscriber: Maybe + +const readLatest = (pubkey: string) => + first(sortEventsDesc(app.get().repository.query([{authors: [pubkey]}]))) + +export const deriveLatestEvent = (pubkey: string) => + readable>(undefined, set => { + let subscribers = latestSubscribers.get(pubkey) + + if (!subscribers) { + subscribers = new Set() + latestSubscribers.set(pubkey, subscribers) + latestByPubkey.set(pubkey, readLatest(pubkey)) + } + + subscribers.add(set) + set(latestByPubkey.get(pubkey)) + + latestUnsubscriber ??= on(app.get().repository, "update", ({added, removed}) => { + const touched = new Set() + + for (const event of added) { + if (latestSubscribers.has(event.pubkey)) { + const current = latestByPubkey.get(event.pubkey) + + if (!current || event.created_at > current.created_at) { + latestByPubkey.set(event.pubkey, event) + touched.add(event.pubkey) + } + } + } + + // A removal can take the very event a row is showing, so that author has to be looked up + // again rather than just dropped + for (const [author, event] of latestByPubkey) { + if (event && removed.has(event.id)) { + latestByPubkey.set(author, readLatest(author)) + touched.add(author) + } + } + + for (const author of touched) { + for (const subscriber of latestSubscribers.get(author) || []) { + subscriber(latestByPubkey.get(author)) + } + } + }) + + return () => { + subscribers.delete(set) + + if (subscribers.size === 0) { + latestSubscribers.delete(pubkey) + latestByPubkey.delete(pubkey) + + if (latestSubscribers.size === 0) { + latestUnsubscriber?.() + latestUnsubscriber = undefined + } + } + } + })