Build out @welshman/domain on top of the DomainObject/EncryptableList base
patterns, porting domain-object use cases from @welshman/util and flotilla
that weren't yet represented.
New classes:
- Relay lists: RelayList (NIP-65 read/write markers), Blocked/Search/Messaging
relay lists, RelaySet (NIP-51 30002 named set)
- Server lists: Blossom, FileServer
- NIP-51 lists: Follow, Pin, Bookmark, Community, Channel, Room, Feed, Topic,
Emoji
- Zaps: ZapRequest, ZapReceipt, ZapGoal
- NIP-89 handlers: Handler, HandlerRecommendation
- Rooms/groups (NIP-29): RoomMeta, RoomAdmins, RoomMembers, RoomMembershipOp,
Room create/delete/join/leave, RoomCreatePermission, RelayMembers,
RelayMembershipOp, Relay join/leave/invite
- Content: Poll, PollResponse, Thread, Comment, Classified, CalendarEvent,
Report, Feed, Settings
Also fix unfinished accessors in Profile, method-call bugs in MuteList, and
correct RelayList.set{Read,Write}Relays to preserve a relay's complementary
read/write capability instead of dropping modeless entries.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V67tPYdvh1qCkjEBhJGZUR
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import {uniq} from "@welshman/lib"
|
||||
import {RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER, getPubkeyTagValues} from "@welshman/util"
|
||||
import type {EventTemplate, TrustedEvent} from "@welshman/util"
|
||||
import type {ISigner} from "@welshman/signer"
|
||||
import {DomainObject} from "./base.js"
|
||||
|
||||
export type RelayMembershipOpValues = {
|
||||
kind: number
|
||||
pubkeys: string[]
|
||||
}
|
||||
|
||||
export const makeRelayMembershipOpValues = (
|
||||
values: Partial<RelayMembershipOpValues> = {},
|
||||
): RelayMembershipOpValues => ({
|
||||
kind: RELAY_ADD_MEMBER,
|
||||
pubkeys: [],
|
||||
...values,
|
||||
})
|
||||
|
||||
export const makeRelayAddMember = (pubkeys: string[]) =>
|
||||
RelayMembershipOp.init({kind: RELAY_ADD_MEMBER, pubkeys})
|
||||
|
||||
export const makeRelayRemoveMember = (pubkeys: string[]) =>
|
||||
RelayMembershipOp.init({kind: RELAY_REMOVE_MEMBER, pubkeys})
|
||||
|
||||
// Relay/space-level moderation op for adding (kind 8000) or removing (kind 8001)
|
||||
// members. These are regular (non-addressable) events carrying the affected
|
||||
// pubkeys in "p" tags. The two kinds share an identical shape, so they're merged
|
||||
// into one kind-discriminated class.
|
||||
//
|
||||
// Flotilla's deriveUserSpaceMembershipStatus replays this history (RELAY_ADD_MEMBER
|
||||
// => isMember true, RELAY_REMOVE_MEMBER => isMember false) when no RELAY_MEMBERS
|
||||
// snapshot is available.
|
||||
//
|
||||
// Because the base DomainObject treats `kind` as a fixed value and asserts
|
||||
// event.kind === this.kind in parse(), `kind` is a mutable instance field here:
|
||||
// it's seeded from values.kind in normalizeValues, and parse() is overridden to
|
||||
// adopt the event's kind before normalizing.
|
||||
export class RelayMembershipOp extends DomainObject<RelayMembershipOpValues> {
|
||||
kind = RELAY_ADD_MEMBER
|
||||
values = makeRelayMembershipOpValues()
|
||||
|
||||
protected normalizeValues(values: Partial<RelayMembershipOpValues> = {}) {
|
||||
const normalized = makeRelayMembershipOpValues(values)
|
||||
|
||||
this.kind = normalized.kind
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
protected parseEvent(event: TrustedEvent): Partial<RelayMembershipOpValues> {
|
||||
return {
|
||||
kind: event.kind,
|
||||
pubkeys: uniq(getPubkeyTagValues(event.tags)),
|
||||
}
|
||||
}
|
||||
|
||||
async parse(event: TrustedEvent, signer?: ISigner) {
|
||||
this.event = event
|
||||
this.kind = event.kind
|
||||
this.values = this.normalizeValues(await this.parseEvent(event, signer))
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
pubkeys() {
|
||||
return this.values.pubkeys
|
||||
}
|
||||
|
||||
isAdd() {
|
||||
return this.kind === RELAY_ADD_MEMBER
|
||||
}
|
||||
|
||||
async toTemplate(): Promise<EventTemplate> {
|
||||
return {
|
||||
kind: this.kind,
|
||||
tags: this.values.pubkeys.map(pk => ["p", pk]),
|
||||
content: "",
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user