mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-09 00:28:51 +00:00
nip10: improve, support quotes, author hints, change the way legacy refs are discovered.
This commit is contained in:
149
nip10.ts
149
nip10.ts
@@ -1,7 +1,7 @@
|
||||
import type { Event } from './core.ts'
|
||||
import type { EventPointer, ProfilePointer } from './nip19.ts'
|
||||
|
||||
export type NIP10Result = {
|
||||
export function parse(event: Pick<Event, 'tags'>): {
|
||||
/**
|
||||
* Pointer to the root of the thread.
|
||||
*/
|
||||
@@ -13,29 +13,80 @@ export type NIP10Result = {
|
||||
reply: EventPointer | undefined
|
||||
|
||||
/**
|
||||
* Pointers to events which may or may not be in the reply chain.
|
||||
* Pointers to events that may or may not be in the reply chain.
|
||||
*/
|
||||
mentions: EventPointer[]
|
||||
|
||||
/**
|
||||
* Pointers to events that were directly quoted.
|
||||
*/
|
||||
quotes: EventPointer[]
|
||||
|
||||
/**
|
||||
* List of pubkeys that are involved in the thread in no particular order.
|
||||
*/
|
||||
profiles: ProfilePointer[]
|
||||
}
|
||||
|
||||
export function parse(event: Pick<Event, 'tags'>): NIP10Result {
|
||||
const result: NIP10Result = {
|
||||
} {
|
||||
const result: ReturnType<typeof parse> = {
|
||||
reply: undefined,
|
||||
root: undefined,
|
||||
mentions: [],
|
||||
profiles: [],
|
||||
quotes: [],
|
||||
}
|
||||
|
||||
const eTags: string[][] = []
|
||||
let maybeParent: EventPointer | undefined
|
||||
let maybeRoot: EventPointer | undefined
|
||||
|
||||
for (let i = event.tags.length - 1; i >= 0; i--) {
|
||||
const tag = event.tags[i]
|
||||
|
||||
for (const tag of event.tags) {
|
||||
if (tag[0] === 'e' && tag[1]) {
|
||||
eTags.push(tag)
|
||||
const [_, eTagEventId, eTagRelayUrl, eTagMarker, eTagAuthor] = tag as [
|
||||
string,
|
||||
string,
|
||||
undefined | string,
|
||||
undefined | string,
|
||||
undefined | string,
|
||||
]
|
||||
|
||||
const eventPointer: EventPointer = {
|
||||
id: eTagEventId,
|
||||
relays: eTagRelayUrl ? [eTagRelayUrl] : [],
|
||||
author: eTagAuthor,
|
||||
}
|
||||
|
||||
if (eTagMarker === 'root') {
|
||||
result.root = eventPointer
|
||||
continue
|
||||
}
|
||||
|
||||
if (eTagMarker === 'reply') {
|
||||
result.reply = eventPointer
|
||||
continue
|
||||
}
|
||||
|
||||
if (eTagMarker === 'mention') {
|
||||
result.mentions.push(eventPointer)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!maybeParent) {
|
||||
maybeParent = eventPointer
|
||||
} else {
|
||||
maybeRoot = eventPointer
|
||||
}
|
||||
|
||||
result.mentions.push(eventPointer)
|
||||
continue
|
||||
}
|
||||
|
||||
if (tag[0] === 'q' && tag[1]) {
|
||||
const [_, eTagEventId, eTagRelayUrl] = tag as [string, string, undefined | string]
|
||||
result.quotes.push({
|
||||
id: eTagEventId,
|
||||
relays: eTagRelayUrl ? [eTagRelayUrl] : [],
|
||||
})
|
||||
}
|
||||
|
||||
if (tag[0] === 'p' && tag[1]) {
|
||||
@@ -43,49 +94,51 @@ export function parse(event: Pick<Event, 'tags'>): NIP10Result {
|
||||
pubkey: tag[1],
|
||||
relays: tag[2] ? [tag[2]] : [],
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for (let eTagIndex = 0; eTagIndex < eTags.length; eTagIndex++) {
|
||||
const eTag = eTags[eTagIndex]
|
||||
|
||||
const [_, eTagEventId, eTagRelayUrl, eTagMarker] = eTag as [string, string, undefined | string, undefined | string]
|
||||
|
||||
const eventPointer: EventPointer = {
|
||||
id: eTagEventId,
|
||||
relays: eTagRelayUrl ? [eTagRelayUrl] : [],
|
||||
}
|
||||
|
||||
const isFirstETag = eTagIndex === 0
|
||||
const isLastETag = eTagIndex === eTags.length - 1
|
||||
|
||||
if (eTagMarker === 'root') {
|
||||
result.root = eventPointer
|
||||
continue
|
||||
}
|
||||
|
||||
if (eTagMarker === 'reply') {
|
||||
result.reply = eventPointer
|
||||
continue
|
||||
}
|
||||
|
||||
if (eTagMarker === 'mention') {
|
||||
result.mentions.push(eventPointer)
|
||||
continue
|
||||
}
|
||||
|
||||
if (isFirstETag) {
|
||||
result.root = eventPointer
|
||||
continue
|
||||
}
|
||||
|
||||
if (isLastETag) {
|
||||
result.reply = eventPointer
|
||||
continue
|
||||
}
|
||||
|
||||
result.mentions.push(eventPointer)
|
||||
// get legacy (positional) markers, set reply to root and vice-versa if one of them is missing
|
||||
if (!result.root) {
|
||||
result.root = maybeRoot || maybeParent || result.reply
|
||||
}
|
||||
if (!result.reply) {
|
||||
result.reply = maybeParent || result.root
|
||||
}
|
||||
|
||||
// remove root and reply from mentions, inherit relay hints from authors if any
|
||||
;[result.reply, result.root].forEach(ref => {
|
||||
let idx = result.mentions.indexOf(ref!)
|
||||
if (idx !== -1) {
|
||||
result.mentions.splice(idx, 1)
|
||||
}
|
||||
if (ref!.author) {
|
||||
let author = result.profiles.find(p => p.pubkey === ref!.author)
|
||||
if (author && author.relays) {
|
||||
if (!ref!.relays) {
|
||||
ref!.relays = []
|
||||
}
|
||||
author.relays.forEach(url => {
|
||||
if (ref?.relays!?.indexOf(url) === -1) ref!.relays!.push(url)
|
||||
})
|
||||
author.relays = ref!.relays
|
||||
}
|
||||
}
|
||||
})
|
||||
result.mentions.forEach(ref => {
|
||||
if (ref!.author) {
|
||||
let author = result.profiles.find(p => p.pubkey === ref.author)
|
||||
if (author && author.relays) {
|
||||
if (!ref.relays) {
|
||||
ref.relays = []
|
||||
}
|
||||
author.relays.forEach(url => {
|
||||
if (ref.relays!.indexOf(url) === -1) ref.relays!.push(url)
|
||||
})
|
||||
author.relays = ref.relays
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user