kind.go raw

   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