nostr

package module
v0.0.0-...-a7bfc0e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2026 License: Unlicense Imports: 40 Imported by: 32

README

nostr

A comprehensive Go library for the Nostr protocol, providing everything needed to build relays, clients, or hybrid applications.

This is a new, much improved in all aspects, version of go-nostr.

Installation

go get fiatjaf.com/nostr

Components

  • eventstore: Pluggable storage backends (Bleve, BoltDB, LMDB, in-memory, MMM)
  • khatru: Flexible framework for building Nostr relays
  • khatru/blossom: Plugin for a Khatru server that adds flexible Blossom server support
  • khatru/grasp: Plugin for a Khatru server that adds Grasp server support
  • sdk: Client SDK with caching, data loading, and outbox relay management
  • keyer: Key and bunker management utilities
  • NIP-specific libraries with helpers and other things for many NIPs and related stuff, including blossom, negentropy and cashu mini-libraries.

Documentation

Index

Constants

View Source
const MAX_LOCKS = 50

Variables

View Source
var (
	UnknownLabel        = errors.New("unknown envelope label")
	InvalidJsonEnvelope = errors.New("invalid json envelope")
)
View Source
var (
	ZeroPK = PubKey{}

	// this special public key doesn't have a secret key known to anyone,
	// it corresponds to the hash of the block #3 of bitcoin (the first 3 block hashes are not valid public keys)
	NUMS = MustPubKeyFromHex("0000000082b5015589a3fdf2d4baff403e6f0be035a5d9742c1cae6295464449")
)
View Source
var (
	// call SetOutput on InfoLogger to enable info logging
	InfoLogger = log.New(os.Stderr, "[nl][info] ", log.LstdFlags)

	// call SetOutput on DebugLogger to enable debug logging
	DebugLogger = log.New(os.Stderr, "[nl][debug] ", log.LstdFlags)
)
View Source
var (
	ErrDisconnected = errors.New("<disconnected>")
	ErrPingFailed   = errors.New("<ping failed>")
)
View Source
var (
	ErrNotConnected = errors.New("not connected")
	ErrFireFailed   = errors.New("failed to fire")
)
View Source
var KeyOne = SecretKey{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
View Source
var ZeroID = ID{}

Functions

func AppendUnique

func AppendUnique[I comparable](list []I, newEls ...I) []I

AppendUnique adds items to an array only if they don't already exist in the array. Returns the modified array.

func CompareEvent

func CompareEvent(a, b Event) int

CompareEvent is meant to to be used with slices.Sort

func CompareEventReverse

func CompareEventReverse(b, a Event) int

CompareEventReverse is meant to to be used with slices.Sort

func CompareRelayEvent

func CompareRelayEvent(a, b RelayEvent) int

CompareRelayEvent is meant to to be used with slices.Sort

func CompareRelayEventReverse

func CompareRelayEventReverse(b, a RelayEvent) int

CompareRelayEventReverse is meant to to be used with slices.Sort

func ContainsID

func ContainsID(haystack []ID, needle ID) bool

func ContainsPubKey

func ContainsPubKey(haystack []PubKey, needle PubKey) bool

func FilterEqual

func FilterEqual(a Filter, b Filter) bool

func HexDecodeString

func HexDecodeString(s string) ([]byte, error)

HexDecodeString decodes a hex string into bytes.

func HexEncodeToString

func HexEncodeToString(src []byte) string

HexEncodeToString encodes src into a hex string.

func IsOlder

func IsOlder(previous, next Event) bool

func IsValid32ByteHex

func IsValid32ByteHex(thing string) bool

IsValid32ByteHex checks if a string is a valid 32-byte hex string.

func IsValidRelayURL

func IsValidRelayURL(u string) bool

IsValidRelayURL checks if a URL is a valid relay URL (ws:// or wss://).

func NormalizeHTTPURL

func NormalizeHTTPURL(s string) (string, error)

NormalizeHTTPURL does normalization of http(s):// URLs according to rfc3986. Don't use for relay URLs.

func NormalizeOKMessage

func NormalizeOKMessage(reason string, prefix string) string

NormalizeOKMessage takes a string message that is to be sent in an `OK` or `CLOSED` command and prefixes it with "<prefix>: " if it doesn't already have an acceptable prefix.

func NormalizeURL

func NormalizeURL(u string) string

NormalizeURL normalizes the url and replaces http://, https:// schemes with ws://, wss:// and normalizes the path.

Types

type AuthEnvelope

type AuthEnvelope struct {
	Challenge *string
	Event     Event
}

AuthEnvelope represents an AUTH message.

func (*AuthEnvelope) FromJSON

func (v *AuthEnvelope) FromJSON(data string) error

func (AuthEnvelope) Label

func (_ AuthEnvelope) Label() string

func (AuthEnvelope) MarshalJSON

func (v AuthEnvelope) MarshalJSON() ([]byte, error)

func (AuthEnvelope) String

func (a AuthEnvelope) String() string

type Cipher

type Cipher interface {
	// Encrypt encrypts a plaintext message for a recipient using NIP-44.
	// Returns the encrypted message as a base64-encoded string.
	Encrypt(ctx context.Context, plaintext string, recipient PubKey) (base64ciphertext string, err error)

	// Decrypt decrypts a base64-encoded ciphertext from a sender using NIP-44.
	// Returns the decrypted plaintext.
	Decrypt(ctx context.Context, base64ciphertext string, sender PubKey) (plaintext string, err error)

	// Nip04Encrypt encrypts a plaintext message for a recipient using NIP-04.
	Nip04Encrypt(ctx context.Context, plaintext string, recipient PubKey) (ciphertext string, err error)

	// Nip04Decrypt decrypts a ciphertext from a sender using NIP-04.
	Nip04Decrypt(ctx context.Context, ciphertext string, sender PubKey) (plaintext string, err error)
}

Cipher is an interface for encrypting and decrypting messages

type CloseEnvelope

type CloseEnvelope string

CloseEnvelope represents a CLOSE message.

func (*CloseEnvelope) FromJSON

func (v *CloseEnvelope) FromJSON(data string) error

func (CloseEnvelope) Label

func (_ CloseEnvelope) Label() string

func (CloseEnvelope) MarshalJSON

func (v CloseEnvelope) MarshalJSON() ([]byte, error)

func (CloseEnvelope) String

func (c CloseEnvelope) String() string

type ClosedEnvelope

type ClosedEnvelope struct {
	SubscriptionID string
	Reason         string
}

ClosedEnvelope represents a CLOSED message.

func (*ClosedEnvelope) FromJSON

func (v *ClosedEnvelope) FromJSON(data string) error

func (ClosedEnvelope) Label

func (_ ClosedEnvelope) Label() string

func (ClosedEnvelope) MarshalJSON

func (v ClosedEnvelope) MarshalJSON() ([]byte, error)

func (ClosedEnvelope) String

func (c ClosedEnvelope) String() string

type CountEnvelope

type CountEnvelope struct {
	SubscriptionID string
	Filter
	Count       *uint32
	HyperLogLog []byte
}

CountEnvelope represents a COUNT message.

func (*CountEnvelope) FromJSON

func (v *CountEnvelope) FromJSON(data string) error

func (CountEnvelope) Label

func (_ CountEnvelope) Label() string

func (CountEnvelope) MarshalJSON

func (v CountEnvelope) MarshalJSON() ([]byte, error)

func (CountEnvelope) String

func (c CountEnvelope) String() string

type DirectedFilter

type DirectedFilter struct {
	Filter
	Relay string
}

DirectedFilter combines a Filter with a specific relay URL.

func (DirectedFilter) String

func (df DirectedFilter) String() string

type EOSEEnvelope

type EOSEEnvelope string

EOSEEnvelope represents an EOSE (End of Stored Events) message.

func (*EOSEEnvelope) FromJSON

func (v *EOSEEnvelope) FromJSON(data string) error

func (EOSEEnvelope) Label

func (_ EOSEEnvelope) Label() string

func (EOSEEnvelope) MarshalJSON

func (v EOSEEnvelope) MarshalJSON() ([]byte, error)

func (EOSEEnvelope) String

func (e EOSEEnvelope) String() string

type EntityPointer

type EntityPointer struct {
	PublicKey  PubKey
	Kind       Kind
	Identifier string
	Relays     []string
}

EntityPointer represents a pointer to a nostr entity (addressable event).

func EntityPointerFromTag

func EntityPointerFromTag(refTag Tag) (EntityPointer, error)

EntityPointerFromTag creates an EntityPointer from an "a" tag (but it doesn't check if the tag is really "a", it could be anything).

func ParseAddrString

func ParseAddrString(addr string) (EntityPointer, error)

func (EntityPointer) AsFilter

func (ep EntityPointer) AsFilter() Filter

func (EntityPointer) AsTag

func (ep EntityPointer) AsTag() Tag

func (EntityPointer) AsTagReference

func (ep EntityPointer) AsTagReference() string

func (EntityPointer) MarshalEasyJSON

func (v EntityPointer) MarshalEasyJSON(w *jwriter.Writer)

MarshalEasyJSON supports easyjson.Marshaler interface

func (EntityPointer) MarshalJSON

func (v EntityPointer) MarshalJSON() ([]byte, error)

MarshalJSON supports json.Marshaler interface

func (EntityPointer) MatchesEvent

func (ep EntityPointer) MatchesEvent(evt Event) bool

MatchesEvent checks if the pointer matches an event.

func (*EntityPointer) UnmarshalEasyJSON

func (v *EntityPointer) UnmarshalEasyJSON(l *jlexer.Lexer)

UnmarshalEasyJSON supports easyjson.Unmarshaler interface

func (*EntityPointer) UnmarshalJSON

func (v *EntityPointer) UnmarshalJSON(data []byte) error

UnmarshalJSON supports json.Unmarshaler interface

type Envelope

type Envelope interface {
	Label() string
	FromJSON(string) error
	MarshalJSON() ([]byte, error)
	String() string
}

Envelope is the interface for all nostr message envelopes.

func ParseMessage

func ParseMessage(message string) (Envelope, error)

type Event

type Event struct {
	ID        ID
	PubKey    PubKey
	CreatedAt Timestamp
	Kind      Kind
	Tags      Tags
	Content   string
	Sig       [64]byte
}

Event represents a Nostr event.

func (Event) CheckID

func (evt Event) CheckID() bool

CheckID checks if the implied ID matches the currently assigned ID.

func (Event) GetID

func (evt Event) GetID() ID

GetID serializes and returns the event ID as a string.

func (Event) MarshalEasyJSON

func (v Event) MarshalEasyJSON(w *jwriter.Writer)

MarshalEasyJSON supports easyjson.Marshaler interface

func (Event) MarshalJSON

func (v Event) MarshalJSON() ([]byte, error)

MarshalJSON supports json.Marshaler interface

func (Event) Serialize

func (evt Event) Serialize() []byte

Serialize outputs a byte array that can be hashed to produce the canonical event "id".

func (*Event) SetID

func (evt *Event) SetID()

SetID calculates and sets the id to the event in a single operation.

func (*Event) Sign

func (evt *Event) Sign(secretKey [32]byte) error

Sign signs an event with a given privateKey.

It sets the event's ID, PubKey, and Sig fields.

Returns an error if the private key is invalid or if signing fails.

func (Event) String

func (evt Event) String() string

func (*Event) UnmarshalEasyJSON

func (v *Event) UnmarshalEasyJSON(l *jlexer.Lexer)

UnmarshalEasyJSON supports easyjson.Unmarshaler interface

func (*Event) UnmarshalJSON

func (v *Event) UnmarshalJSON(data []byte) error

UnmarshalJSON supports json.Unmarshaler interface

func (Event) VerifySignature

func (evt Event) VerifySignature() bool

Verify checks if the event signature is valid for the given event. It won't look at the ID field, instead it will recompute the id from the entire event body. Returns true if the signature is valid, false otherwise.

type EventEnvelope

type EventEnvelope struct {
	SubscriptionID *string
	Event
}

EventEnvelope represents an EVENT message.

func (*EventEnvelope) FromJSON

func (v *EventEnvelope) FromJSON(data string) error

func (EventEnvelope) Label

func (_ EventEnvelope) Label() string

func (EventEnvelope) MarshalJSON

func (v EventEnvelope) MarshalJSON() ([]byte, error)

type EventPointer

type EventPointer struct {
	ID     ID
	Relays []string
	Author PubKey
	Kind   Kind
}

EventPointer represents a pointer to a nostr event.

func EventPointerFromTag

func EventPointerFromTag(refTag Tag) (EventPointer, error)

EventPointerFromTag creates an EventPointer from an "e" tag (but it could be other tag name, it isn't checked).

func (EventPointer) AsFilter

func (ep EventPointer) AsFilter() Filter

func (EventPointer) AsTag

func (ep EventPointer) AsTag() Tag

AsTag converts the pointer to a Tag.

func (EventPointer) AsTagReference

func (ep EventPointer) AsTagReference() string

func (EventPointer) MarshalEasyJSON

func (v EventPointer) MarshalEasyJSON(w *jwriter.Writer)

MarshalEasyJSON supports easyjson.Marshaler interface

func (EventPointer) MarshalJSON

func (v EventPointer) MarshalJSON() ([]byte, error)

MarshalJSON supports json.Marshaler interface

func (EventPointer) MatchesEvent

func (ep EventPointer) MatchesEvent(evt Event) bool

func (*EventPointer) UnmarshalEasyJSON

func (v *EventPointer) UnmarshalEasyJSON(l *jlexer.Lexer)

UnmarshalEasyJSON supports easyjson.Unmarshaler interface

func (*EventPointer) UnmarshalJSON

func (v *EventPointer) UnmarshalJSON(data []byte) error

UnmarshalJSON supports json.Unmarshaler interface

type Filter

type Filter struct {
	IDs     []ID
	Kinds   []Kind
	Authors []PubKey
	Tags    TagMap
	Since   Timestamp
	Until   Timestamp
	Limit   int
	Search  string

	// LimitZero is or must be set when there is a "limit":0 in the filter, and not when "limit" is just omitted
	LimitZero bool `json:"-"`
}

func (Filter) Clone

func (ef Filter) Clone() Filter

func (Filter) GetTheoreticalLimit

func (filter Filter) GetTheoreticalLimit() int

GetTheoreticalLimit gets the maximum number of events that a normal filter would ever return, for example, if there is a number of "ids" in the filter, the theoretical limit will be that number of ids.

It returns math.MaxInt if there are no theoretical limits.

The given .Limit present in the filter is ignored.

func (Filter) MarshalEasyJSON

func (v Filter) MarshalEasyJSON(w *jwriter.Writer)

MarshalEasyJSON supports easyjson.Marshaler interface

func (Filter) MarshalJSON

func (v Filter) MarshalJSON() ([]byte, error)

MarshalJSON supports json.Marshaler interface

func (Filter) Matches

func (ef Filter) Matches(event Event) bool

func (Filter) MatchesIgnoringTimestampConstraints

func (ef Filter) MatchesIgnoringTimestampConstraints(event Event) bool

func (Filter) String

func (ef Filter) String() string

func (*Filter) UnmarshalEasyJSON

func (v *Filter) UnmarshalEasyJSON(l *jlexer.Lexer)

UnmarshalEasyJSON supports easyjson.Unmarshaler interface

func (*Filter) UnmarshalJSON

func (v *Filter) UnmarshalJSON(data []byte) error

UnmarshalJSON supports json.Unmarshaler interface

type ID

type ID [32]byte

ID represents an event id

func IDFromHex

func IDFromHex(idh string) (ID, error)

func MustIDFromHex

func MustIDFromHex(idh string) ID

func (ID) Hex

func (id ID) Hex() string

func (ID) MarshalJSON

func (id ID) MarshalJSON() ([]byte, error)

func (ID) String

func (id ID) String() string

func (*ID) UnmarshalJSON

func (id *ID) UnmarshalJSON(buf []byte) error

type Keyer

type Keyer interface {
	// Signer provides event signing capabilities
	Signer

	// Cipher provides encryption and decryption capabilities (NIP-44)
	Cipher
}

Keyer is an interface for signing events and performing cryptographic operations. It abstracts away the details of key management, allowing for different implementations such as in-memory keys, hardware wallets, or remote signing services (bunker).

type Kind

type Kind uint16
const (
	KindProfileMetadata                    Kind = 0
	KindTextNote                           Kind = 1
	KindRecommendServer                    Kind = 2
	KindFollowList                         Kind = 3
	KindEncryptedDirectMessage             Kind = 4
	KindDeletion                           Kind = 5
	KindRepost                             Kind = 6
	KindReaction                           Kind = 7
	KindBadgeAward                         Kind = 8
	KindSimpleGroupChatMessage             Kind = 9
	KindSimpleGroupThreadedReply           Kind = 10
	KindSimpleGroupThread                  Kind = 11
	KindSimpleGroupReply                   Kind = 12
	KindSeal                               Kind = 13
	KindDirectMessage                      Kind = 14
	KindFileMessage                        Kind = 15
	KindGenericRepost                      Kind = 16
	KindReactionToWebsite                  Kind = 17
	KindPhoto                              Kind = 20
	KindNormalVideoEvent                   Kind = 21
	KindShortVideoEvent                    Kind = 22
	KindPublicMessage                      Kind = 24
	KindChannelCreation                    Kind = 40
	KindChannelMetadata                    Kind = 41
	KindChannelMessage                     Kind = 42
	KindChannelHideMessage                 Kind = 43
	KindChannelMuteUser                    Kind = 44
	KindPodcastEpisode                     Kind = 54
	KindChess                              Kind = 64
	KindMergeRequests                      Kind = 818
	KindPollResponse                       Kind = 1018
	KindBid                                Kind = 1021
	KindBidConfirmation                    Kind = 1022
	KindOpenTimestamps                     Kind = 1040
	KindGiftWrap                           Kind = 1059
	KindFileMetadata                       Kind = 1063
	KindPoll                               Kind = 1068
	KindComment                            Kind = 1111
	KindVoiceMessage                       Kind = 1222
	KindScroll                             Kind = 1227
	KindVoiceMessageComment                Kind = 1244
	KindLiveChatMessage                    Kind = 1311
	KindCodeSnippet                        Kind = 1337
	KindPatch                              Kind = 1617
	KindGitPullRequest                     Kind = 1618
	KindGitPullRequestUpdate               Kind = 1619
	KindIssue                              Kind = 1621
	KindReply                              Kind = 1622
	KindStatusOpen                         Kind = 1630
	KindStatusApplied                      Kind = 1631
	KindStatusClosed                       Kind = 1632
	KindStatusDraft                        Kind = 1633
	KindProblemTracker                     Kind = 1971
	KindReporting                          Kind = 1984
	KindLabel                              Kind = 1985
	KindRelayReviews                       Kind = 1986
	KindAIEmbeddings                       Kind = 1987
	KindTorrent                            Kind = 2003
	KindTorrentComment                     Kind = 2004
	KindCoinjoinPool                       Kind = 2022
	KindDecoupledKeyClientAnnouncement     Kind = 4454
	KindDecoupledEncryptionKeyDistribution Kind = 4455
	KindCommunityPostApproval              Kind = 4550
	KindJobFeedback                        Kind = 7000
	KindReservedCashuWalletTokens          Kind = 7374
	KindCashuWalletTokens                  Kind = 7375
	KindCashuWalletHistory                 Kind = 7376
	KindGeocacheLog                        Kind = 7516
	KindGeocacheProofOfFind                Kind = 7517
	KindSimpleGroupPutUser                 Kind = 9000
	KindSimpleGroupRemoveUser              Kind = 9001
	KindSimpleGroupEditMetadata            Kind = 9002
	KindSimpleGroupDeleteEvent             Kind = 9005
	KindSimpleGroupCreateGroup             Kind = 9007
	KindSimpleGroupDeleteGroup             Kind = 9008
	KindSimpleGroupCreateInvite            Kind = 9009
	KindSimpleGroupJoinRequest             Kind = 9021
	KindSimpleGroupLeaveRequest            Kind = 9022
	KindZapGoal                            Kind = 9041
	KindNutZap                             Kind = 9321
	KindTidalLogin                         Kind = 9467
	KindZapRequest                         Kind = 9734
	KindZap                                Kind = 9735
	KindHighlights                         Kind = 9802
	KindMuteList                           Kind = 10000
	KindPinList                            Kind = 10001
	KindRelayListMetadata                  Kind = 10002
	KindBookmarkList                       Kind = 10003
	KindCommunityList                      Kind = 10004
	KindPublicChatList                     Kind = 10005
	KindBlockedRelayList                   Kind = 10006
	KindSearchRelayList                    Kind = 10007
	KindSimpleGroupList                    Kind = 10009
	KindFavoriteRelaysList                 Kind = 10012
	KindPrivateEventRelayList              Kind = 10013
	KindInterestList                       Kind = 10015
	KindNutZapInfo                         Kind = 10019
	KindMediaFollows                       Kind = 10020
	KindEmojiList                          Kind = 10030
	KindDecoupledKeyAnnouncement           Kind = 10044
	KindDMRelayList                        Kind = 10050
	KindFavoritePodcasts                   Kind = 10054
	KindUserServerList                     Kind = 10063
	KindFileStorageServerList              Kind = 10096
	KindGoodWikiAuthorList                 Kind = 10101
	KindGoodWikiRelayList                  Kind = 10102
	KindPodcastMetadata                    Kind = 10154
	KindAuthoredPodcasts                   Kind = 10164
	KindRelayMonitorAnnouncement           Kind = 10166
	KindRoomPresence                       Kind = 10312
	KindUserGraspList                      Kind = 10317
	KindProxyAnnouncement                  Kind = 10377
	KindTransportMethodAnnouncement        Kind = 11111
	KindNWCWalletInfo                      Kind = 13194
	KindNsiteRoot                          Kind = 15128
	KindCashuWalletEvent                   Kind = 17375
	KindLightningPubRPC                    Kind = 21000
	KindClientAuthentication               Kind = 22242
	KindNWCWalletRequest                   Kind = 23194
	KindNWCWalletResponse                  Kind = 23195
	KindNostrConnect                       Kind = 24133
	KindBlobs                              Kind = 24242
	KindHTTPAuth                           Kind = 27235
	KindCategorizedPeopleList              Kind = 30000
	KindCategorizedBookmarksList           Kind = 30001
	KindRelaySets                          Kind = 30002
	KindBookmarkSets                       Kind = 30003
	KindCuratedSets                        Kind = 30004
	KindCuratedVideoSets                   Kind = 30005
	KindMuteSets                           Kind = 30007
	KindProfileBadges                      Kind = 30008
	KindBadgeDefinition                    Kind = 30009
	KindInterestSets                       Kind = 30015
	KindStallDefinition                    Kind = 30017
	KindProductDefinition                  Kind = 30018
	KindMarketplaceUI                      Kind = 30019
	KindProductSoldAsAuction               Kind = 30020
	KindArticle                            Kind = 30023
	KindDraftArticle                       Kind = 30024
	KindEmojiSets                          Kind = 30030
	KindModularArticleHeader               Kind = 30040
	KindModularArticleContent              Kind = 30041
	KindReleaseArtifactSets                Kind = 30063
	KindApplicationSpecificData            Kind = 30078
	KindRelayDiscovery                     Kind = 30166
	KindAppCurationSet                     Kind = 30267
	KindLiveEvent                          Kind = 30311
	KindInteractiveRoom                    Kind = 30312
	KindConferenceEvent                    Kind = 30313
	KindUserStatuses                       Kind = 30315
	KindSlideSet                           Kind = 30388
	KindClassifiedListing                  Kind = 30402
	KindDraftClassifiedListing             Kind = 30403
	KindRepositoryAnnouncement             Kind = 30617
	KindRepositoryState                    Kind = 30618
	KindWikiArticle                        Kind = 30818
	KindRedirects                          Kind = 30819
	KindDraftEvent                         Kind = 31234
	KindLinkSet                            Kind = 31388
	KindFeed                               Kind = 31890
	KindDateCalendarEvent                  Kind = 31922
	KindTimeCalendarEvent                  Kind = 31923
	KindCalendar                           Kind = 31924
	KindCalendarEventRSVP                  Kind = 31925
	KindHandlerRecommendation              Kind = 31989
	KindHandlerInformation                 Kind = 31990
	KindSoftwareApplication                Kind = 32267
	KindLegacyNsiteFile                    Kind = 34128
	KindVideoViewEvent                     Kind = 34237
	KindCommunityDefinition                Kind = 34550
	KindNsiteNamed                         Kind = 35128
	KindGeocacheListing                    Kind = 37515
	KindGeocacheLogEntry                   Kind = 37516
	KindCashuMintAnnouncement              Kind = 38172
	KindFedimintAnnouncement               Kind = 38173
	KindPeerToPeerOrderEvents              Kind = 38383
	KindSimpleGroupMetadata                Kind = 39000
	KindSimpleGroupAdmins                  Kind = 39001
	KindSimpleGroupMembers                 Kind = 39002
	KindSimpleGroupRoles                   Kind = 39003
	KindSimpleGroupLiveKitParticipants     Kind = 39004
	KindStarterPacks                       Kind = 39089
	KindMediaStarterPacks                  Kind = 39092
	KindWebBookmarks                       Kind = 39701
)

func (Kind) IsAddressable

func (kind Kind) IsAddressable() bool

func (Kind) IsEphemeral

func (kind Kind) IsEphemeral() bool

func (Kind) IsRegular

func (kind Kind) IsRegular() bool

func (Kind) IsReplaceable

func (kind Kind) IsReplaceable() bool

func (Kind) Name

func (kind Kind) Name() string

func (Kind) Num

func (kind Kind) Num() uint16

func (Kind) String

func (kind Kind) String() string

type NoticeEnvelope

type NoticeEnvelope string

NoticeEnvelope represents a NOTICE message.

func (*NoticeEnvelope) FromJSON

func (v *NoticeEnvelope) FromJSON(data string) error

func (NoticeEnvelope) Label

func (_ NoticeEnvelope) Label() string

func (NoticeEnvelope) MarshalJSON

func (v NoticeEnvelope) MarshalJSON() ([]byte, error)

func (NoticeEnvelope) String

func (n NoticeEnvelope) String() string

type OKEnvelope

type OKEnvelope struct {
	EventID ID
	OK      bool
	Reason  string
}

OKEnvelope represents an OK message.

func (*OKEnvelope) FromJSON

func (v *OKEnvelope) FromJSON(data string) error

func (OKEnvelope) Label

func (_ OKEnvelope) Label() string

func (OKEnvelope) MarshalJSON

func (v OKEnvelope) MarshalJSON() ([]byte, error)

func (OKEnvelope) String

func (o OKEnvelope) String() string

type Pointer

type Pointer interface {
	// AsTagReference returns the pointer as a string as it would be seen in the value of a tag (i.e. the tag's second item).
	AsTagReference() string

	// AsTag converts the pointer with all the information available to a tag that can be included in events.
	AsTag() Tag

	// AsFilter converts the pointer to a Filter that can be used to query for it on relays.
	AsFilter() Filter
	MatchesEvent(Event) bool
}

Pointer is an interface for different types of Nostr pointers.

In this context, a "pointer" is a reference to an event or profile potentially including relays and other metadata that might help find it.

type Pool

type Pool struct {
	Relays  *xsync.MapOf[string, *Relay]
	Context context.Context

	// AuthRequiredHandler, if given, must be a function that signs the auth event when called.
	// it will be called whenever any relay in the pool returns a `CLOSED` or `OK` message
	// with the "auth-required:" prefix, only once for each relay
	AuthRequiredHandler func(context.Context, *Event) error

	// EventMiddleware is a function that will be called with all events received.
	EventMiddleware func(RelayEvent)

	// DuplicateMiddleware is a function that will be called with all duplicate ids received.
	DuplicateMiddleware func(relay string, id ID)

	// AuthorKindQueryMiddleware is a function that will be called with every combination of
	// relay+pubkey+kind queried in a .SubscribeMany*() call -- when applicable (i.e. when the query
	// contains a pubkey and a kind).
	QueryMiddleware func(relay string, pubkey PubKey, kind Kind)

	// RelayOptions are any options that should be passed to Relays instantiated by this pool
	RelayOptions RelayOptions
	// contains filtered or unexported fields
}

Pool manages connections to multiple relays, ensures they are reopened when necessary and not duplicated.

func NewPool

func NewPool() *Pool

NewPool creates a new Pool with the given context and options.

func (*Pool) AddToPenaltyBox

func (pool *Pool) AddToPenaltyBox(url string, duration time.Duration)

AddToPenaltyBox manually adds a relay to the penalty box for the specified duration. This prevents EnsureRelay from attempting to connect to the relay until the duration expires.

func (*Pool) BatchedQueryMany

func (pool *Pool) BatchedQueryMany(
	ctx context.Context,
	dfs []DirectedFilter,
	opts SubscriptionOptions,
) chan RelayEvent

BatchedQueryMany takes a bunch of filters and sends each to the target relay but deduplicates results smartly.

func (*Pool) BatchedQueryManyNotifyClosed

func (pool *Pool) BatchedQueryManyNotifyClosed(
	ctx context.Context,
	dfs []DirectedFilter,
	opts SubscriptionOptions,
) (chan RelayEvent, chan RelayClosed)

func (*Pool) BatchedSubscribeMany

func (pool *Pool) BatchedSubscribeMany(
	ctx context.Context,
	dfs []DirectedFilter,
	opts SubscriptionOptions,
) chan RelayEvent

BatchedSubscribeMany is like BatchedQueryMany but keeps the subscription open.

func (*Pool) BatchedSubscribeManyNotifyClosed

func (pool *Pool) BatchedSubscribeManyNotifyClosed(
	ctx context.Context,
	dfs []DirectedFilter,
	opts SubscriptionOptions,
) (chan RelayEvent, chan RelayClosed)

func (*Pool) Close

func (pool *Pool) Close(reason string)

Close closes the pool with the given reason.

func (*Pool) CountMany

func (pool *Pool) CountMany(
	ctx context.Context,
	urls []string,
	filter Filter,
	opts SubscriptionOptions,
) int

CountMany aggregates count results from multiple relays using NIP-45 HyperLogLog

func (*Pool) EnsureRelay

func (pool *Pool) EnsureRelay(url string) (*Relay, error)

EnsureRelay ensures that a relay connection exists and is active. If the relay is not connected, it attempts to connect.

func (*Pool) FetchMany

func (pool *Pool) FetchMany(
	ctx context.Context,
	urls []string,
	filter Filter,
	opts SubscriptionOptions,
) chan RelayEvent

FetchMany opens a subscription, much like SubscribeMany, but it ends as soon as all Relays return an EOSE message.

func (*Pool) FetchManyNotifyClosed

func (pool *Pool) FetchManyNotifyClosed(
	ctx context.Context,
	urls []string,
	filter Filter,
	opts SubscriptionOptions,
) (chan RelayEvent, chan RelayClosed)

func (*Pool) FetchManyReplaceable

func (pool *Pool) FetchManyReplaceable(
	ctx context.Context,
	urls []string,
	filter Filter,
	opts SubscriptionOptions,
) *xsync.MapOf[ReplaceableKey, Event]

FetchManyReplaceable is like FetchMany, but deduplicates replaceable and addressable events and returns only the latest for each "d" tag.

func (*Pool) PaginatorWithInterval

func (pool *Pool) PaginatorWithInterval(
	interval time.Duration,
) func(ctx context.Context, urls []string, filter Filter, opts SubscriptionOptions) chan RelayEvent

func (*Pool) PublishMany

func (pool *Pool) PublishMany(ctx context.Context, urls []string, evt Event) chan PublishResult

PublishMany publishes an event to multiple relays and returns a channel of results emitted as they're received.

func (*Pool) QuerySingle

func (pool *Pool) QuerySingle(
	ctx context.Context,
	urls []string,
	filter Filter,
	opts SubscriptionOptions,
) *RelayEvent

QuerySingle returns the first event returned by the first relay, cancels everything else.

func (*Pool) StartPenaltyBox

func (pool *Pool) StartPenaltyBox()

func (*Pool) StopPenaltyBox

func (pool *Pool) StopPenaltyBox()

func (*Pool) SubscribeMany

func (pool *Pool) SubscribeMany(
	ctx context.Context,
	urls []string,
	filter Filter,
	opts SubscriptionOptions,
) chan RelayEvent

SubscribeMany opens a subscription with the given filter to multiple relays the subscriptions ends when the context is canceled or when all relays return a CLOSED.

func (*Pool) SubscribeManyNotifyClosed

func (pool *Pool) SubscribeManyNotifyClosed(
	ctx context.Context,
	urls []string,
	filter Filter,
	opts SubscriptionOptions,
) (chan RelayEvent, chan RelayClosed)

SubscribeManyNotifyClosed is like SubscribeMany, but also returns a channel that emits every time a subscription receives a CLOSED message

func (*Pool) SubscribeManyNotifyEOSE

func (pool *Pool) SubscribeManyNotifyEOSE(
	ctx context.Context,
	urls []string,
	filter Filter,
	opts SubscriptionOptions,
) (chan RelayEvent, chan struct{})

SubscribeManyNotifyEOSE is like SubscribeMany, but also returns a channel that is closed when all subscriptions have received an EOSE

type ProfilePointer

type ProfilePointer struct {
	PublicKey PubKey
	Relays    []string
}

ProfilePointer represents a pointer to a Nostr profile.

func ProfilePointerFromTag

func ProfilePointerFromTag(refTag Tag) (ProfilePointer, error)

ProfilePointerFromTag creates a ProfilePointer from a "p" tag (but it doesn't have to be necessarily a "p" tag, could be something else).

func (ProfilePointer) AsFilter

func (ep ProfilePointer) AsFilter() Filter

func (ProfilePointer) AsTag

func (ep ProfilePointer) AsTag() Tag

func (ProfilePointer) AsTagReference

func (ep ProfilePointer) AsTagReference() string

func (ProfilePointer) MarshalEasyJSON

func (v ProfilePointer) MarshalEasyJSON(w *jwriter.Writer)

MarshalEasyJSON supports easyjson.Marshaler interface

func (ProfilePointer) MarshalJSON

func (v ProfilePointer) MarshalJSON() ([]byte, error)

MarshalJSON supports json.Marshaler interface

func (ProfilePointer) MatchesEvent

func (ep ProfilePointer) MatchesEvent(_ Event) bool

MatchesEvent checks if the pointer matches an event.

func (*ProfilePointer) UnmarshalEasyJSON

func (v *ProfilePointer) UnmarshalEasyJSON(l *jlexer.Lexer)

UnmarshalEasyJSON supports easyjson.Unmarshaler interface

func (*ProfilePointer) UnmarshalJSON

func (v *ProfilePointer) UnmarshalJSON(data []byte) error

UnmarshalJSON supports json.Unmarshaler interface

type PubKey

type PubKey [32]byte

func GetPublicKey

func GetPublicKey(sk [32]byte) PubKey

func MustPubKeyFromHex

func MustPubKeyFromHex(pkh string) PubKey

func PubKeyFromHex

func PubKeyFromHex(pkh string) (PubKey, error)

func PubKeyFromHexCheap

func PubKeyFromHexCheap(pkh string) (PubKey, error)

func (PubKey) Hex

func (pk PubKey) Hex() string

func (PubKey) MarshalJSON

func (pk PubKey) MarshalJSON() ([]byte, error)

func (PubKey) String

func (pk PubKey) String() string

func (*PubKey) UnmarshalJSON

func (pk *PubKey) UnmarshalJSON(buf []byte) error

type PublishResult

type PublishResult struct {
	Error    error
	RelayURL string
	Relay    *Relay
}

PublishResult represents the result of publishing an event to a relay.

type Publisher

type Publisher interface {
	Publish(context.Context, Event) error
}

type Querier

type Querier interface {
	QueryEvents(Filter) iter.Seq[Event]
}

type QuerierPublisher

type QuerierPublisher interface {
	Querier
	Publisher
}

type Relay

type Relay struct {
	URL string

	Subscriptions *xsync.MapOf[int64, *Subscription]

	ConnectionError error

	// custom things that aren't often used
	//
	AssumeValid bool // this will skip verifying signatures for events received from this relay
	// contains filtered or unexported fields
}

Relay represents a connection to a Nostr relay.

func NewRelay

func NewRelay(ctx context.Context, url string, opts RelayOptions) *Relay

NewRelay returns a new relay. It takes a context that, when canceled, will close the relay connection.

func RelayConnect

func RelayConnect(ctx context.Context, url string, opts RelayOptions) (*Relay, error)

RelayConnect returns a relay object connected to url.

The given subscription is only used during the connection phase. Once successfully connected, cancelling ctx has no effect.

The ongoing relay connection uses a background context. To close the connection, call r.Close(). If you need fine grained long-term connection contexts, use NewRelay() instead.

func (*Relay) Auth

func (r *Relay) Auth(ctx context.Context, sign func(context.Context, *Event) error) error

Auth sends an "AUTH" command client->relay as in NIP-42 and waits for an OK response.

You don't have to build the AUTH event yourself, this function takes a function to which the event that must be signed will be passed, so it's only necessary to sign that.

func (*Relay) Close

func (r *Relay) Close() error

Close closes the relay connection.

func (*Relay) Connect

func (r *Relay) Connect(ctx context.Context) error

Connect tries to establish a websocket connection to r.URL. If the context expires before the connection is complete, an error is returned. Once successfully connected, context expiration has no effect: call r.Close to close the connection.

The given context here is only used during the connection phase. The long-living relay connection will be based on the context given to NewRelay().

func (*Relay) ConnectWithClient

func (r *Relay) ConnectWithClient(ctx context.Context, client *http.Client) error

ConnectWithClient is like Connect(), but takes a special *http.Client if you need that.

func (*Relay) ConnectWithTLS

func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error

ConnectWithTLS is like Connect(), but takes a special tls.Config if you need that.

func (*Relay) Context

func (r *Relay) Context() context.Context

Context retrieves the context that is associated with this relay connection. It will be closed when the relay is disconnected.

func (*Relay) Count

func (r *Relay) Count(ctx context.Context, filter Filter, opts SubscriptionOptions) (uint32, []byte, error)

Count sends a "COUNT" command to the relay and returns the count of events matching the filters. If opts.AutoAuth is set, it will handle "auth-required:" CLOSEs using RelayOptions.AuthHandler.

func (*Relay) IsConnected

func (r *Relay) IsConnected() bool

IsConnected returns true if the connection to this relay seems to be active.

func (*Relay) PrepareSubscription

func (r *Relay) PrepareSubscription(ctx context.Context, filter Filter, opts SubscriptionOptions) *Subscription

PrepareSubscription creates a subscription, but doesn't fire it.

Remember to cancel subscriptions, either by calling `.Unsub()` on them or ensuring their `context.Context` will be canceled at some point. Failure to do that will result in a huge number of halted goroutines being created.

func (*Relay) Publish

func (r *Relay) Publish(ctx context.Context, event Event) error

Publish sends an "EVENT" command to the relay r as in NIP-01 and waits for an OK response.

func (*Relay) QueryEvents

func (r *Relay) QueryEvents(filter Filter) iter.Seq[Event]

implement Querier interface

func (*Relay) String

func (r *Relay) String() string

String just returns the relay URL.

func (*Relay) Subscribe

func (r *Relay) Subscribe(ctx context.Context, filter Filter, opts SubscriptionOptions) (*Subscription, error)

Subscribe sends a "REQ" command to the relay r as in NIP-01. Events are returned through the channel sub.Events. The subscription is closed when context ctx is cancelled ("CLOSE" in NIP-01).

Remember to cancel subscriptions, either by calling `.Unsub()` on them or ensuring their `context.Context` will be canceled at some point. Failure to do that will result in a huge number of halted goroutines being created.

func (*Relay) Write

func (r *Relay) Write(msg []byte)

Write queues an arbitrary message to be sent to the relay.

func (*Relay) WriteWithError

func (r *Relay) WriteWithError(msg []byte) error

WriteWithError is like Write, but returns an error if the write fails (and the connection gets closed).

type RelayClosed

type RelayClosed struct {
	Reason string
	Relay  *Relay

	// this is true when the close reason was "auth-required" and already handled internally
	HandledAuth bool
}

type RelayEvent

type RelayEvent struct {
	Event
	Relay *Relay
}

RelayEvent represents an event received from a specific relay.

func (RelayEvent) String

func (ie RelayEvent) String() string

type RelayOptions

type RelayOptions struct {
	// AuthHandler is fired when an AUTH message is received. It is given the AUTH event, unsigned, and expects you to sign it.
	AuthHandler func(context.Context, *Relay, *Event) error

	// NoticeHandler just takes notices and is expected to do something with them.
	// When not given defaults to logging the notices.
	NoticeHandler func(relay *Relay, notice string)

	// CustomHandler, if given, must be a function that handles any relay message
	// that couldn't be parsed as a standard envelope.
	CustomHandler func(data string)

	// RequestHeader sets the HTTP request header of the websocket preflight request
	RequestHeader http.Header

	// AssumeValid disables signature verification for events received from this relay
	AssumeValid bool
}

type ReplaceableKey

type ReplaceableKey struct {
	PubKey PubKey
	D      string
}

type ReqEnvelope

type ReqEnvelope struct {
	SubscriptionID string
	Filters        []Filter
}

ReqEnvelope represents a REQ message.

func (*ReqEnvelope) FromJSON

func (v *ReqEnvelope) FromJSON(data string) error

func (ReqEnvelope) Label

func (_ ReqEnvelope) Label() string

func (ReqEnvelope) MarshalJSON

func (v ReqEnvelope) MarshalJSON() ([]byte, error)

func (ReqEnvelope) String

func (c ReqEnvelope) String() string

type SecretKey

type SecretKey [32]byte

func Generate

func Generate() SecretKey

func MustSecretKeyFromHex

func MustSecretKeyFromHex(idh string) SecretKey

func SecretKeyFromHex

func SecretKeyFromHex(skh string) (SecretKey, error)

func (SecretKey) Hex

func (sk SecretKey) Hex() string

func (SecretKey) MarshalJSON

func (pk SecretKey) MarshalJSON() ([]byte, error)

func (SecretKey) Public

func (sk SecretKey) Public() PubKey

func (SecretKey) String

func (sk SecretKey) String() string

func (*SecretKey) UnmarshalJSON

func (pk *SecretKey) UnmarshalJSON(buf []byte) error

type Signer

type Signer interface {
	User

	// SignEvent signs the provided event, setting its ID, PubKey, and Sig fields.
	// The context can be used for operations that may require user interaction or
	// network access, such as with remote signers.
	SignEvent(ctx context.Context, evt *Event) error
}

Signer is a User that can also sign events.

type Subscription

type Subscription struct {
	Relay  *Relay
	Filter Filter

	// the Events channel emits all EVENTs that come in a Subscription
	// will be closed when the subscription ends
	Events chan Event

	// the EndOfStoredEvents channel gets closed when an EOSE comes for that subscription
	EndOfStoredEvents chan struct{}

	// the ClosedReason channel emits the reason when a CLOSED message is received
	ClosedReason chan string

	// Context will be .Done() when the subscription ends
	Context context.Context
	// contains filtered or unexported fields
}

Subscription represents a subscription to a relay.

func (*Subscription) Fire

func (sub *Subscription) Fire() error

Fire sends the "REQ" command to the relay.

func (*Subscription) GetID

func (sub *Subscription) GetID() string

GetID returns the subscription ID.

func (*Subscription) Sub

func (sub *Subscription) Sub(_ context.Context, filter Filter)

Sub sets sub.Filters and then calls sub.Fire(ctx). The subscription will be closed if the context expires.

func (*Subscription) Unsub

func (sub *Subscription) Unsub()

Unsub closes the subscription, sending "CLOSE" to relay as in NIP-01. Unsub() also closes the channel sub.Events and makes a new one.

type SubscriptionOptions

type SubscriptionOptions struct {
	// Label puts a label on the subscription (it is prepended to the automatic id) that is sent to relays.
	Label string

	// CheckDuplicate is a function that, when present, is ran on events before they're parsed.
	// if it returns true the event will be discarded and not processed further.
	CheckDuplicate func(id ID, relay string) bool

	// CheckDuplicateReplaceable is like CheckDuplicate, but runs on replaceable/addressable events
	CheckDuplicateReplaceable func(rk ReplaceableKey, ts Timestamp) bool

	// a fake EndOfStoredEvents will be dispatched at this time if nothing is received before.
	// defaults to 7s (in order to disable, set it to time.Duration(math.MaxInt64))
	MaxWaitForEOSE time.Duration
}

All SubscriptionOptions fields are optional

type Tag

type Tag []string

func (Tag) Clone

func (tag Tag) Clone() Tag

Clone creates a new array with these tag items inside.

type TagMap

type TagMap map[string][]string

type Tags

type Tags []Tag

func (Tags) Clone

func (tags Tags) Clone() Tags

Clone creates a new array with these tags inside.

func (Tags) CloneDeep

func (tags Tags) CloneDeep() Tags

CloneDeep creates a new array with clones of these tags inside.

func (Tags) ContainsAny

func (tags Tags) ContainsAny(tagName string, values []string) bool

func (Tags) Eq

func (tags Tags) Eq(other Tags) bool

func (Tags) Find

func (tags Tags) Find(key string) Tag

Find returns the first tag with the given key/tagName that also has one value (i.e. at least 2 items)

func (Tags) FindAll

func (tags Tags) FindAll(key string) iter.Seq[Tag]

FindAll yields all the tags the given key/tagName that also have one value (i.e. at least 2 items)

func (Tags) FindLast

func (tags Tags) FindLast(key string) Tag

FindLast is like Find, but starts at the end

func (Tags) FindLastWithValue

func (tags Tags) FindLastWithValue(key, value string) Tag

FindLastWithValue is like FindLast, but starts at the end

func (Tags) FindWithValue

func (tags Tags) FindWithValue(key, value string) Tag

FindWithValue is like Find, but also checks if the value (the second item) matches

func (Tags) GetD

func (tags Tags) GetD() string

GetD gets the first "d" tag (for parameterized replaceable events) value or ""

func (Tags) Has

func (tags Tags) Has(key string) bool

Has returns true if a tag exists with the given key (whether or not it has a value)

type Timestamp

type Timestamp int64

func Now

func Now() Timestamp

func (Timestamp) Time

func (t Timestamp) Time() time.Time

type User

type User interface {
	// GetPublicKey returns the public key associated with this user.
	GetPublicKey(ctx context.Context) (PubKey, error)
}

User is an entity that has a public key (although they can't sign anything).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL