NIP fixes: - RelayMembers (13534): use NIP-43 `member` tags (not `p`) and set the required NIP-70 `-` protected tag. - Profile (kind 0): remove display-name support entirely (getter, setter, display() fallback, and the search weight). - Comment (1111): A/a tags now carry a real address, not the event id. - BlossomServerList (10063): normalize server URLs with normalizeUrl (HTTP), not normalizeRelayUrl (which forced wss://). - HandlerRecommendation (31989): fix inverted removeRecommendation filter; add setSupportedKind()/supportedKind() for the NIP-89 d-tag. - Report (1984): place the report-type string on the e tag (note reports) or p tag (profile reports); always emit the p tag. Docs/skills: - Add @welshman/domain docs (docs/domain/) and the welshman-domain skill. - Prune @welshman/util docs/skill of the moved Profile/List/Handler/Encryptable helpers; register domain in the sidebar, index, and skills README. - Apply accuracy fixes to the @welshman/app docs/skill. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsMjvv7krpZeHK1Njeneru
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import {uniq, nthEq} from "@welshman/lib"
|
||||
import {BLOSSOM_SERVERS, getTagValues, normalizeRelayUrl} from "@welshman/util"
|
||||
import {uniq, nthEq, normalizeUrl} from "@welshman/lib"
|
||||
import {BLOSSOM_SERVERS, getTagValues} from "@welshman/util"
|
||||
import {ListReader} from "../ListReader.js"
|
||||
import {ListBuilder} from "../ListBuilder.js"
|
||||
|
||||
@@ -8,11 +8,11 @@ export class BlossomServerList extends ListReader {
|
||||
readonly kind = BLOSSOM_SERVERS
|
||||
|
||||
urls() {
|
||||
return uniq(getTagValues("server", this.tags()).map(normalizeRelayUrl))
|
||||
return uniq(getTagValues("server", this.tags()).map(normalizeUrl))
|
||||
}
|
||||
|
||||
includes(url: string) {
|
||||
return this.urls().includes(normalizeRelayUrl(url))
|
||||
return this.urls().includes(normalizeUrl(url))
|
||||
}
|
||||
|
||||
builder() {
|
||||
@@ -24,16 +24,16 @@ export class BlossomServerListBuilder extends ListBuilder<BlossomServerList> {
|
||||
readonly kind = BLOSSOM_SERVERS
|
||||
|
||||
addUrl(url: string) {
|
||||
return this.addPublic(["server", normalizeRelayUrl(url)])
|
||||
return this.addPublic(["server", normalizeUrl(url)])
|
||||
}
|
||||
|
||||
removeUrl(url: string) {
|
||||
return this.drop(nthEq(1, normalizeRelayUrl(url)))
|
||||
return this.drop(nthEq(1, normalizeUrl(url)))
|
||||
}
|
||||
|
||||
setUrls(urls: string[]) {
|
||||
this.clear()
|
||||
|
||||
return this.addPublic(...urls.map(url => ["server", normalizeRelayUrl(url)]))
|
||||
return this.addPublic(...urls.map(url => ["server", normalizeUrl(url)]))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {first} from "@welshman/lib"
|
||||
import {COMMENT, Address, getAddress, getTagValue, isReplaceableKind} from "@welshman/util"
|
||||
import {COMMENT, Address, getTagValue} from "@welshman/util"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import type {ISigner} from "@welshman/signer"
|
||||
import {EventReader} from "../EventReader.js"
|
||||
@@ -68,7 +68,7 @@ export class CommentBuilder extends EventBuilder<Comment> {
|
||||
this.rootTags = [["K", String(kind)], ["E", id], ["P", pubkey]]
|
||||
|
||||
if (identifier) {
|
||||
this.rootTags.push(["A", id])
|
||||
this.rootTags.push(["A", new Address(kind, pubkey, identifier).toString()])
|
||||
}
|
||||
|
||||
return this
|
||||
@@ -78,7 +78,7 @@ export class CommentBuilder extends EventBuilder<Comment> {
|
||||
this.parentTags = [["k", String(kind)], ["e", id], ["p", pubkey]]
|
||||
|
||||
if (identifier) {
|
||||
this.parentTags.push(["a", id])
|
||||
this.parentTags.push(["a", new Address(kind, pubkey, identifier).toString()])
|
||||
}
|
||||
|
||||
return this
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {nthEq, last} from "@welshman/lib"
|
||||
import {nthNe, last} from "@welshman/lib"
|
||||
import {HANDLER_RECOMMENDATION, getAddressTags, getAddressTagValues} from "@welshman/util"
|
||||
import {EventReader} from "../EventReader.js"
|
||||
import {EventBuilder} from "../EventBuilder.js"
|
||||
@@ -22,6 +22,11 @@ export class HandlerRecommendation extends EventReader {
|
||||
return tag?.[1]
|
||||
}
|
||||
|
||||
// NIP-89: the `d` tag is the event-kind this recommendation applies to.
|
||||
supportedKind() {
|
||||
return this.identifier()
|
||||
}
|
||||
|
||||
builder() {
|
||||
return new HandlerRecommendationBuilder(this)
|
||||
}
|
||||
@@ -38,6 +43,14 @@ export class HandlerRecommendationBuilder extends EventBuilder<HandlerRecommenda
|
||||
this.addressTags = this.consumeTags("a")
|
||||
}
|
||||
|
||||
// NIP-89: set the `d` tag to the event-kind being recommended for, so the
|
||||
// standard {kinds:[31989], "#d":[kind]} query resolves.
|
||||
setSupportedKind(kind: number) {
|
||||
this.setIdentifier(String(kind))
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
addRecommendation(address: string, relay?: string, platform?: string) {
|
||||
if (!this.addressTags.some(t => t[1] === address)) {
|
||||
this.addressTags = [...this.addressTags, ["a", address, relay || "", platform || ""]]
|
||||
@@ -47,7 +60,7 @@ export class HandlerRecommendationBuilder extends EventBuilder<HandlerRecommenda
|
||||
}
|
||||
|
||||
removeRecommendation(address: string) {
|
||||
this.addressTags = this.addressTags.filter(nthEq(1, address))
|
||||
this.addressTags = this.addressTags.filter(nthNe(1, address))
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -41,10 +41,6 @@ export class Profile extends EventReader {
|
||||
return this.values.name
|
||||
}
|
||||
|
||||
displayName(): Maybe<string> {
|
||||
return this.values.display_name
|
||||
}
|
||||
|
||||
nip05(): Maybe<string> {
|
||||
return this.values.nip05
|
||||
}
|
||||
@@ -74,10 +70,6 @@ export class Profile extends EventReader {
|
||||
|
||||
if (name) return ellipsize(name, 60).trim()
|
||||
|
||||
const displayName= this.displayName()
|
||||
|
||||
if (displayName) return ellipsize(displayName, 60).trim()
|
||||
|
||||
return displayPubkey(this.event.pubkey).trim() || fallback.trim()
|
||||
}
|
||||
|
||||
@@ -107,12 +99,6 @@ export class ProfileBuilder extends EventBuilder<Profile> {
|
||||
return this
|
||||
}
|
||||
|
||||
setDisplayName(displayName: string) {
|
||||
this.values.displayName = displayName
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
setNip05(nip05: string) {
|
||||
this.values.nip05 = nip05
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import {uniq, nth, nthNe, uniqBy} from "@welshman/lib"
|
||||
import {RELAY_MEMBERS, getPubkeyTagValues} from "@welshman/util"
|
||||
import {RELAY_MEMBERS, getTagValues} from "@welshman/util"
|
||||
import {EventReader} from "../EventReader.js"
|
||||
import {EventBuilder} from "../EventBuilder.js"
|
||||
|
||||
// Flotilla kind-13534 relay/space member-list snapshot.
|
||||
// Flotilla kind-13534 relay/space member-list snapshot. Members are carried in
|
||||
// NIP-43 `member` tags, and the event is NIP-70 protected (`-`).
|
||||
export class RelayMembers extends EventReader {
|
||||
readonly kind = RELAY_MEMBERS
|
||||
|
||||
pubkeys() {
|
||||
return uniq(getPubkeyTagValues(this.event.tags))
|
||||
return uniq(getTagValues("member", this.event.tags))
|
||||
}
|
||||
|
||||
isMember(pubkey: string) {
|
||||
@@ -28,11 +29,14 @@ export class RelayMembersBuilder extends EventBuilder<RelayMembers> {
|
||||
constructor(readonly reader?: RelayMembers) {
|
||||
super(reader)
|
||||
|
||||
this.pubkeyTags = uniqBy(nth(1), this.consumeTags("p"))
|
||||
this.pubkeyTags = uniqBy(nth(1), this.consumeTags("member"))
|
||||
|
||||
// NIP-43 requires kind-13534 member lists to be NIP-70 protected.
|
||||
this.setProtected(true)
|
||||
}
|
||||
|
||||
addPubkey(pubkey: string) {
|
||||
this.pubkeyTags = uniqBy(nth(1), [...this.pubkeyTags, ["p", pubkey]])
|
||||
this.pubkeyTags = uniqBy(nth(1), [...this.pubkeyTags, ["member", pubkey]])
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ export class Report extends EventReader {
|
||||
}
|
||||
|
||||
reason() {
|
||||
return getTag("e", this.event.tags)?.[2]
|
||||
// NIP-56: the report-type string is the 3rd entry of the reported tag — the
|
||||
// `e` tag for note reports, or the `p` tag for profile-only reports.
|
||||
return getTag("e", this.event.tags)?.[2] ?? getTag("p", this.event.tags)?.[2]
|
||||
}
|
||||
|
||||
builder() {
|
||||
@@ -39,7 +41,7 @@ export class ReportBuilder extends EventBuilder<Report> {
|
||||
|
||||
this.reportedPubkey = p?.[1]
|
||||
this.eventId = e?.[1]
|
||||
this.reason = e?.[2]
|
||||
this.reason = e?.[2] ?? p?.[2]
|
||||
}
|
||||
|
||||
setReportedPubkey(reportedPubkey: string) {
|
||||
@@ -63,8 +65,15 @@ export class ReportBuilder extends EventBuilder<Report> {
|
||||
protected buildTags() {
|
||||
const tags: string[][] = []
|
||||
|
||||
// NIP-56: a `p` tag referencing the reported pubkey is mandatory. The
|
||||
// report-type string goes on the reported object — the `e` tag for note
|
||||
// reports, otherwise the `p` tag for profile-only reports.
|
||||
if (this.reportedPubkey) {
|
||||
tags.push(["p", this.reportedPubkey])
|
||||
tags.push(
|
||||
this.eventId
|
||||
? ["p", this.reportedPubkey]
|
||||
: ["p", this.reportedPubkey, ...(this.reason ? [this.reason] : [])],
|
||||
)
|
||||
}
|
||||
|
||||
if (this.eventId) {
|
||||
|
||||
Reference in New Issue
Block a user