Refine domain, integrate into app
tests / tests (push) Failing after 5m14s

This commit is contained in:
Jon Staab
2026-06-19 12:50:34 -07:00
parent 1bd62d3024
commit e2a6ef21cd
115 changed files with 1354 additions and 3176 deletions
+33 -137
View File
@@ -5,8 +5,6 @@ import type {ISigner} from "@welshman/signer"
import {EventReader} from "../EventReader.js"
import {EventBuilder} from "../EventBuilder.js"
// A NIP-22 reference to another event: its id, address (for addressable roots),
// kind, and pubkey. All optional since a comment may reference any subset.
export type CommentRef = {
id?: string
address?: string
@@ -14,91 +12,25 @@ export type CommentRef = {
pubkey?: string
}
// Build a reference from a full event, deriving the address only when the event
// is addressable/replaceable.
const refFromEvent = (event: TrustedEvent): CommentRef => ({
id: event.id,
pubkey: event.pubkey,
kind: String(event.kind),
address: isReplaceableKind(event.kind) ? getAddress(event) : undefined,
})
// Build the NIP-22 reference tags for one struct: pass uppercase keys for the
// root, lowercase for the parent.
const refTags = (ref: CommentRef, [idKey, addressKey, kindKey, pubkeyKey]: string[]) => {
const tags: string[][] = []
if (ref.id) tags.push([idKey, ref.id])
if (ref.address) tags.push([addressKey, ref.address])
if (ref.kind) tags.push([kindKey, ref.kind])
if (ref.pubkey) tags.push([pubkeyKey, ref.pubkey])
return tags
}
// Read side of NIP-22 kind-1111 generic comment, flotilla's universal reply
// primitive: threads, goals, and polls reference their root event via uppercase
// E/A/K/P tags, while classifieds and calendar events reference addressable
// roots via #A. Uppercase tags (E/A/K/P) name the root of the thread; lowercase
// tags (e/a/k/p) name the immediate parent. The comment body is plain text in
// the event content (not JSON).
//
// The reference tags are read lazily into the root/parent accessors; any other
// tags round-trip via the base extraTags.
// NIP-22 kind-1111 comment (uppercase E/A/K/P tags = thread root, lowercase = immediate parent).
export class Comment extends EventReader {
readonly kind = COMMENT
content() {
return this.event.content || ""
}
rootId() {
return getTagValue("E", this.event.tags)
}
rootAddress() {
return getTagValue("A", this.event.tags)
}
rootKind() {
return getTagValue("K", this.event.tags)
}
rootPubkey() {
return getTagValue("P", this.event.tags)
}
parentId() {
return getTagValue("e", this.event.tags)
}
parentAddress() {
return getTagValue("a", this.event.tags)
}
parentKind() {
return getTagValue("k", this.event.tags)
}
parentPubkey() {
return getTagValue("p", this.event.tags)
}
root(): CommentRef {
return {
id: this.rootId(),
address: this.rootAddress(),
kind: this.rootKind(),
pubkey: this.rootPubkey(),
id: getTagValue("E", this.event.tags),
address: getTagValue("A", this.event.tags),
kind: getTagValue("K", this.event.tags),
pubkey: getTagValue("P", this.event.tags),
}
}
parent(): CommentRef {
return {
id: this.parentId(),
address: this.parentAddress(),
kind: this.parentKind(),
pubkey: this.parentPubkey(),
id: getTagValue("e", this.event.tags),
address: getTagValue("a", this.event.tags),
kind: getTagValue("k", this.event.tags),
pubkey: getTagValue("p", this.event.tags),
}
}
@@ -107,100 +39,64 @@ export class Comment extends EventReader {
}
}
// Write side of NIP-22 kind-1111 generic comment. Set the body via setContent and
// the root/parent references via setRoot/setParent (or the *FromEvent variants);
// buildTags rebuilds the uppercase/lowercase reference tags from those structs.
export class CommentBuilder extends EventBuilder<Comment> {
readonly kind = COMMENT
content = ""
root: CommentRef = {}
parent: CommentRef = {}
rootTags: string[][] = []
parentTags: string[][] = []
constructor(readonly reader?: Comment) {
super(reader)
// Consume the represented reference tags out of the carried-over extraTags so
// they round-trip through the root/parent structs below rather than being
// emitted twice (once from buildTags, once from the base's extraTags
// pass-through). Uppercase keys name the root, lowercase the parent.
const rootId = first(this.consumeTags("E"))
const rootAddress = first(this.consumeTags("A"))
const rootKind = first(this.consumeTags("K"))
const rootPubkey = first(this.consumeTags("P"))
const parentId = first(this.consumeTags("e"))
const parentAddress = first(this.consumeTags("a"))
const parentKind = first(this.consumeTags("k"))
const parentPubkey = first(this.consumeTags("p"))
this.content = reader?.event.content ?? ""
this.root = {
id: rootId?.[1],
address: rootAddress?.[1],
kind: rootKind?.[1],
pubkey: rootPubkey?.[1],
}
this.parent = {
id: parentId?.[1],
address: parentAddress?.[1],
kind: parentKind?.[1],
pubkey: parentPubkey?.[1],
}
this.rootTags = this.consumeRefTags("E", "A", "K", "P")
this.parentTags = this.consumeRefTags("e", "a", "k", "p")
}
setContent(content: string) {
this.content = content
private consumeRefTags(...keys: string[]) {
const tags: string[][] = []
return this
for (const key of keys) {
const tag = first(this.consumeTags(key))
if (tag) tags.push(tag)
}
return tags
}
// Set the thread root reference, deriving the address from kind/pubkey/identifier
// when the referenced event is addressable.
setRoot(kind: number, id: string, pubkey: string, identifier?: string) {
this.root = {
id,
pubkey,
kind: String(kind),
address: identifier == null ? undefined : new Address(kind, pubkey, identifier).toString(),
this.rootTags = [["K", String(kind)], ["E", id], ["P", pubkey]]
if (identifier) {
this.rootTags.push(["A", id])
}
return this
}
// Set the immediate parent reference, deriving the address as above.
setParent(kind: number, id: string, pubkey: string, identifier?: string) {
this.parent = {
id,
pubkey,
kind: String(kind),
address: identifier == null ? undefined : new Address(kind, pubkey, identifier).toString(),
this.parentTags = [["k", String(kind)], ["e", id], ["p", pubkey]]
if (identifier) {
this.parentTags.push(["a", id])
}
return this
}
// Set the thread root reference from a full event.
setRootFromEvent(event: TrustedEvent) {
this.root = refFromEvent(event)
this.setRoot(event.kind, event.id, event.pubkey, getTagValue("d", event.tags))
return this
}
// Set the immediate parent reference from a full event.
setParentFromEvent(event: TrustedEvent) {
this.parent = refFromEvent(event)
this.setParent(event.kind, event.id, event.pubkey, getTagValue("d", event.tags))
return this
}
protected buildContent(_signer?: ISigner) {
return this.content
}
protected buildTags() {
return [
...refTags(this.root, ["E", "A", "K", "P"]),
...refTags(this.parent, ["e", "a", "k", "p"]),
]
return [...this.rootTags, ...this.parentTags]
}
}