Files
welshman/packages/domain/src/HandlerRecommendation.ts
T
hodlbod bfd91f2d39
tests / tests (push) Failing after 5m7s
Rewrite domain objects as a Reader/Builder split
Replace the single DomainObject/EncryptableList classes with a read/write split
that removes the optional-event ambiguity:

- base.ts: EventReader<P> (static kind; fromEvent(event, signer?) eagerly computes
  a generic `plain`, validates leniently, throws-or-passes; lazy method accessors;
  group/protect/expires + extraTags carry-over; builder()) and EventBuilder<P>
  (chainable setters, buildTags/buildContent, validate-on-emit).
- List.ts: ListReader/ListBuilder for NIP-51 lists (decrypt-on-read into `plain`,
  re-encrypt-on-emit, tag mutators).
- Every kind converted to a <Noun> reader + <Noun>Builder pair; membership ops
  split into per-kind reader/builder pairs over a shared abstract base.

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

83 lines
2.2 KiB
TypeScript

import {last} from "@welshman/lib"
import {HANDLER_RECOMMENDATION, getAddressTags, getAddressTagValues} from "@welshman/util"
import {EventReader, EventBuilder} from "./base.js"
// NIP-89 kind-31989 handler recommendation. Addressable (the `d` tag holds the
// recommended kind), tags-only with empty content. Each entry is a raw `a` tag
// pointing at a kind-31990 handler, optionally carrying a relay hint and a
// trailing platform marker (e.g. "web").
export class HandlerRecommendation extends EventReader {
static kind = HANDLER_RECOMMENDATION
protected validate() {
if (!this.identifier()) {
throw new Error("HandlerRecommendation requires a d tag")
}
}
protected reservedTagKeys() {
return ["d", "a"]
}
// Raw `a` tags: ["a", address, relay?, platform?].
addressTags() {
return getAddressTags(this.event.tags)
}
addresses() {
return getAddressTagValues(this.event.tags)
}
// Prefer the recommendation marked as a "web" handler, otherwise fall back to
// the first recommendation.
handlerAddress() {
const tags = this.addressTags()
const tag = tags.find(t => last(t) === "web") || tags[0]
return tag?.[1]
}
builder() {
const builder = new HandlerRecommendationBuilder(this.identifier() || "")
builder.addressTags = this.addressTags()
return this.seedBuilder(builder)
}
}
export class HandlerRecommendationBuilder extends EventBuilder {
static kind = HANDLER_RECOMMENDATION
// Raw `a` tags: ["a", address, relay?, platform?].
addressTags: string[][] = []
constructor(public identifier: string) {
super()
}
addRecommendation(address: string, relay?: string, platform?: string) {
if (!this.addressTags.some(t => t[1] === address)) {
this.addressTags = [...this.addressTags, ["a", address, relay || "", platform || ""]]
}
return this
}
removeRecommendation(address: string) {
this.addressTags = this.addressTags.filter(t => t[1] !== address)
return this
}
protected validate() {
if (!this.identifier) {
throw new Error("HandlerRecommendation requires a d identifier")
}
}
protected buildTags() {
return [["d", this.identifier], ...this.addressTags]
}
}