flotilla/src/app/management.ts

72 lines
2.1 KiB
TypeScript
Raw Normal View History

2026-07-28 16:16:26 +00:00
import {derived, readable, writable} from "svelte/store"
import {ago, MINUTE, now, simpleCache} from "@welshman/lib"
import {ROOM_CREATE_PERMISSION, hexTags, tagValues} from "@welshman/util"
import {fromApp, relayManagement, user} from "@app/core"
2026-07-28 16:16:26 +00:00
import {deriveEventsForUrl} from "@app/repository"
export type BannedPubkeyItem = {
pubkey: string
reason: string
}
export const deriveSpaceBannedPubkeyItems = (url: string) => {
const store = writable<BannedPubkeyItem[]>([])
relayManagement
.get()
.forUrl(url)
.listBannedPubkeys()
.then(({result = []}) => store.set(result))
return store
}
const deriveSupportedMethodsForPubkey = simpleCache(([, url]: [pubkey: string, url: string]) => {
2026-07-28 16:16:26 +00:00
let checkedAt = 0
return readable<string[]>([], set => {
if (checkedAt < ago(5, MINUTE)) {
2026-07-28 16:16:26 +00:00
checkedAt = now()
relayManagement
.get()
.forUrl(url)
.supportedMethods()
.then(({result = []}) => set(result))
.catch(error => {
checkedAt = 0
console.error(error)
})
}
})
})
// The request is signed as the logged in user and answered for that pubkey, so the methods
// belong to a user as much as to a url and logging in has to swap them out.
export const deriveSpaceSupportedMethods = (url?: string) =>
fromApp($app => {
if (url && $app.user) {
return deriveSupportedMethodsForPubkey($app.user.pubkey, url)
}
return readable<string[]>([])
})
2026-07-28 16:16:26 +00:00
// User
// Holding any management method at all is what makes someone staff here. A relay that still
// answers relay-wide tells us only that the call wasn't refused outright.
2026-07-28 16:16:26 +00:00
export const deriveUserIsSpaceAdmin = (url?: string) =>
derived(deriveSpaceSupportedMethods(url), $methods => $methods.length > 0)
export const deriveUserCanCreateRoom = (url: string) =>
derived(
[
user,
deriveEventsForUrl(url, [{kinds: [ROOM_CREATE_PERMISSION]}]),
deriveUserIsSpaceAdmin(url),
],
([$user, $events, $isAdmin]) =>
$isAdmin || $events.some(event => tagValues(hexTags("p"), event.tags).includes($user.pubkey)),
)