diff --git a/snapshot/src/core/nip09-filter.ts b/snapshot/src/core/nip09-filter.ts new file mode 100644 index 0000000..cd2d602 --- /dev/null +++ b/snapshot/src/core/nip09-filter.ts @@ -0,0 +1,22 @@ +import type { SignedEvent } from './types.ts' + +export function filterDeleted( + events: SignedEvent[], + deletions: SignedEvent[], + authorPubkey: string, +): SignedEvent[] { + const deletedCoords = new Set() + for (const del of deletions) { + if (del.kind !== 5) continue + if (del.pubkey !== authorPubkey) continue + for (const tag of del.tags) { + if (tag[0] === 'a' && tag[1]) deletedCoords.add(tag[1]) + } + } + return events.filter((ev) => { + const d = ev.tags.find((t) => t[0] === 'd')?.[1] + if (!d) return true + const coord = `${ev.kind}:${ev.pubkey}:${d}` + return !deletedCoords.has(coord) + }) +} diff --git a/snapshot/tests/nip09-filter.test.ts b/snapshot/tests/nip09-filter.test.ts new file mode 100644 index 0000000..0eabf6b --- /dev/null +++ b/snapshot/tests/nip09-filter.test.ts @@ -0,0 +1,30 @@ +import { assertEquals } from '@std/assert' +import { filterDeleted } from '../src/core/nip09-filter.ts' +import type { SignedEvent } from '../src/core/types.ts' + +function post(d: string, id: string): SignedEvent { + return { id, pubkey: 'P', created_at: 1, kind: 30023, sig: 's', content: '', tags: [['d', d]] } +} +function deletion(coords: string[]): SignedEvent { + return { + id: 'del', pubkey: 'P', created_at: 2, kind: 5, sig: 's', content: '', + tags: coords.map((c) => ['a', c]), + } +} + +Deno.test('filterDeleted entfernt events deren coord in einem kind:5 referenziert ist', () => { + const out = filterDeleted( + [post('alive', 'a'), post('dead', 'b')], + [deletion(['30023:P:dead'])], + 'P', + ) + assertEquals(out.map((e) => e.id), ['a']) +}) + +Deno.test('filterDeleted ignoriert kind:5 fremder pubkeys', () => { + const fremde: SignedEvent = { + ...deletion(['30023:P:alive']), pubkey: 'OTHER', + } + const out = filterDeleted([post('alive', 'a')], [fremde], 'P') + assertEquals(out.length, 1) +})