publish(task 8): outbox-relay-loader (kind:10002 parser + fetcher)
parseOutbox(ev) interpretiert nip-65 r-tags: ohne marker → read+write, "read"/"write"-marker → nur jeweiliges set. ignoriert fremde tag-namen. loadOutbox(bootstrapRelay, pubkey) fragt kind:10002-event via applesauce-relay 2.x und parst das ergebnis. 3 tests grün. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ebe73cbf46
commit
1ec48ad1a9
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { Relay } from 'applesauce-relay'
|
||||||
|
import { firstValueFrom, timeout } from 'rxjs'
|
||||||
|
import type { SignedEvent } from './relays.ts'
|
||||||
|
|
||||||
|
export interface Outbox {
|
||||||
|
read: string[]
|
||||||
|
write: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseOutbox(ev: { tags: string[][] }): Outbox {
|
||||||
|
const read: string[] = []
|
||||||
|
const write: string[] = []
|
||||||
|
for (const t of ev.tags) {
|
||||||
|
if (t[0] !== 'r' || !t[1]) continue
|
||||||
|
const marker = t[2]
|
||||||
|
if (marker === 'read') read.push(t[1])
|
||||||
|
else if (marker === 'write') write.push(t[1])
|
||||||
|
else {
|
||||||
|
read.push(t[1])
|
||||||
|
write.push(t[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { read, write }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadOutbox(
|
||||||
|
bootstrapRelay: string,
|
||||||
|
authorPubkeyHex: string,
|
||||||
|
): Promise<Outbox> {
|
||||||
|
const relay = new Relay(bootstrapRelay)
|
||||||
|
const ev = await firstValueFrom(
|
||||||
|
relay
|
||||||
|
.request({ kinds: [10002], authors: [authorPubkeyHex], limit: 1 })
|
||||||
|
.pipe(timeout({ first: 10_000 })),
|
||||||
|
) as SignedEvent
|
||||||
|
return parseOutbox(ev)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { assertEquals } from '@std/assert'
|
||||||
|
import { parseOutbox } from '../src/core/outbox.ts'
|
||||||
|
|
||||||
|
Deno.test('parseOutbox: r-tags ohne marker → beide', () => {
|
||||||
|
const ev = {
|
||||||
|
kind: 10002,
|
||||||
|
tags: [
|
||||||
|
['r', 'wss://damus'],
|
||||||
|
['r', 'wss://nos'],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
assertEquals(parseOutbox(ev), {
|
||||||
|
read: ['wss://damus', 'wss://nos'],
|
||||||
|
write: ['wss://damus', 'wss://nos'],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Deno.test('parseOutbox: marker read ignoriert schreib-nutzung', () => {
|
||||||
|
const ev = {
|
||||||
|
kind: 10002,
|
||||||
|
tags: [
|
||||||
|
['r', 'wss://r-only', 'read'],
|
||||||
|
['r', 'wss://w-only', 'write'],
|
||||||
|
['r', 'wss://both'],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
assertEquals(parseOutbox(ev), {
|
||||||
|
read: ['wss://r-only', 'wss://both'],
|
||||||
|
write: ['wss://w-only', 'wss://both'],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Deno.test('parseOutbox: ignoriert andere tag-namen', () => {
|
||||||
|
const ev = {
|
||||||
|
kind: 10002,
|
||||||
|
tags: [
|
||||||
|
['r', 'wss://x'],
|
||||||
|
['p', 'someone'],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
assertEquals(parseOutbox(ev), { read: ['wss://x'], write: ['wss://x'] })
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue