Fix space notifications

This commit is contained in:
Jon Staab
2024-12-16 10:30:42 -08:00
parent 9f3bfd5ac0
commit 85e5413951
6 changed files with 59 additions and 24 deletions

8
package-lock.json generated
View File

@@ -34,7 +34,7 @@
"@welshman/content": "~0.0.13", "@welshman/content": "~0.0.13",
"@welshman/dvm": "~0.0.11", "@welshman/dvm": "~0.0.11",
"@welshman/feeds": "~0.0.26", "@welshman/feeds": "~0.0.26",
"@welshman/lib": "~0.0.30", "@welshman/lib": "~0.0.32",
"@welshman/net": "~0.0.41", "@welshman/net": "~0.0.41",
"@welshman/signer": "~0.0.16", "@welshman/signer": "~0.0.16",
"@welshman/store": "~0.0.13", "@welshman/store": "~0.0.13",
@@ -4715,9 +4715,9 @@
} }
}, },
"node_modules/@welshman/lib": { "node_modules/@welshman/lib": {
"version": "0.0.30", "version": "0.0.32",
"resolved": "https://registry.npmjs.org/@welshman/lib/-/lib-0.0.30.tgz", "resolved": "https://registry.npmjs.org/@welshman/lib/-/lib-0.0.32.tgz",
"integrity": "sha512-UeYFh9H3m7NfsokyaOeOCAdp4dg2uv20+XtkDxlaLVMMJDtuePBLJBYQJKuxMavGAJURr4pXt2Xna53hN/R5Lg==", "integrity": "sha512-mQ3vG2ttsdlzQm9bkvxBsrjxHVt/3JgQWp9o32ep5H8s1sVbdjG0adtuSv0xrkrZg5zB0p0P3jRb7LXgsq89FA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@scure/base": "^1.1.6", "@scure/base": "^1.1.6",

View File

@@ -62,11 +62,11 @@
"@welshman/content": "~0.0.13", "@welshman/content": "~0.0.13",
"@welshman/dvm": "~0.0.11", "@welshman/dvm": "~0.0.11",
"@welshman/feeds": "~0.0.26", "@welshman/feeds": "~0.0.26",
"@welshman/lib": "~0.0.30", "@welshman/lib": "~0.0.33",
"@welshman/net": "~0.0.41", "@welshman/net": "~0.0.41",
"@welshman/signer": "~0.0.16", "@welshman/signer": "~0.0.16",
"@welshman/store": "~0.0.13", "@welshman/store": "~0.0.13",
"@welshman/util": "~0.0.49", "@welshman/util": "~0.0.50",
"daisyui": "^4.12.10", "daisyui": "^4.12.10",
"date-picker-svelte": "^2.13.0", "date-picker-svelte": "^2.13.0",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",

View File

@@ -5,8 +5,15 @@ import {repository, pubkey} from "@welshman/app"
import {prop, max, sortBy, assoc, lt, now} from "@welshman/lib" import {prop, max, sortBy, assoc, lt, now} from "@welshman/lib"
import type {Filter, TrustedEvent} from "@welshman/util" import type {Filter, TrustedEvent} from "@welshman/util"
import {DIRECT_MESSAGE, MESSAGE, THREAD, COMMENT} from "@welshman/util" import {DIRECT_MESSAGE, MESSAGE, THREAD, COMMENT} from "@welshman/util"
import {makeSpacePath} from "@app/routes" import {makeSpacePath, makeThreadPath, makeRoomPath} from "@app/routes"
import {LEGACY_THREAD, deriveEventsForUrl, getMembershipUrls, userMembership} from "@app/state" import {
LEGACY_THREAD,
getEventsForUrl,
deriveEventsForUrl,
getMembershipUrls,
userRoomsByUrl,
repositoryStore,
} from "@app/state"
// Checked state // Checked state
@@ -62,17 +69,30 @@ export const deriveNotification = (path: string, filters: Filter[], url?: string
} }
export const spacesNotifications = derived( export const spacesNotifications = derived(
[pubkey, checked, userMembership, deriveEvents(repository, {filters: SPACE_FILTERS})], [pubkey, checked, userRoomsByUrl, repositoryStore],
([$pubkey, $checked, $userMembership, $events]) => { ([$pubkey, $checked, $userRoomsByUrl, $repository]) => {
return getMembershipUrls($userMembership) const hasNotification = (url: string, path: string, filters: Filter[]) => {
.filter(url => { const lastChecked = max([$checked["*"], $checked[path]])
const path = makeSpacePath(url) const events = getEventsForUrl($repository, url, filters)
const lastChecked = max([$checked["*"], $checked[path]])
const [latestEvent] = sortBy($e => -$e.created_at, $events)
return latestEvent?.pubkey !== $pubkey && lt(lastChecked, latestEvent?.created_at) return getNotification($pubkey, lastChecked, events)
}
return Array.from($userRoomsByUrl.entries())
.filter(([url, rooms]) => {
if (hasNotification(url, makeThreadPath(url), THREAD_FILTERS)) {
return true
}
for (const room of rooms) {
if (hasNotification(url, makeRoomPath(url, room), [{kinds: [MESSAGE], "#h": [room]}])) {
return true
}
}
return false
}) })
.map(url => makeSpacePath(url)) .map(([url]) => makeSpacePath(url))
}, },
) )

View File

@@ -4,7 +4,7 @@ import {MESSAGE, DELETE, THREAD, COMMENT} from "@welshman/util"
import type {SubscribeRequestWithHandlers, Subscription} from "@welshman/net" import type {SubscribeRequestWithHandlers, Subscription} from "@welshman/net"
import {SubscriptionEvent} from "@welshman/net" import {SubscriptionEvent} from "@welshman/net"
import type {AppSyncOpts} from "@welshman/app" import type {AppSyncOpts} from "@welshman/app"
import {subscribe, load, pull, hasNegentropy} from "@welshman/app" import {subscribe, repository, load, pull, hasNegentropy} from "@welshman/app"
import {userRoomsByUrl, LEGACY_MESSAGE, GENERAL, getEventsForUrl} from "@app/state" import {userRoomsByUrl, LEGACY_MESSAGE, GENERAL, getEventsForUrl} from "@app/state"
// Utils // Utils
@@ -16,7 +16,7 @@ export const pullConservatively = ({relays, filters}: AppSyncOpts) => {
// Since pulling from relays without negentropy is expensive, limit how many // Since pulling from relays without negentropy is expensive, limit how many
// duplicates we repeatedly download // duplicates we repeatedly download
for (const url of dumb) { for (const url of dumb) {
const events = getEventsForUrl(url, filters) const events = getEventsForUrl(repository, url, filters)
if (events.length > 100) { if (events.length > 100) {
filters = filters.map(assoc("since", events[10]!.created_at)) filters = filters.map(assoc("since", events[10]!.created_at))

View File

@@ -15,8 +15,15 @@ export const makeChatPath = (pubkeys: string[]) => `/chat/${makeChatId(pubkeys)}
export const makeRoomPath = (url: string, room: string) => `/spaces/${encodeRelay(url)}/${room}` export const makeRoomPath = (url: string, room: string) => `/spaces/${encodeRelay(url)}/${room}`
export const makeThreadPath = (url: string, eventId: string) => export const makeThreadPath = (url: string, eventId?: string) => {
`/spaces/${encodeRelay(url)}/threads/${eventId}` let path = `/spaces/${encodeRelay(url)}/threads`
if (eventId) {
path += "/" + eventId
}
return path
}
export const getPrimaryNavItem = ($page: Page) => $page.route?.id?.split("/")[1] export const getPrimaryNavItem = ($page: Page) => $page.route?.id?.split("/")[1]

View File

@@ -53,6 +53,7 @@ import {
makeRouter, makeRouter,
tracker, tracker,
makeTrackerStore, makeTrackerStore,
makeRepositoryStore,
relay, relay,
getSession, getSession,
getSigner, getSigner,
@@ -208,6 +209,8 @@ export const ensureUnwrapped = async (event: TrustedEvent) => {
export const trackerStore = makeTrackerStore() export const trackerStore = makeTrackerStore()
export const repositoryStore = makeRepositoryStore()
export const deriveEvent = (idOrAddress: string, hints: string[] = []) => { export const deriveEvent = (idOrAddress: string, hints: string[] = []) => {
let attempted = false let attempted = false
@@ -251,7 +254,7 @@ export const getUrlsForEvent = derived([trackerStore, thunks], ([$tracker, $thun
} }
}) })
export const getEventsForUrl = (url: string, filters: Filter[]) => { export const getEventsForUrl = (repository: Repository, url: string, filters: Filter[]) => {
const $getUrlsForEvent = get(getUrlsForEvent) const $getUrlsForEvent = get(getUrlsForEvent)
const $events = repository.query(filters) const $events = repository.query(filters)
@@ -604,19 +607,24 @@ export const userMembership = withGetter(
export const userRoomsByUrl = withGetter( export const userRoomsByUrl = withGetter(
derived(userMembership, $userMembership => { derived(userMembership, $userMembership => {
const tags = getListTags($userMembership)
const $userRoomsByUrl = new Map<string, Set<string>>() const $userRoomsByUrl = new Map<string, Set<string>>()
for (const [_, room, url] of getGroupTags(getListTags($userMembership))) { for (const [_, room, url] of getGroupTags(tags)) {
addToMapKey($userRoomsByUrl, url, room) addToMapKey($userRoomsByUrl, url, room)
} }
for (const url of getRelayTagValues(tags)) {
addToMapKey($userRoomsByUrl, url, GENERAL)
}
return $userRoomsByUrl return $userRoomsByUrl
}), }),
) )
export const deriveUserRooms = (url: string) => export const deriveUserRooms = (url: string) =>
derived(userRoomsByUrl, $userRoomsByUrl => derived(userRoomsByUrl, $userRoomsByUrl =>
sortBy(roomComparator(url), uniq(Array.from($userRoomsByUrl.get(url) || []).concat(GENERAL))), sortBy(roomComparator(url), uniq(Array.from($userRoomsByUrl.get(url) || []))),
) )
export const deriveOtherRooms = (url: string) => export const deriveOtherRooms = (url: string) =>