Refactor: use relay-provided member lists as source of truth #191

Merged
hodlbod merged 8 commits from :dev into dev 2026-04-13 21:12:51 +00:00
10 changed files with 250 additions and 175 deletions
Showing only changes of commit 667e170351 - Show all commits
+7 -3
View File
@@ -33,7 +33,7 @@
import RoomImage from "@app/components/RoomImage.svelte"
import {
deriveRoom,
deriveRoomMembers,
deriveRoomMemberList,
deriveUserIsRoomAdmin,
deriveUserRoomMembershipStatus,
deriveUserRooms,
@@ -57,7 +57,7 @@
const {url, h}: Props = $props()
const room = deriveRoom(url, h)
const members = deriveRoomMembers(url, h)
const members = deriveRoomMemberList(url, h)
const userIsAdmin = deriveUserIsRoomAdmin(url, h)
const membershipStatus = deriveUserRoomMembershipStatus(url, h)
const userRooms = deriveUserRooms(url)
@@ -243,7 +243,7 @@
{/if}
</div>
</div>
{#if $members.length > 0}
{#if $members !== undefined && $members.length > 0}
<div class="card2 card2-sm bg-alt flex items-center justify-between gap-4">
<div class="flex items-center gap-4">
<span>Members:</span>
@@ -251,6 +251,10 @@
</div>
<Button class="btn btn-neutral btn-sm" onclick={showMembers}>View All</Button>
</div>
{:else if $members === undefined}
<div class="card2 card2-sm bg-base-200 flex items-center gap-4">
<span class="text-error">Member list not available from this relay</span>
</div>
{/if}
<div class="card2 card2-sm bg-alt col-4">
<strong class="text-lg">Room Settings</strong>
+38 -28
View File
@@ -18,7 +18,7 @@
import Profile from "@app/components/Profile.svelte"
import RoomName from "@app/components/RoomName.svelte"
import RoomMembersAdd from "@app/components/RoomMembersAdd.svelte"
import {deriveRoom, deriveRoomMembers, deriveUserIsRoomAdmin} from "@app/core/state"
import {deriveRoom, deriveRoomMemberList, deriveUserIsRoomAdmin} from "@app/core/state"
import {pushModal} from "@app/util/modal"
import {pushToast} from "@app/util/toast"
@@ -30,7 +30,7 @@
const {url, h}: Props = $props()
const room = deriveRoom(url, h)
const members = deriveRoomMembers(url, h)
const members = deriveRoomMemberList(url, h)
const userIsAdmin = deriveUserIsRoomAdmin(url, h)
const back = () => history.back()
@@ -73,34 +73,44 @@
</ModalSubtitle>
</ModalHeader>
<div class="flex flex-col gap-2">
{#each $members as pubkey (pubkey)}
<div class="card2 bg-alt relative">
<div class="flex items-center justify-between gap-2">
<div class="min-w-0 flex-1">
<Profile {pubkey} {url} />
</div>
<div class="relative">
<Button class="btn btn-circle btn-ghost btn-sm" onclick={() => toggleMenu(pubkey)}>
<Icon icon={MenuDots} />
</Button>
{#if menuPubkey === pubkey}
<Popover hideOnClick onClose={closeMenu}>
<ul
transition:fly
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
<li>
<Button class="text-error" onclick={() => removeMember(pubkey)}>
<Icon icon={MinusCircle} />
Remove Member
</Button>
</li>
</ul>
</Popover>
{/if}
{#if $members === undefined}
<div class="card2 bg-base-200 p-4">
<span class="text-error">Member list not available from this relay</span>
</div>
{:else if $members.length === 0}
<div class="card2 bg-base-200 p-4">
<span class="text-base-content/70">No members yet</span>
</div>
{:else}
{#each $members as pubkey (pubkey)}
<div class="card2 bg-alt relative">
<div class="flex items-center justify-between gap-2">
<div class="min-w-0 flex-1">
<Profile {pubkey} {url} />
</div>
<div class="relative">
<Button class="btn btn-circle btn-ghost btn-sm" onclick={() => toggleMenu(pubkey)}>
<Icon icon={MenuDots} />
</Button>
{#if menuPubkey === pubkey}
<Popover hideOnClick onClose={closeMenu}>
<ul
transition:fly
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
<li>
<Button class="text-error" onclick={() => removeMember(pubkey)}>
<Icon icon={MinusCircle} />
Remove Member
</Button>
</li>
</ul>
</Popover>
{/if}
</div>
</div>
</div>
</div>
{/each}
{/each}
{/if}
</div>
</ModalBody>
<ModalFooter>
+11 -2
View File
@@ -20,7 +20,7 @@
import ProfileMultiSelect from "@app/components/ProfileMultiSelect.svelte"
import {pushToast} from "@app/util/toast"
import {pushModal} from "@app/util/modal"
import {deriveRoom, deriveSpaceMembers} from "@app/core/state"
import {deriveRoom, deriveRelayMemberList} from "@app/core/state"
import {addRoomMembers} from "@app/core/commands"
interface Props {
@@ -31,7 +31,7 @@
const {url, h}: Props = $props()
const room = deriveRoom(url, h)
const spaceMembers = deriveSpaceMembers(url)
const spaceMembers = deriveRelayMemberList(url)
const back = () => history.back()
@@ -56,6 +56,15 @@
}
const onSubmit = async () => {
// Space member list is required to add members to a room
if (!$spaceMembers) {
pushToast({
theme: "error",
message: "Cannot add members: space member list not available from this relay",
})
return
}
hodlbod marked this conversation as resolved Outdated
Outdated
Review

Don't fail here, just skip the space membership step if there's no member list.

Don't fail here, just skip the space membership step if there's no member list.
const pubkeysSnapshot = $state.snapshot(pubkeys)
const nonSpaceMembers = pubkeysSnapshot.filter(pubkey => !$spaceMembers.includes(pubkey))
+53 -41
View File
@@ -22,7 +22,7 @@
import SpaceMembersAdd from "@app/components/SpaceMembersAdd.svelte"
import SpaceMembersBanned from "@app/components/SpaceMembersBanned.svelte"
import {
deriveSpaceMembers,
deriveRelayMemberList,
deriveSpaceBannedPubkeyItems,
deriveUserIsSpaceAdmin,
deriveSupportedMethods,
@@ -36,7 +36,7 @@
const {url}: Props = $props()
const members = deriveSpaceMembers(url)
const members = deriveRelayMemberList(url)
const bans = deriveSpaceBannedPubkeyItems(url)
const userIsAdmin = deriveUserIsSpaceAdmin(url)
const supportedMethods = deriveSupportedMethods(url)
@@ -112,46 +112,58 @@
{/if}
{/if}
<div class="flex flex-col gap-2">
{#each $members as pubkey (pubkey)}
<div class="card2 card2-sm bg-alt relative">
<div class="flex items-center justify-between gap-2">
<div class="min-w-0 flex-1">
<Profile {pubkey} {url} />
</div>
{#if canBan || canUnallow}
<div class="relative">
<Button class="btn btn-circle btn-ghost btn-sm" onclick={() => toggleMenu(pubkey)}>
<Icon icon={MenuDots} />
</Button>
{#if menuPubkey === pubkey}
<Popover hideOnClick onClose={closeMenu}>
<ul
transition:fly
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
{#if canUnallow}
<li>
<Button onclick={() => unallowMember(pubkey)}>
<Icon icon={UserMinus} />
Remove User
</Button>
</li>
{/if}
{#if canBan}
<li>
<Button class="text-error" onclick={() => banMember(pubkey)}>
<Icon icon={MinusCircle} />
Ban User
</Button>
</li>
{/if}
</ul>
</Popover>
{/if}
</div>
{/if}
</div>
{#if $members === undefined}
<div class="card2 bg-base-200 p-4">
<span class="text-error">Member list not available from this relay</span>
hodlbod marked this conversation as resolved Outdated
Outdated
Review

Use "space" instead of "relay"

Use "space" instead of "relay"
</div>
{/each}
{:else if $members.length === 0}
<div class="card2 bg-base-200 p-4">
<span class="text-base-content/70">No members yet</span>
</div>
{:else}
{#each $members as pubkey (pubkey)}
<div class="card2 card2-sm bg-alt relative">
<div class="flex items-center justify-between gap-2">
<div class="min-w-0 flex-1">
<Profile {pubkey} {url} />
</div>
{#if canBan || canUnallow}
<div class="relative">
<Button
class="btn btn-circle btn-ghost btn-sm"
onclick={() => toggleMenu(pubkey)}>
<Icon icon={MenuDots} />
</Button>
{#if menuPubkey === pubkey}
<Popover hideOnClick onClose={closeMenu}>
<ul
transition:fly
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
{#if canUnallow}
<li>
<Button onclick={() => unallowMember(pubkey)}>
<Icon icon={UserMinus} />
Remove User
</Button>
</li>
{/if}
{#if canBan}
<li>
<Button class="text-error" onclick={() => banMember(pubkey)}>
<Icon icon={MinusCircle} />
Ban User
</Button>
</li>
{/if}
</ul>
</Popover>
{/if}
</div>
{/if}
</div>
</div>
{/each}
{/if}
</div>
</ModalBody>
<ModalFooter>
+7 -3
View File
@@ -44,7 +44,7 @@
import {
ENABLE_ZAPS,
CONTENT_KINDS,
deriveSpaceMembers,
deriveRelayMemberList,
deriveUserRooms,
deriveOtherRooms,
deriveOtherVoiceRooms,
@@ -76,7 +76,7 @@
const userRooms = deriveUserRooms(url)
const otherRooms = deriveOtherRooms(url)
const otherVoiceRooms = deriveOtherVoiceRooms(url)
const members = deriveSpaceMembers(url)
const members = deriveRelayMemberList(url)
const userIsAdmin = deriveUserIsSpaceAdmin(url)
const actionItems = deriveSpaceActionItems(url)
@@ -181,7 +181,11 @@
<li>
<Button onclick={showMembers}>
<Icon icon={UserRounded} />
View Members ({$members.length})
{#if $members === undefined}
View Members (unavailable)
Outdated
Review

Remove (unavailable)

Remove `(unavailable)`
{:else}
View Members ({$members.length})
{/if}
</Button>
</li>
{#if $userIsAdmin}
+8 -2
View File
@@ -95,7 +95,7 @@ import {
stripPrefix,
relaysMostlyRestricted,
deriveSocket,
deriveSpaceMembers,
deriveRelayMemberList,
} from "@app/core/state"
// Utils
@@ -765,7 +765,13 @@ export const addSpaceMembers = async (
url: string,
pubkeys: string[],
): Promise<string | undefined> => {
const spaceMembers = get(deriveSpaceMembers(url))
const spaceMembers = get(deriveRelayMemberList(url))
// Cannot add members without access to the member list
if (spaceMembers === undefined) {
return "Member list not available from this relay"
}
hodlbod marked this conversation as resolved Outdated
Outdated
Review

Don't fail hard, just send all pubkeys (change the filter line to .filter(pubkey => spaceMembers && !spaceMembers.includes(pubkey)))

Don't fail hard, just send all pubkeys (change the filter line to `.filter(pubkey => spaceMembers && !spaceMembers.includes(pubkey))`)
const results = await Promise.all(
pubkeys
.filter(pubkey => !spaceMembers.includes(pubkey))
+110 -84
View File
@@ -8,6 +8,7 @@ import {
on,
gt,
max,
find,
spec,
call,
first,
@@ -806,36 +807,51 @@ export const deriveOtherRooms = (url: string) =>
// Space/room memberships
const getSpaceMembers = (_url: string, events: TrustedEvent[]) => {
const members = new Set<string>()
export const deriveRelayMemberList = (url: string) =>
hodlbod marked this conversation as resolved Outdated
Outdated
Review

Let's just keep calling this getSpaceMembers. I was thinking of using the list directly, but it's more convenient to return the uniqe list of pubkeys. However, you might change the body to:

([event]) => uniq(getTagValues("member", event?.tags ?? []))

Same thing in deriveRoomMemberList (which should be deriveRoomMembers).

Let's just keep calling this `getSpaceMembers`. I was thinking of using the list directly, but it's more convenient to return the uniqe list of pubkeys. However, you might change the body to: ```typescript ([event]) => uniq(getTagValues("member", event?.tags ?? [])) ``` Same thing in deriveRoomMemberList (which should be deriveRoomMembers).
derived(deriveRelaySignedEvents(url, [{kinds: [RELAY_MEMBERS]}]), $events => {
hodlbod marked this conversation as resolved Outdated
Outdated
Review

This should be renamed to deriveSpaceMembers since it returns a svelte store, not the value itself.

This should be renamed to deriveSpaceMembers since it returns a svelte store, not the value itself.
const membersEvent = $events.find(spec({kind: RELAY_MEMBERS}))
return membersEvent ? uniq(getTagValues("member", membersEvent.tags)) : undefined
})
for (const event of sortEventsAsc(events)) {
if (event.kind === RELAY_MEMBERS) {
members.clear()
export const deriveRoomMemberList = (url: string, h: string) => {
const filters: Filter[] = [{kinds: [ROOM_MEMBERS], "#d": [h]}]
for (const pubkey of uniq(getTagValues("member", event.tags))) {
members.add(pubkey)
}
return derived(deriveEventsForUrl(url, filters), $events => {
const membersEvent = find(spec({kind: ROOM_MEMBERS}), $events)
return membersEvent ? uniq(getPubkeyTagValues(membersEvent.tags)) : undefined
})
}
continue
export type BannedPubkeyItem = {
pubkey: string
reason: string
}
export const spaceBannedPubkeyItems = new Map<string, BannedPubkeyItem[]>()
export const deriveSpaceBannedPubkeyItems = (url: string) => {
const store = writable(spaceBannedPubkeyItems.get(url) || [])
manageRelay(url, {method: ManagementMethod.ListBannedPubkeys, params: []}).then(res => {
spaceBannedPubkeyItems.set(url, res.result)
store.set(res.result)
})
return store
}
export const deriveRoomAdmins = (url: string, h: string) => {
const filters: Filter[] = [{kinds: [ROOM_ADMINS], "#d": [h]}]
return derived(deriveEventsForUrl(url, filters), $events => {
const adminsEvent = first($events)
if (adminsEvent) {
return getPubkeyTagValues(adminsEvent.tags)
}
const pubkeys = getPubkeyTagValues(event.tags)
if (event.kind === RELAY_ADD_MEMBER) {
for (const pubkey of pubkeys) {
members.add(pubkey)
}
}
if (event.kind === RELAY_REMOVE_MEMBER) {
for (const pubkey of pubkeys) {
members.delete(pubkey)
}
}
}
return Array.from(members)
return []
})
}
const getRoomMembers = (_url: string, h: string, events: TrustedEvent[]) => {
@@ -874,53 +890,6 @@ const getRoomMembers = (_url: string, h: string, events: TrustedEvent[]) => {
return Array.from(members)
}
export const deriveSpaceMembers = (url: string) =>
derived(
deriveRelaySignedEvents(url, [{kinds: [RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER, RELAY_MEMBERS]}]),
$events => getSpaceMembers(url, $events),
)
export type BannedPubkeyItem = {
pubkey: string
reason: string
}
export const spaceBannedPubkeyItems = new Map<string, BannedPubkeyItem[]>()
export const deriveSpaceBannedPubkeyItems = (url: string) => {
const store = writable(spaceBannedPubkeyItems.get(url) || [])
manageRelay(url, {method: ManagementMethod.ListBannedPubkeys, params: []}).then(res => {
spaceBannedPubkeyItems.set(url, res.result)
store.set(res.result)
})
return store
}
export const deriveRoomMembers = (url: string, h: string) => {
const filters: Filter[] = [
{kinds: [ROOM_MEMBERS], "#d": [h]},
{kinds: [ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER], "#h": [h]},
]
return derived(deriveEventsForUrl(url, filters), $events => getRoomMembers(url, h, $events))
}
export const deriveRoomAdmins = (url: string, h: string) => {
const filters: Filter[] = [{kinds: [ROOM_ADMINS], "#d": [h]}]
return derived(deriveEventsForUrl(url, filters), $events => {
const adminsEvent = first($events)
if (adminsEvent) {
return getPubkeyTagValues(adminsEvent.tags)
}
return []
})
}
// Action items (admin review queue)
// const pendingJoins: TrustedEvent[] = []
@@ -1017,19 +986,49 @@ export const deriveUserIsSpaceAdmin = memoize((url?: string) => {
})
export const deriveUserSpaceMembershipStatus = (url: string) => {
const filters: Filter[] = [{kinds: [RELAY_JOIN, RELAY_LEAVE]}]
// Fetch member list and user add/remove events directly in this derivation.
const memberListFilters: Filter[] = [{kinds: [RELAY_MEMBERS]}]
const userEventFilters: Filter[] = [{kinds: [RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER]}]
return derived(
[
pubkey,
deriveSpaceMembers(url),
deriveEventsForUrl(url, filters),
deriveRelaySignedEvents(url, memberListFilters),
deriveRelaySignedEvents(url, userEventFilters),
deriveEventsForUrl(url, [{kinds: [RELAY_JOIN, RELAY_LEAVE]}]),
deriveUserIsSpaceAdmin(url),
],
([$pubkey, $members, $events, $isAdmin]) => {
const isMember = $members.includes($pubkey!) || $isAdmin
([$pubkey, $memberListEvents, $userAddRemoveEvents, $joinLeaveEvents, $isAdmin]) => {
// If admin, always granted.
if ($isAdmin) {
return MembershipStatus.Granted
}
for (const event of $events) {
const membersEvent = $memberListEvents.find(spec({kind: RELAY_MEMBERS}))
const memberList = membersEvent ? uniq(getTagValues("member", membersEvent.tags)) : undefined
let isMember = false
if (memberList) {
// Member list exists - check if user is in it.
isMember = memberList.includes($pubkey!)
} else {
// No member list available - replay the user's add/remove history.
for (const event of sortBy(e => e.created_at, $userAddRemoveEvents)) {
if (event.pubkey !== $pubkey) {
continue
}
if (event.kind === RELAY_ADD_MEMBER) {
isMember = true
} else if (event.kind === RELAY_REMOVE_MEMBER) {
isMember = false
}
}
}
for (const event of $joinLeaveEvents) {
// Join events indicate pending or granted status, leave resets to initial.
if (event.pubkey !== $pubkey) {
continue
}
@@ -1055,19 +1054,46 @@ export const deriveUserIsRoomAdmin = (url: string, h: string) =>
)
export const deriveUserRoomMembershipStatus = (url: string, h: string) => {
const filters: Filter[] = [{kinds: [ROOM_JOIN, ROOM_LEAVE], "#h": [h]}]
// Fetch the room member list and the current user's add/remove events.
const userEventFilters: Filter[] = [{kinds: [ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER], "#h": [h]}]
const joinLeaveFilters: Filter[] = [{kinds: [ROOM_JOIN, ROOM_LEAVE], "#h": [h]}]
return derived(
[
pubkey,
deriveRoomMembers(url, h),
deriveEventsForUrl(url, filters),
deriveRoomMemberList(url, h),
deriveEventsForUrl(url, userEventFilters),
deriveEventsForUrl(url, joinLeaveFilters),
deriveUserIsRoomAdmin(url, h),
],
([$pubkey, $members, $events, $isAdmin]) => {
const isMember = $members.includes($pubkey!) || $isAdmin
([$pubkey, $memberList, $userAddRemoveEvents, $joinLeaveEvents, $isAdmin]) => {
// If admin of this room's space, always granted.
if ($isAdmin) {
return MembershipStatus.Granted
}
for (const event of $events) {
let isMember = false
if ($memberList) {
// Member list exists - check if user is in it.
isMember = $memberList.includes($pubkey!)
} else {
// No member list available - replay the user's add/remove history.
for (const event of sortEventsAsc($userAddRemoveEvents)) {
if (event.pubkey !== $pubkey) {
continue
}
if (event.kind === ROOM_ADD_MEMBER) {
isMember = true
} else if (event.kind === ROOM_REMOVE_MEMBER) {
isMember = false
}
}
}
for (const event of $joinLeaveEvents) {
// Join events indicate pending or granted status, leave resets to initial.
if (event.pubkey !== $pubkey) {
continue
}
+10 -7
View File
@@ -174,8 +174,9 @@ const syncUserSpaceMembership = (url: string) => {
url,
signal: controller.signal,
filters: [
{kinds: [RELAY_ADD_MEMBER], "#p": [$pubkey], limit: 1},
{kinds: [RELAY_REMOVE_MEMBER], "#p": [$pubkey], limit: 1},
// Keep current-user membership history so status replay stays deterministic.
{kinds: [RELAY_ADD_MEMBER], "#p": [$pubkey]},
{kinds: [RELAY_REMOVE_MEMBER], "#p": [$pubkey]},
Outdated
Review

Keep the limit, we want that

Keep the limit, we want that
{kinds: [ROOM_CREATE_PERMISSION], "#p": [$pubkey], limit: 1},
],
})
@@ -193,8 +194,9 @@ const syncUserRoomMembership = (url: string, h: string) => {
url,
signal: controller.signal,
filters: [
{kinds: [ROOM_ADD_MEMBER], "#p": [$pubkey], "#h": [h], limit: 1},
{kinds: [ROOM_REMOVE_MEMBER], "#p": [$pubkey], "#h": [h], limit: 1},
// Keep current-user membership history so status replay stays deterministic.
{kinds: [ROOM_ADD_MEMBER], "#p": [$pubkey], "#h": [h]},
{kinds: [ROOM_REMOVE_MEMBER], "#p": [$pubkey], "#h": [h]},
Outdated
Review

Keep the limit, remove the comment

Keep the limit, remove the comment
],
})
}
@@ -297,15 +299,16 @@ const syncSpace = (url: string, rooms: string[]) => {
pullRoomContent(room)
}
const relayKinds = [RELAY_MEMBERS, RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER]
// Fetch authoritative member lists and room metadata.
hodlbod marked this conversation as resolved Outdated
Outdated
Review

Remove the comment

Remove the comment
const relayKinds = [RELAY_MEMBERS]
const roomMetaKinds = [ROOM_META, ROOM_ADMINS, ROOM_MEMBERS, LIVEKIT_PARTICIPANTS]
const roomMemberKinds = [ROOM_DELETE, ROOM_JOIN, ROOM_LEAVE, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER]
const roomDeleteKinds = [ROOM_DELETE]
pullAndListen({
url,
signal: controller.signal,
filters: [
{kinds: [...relayKinds, ...roomMetaKinds, ...roomMemberKinds, ...CONTENT_KINDS, MESSAGE]},
{kinds: [...relayKinds, ...roomMetaKinds, ...roomDeleteKinds, ...CONTENT_KINDS, MESSAGE]},
makeCommentFilter(CONTENT_KINDS, {since}),
{kinds: [PollResponse], since},
],
+4 -3
View File
@@ -19,7 +19,7 @@ import {escapeHtml} from "@lib/html"
import {makeMentionNodeView} from "@app/editor/MentionNodeView"
import ProfileSuggestion from "@app/editor/ProfileSuggestion.svelte"
import {uploadFile} from "@app/core/commands"
import {deriveSpaceMembers} from "@app/core/state"
import {deriveRelayMemberList} from "@app/core/state"
import {pushToast} from "@app/util/toast"
export const makeEditor = async ({
@@ -49,7 +49,7 @@ export const makeEditor = async ({
[
throttled(800, profiles),
throttled(800, handlesByNip05),
throttled(800, deriveSpaceMembers(url || "")),
throttled(800, deriveRelayMemberList(url || "")),
],
([$profiles, $handlesByNip05, $spaceMembers]) => {
// Remove invalid nip05's from profiles
@@ -64,7 +64,8 @@ export const makeEditor = async ({
getValue: (profile: PublishedProfile) => profile.event.pubkey,
sortFn: ({score = 1, item}) => {
const wotScore = getWotGraph().get(item.event.pubkey) || 0
const membershipScale = $spaceMembers.includes(item.event.pubkey) ? 2 : 1
// Boost score for space members. If member list is unavailable, this falls through to 1x multiplier
Outdated
Review

Remove the comment

Remove the comment
const membershipScale = $spaceMembers?.includes(item.event.pubkey) ? 2 : 1
return dec(score) * inc(wotScore / getMaxWot()) * membershipScale
},
+2 -2
View File
@@ -26,7 +26,7 @@
import RoomCompose from "@app/components/RoomCompose.svelte"
import RoomComposeEdit from "@src/app/components/RoomComposeEdit.svelte"
import RoomComposeParent from "@app/components/RoomComposeParent.svelte"
import {userSettingsValues, decodeRelay, PROTECTED} from "@app/core/state"
import {userSettingsValues, decodeRelay, PROTECTED, CONTENT_KINDS} from "@app/core/state"
import {prependParent, canEnforceNip70, publishDelete} from "@app/core/commands"
import {checked} from "@app/util/notifications"
import {pushToast} from "@app/util/toast"
@@ -258,7 +258,7 @@
url,
at: at || now(),
element: element!,
filters: [{kinds: [MESSAGE, RELAY_ADD_MEMBER]}],
filters: [{kinds: [...CONTENT_KINDS, MESSAGE]}],
Outdated
Review

This is incorrect, it should be the way it was before.

This is incorrect, it should be the way it was before.
onBackwardExhausted: () => {
loadingBackward = false
},