1 // Package kind includes a type for convenient handling of event kinds, and a
2 // kind database with reverse lookup for human-readable information about event
3 // kinds.
4 package kind
5 6 import (
7 "sync"
8 9 "next.orly.dev/pkg/nostr/encoders/ints"
10 "golang.org/x/exp/constraints"
11 "next.orly.dev/pkg/lol/chk"
12 )
13 14 // K - which will be externally referenced as kind.K is the event type in the
15 // nostr protocol, the use of the capital K signifying type, consistent with Go
16 // idiom, the Go standard library, and much, conformant, existing code.
17 type K struct {
18 K uint16
19 }
20 21 // New creates a new kind.K with a provided integer value. Note that anything
22 // larger than 2^16 will be truncated.
23 func New[V constraints.Integer](k V) (ki *K) { return &K{uint16(k)} }
24 25 // ToInt returns the value of the kind.K as an int.
26 func (k *K) ToInt() int {
27 if k == nil {
28 return 0
29 }
30 return int(k.K)
31 }
32 33 // ToU16 returns the value of the kind.K as an uint16 (the native form).
34 func (k *K) ToU16() uint16 {
35 if k == nil {
36 return 0
37 }
38 return k.K
39 }
40 41 // ToI32 returns the value of the kind.K as an int32.
42 func (k *K) ToI32() int32 {
43 if k == nil {
44 return 0
45 }
46 return int32(k.K)
47 }
48 49 // ToU64 returns the value of the kind.K as an uint64.
50 func (k *K) ToU64() uint64 {
51 if k == nil {
52 return 0
53 }
54 return uint64(k.K)
55 }
56 57 // Name returns the human readable string describing the semantics of the
58 // kind.K.
59 func (k *K) Name() string { return GetString(k.K) }
60 61 // Equal checks if
62 func (k *K) Equal(k2 uint16) bool {
63 if k == nil {
64 return false
65 }
66 return k.K == k2
67 }
68 69 var Privileged = []*K{
70 EncryptedDirectMessage,
71 GiftWrap,
72 GiftWrapWithKind4,
73 JWTBinding,
74 ApplicationSpecificData,
75 Seal,
76 DirectMessage,
77 FileMessage,
78 MLSKeyPackage,
79 KeyPackageRelaysList,
80 ChannelCreation,
81 ChannelMetadata,
82 ChannelMessage,
83 ChannelHideMessage,
84 ChannelMuteUser,
85 }
86 87 // IsChannelKind returns true if the kind is a channel-related kind (40-44).
88 // These use channel membership rather than p-tag involvement for access control.
89 func IsChannelKind(k uint16) bool {
90 return k >= ChannelCreation.K && k <= ChannelMuteUser.K
91 }
92 93 // IsDiscoverableChannelKind returns true for kinds 40 and 41, which should be
94 // readable by all authenticated users for channel discovery purposes.
95 func IsDiscoverableChannelKind(k uint16) bool {
96 return k == ChannelCreation.K || k == ChannelMetadata.K
97 }
98 99 // IsPrivileged returns true if the type is the kind of message nobody else than
100 // the pubkeys in the event and p tags of the event are party to.
101 func IsPrivileged(k uint16) (is bool) {
102 for i := range Privileged {
103 if k == Privileged[i].K {
104 return true
105 }
106 }
107 return
108 }
109 110 // Marshal renders the kind.K into bytes containing the ASCII string form of the
111 // kind number.
112 func (k *K) Marshal(dst []byte) (b []byte) {
113 return ints.New(k.ToU64()).Marshal(dst)
114 }
115 116 // Unmarshal decodes a byte string into a kind.K.
117 func (k *K) Unmarshal(b []byte) (r []byte, err error) {
118 n := ints.New(0)
119 if r, err = n.Unmarshal(b); chk.T(err) {
120 return
121 }
122 k.K = n.Uint16()
123 return
124 }
125 126 // GetString returns a human-readable identifier for a kind.K.
127 func GetString(t uint16) string {
128 MapMx.RLock()
129 defer MapMx.RUnlock()
130 return Map[t]
131 }
132 133 // IsEphemeral returns true if the event kind is an ephemeral event. (not to be
134 // stored)
135 func IsEphemeral(k uint16) bool {
136 return k >= EphemeralStart.K && k < EphemeralEnd.K
137 }
138 139 // IsReplaceable returns true if the event kind is a replaceable kind - that is,
140 // if the newest version is the one that is in force (eg follow lists, relay
141 // lists, etc.
142 func IsReplaceable(k uint16) bool {
143 return k == ProfileMetadata.K || k == FollowList.K ||
144 (k >= ReplaceableStart.K && k < ReplaceableEnd.K)
145 }
146 147 // IsParameterizedReplaceable is a kind of event that is one of a group of
148 // events that replaces based on matching criteria.
149 func IsParameterizedReplaceable(k uint16) bool {
150 return k >= ParameterizedReplaceableStart.K &&
151 k < ParameterizedReplaceableEnd.K
152 }
153 154 // Directory events are events that necessarily need to be readable by anyone in
155 // order to interact with users who have access to the relay, in order to
156 // facilitate other users to find and interact with users on an auth-required
157 // relay.
158 var Directory = []*K{
159 ProfileMetadata,
160 FollowList,
161 EventDeletion,
162 Reporting,
163 RelayListMetadata,
164 MuteList,
165 DMRelaysList,
166 }
167 168 // IsDirectoryEvent returns whether an event kind is a Directory event, which
169 // should grant permission to read such events without requiring authentication.
170 func IsDirectoryEvent(k uint16) bool {
171 for i := range Directory {
172 if k == Directory[i].K {
173 return true
174 }
175 }
176 return false
177 }
178 179 var (
180 // ProfileMetadata is an event type that stores user profile data, pet
181 // names, bio, lightning address, etc.
182 ProfileMetadata = &K{0}
183 // SetMetadata is a synonym for ProfileMetadata.
184 SetMetadata = &K{0}
185 // TextNote is a standard short text note of plain text a la twitter
186 TextNote = &K{1}
187 // RecommendServer is an event type that...
188 RecommendRelay = &K{2}
189 // FollowList an event containing a list of pubkeys of users that should be
190 // shown as follows in a timeline.
191 FollowList = &K{3}
192 Follows = &K{3}
193 // EncryptedDirectMessage is an event type that...
194 EncryptedDirectMessage = &K{4}
195 // EventDeletion is an event type that...
196 EventDeletion = &K{5}
197 Deletion = &K{5}
198 // Repost is an event type that...
199 Repost = &K{6}
200 // Reaction is an event type that...
201 Reaction = &K{7}
202 // BadgeAward is an event type
203 BadgeAward = &K{8}
204 // ChatMessage is an event type for NIP-C7 chat messages
205 ChatMessage = &K{9}
206 // GroupChatThreadedReply is deprecated
207 GroupChatThreadedReply = &K{10}
208 // Thread is an event type for NIP-7D threads
209 Thread = &K{11}
210 // GroupThreadReply is deprecated
211 GroupThreadReply = &K{12}
212 // Seal is an event that wraps a PrivateDirectMessage and is placed inside a
213 // GiftWrap or GiftWrapWithKind4
214 Seal = &K{13}
215 // DirectMessage is a nip-17 direct message with a different
216 // construction. It doesn't actually appear as an event a relay might receive
217 // but only as the stringified content of a GiftWrap or GiftWrapWithKind4 inside
218 // a
219 DirectMessage = &K{14}
220 // FileMessage is a NIP-17 file message
221 FileMessage = &K{15}
222 // GenericRepost is an event type that...
223 GenericRepost = &K{16}
224 // ReactionToWebsite is a reaction to a website
225 ReactionToWebsite = &K{17}
226 // Picture is an event type for NIP-68 picture-first feeds
227 Picture = &K{20}
228 // VideoEventHorizontal is for horizontal video events
229 VideoEventHorizontal = &K{34235}
230 // VideoEventVertical is for vertical video events
231 VideoEventVertical = &K{34236}
232 // MLSKeyPackage is a NIP-EE (WhiteNoise) event publishing a user's MLS
233 // KeyPackage for group invitations. Author-only; no p tags.
234 MLSKeyPackage = &K{443}
235 // MLSWelcome is a NIP-EE (WhiteNoise) event delivering an MLS Welcome
236 // message to a newly added group member. Delivered via gift-wrap.
237 MLSWelcome = &K{444}
238 // MLSGroupEvent is a NIP-EE (WhiteNoise) event for MLS group messages.
239 // Uses h tag for group ID; encrypted content.
240 MLSGroupEvent = &K{445}
241 // ChannelCreation is an event type that...
242 ChannelCreation = &K{40}
243 // ChannelMetadata is an event type that...
244 ChannelMetadata = &K{41}
245 // ChannelMessage is an event type that...
246 ChannelMessage = &K{42}
247 // ChannelHideMessage is an event type that...
248 ChannelHideMessage = &K{43}
249 // ChannelMuteUser is an event type that...
250 ChannelMuteUser = &K{44}
251 // Bid is an event type that...
252 Bid = &K{1021}
253 // BidConfirmation is an event type that...
254 BidConfirmation = &K{1022}
255 // OpenTimestamps is an event type that...
256 OpenTimestamps = &K{1040}
257 GiftWrap = &K{1059}
258 GiftWrapWithKind4 = &K{1060}
259 // FileMetadata is an event type that...
260 FileMetadata = &K{1063}
261 // LiveChatMessage is an event type that...
262 LiveChatMessage = &K{1311}
263 // BitcoinBlock is an event type created for the Nostrocket
264 BitcoinBlock = &K{1517}
265 // LiveStream from zap.stream
266 LiveStream = &K{1808}
267 // ProblemTracker is an event type used by Nostrocket
268 ProblemTracker = &K{1971}
269 // MemoryHole is an event type contains a report about an event (usually
270 // text note or other human readable)
271 MemoryHole = &K{1984}
272 Reporting = &K{1984}
273 // Label is an event type has L and l tags, namespace and type - NIP-32
274 Label = &K{1985}
275 // CommunityPostApproval is an event type that...
276 CommunityPostApproval = &K{4550}
277 JobRequestStart = &K{5000}
278 JobRequestEnd = &K{5999}
279 JobResultStart = &K{6000}
280 JobResultEnd = &K{6999}
281 JobFeedback = &K{7000}
282 ZapGoal = &K{9041}
283 // ZapRequest is an event type that...
284 ZapRequest = &K{9734}
285 // Zap is an event type that...
286 Zap = &K{9735}
287 Highlights = &K{9802}
288 // ReplaceableStart is an event type that...
289 ReplaceableStart = &K{10000}
290 // MuteList is an event type that...
291 MuteList = &K{10000}
292 BlockList = &K{10000}
293 // PinList is an event type that...
294 PinList = &K{10001}
295 // RelayListMetadata is an event type that...
296 RelayListMetadata = &K{10002}
297 BookmarkList = &K{10003}
298 CommunitiesList = &K{10004}
299 PublicChatsList = &K{10005}
300 BlockedRelaysList = &K{10006}
301 SearchRelaysList = &K{10007}
302 RelayGroupConfig = &K{10008}
303 InterestsList = &K{10015}
304 UserEmojiList = &K{10030}
305 DMRelaysList = &K{10050}
306 // KeyPackageRelaysList is a NIP-EE (WhiteNoise) event advertising relays
307 // where a user publishes KeyPackage events. Author-only; no p tags.
308 KeyPackageRelaysList = &K{10051}
309 FileStorageServerList = &K{10096}
310 // JWTBinding is an event kind that creates a link between a JWT certificate and a pubkey
311 JWTBinding = &K{13004}
312 // NWCWalletServiceInfo is an event type that...
313 NWCWalletServiceInfo = &K{13194}
314 WalletServiceInfo = &K{13194}
315 // ReplaceableEnd is an event type that...
316 ReplaceableEnd = &K{19999}
317 // EphemeralStart is an event type that...
318 EphemeralStart = &K{20000}
319 LightningPubRPC = &K{21000}
320 // ClientAuthentication is an event type that...
321 ClientAuthentication = &K{22242}
322 // NWCWalletRequest is an event type that...
323 NWCWalletRequest = &K{23194}
324 WalletRequest = &K{23194}
325 // NWCWalletResponse is an event type that...
326 NWCWalletResponse = &K{23195}
327 WalletResponse = &K{23195}
328 NWCNotification = &K{23196}
329 WalletNotificationNip4 = &K{23196}
330 WalletNotification = &K{23197}
331 // NostrConnect is an event type that...
332 NostrConnect = &K{24133}
333 HTTPAuth = &K{27235}
334 // EphemeralEnd is an event type that...
335 EphemeralEnd = &K{29999}
336 // ParameterizedReplaceableStart is an event type that...
337 ParameterizedReplaceableStart = &K{30000}
338 // CategorizedPeopleList is an event type that...
339 CategorizedPeopleList = &K{30000}
340 FollowSets = &K{30000}
341 // CategorizedBookmarksList is an event type that...
342 CategorizedBookmarksList = &K{30001}
343 GenericLists = &K{30001}
344 RelaySets = &K{30002}
345 BookmarkSets = &K{30003}
346 CurationSets = &K{30004}
347 // ProfileBadges is an event type that...
348 ProfileBadges = &K{30008}
349 // BadgeDefinition is an event type that...
350 BadgeDefinition = &K{30009}
351 InterestSets = &K{30015}
352 // StallDefinition creates or updates a stall
353 StallDefinition = &K{30017}
354 // ProductDefinition creates or updates a product
355 ProductDefinition = &K{30018}
356 MarketplaceUIUX = &K{30019}
357 ProductSoldAsAuction = &K{30020}
358 // Article is an event type that...
359 Article = &K{30023}
360 LongFormContent = &K{30023}
361 DraftLongFormContent = &K{30024}
362 EmojiSets = &K{30030}
363 // ApplicationSpecificData is an event type stores data about application
364 // configuration, this, like DMs and giftwraps must be protected by user
365 // auth.
366 ApplicationSpecificData = &K{30078}
367 LiveEvent = &K{30311}
368 UserStatuses = &K{30315}
369 ClassifiedListing = &K{30402}
370 DraftClassifiedListing = &K{30403}
371 DateBasedCalendarEvent = &K{31922}
372 TimeBasedCalendarEvent = &K{31923}
373 Calendar = &K{31924}
374 CalendarEventRSVP = &K{31925}
375 HandlerRecommendation = &K{31989}
376 HandlerInformation = &K{31990}
377 // WaveLakeTrack which has no spec and uses malformed tags
378 WaveLakeTrack = &K{32123}
379 CommunityDefinition = &K{34550}
380 ACLEvent = &K{39998}
381 // PolicyConfig is an event type for relay-internal policy configuration updates.
382 // Only policy administrators can read/write these events.
383 // The content field contains the JSON policy configuration.
384 PolicyConfig = &K{12345}
385 // ParameterizedReplaceableEnd is an event type that...
386 ParameterizedReplaceableEnd = &K{40000}
387 )
388 389 var MapMx sync.RWMutex
390 391 // Map is populated from the embedded kinds.json during init()
392 var Map = make(map[uint16]string)
393