Files
welshman/packages/domain/src/RoomMembershipOp.ts
T
hodlbod 5e142e4db4
tests / tests (push) Failing after 5m10s
Refine domain classes: behavior tags, extra-tag passthrough, cleanups
Iterate on @welshman/domain following review:

- base: add `group`/`protect`/`expires` behavior tags (parsed in base, emitted
  via addBehaviorTags before hashing) and an `extraTags` passthrough (opt-in via
  reservedTagKeys) so tag carry-over lives in one place; migrate Handler, Comment,
  Thread onto it. Comment gains nested root/parent ref structs + setters.
- List: fix inverted keepTags; add clearTags/clearPublicTags/clearPrivateTags and
  use them in the relay/server list setters.
- RelayList: preserve complementary read/write capability instead of dropping
  modeless entries.
- Split Relay/Room membership ops into per-kind classes (RelayAddMember/
  RelayRemoveMember, RoomAddMember/RoomRemoveMember) over a shared base.
- TimeEvent (renamed from CalendarEvent): derive "D" day tags in toTemplate.
- Feed: default to an empty feed, fail parse when the "feed" tag is missing.
- RelaySet added; CommunityList renamed to GroupList; predicate bare add/remove
  mutators; RoomMeta uses randomId; PollResponse.selections drops pollType.
- Remove ChannelList, FileServerList, Settings, and event-asserting getAddress/
  display accessors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V67tPYdvh1qCkjEBhJGZUR
2026-06-18 22:42:10 +00:00

55 lines
1.6 KiB
TypeScript

import {uniq} from "@welshman/lib"
import {ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER, getPubkeyTagValues} from "@welshman/util"
import type {EventTemplate, TrustedEvent} from "@welshman/util"
import {DomainObject} from "./base.js"
export type RoomMembershipValues = {
pubkeys: string[]
}
export const makeRoomMembershipValues = (
values: Partial<RoomMembershipValues> = {},
): RoomMembershipValues => ({
pubkeys: [],
...values,
})
// NIP-29 moderation op for adding (kind 9000) or removing (kind 9001) room
// members. Regular (non-addressable) events carrying the affected pubkeys in "p"
// tags; the target group id is the base `group` ("h") behavior tag. Add and
// remove share this shape; each is its own concrete class fixing the kind.
//
// Flotilla's membership replay treats RoomAddMember => member, RoomRemoveMember
// => not a member.
export abstract class RoomMembershipOp extends DomainObject<RoomMembershipValues> {
values = makeRoomMembershipValues()
protected normalizeValues(values: Partial<RoomMembershipValues> = {}) {
return makeRoomMembershipValues(values)
}
protected parseEvent(event: TrustedEvent): Partial<RoomMembershipValues> {
return {pubkeys: uniq(getPubkeyTagValues(event.tags))}
}
pubkeys() {
return this.values.pubkeys
}
async toTemplate(): Promise<EventTemplate> {
return {
kind: this.kind,
tags: this.values.pubkeys.map(pk => ["p", pk]),
content: "",
}
}
}
export class RoomAddMember extends RoomMembershipOp {
readonly kind = ROOM_ADD_MEMBER
}
export class RoomRemoveMember extends RoomMembershipOp {
readonly kind = ROOM_REMOVE_MEMBER
}