enzyme.go raw
1 package nostr
2
3 import (
4 "fmt"
5 "strings"
6
7 "git.mleku.dev/mleku/dendrite/pkg/axiom"
8 )
9
10 // element is the concrete axiom.Element type for Nostr events.
11 type element struct {
12 tag string
13 val any
14 }
15
16 func (e element) Type() string { return e.tag }
17 func (e element) Value() any { return e.val }
18
19 // EventToElements decomposes a validated Nostr event into typed lattice
20 // elements. Each event produces elements for its structural parts:
21 // pubkey, kind, content words, tags, and references.
22 func EventToElements(ev *Event) []axiom.Element {
23 var elems []axiom.Element
24
25 // The event itself.
26 elems = append(elems, element{"event", ev.ID[:16]})
27
28 // Author identity.
29 elems = append(elems, element{"pubkey", ev.Pubkey})
30
31 // Kind as a typed element.
32 elems = append(elems, element{"kind", fmt.Sprintf("%d", ev.Kind)})
33
34 // Content — decompose into words for bonding.
35 if ev.Content != "" {
36 words := strings.Fields(ev.Content)
37 for _, w := range words {
38 // Skip very short words.
39 if len(w) > 2 {
40 elems = append(elems, element{"word", w})
41 }
42 }
43 // Also emit the content as a literal for format-string absorption.
44 if len(ev.Content) > 10 && len(ev.Content) < 200 {
45 elems = append(elems, element{"literal", fmt.Sprintf("%q", ev.Content)})
46 }
47 }
48
49 // Tags — each tag becomes a typed element.
50 for _, tag := range ev.Tags {
51 if len(tag) < 2 {
52 continue
53 }
54 switch tag[0] {
55 case "e":
56 // Event reference.
57 elems = append(elems, element{"e-tag", tag[1]})
58 case "p":
59 // Pubkey mention.
60 elems = append(elems, element{"p-tag", tag[1]})
61 case "t":
62 // Hashtag.
63 elems = append(elems, element{"hashtag", tag[1]})
64 default:
65 // Generic tag.
66 elems = append(elems, element{"tag", tag[0] + ":" + tag[1]})
67 }
68 }
69
70 // Timestamp as a structural element.
71 elems = append(elems, element{"timestamp", fmt.Sprintf("%d", ev.CreatedAt)})
72
73 return elems
74 }
75