database

package
v0.36.19 Latest Latest
Warning

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

Go to latest
Published: Dec 25, 2025 License: Unlicense Imports: 50 Imported by: 0

Documentation

Overview

Package database provides filter utilities for normalizing tag values.

The nostr library optimizes e/p tag values by storing them in binary format (32 bytes + null terminator) rather than hex strings (64 chars). However, filter tags from client queries come as hex strings and don't go through the same binary encoding during unmarshalling.

This file provides utilities to normalize filter tags to match the binary encoding used in stored events, ensuring consistent index lookups and tag comparisons.

Package database provides shared import utilities for events

Index

Constants

View Source
const (
	CompactFormatVersion = 1

	// Tag element type flags
	TagElementRaw          = 0x00 // Raw bytes (varint length + data)
	TagElementPubkeySerial = 0x01 // Pubkey serial reference (5 bytes)
	TagElementEventSerial  = 0x02 // Event ID serial reference (5 bytes)
	TagElementEventIdFull  = 0x03 // Full event ID (32 bytes) - for unknown refs
)
View Source
const (
	// BinaryEncodedLen is the length of a binary-encoded 32-byte hash with null terminator
	BinaryEncodedLen = 33
	// HexEncodedLen is the length of a hex-encoded 32-byte hash
	HexEncodedLen = 64
	// HashLen is the raw length of a hash (pubkey/event ID)
	HashLen = 32
)

Tag binary encoding constants (matching the nostr library)

View Source
const WriteOpType = 1

WriteOpType is the operation type constant for write operations

Variables

View Source
var (
	ErrPubkeyNotFound = errors.New("pubkey not found in database")
	ErrEventNotFound  = errors.New("event not found in database")
)

Graph traversal errors

View Source
var (
	// ErrOlderThanExisting is returned when a candidate event is older than an existing replaceable/addressable event.
	ErrOlderThanExisting = errors.New("older than existing event")
	// ErrMissingDTag is returned when a parameterized replaceable event lacks the required 'd' tag.
	ErrMissingDTag = errors.New("event is missing a d tag identifier")
)

Functions

func BinaryToHex added in v0.30.3

func BinaryToHex(binVal []byte) []byte

BinaryToHex converts a 33-byte binary value to 64-character hex string Returns nil if the input is not in binary format

func CanUsePTagGraph added in v0.29.11

func CanUsePTagGraph(f *filter.F) bool

CanUsePTagGraph determines if a filter can benefit from p-tag graph optimization.

Requirements: - Filter must have #p tags - Filter should NOT have authors (different index is better for that case) - Optimization works best with kinds filter but is optional

func CheckExpiration

func CheckExpiration(ev *event.E) (expired bool)

func CreateIdHashFromData

func CreateIdHashFromData(data []byte) (i *types2.IdHash, err error)

CreateIdHashFromData creates an IdHash from data that could be hex or binary

func CreatePubHashFromData

func CreatePubHashFromData(data []byte) (p *types2.PubHash, err error)

CreatePubHashFromData creates a PubHash from data that could be hex or binary

func GetCumulativeCompactSavings added in v0.33.0

func GetCumulativeCompactSavings() int64

GetCumulativeCompactSavings returns total bytes saved across all compact saves.

func GetIndexesForEvent

func GetIndexesForEvent(ev *event.E, serial uint64) (
	idxs [][]byte, err error,
)

GetIndexesForEvent creates all the indexes for an event.E instance as defined in keys.go. It returns a slice of byte slices that can be used to store the event in the database.

func HexToBinary added in v0.30.3

func HexToBinary(hexVal []byte) []byte

HexToBinary converts a 64-character hex string to 33-byte binary format Returns nil if the input is not a valid hex string

func IsBinaryEncoded added in v0.30.3

func IsBinaryEncoded(val []byte) bool

IsBinaryEncoded checks if a value field is stored in optimized binary format

func IsBinaryOptimizedTag added in v0.30.3

func IsBinaryOptimizedTag(key byte) bool

IsBinaryOptimizedTag returns true if the given tag key uses binary encoding

func IsHexString

func IsHexString(data []byte) (isHex bool)

IsHexString checks if the byte slice contains only hex characters

func IsValidHexValue added in v0.30.3

func IsValidHexValue(b []byte) bool

IsValidHexValue checks if a byte slice is a valid 64-character hex string

func MarshalCompactEvent added in v0.33.0

func MarshalCompactEvent(ev *event.E, resolver SerialResolver) (data []byte, err error)

MarshalCompactEvent encodes an event using compact serial references. The resolver is used to look up/create serial mappings for pubkeys and event IDs.

func NewLogger

func NewLogger(logLevel int, label string) (l *logger)

NewLogger creates a new badger logger.

func NormalizeFilter added in v0.30.3

func NormalizeFilter(f *filter.F) *filter.F

NormalizeFilter normalizes a filter's tags for consistent database queries. This should be called before using a filter for database lookups. The original filter is not modified; a copy with normalized tags is returned.

func NormalizeFilterTag added in v0.30.3

func NormalizeFilterTag(t *tag.T) *tag.T

NormalizeFilterTag creates a new tag with binary-encoded values for e/p tags. The original tag is not modified.

func NormalizeFilterTags added in v0.30.3

func NormalizeFilterTags(tags *tag.S) *tag.S

NormalizeFilterTags normalizes all tags in a tag.S, converting e/p hex values to binary. Returns a new tag.S with normalized tags.

func NormalizeTagToHex added in v0.30.3

func NormalizeTagToHex(val []byte) []byte

NormalizeTagToHex returns the hex representation of a tag value. For binary-encoded values, converts to hex. For hex values, returns as-is.

func NormalizeTagValue added in v0.30.3

func NormalizeTagValue(key byte, val []byte) []byte

NormalizeTagValue normalizes a tag value for the given key. For e/p tags, hex values are converted to binary format. Other tags are returned unchanged.

func NormalizeTagValueForHash added in v0.30.3

func NormalizeTagValueForHash(key byte, valueBytes []byte) []byte

NormalizeTagValueForHash normalizes a tag value for consistent hashing. For 'e' and 'p' tags, the nostr library stores values in binary format (32 bytes), but filters from clients come with hex strings (64 chars). This function ensures that filter values are converted to binary to match the stored index format.

This function delegates to NormalizeTagValue from filter_utils.go for consistency.

func RegisterNeo4jFactory added in v0.29.3

func RegisterNeo4jFactory(factory func(context.Context, context.CancelFunc, *DatabaseConfig) (Database, error))

RegisterNeo4jFactory registers the neo4j database factory This is called from the neo4j package's init() function

func RegisterWasmDBFactory added in v0.32.0

func RegisterWasmDBFactory(factory func(context.Context, context.CancelFunc, *DatabaseConfig) (Database, error))

RegisterWasmDBFactory registers the wasmdb database factory This is called from the wasmdb package's init() function

func ResetCompactSavingsCounter added in v0.33.0

func ResetCompactSavingsCounter()

ResetCompactSavingsCounter resets the cumulative savings counter.

func TagValuesMatch added in v0.30.3

func TagValuesMatch(key byte, eventVal, filterVal []byte) bool

TagValuesMatch compares two tag values, handling both binary and hex encodings. This is useful for post-query tag matching where event values may be binary and filter values may be hex (or vice versa).

func TagValuesMatchUsingTagMethods added in v0.30.3

func TagValuesMatchUsingTagMethods(eventTag *tag.T, filterVal []byte) bool

TagValuesMatchUsingTagMethods compares an event tag's value with a filter value using the tag.T methods. This leverages the nostr library's ValueHex() method for proper binary/hex conversion.

func TokenHashes added in v0.9.0

func TokenHashes(content []byte) [][]byte

TokenHashes extracts unique word hashes (8-byte truncated sha256) from content. Rules: - Unicode-aware: words are sequences of letters or numbers. - Lowercased using unicode case mapping. - Ignore URLs (starting with http://, https://, www., or containing "://"). - Ignore nostr: URIs and #[n] mentions. - Ignore words shorter than 2 runes. - Exclude 64-character hexadecimal strings (likely IDs/pubkeys).

func TrackCompactSaving added in v0.33.0

func TrackCompactSaving(legacySize, compactSize int)

TrackCompactSaving records bytes saved for a single event. Call this during event save to track cumulative savings.

func UnmarshalCompactEvent added in v0.33.0

func UnmarshalCompactEvent(data []byte, eventId []byte, resolver SerialResolver) (ev *event.E, err error)

UnmarshalCompactEvent decodes a compact event back to a full event.E. The resolver is used to look up pubkeys and event IDs from serials. The eventId parameter is the full 32-byte event ID (from SerialEventId table).

Types

type AllowedEvent added in v0.17.0

type AllowedEvent struct {
	ID     string    `json:"id"`
	Reason string    `json:"reason,omitempty"`
	Added  time.Time `json:"added"`
}

AllowedEvent represents an allowed event entry

type AllowedKind added in v0.17.0

type AllowedKind struct {
	Kind  int       `json:"kind"`
	Added time.Time `json:"added"`
}

AllowedKind represents an allowed event kind

type AllowedPubkey added in v0.17.0

type AllowedPubkey struct {
	Pubkey string    `json:"pubkey"`
	Reason string    `json:"reason,omitempty"`
	Added  time.Time `json:"added"`
}

AllowedPubkey represents an allowed public key entry

type BannedEvent added in v0.17.0

type BannedEvent struct {
	ID     string    `json:"id"`
	Reason string    `json:"reason,omitempty"`
	Added  time.Time `json:"added"`
}

BannedEvent represents a banned event entry

type BannedPubkey added in v0.17.0

type BannedPubkey struct {
	Pubkey string    `json:"pubkey"`
	Reason string    `json:"reason,omitempty"`
	Added  time.Time `json:"added"`
}

BannedPubkey represents a banned public key entry

type BlockedIP added in v0.17.0

type BlockedIP struct {
	IP     string    `json:"ip"`
	Reason string    `json:"reason,omitempty"`
	Added  time.Time `json:"added"`
}

BlockedIP represents a blocked IP address entry

type CompactStorageStats added in v0.33.0

type CompactStorageStats struct {
	// Event counts
	CompactEvents int64 // Number of events in compact format (cmp prefix)
	LegacyEvents  int64 // Number of events in legacy format (evt/sev prefixes)
	TotalEvents   int64 // Total events

	// Storage sizes
	CompactBytes int64 // Total bytes used by compact format
	LegacyBytes  int64 // Total bytes used by legacy format (would be used without compact)

	// Savings
	BytesSaved     int64   // Bytes saved by using compact format
	PercentSaved   float64 // Percentage of space saved
	AverageCompact float64 // Average compact event size
	AverageLegacy  float64 // Average legacy event size (estimated)

	// Serial mappings
	SerialEventIdEntries int64 // Number of sei (serial -> event ID) mappings
	SerialEventIdBytes   int64 // Bytes used by sei mappings
}

CompactStorageStats holds statistics about compact vs legacy storage.

type D

type D struct {
	Logger *logger
	*badger.DB
	// contains filtered or unexported fields
}

D implements the Database interface using Badger as the storage backend

func New

func New(
	ctx context.Context, cancel context.CancelFunc, dataDir, logLevel string,
) (
	d *D, err error,
)

New creates a new Badger database instance with default configuration. This is provided for backward compatibility with existing callers. For full configuration control, use NewWithConfig instead.

func NewWithConfig added in v0.31.8

func NewWithConfig(
	ctx context.Context, cancel context.CancelFunc, cfg *DatabaseConfig,
) (
	d *D, err error,
)

NewWithConfig creates a new Badger database instance with full configuration. This is the preferred method when you have access to DatabaseConfig.

func (*D) AddInboundRefsToResult added in v0.34.0

func (d *D) AddInboundRefsToResult(result *GraphResult, depth int, kinds []uint16) error

AddInboundRefsToResult collects inbound references (events that reference discovered items) for events at a specific depth in the result.

For example, if you have a follows graph result and want to find all kind-7 reactions to posts by users at depth 1, this collects those reactions and adds them to result.InboundRefs.

Parameters: - result: The graph result to augment with ref data - depth: The depth at which to collect refs (0 = all depths) - kinds: Event kinds to collect (e.g., [7] for reactions, [6] for reposts)

func (*D) AddNIP43Member added in v0.27.0

func (d *D) AddNIP43Member(pubkey []byte, inviteCode string) error

AddNIP43Member adds a member to the NIP-43 membership list

func (*D) AddOutboundRefsToResult added in v0.34.0

func (d *D) AddOutboundRefsToResult(result *GraphResult, depth int, kinds []uint16) error

AddOutboundRefsToResult collects outbound references (events referenced by discovered items).

For example, find all events that posts by users at depth 1 reference (quoted posts, replied-to posts).

func (*D) CacheEvents added in v0.29.11

func (d *D) CacheEvents(f *filter.F, events event.S)

CacheEvents stores events for a filter (without subscription ID)

func (*D) CacheMarshaledJSON added in v0.29.1

func (d *D) CacheMarshaledJSON(f *filter.F, marshaledJSON [][]byte)

CacheMarshaledJSON stores marshaled JSON event envelopes for a filter

func (*D) CheckForDeleted

func (d *D) CheckForDeleted(ev *event.E, admins [][]byte) (err error)

CheckForDeleted checks if the event is deleted, and returns an error with prefix "blocked:" if it is. This function also allows designating admin pubkeys that also may delete the event, normally only the author is allowed to delete an event.

func (*D) CleanupEphemeralEvents added in v0.25.3

func (d *D) CleanupEphemeralEvents()

func (*D) CleanupKind3WithoutPTags added in v0.31.1

func (d *D) CleanupKind3WithoutPTags(ctx context.Context) error

CleanupKind3WithoutPTags scans for kind 3 follow list events that have no p tags and deletes them. This cleanup is needed because the directory spider may have saved malformed events that lost their tags during serialization.

func (*D) CleanupLegacyEventStorage added in v0.33.0

func (d *D) CleanupLegacyEventStorage()

CleanupLegacyEventStorage removes legacy evt and sev storage entries after compact format migration. This reclaims disk space by removing the old storage format entries once all events have been successfully migrated to cmp format.

The cleanup: 1. Iterates through all cmp entries (compact format) 2. For each serial found in cmp, deletes corresponding evt and sev entries 3. Reports total bytes reclaimed

func (*D) Close

func (d *D) Close() (err error)

Close releases resources and closes the database.

func (*D) CollectRefsForPubkeys added in v0.34.0

func (d *D) CollectRefsForPubkeys(
	pubkeySerials []*types.Uint40,
	refKinds []uint16,
	eventKinds []uint16,
) (*GraphResult, error)

CollectRefsForPubkeys collects inbound references to events by specific pubkeys. This is useful for "find all reactions to posts by these users" queries.

Parameters: - pubkeySerials: The pubkeys whose events should be checked for refs - refKinds: Event kinds to collect (e.g., [7] for reactions) - eventKinds: Event kinds to check for refs (e.g., [1] for notes)

func (*D) CompactStorageStats added in v0.33.0

func (d *D) CompactStorageStats() (stats CompactStorageStats, err error)

CompactStorageStats calculates storage statistics for compact event storage. This scans the database to provide accurate metrics on space savings.

func (*D) ConvertSmallEventsToInline added in v0.28.0

func (d *D) ConvertSmallEventsToInline()

ConvertSmallEventsToInline migrates small events (<=384 bytes) to inline storage. This is a Reiser4-inspired optimization that stores small event data in the key itself, avoiding a second database lookup and improving query performance. Also handles replaceable and addressable events with specialized storage.

func (*D) ConvertToCompactEventFormat added in v0.33.0

func (d *D) ConvertToCompactEventFormat()

ConvertToCompactEventFormat migrates all existing events to the new compact format. This format uses 5-byte serial references instead of 32-byte IDs/pubkeys, dramatically reducing storage requirements (up to 80% savings on ID/pubkey data).

The migration: 1. Reads each event from legacy storage (evt/sev prefixes) 2. Creates SerialEventId mapping (sei prefix) for event ID lookup 3. Re-encodes the event in compact format 4. Stores in cmp prefix 5. Optionally removes legacy storage after successful migration

func (*D) CountEvents added in v0.10.0

func (d *D) CountEvents(c context.Context, f *filter.F) (
	count int, approx bool, err error,
)

CountEvents mirrors the initial selection logic of QueryEvents but stops once we have identified candidate event serials (id/pk/ts). It returns the count of those serials. The `approx` flag is always false as requested.

func (*D) DeleteEvent

func (d *D) DeleteEvent(c context.Context, eid []byte) (err error)

DeleteEvent removes an event from the database identified by `eid`. If noTombstone is false or not provided, a tombstone is created for the event.

func (*D) DeleteEventBySerial

func (d *D) DeleteEventBySerial(
	c context.Context, ser *types.Uint40, ev *event.E,
) (err error)

func (*D) DeleteExpired

func (d *D) DeleteExpired()

func (*D) DeleteInviteCode added in v0.27.0

func (d *D) DeleteInviteCode(code string) error

DeleteInviteCode removes an invite code (after use)

func (*D) DeleteMarker added in v0.6.0

func (d *D) DeleteMarker(key string) (err error)

DeleteMarker removes a marker from the database

func (*D) EventIDHexToSerial added in v0.34.0

func (d *D) EventIDHexToSerial(eventIDHex string) (*types.Uint40, error)

EventIDHexToSerial converts an event ID hex string to its serial, if it exists. Returns an error if the event is not in the database.

func (*D) EventIdsBySerial

func (d *D) EventIdsBySerial(start uint64, count int) (
	evs []uint64, err error,
)

func (*D) Export

func (d *D) Export(c context.Context, w io.Writer, pubkeys ...[]byte)

Export the complete database of stored events to an io.Writer in line structured minified JSON. Supports both legacy and compact event formats.

func (*D) ExtendBlossomSubscription added in v0.23.3

func (d *D) ExtendBlossomSubscription(
	pubkey []byte, level string, storageMB int64, days int,
) error

ExtendBlossomSubscription extends or creates a blossom subscription with service level

func (*D) ExtendSubscription

func (d *D) ExtendSubscription(pubkey []byte, days int) error

func (*D) FetchEventBySerial

func (d *D) FetchEventBySerial(ser *types.Uint40) (ev *event.E, err error)

FetchEventBySerial fetches a single event by its serial. This function tries multiple storage formats in order: 1. cmp (compact format with serial references) - newest, most space-efficient 2. sev (small event inline) - legacy Reiser4 optimization 3. evt (traditional separate storage) - legacy fallback

func (*D) FetchEventsBySerials added in v0.4.9

func (d *D) FetchEventsBySerials(serials []*types.Uint40) (events map[uint64]*event.E, err error)

FetchEventsBySerials fetches multiple events by their serials in a single database transaction. Returns a map of serial uint64 value to event, only including successfully fetched events.

This function tries multiple storage formats in order: 1. cmp (compact format with serial references) - newest, most space-efficient 2. sev (small event inline) - legacy Reiser4 optimization 3. evt (traditional separate storage) - legacy fallback

func (*D) FindEventByAuthorAndKind added in v0.34.0

func (d *D) FindEventByAuthorAndKind(authorSerial *types.Uint40, kind uint16) (*types.Uint40, error)

FindEventByAuthorAndKind finds the most recent event of a specific kind by an author. This is used to find kind-3 contact lists for follow graph traversal. Returns nil, nil if no matching event is found.

func (*D) FindMentions added in v0.34.0

func (d *D) FindMentions(pubkey []byte, kinds []uint16) (*GraphResult, error)

FindMentions finds events that mention a pubkey via p-tags. This returns events grouped by depth, where depth represents how the events relate: - Depth 1: Events that directly mention the seed pubkey - Depth 2+: Not typically used for mentions (reserved for future expansion)

The kinds parameter filters which event kinds to include (e.g., [1] for notes only, [1,7] for notes and reactions, etc.)

func (*D) FindMentionsByPubkeys added in v0.34.0

func (d *D) FindMentionsByPubkeys(pubkeySerials []*types.Uint40, kinds []uint16) (*GraphResult, error)

FindMentionsByPubkeys returns events that mention any of the given pubkeys. Useful for finding mentions across a set of followed accounts.

func (*D) FindMentionsFromHex added in v0.34.0

func (d *D) FindMentionsFromHex(pubkeyHex string, kinds []uint16) (*GraphResult, error)

FindMentionsFromHex is a convenience wrapper that accepts hex-encoded pubkey.

func (*D) GetAllNIP43Members added in v0.27.0

func (d *D) GetAllNIP43Members() ([][]byte, error)

GetAllNIP43Members returns all NIP-43 members

func (*D) GetBlossomStorageQuota added in v0.23.3

func (d *D) GetBlossomStorageQuota(pubkey []byte) (quotaMB int64, err error)

GetBlossomStorageQuota returns the current blossom storage quota in MB for a pubkey

func (*D) GetCachedEvents added in v0.29.11

func (d *D) GetCachedEvents(f *filter.F) (event.S, bool)

GetCachedEvents retrieves cached events for a filter (without subscription ID) Returns nil, false if not found

func (*D) GetCachedJSON added in v0.29.1

func (d *D) GetCachedJSON(f *filter.F) ([][]byte, bool)

GetCachedJSON retrieves cached marshaled JSON for a filter Returns nil, false if not found

func (*D) GetETagsFromEventSerial added in v0.34.0

func (d *D) GetETagsFromEventSerial(eventSerial *types.Uint40) ([]*types.Uint40, error)

GetETagsFromEventSerial extracts e-tag event serials from an event by its serial. This is a pure index-based operation - no event decoding required. It scans the eeg (event-event-graph) index for outbound e-tag edges.

func (*D) GetEventAuthorSerial added in v0.34.0

func (d *D) GetEventAuthorSerial(eventSerial *types.Uint40) (*types.Uint40, error)

GetEventAuthorSerial finds the author pubkey serial for an event. Uses the epg (event-pubkey-graph) index with author direction.

func (*D) GetEventIDFromSerial added in v0.34.0

func (d *D) GetEventIDFromSerial(serial *types.Uint40) (string, error)

GetEventIDFromSerial converts an event serial to its hex ID string.

func (*D) GetEventIdBySerial added in v0.33.0

func (d *D) GetEventIdBySerial(ser *types.Uint40) (eventId []byte, err error)

GetEventIdBySerial looks up an event ID by its serial number. Uses the SerialEventId index (sei prefix).

func (*D) GetEventsByAuthor added in v0.34.0

func (d *D) GetEventsByAuthor(authorSerial *types.Uint40, kinds []uint16) ([]*types.Uint40, error)

GetEventsByAuthor finds all events authored by a pubkey. Uses the peg (pubkey-event-graph) index with direction filter for author edges. Optionally filters by event kinds.

func (*D) GetEventsReferencingPubkey added in v0.34.0

func (d *D) GetEventsReferencingPubkey(pubkeySerial *types.Uint40, kinds []uint16) ([]*types.Uint40, error)

GetEventsReferencingPubkey finds all events that reference a pubkey via p-tags. Uses the peg (pubkey-event-graph) index with direction filter for inbound p-tags. Optionally filters by event kinds.

func (*D) GetFollowersOfPubkeySerial added in v0.34.0

func (d *D) GetFollowersOfPubkeySerial(targetSerial *types.Uint40) ([]*types.Uint40, error)

GetFollowersOfPubkeySerial returns the pubkey serials of users who follow a given pubkey. This finds all kind-3 events that have a p-tag referencing the target pubkey.

func (*D) GetFollowsFromPubkeySerial added in v0.34.0

func (d *D) GetFollowsFromPubkeySerial(pubkeySerial *types.Uint40) ([]*types.Uint40, error)

GetFollowsFromPubkeySerial returns the pubkey serials that a user follows. This extracts p-tags from the user's kind-3 contact list event. Returns an empty slice if no kind-3 event is found.

func (*D) GetFullIdPubkeyBySerial

func (d *D) GetFullIdPubkeyBySerial(ser *types.Uint40) (
	fidpk *store.IdPkTs, err error,
)

func (*D) GetFullIdPubkeyBySerials

func (d *D) GetFullIdPubkeyBySerials(sers []*types.Uint40) (
	fidpks []*store.IdPkTs, err error,
)

GetFullIdPubkeyBySerials seeks directly to each serial's prefix in the FullIdPubkey index. The input sers slice is expected to be sorted in ascending order, allowing efficient forward-only iteration via a single Badger iterator.

func (*D) GetMarker added in v0.6.0

func (d *D) GetMarker(key string) (value []byte, err error)

GetMarker retrieves an arbitrary marker from the database

func (*D) GetNIP43Membership added in v0.27.0

func (d *D) GetNIP43Membership(pubkey []byte) (*NIP43Membership, error)

GetNIP43Membership retrieves membership details for a pubkey

func (*D) GetOrCreatePubkeySerial added in v0.29.11

func (d *D) GetOrCreatePubkeySerial(pubkey []byte) (ser *types.Uint40, err error)

GetOrCreatePubkeySerial returns the serial for a pubkey, creating one if it doesn't exist. The pubkey parameter should be 32 bytes (schnorr public key). This function is thread-safe and uses transactions to ensure atomicity.

func (*D) GetOrCreateRelayIdentitySecret added in v0.8.0

func (d *D) GetOrCreateRelayIdentitySecret() (skb []byte, err error)

GetOrCreateRelayIdentitySecret retrieves the existing relay identity secret key or creates and stores a new one if none exists.

func (*D) GetPTagsFromEventSerial added in v0.34.0

func (d *D) GetPTagsFromEventSerial(eventSerial *types.Uint40) ([]*types.Uint40, error)

GetPTagsFromEventSerial extracts p-tag pubkey serials from an event by its serial. This is a pure index-based operation - no event decoding required. It scans the epg (event-pubkey-graph) index for p-tag edges.

func (*D) GetPaymentHistory

func (d *D) GetPaymentHistory(pubkey []byte) ([]Payment, error)

func (*D) GetPubkeyBySerial added in v0.29.11

func (d *D) GetPubkeyBySerial(ser *types.Uint40) (pubkey []byte, err error)

GetPubkeyBySerial returns the full 32-byte pubkey for a given serial.

func (*D) GetPubkeyHexFromSerial added in v0.34.0

func (d *D) GetPubkeyHexFromSerial(serial *types.Uint40) (string, error)

GetPubkeyHexFromSerial converts a pubkey serial to its hex string representation.

func (*D) GetPubkeySerial added in v0.29.11

func (d *D) GetPubkeySerial(pubkey []byte) (ser *types.Uint40, err error)

GetPubkeySerial returns the serial for a pubkey if it exists. Returns an error if the pubkey doesn't have a serial yet.

func (*D) GetReferencingEvents added in v0.34.0

func (d *D) GetReferencingEvents(targetSerial *types.Uint40, kinds []uint16) ([]*types.Uint40, error)

GetReferencingEvents finds all events that reference a target event via e-tags. Optionally filters by event kinds. Uses the gee (reverse e-tag graph) index.

func (*D) GetRelayIdentitySecret added in v0.8.0

func (d *D) GetRelayIdentitySecret() (skb []byte, err error)

GetRelayIdentitySecret returns the relay identity secret key bytes if present. If the key is not found, returns (nil, badger.ErrKeyNotFound).

func (*D) GetSerialById

func (d *D) GetSerialById(id []byte) (ser *types.Uint40, err error)

func (*D) GetSerialsByIds added in v0.4.9

func (d *D) GetSerialsByIds(ids *tag.T) (
	serials map[string]*types.Uint40, err error,
)

GetSerialsByIds takes a tag.T containing multiple IDs and returns a map of IDs to their corresponding serial numbers. It directly queries the IdPrefix index for matching IDs, which is more efficient than using GetIndexesFromFilter.

func (*D) GetSerialsByIdsWithFilter added in v0.4.9

func (d *D) GetSerialsByIdsWithFilter(
	ids *tag.T, fn func(ev *event.E, ser *types.Uint40) bool,
) (serials map[string]*types.Uint40, err error)

GetSerialsByIdsWithFilter takes a tag.T containing multiple IDs and returns a map of IDs to their corresponding serial numbers, applying a filter function to each event. The function directly creates ID index prefixes for efficient querying.

func (*D) GetSerialsByRange

func (d *D) GetSerialsByRange(idx Range) (
	sers types.Uint40s, err error,
)

func (*D) GetSerialsFromFilter

func (d *D) GetSerialsFromFilter(f *filter.F) (
	sers types.Uint40s, err error,
)

func (*D) GetSubscription

func (d *D) GetSubscription(pubkey []byte) (*Subscription, error)

func (*D) GetThreadParents added in v0.34.0

func (d *D) GetThreadParents(eventID []byte) (*GraphResult, error)

GetThreadParents finds events that a given event references (its parents/quotes).

func (*D) GetThreadReplies added in v0.34.0

func (d *D) GetThreadReplies(eventID []byte, kinds []uint16) (*GraphResult, error)

GetThreadReplies finds all direct replies to an event. This is a convenience method that returns events at depth 1 with inbound direction.

func (*D) HasMarker added in v0.6.0

func (d *D) HasMarker(key string) (exists bool)

HasMarker checks if a marker exists in the database

func (*D) Import

func (d *D) Import(rr io.Reader)

Import a collection of events in line structured minified JSON format (JSONL). This runs synchronously to ensure the reader remains valid during processing. The actual event processing happens after buffering to a temp file, so the caller can close the reader after Import returns.

func (*D) ImportEventsFromReader added in v0.24.0

func (d *D) ImportEventsFromReader(ctx context.Context, rr io.Reader) error

ImportEventsFromReader imports events from an io.Reader containing JSONL data

func (*D) ImportEventsFromStrings added in v0.24.0

func (d *D) ImportEventsFromStrings(ctx context.Context, eventJSONs []string, policyManager interface {
	CheckPolicy(action string, ev *event.E, pubkey []byte, remote string) (bool, error)
}) error

ImportEventsFromStrings imports events from a slice of JSON strings with policy filtering

func (*D) Init

func (d *D) Init(path string) (err error)

Init initializes the database with the given path.

func (*D) InvalidateQueryCache added in v0.29.1

func (d *D) InvalidateQueryCache()

InvalidateQueryCache clears all entries from the query cache

func (*D) IsFirstTimeUser added in v0.8.0

func (d *D) IsFirstTimeUser(pubkey []byte) (bool, error)

IsFirstTimeUser checks if a user is logging in for the first time and marks them as seen

func (*D) IsNIP43Member added in v0.27.0

func (d *D) IsNIP43Member(pubkey []byte) (isMember bool, err error)

IsNIP43Member checks if a pubkey is a NIP-43 member

func (*D) IsSubscriptionActive

func (d *D) IsSubscriptionActive(pubkey []byte) (bool, error)

func (*D) LogCompactSavings added in v0.33.0

func (d *D) LogCompactSavings()

LogCompactSavings logs the storage savings achieved by compact format. Call this periodically or after significant operations.

func (*D) Path

func (d *D) Path() string

Path returns the path where the database files are stored.

func (*D) ProcessDelete

func (d *D) ProcessDelete(ev *event.E, admins [][]byte) (err error)

func (*D) PubkeyHexToSerial added in v0.34.0

func (d *D) PubkeyHexToSerial(pubkeyHex string) (*types.Uint40, error)

PubkeyHexToSerial converts a pubkey hex string to its serial, if it exists. Returns an error if the pubkey is not in the database.

func (*D) PublishNIP43MembershipEvent added in v0.27.0

func (d *D) PublishNIP43MembershipEvent(kind int, pubkey []byte) error

PublishNIP43MembershipEvent publishes membership change events

func (*D) QueryAllVersions added in v0.17.4

func (d *D) QueryAllVersions(c context.Context, f *filter.F) (
	evs event.S, err error,
)

QueryAllVersions queries events and returns all versions of replaceable events

func (*D) QueryCacheStats added in v0.29.1

func (d *D) QueryCacheStats() querycache.CacheStats

QueryCacheStats returns statistics about the query cache

func (*D) QueryDeleteEventsByTargetId added in v0.14.0

func (d *D) QueryDeleteEventsByTargetId(c context.Context, targetEventId []byte) (
	evs event.S, err error,
)

QueryDeleteEventsByTargetId queries for delete events that target a specific event ID

func (*D) QueryEvents

func (d *D) QueryEvents(c context.Context, f *filter.F) (
	evs event.S, err error,
)

func (*D) QueryEventsWithOptions added in v0.14.0

func (d *D) QueryEventsWithOptions(c context.Context, f *filter.F, includeDeleteEvents bool, showAllVersions bool) (
	evs event.S, err error,
)

func (*D) QueryForIds

func (d *D) QueryForIds(c context.Context, f *filter.F) (
	idPkTs []*store.IdPkTs, err error,
)

QueryForIds retrieves a list of IdPkTs based on the provided filter. It supports filtering by ranges and tags but disallows filtering by Ids. Results are sorted by timestamp in reverse chronological order by default. When a search query is present, results are ranked by a 50/50 blend of match count (how many distinct search terms matched) and recency. Returns an error if the filter contains Ids or if any operation fails.

func (*D) QueryForSerials

func (d *D) QueryForSerials(c context.Context, f *filter.F) (
	sers types.Uint40s, err error,
)

QueryForSerials takes a filter and returns the serials of events that match, sorted in reverse chronological order.

func (*D) QueryPTagGraph added in v0.29.11

func (d *D) QueryPTagGraph(f *filter.F) (sers types.Uint40s, err error)

QueryPTagGraph uses the pubkey graph index for efficient p-tag queries.

This query path is optimized for filters like:

{"#p": ["<pubkey>"], "kinds": [1, 6, 7]}

Performance benefits: - 41% smaller index keys (16 bytes vs 27 bytes) - No hash collisions (exact serial match) - Kind-indexed in key structure - Direction-aware filtering

func (*D) Ready added in v0.29.1

func (d *D) Ready() <-chan struct{}

Ready returns a channel that closes when the database is ready to serve requests. This allows callers to wait for database warmup to complete.

func (*D) RebuildWordIndexesWithNormalization added in v0.36.10

func (d *D) RebuildWordIndexesWithNormalization()

RebuildWordIndexesWithNormalization rebuilds all word indexes with unicode normalization applied. This migration: 1. Deletes all existing word indexes (wrd prefix) 2. Re-tokenizes all events with normalizeRune() applied 3. Creates new consolidated indexes where decorative unicode maps to ASCII

After this migration, "ᴅᴇᴀᴛʜ" (small caps) and "𝔇𝔢𝔞𝔱𝔥" (fraktur) will index the same as "death", eliminating duplicate entries and enabling proper search.

func (*D) RecordPayment

func (d *D) RecordPayment(
	pubkey []byte, amount int64, invoice, preimage string,
) error

func (*D) ReencodeEventsWithOptimizedTags added in v0.29.15

func (d *D) ReencodeEventsWithOptimizedTags()

ReencodeEventsWithOptimizedTags re-encodes all events to use the new binary tag format that stores e/p tag values as 33-byte binary (32-byte hash + null) instead of 64-byte hex strings. This reduces memory usage by ~48% for these tags.

func (*D) RemoveNIP43Member added in v0.27.0

func (d *D) RemoveNIP43Member(pubkey []byte) error

RemoveNIP43Member removes a member from the NIP-43 membership list

func (*D) RunMigrations

func (d *D) RunMigrations()

func (*D) SaveEvent

func (d *D) SaveEvent(c context.Context, ev *event.E) (
	replaced bool, err error,
)

SaveEvent saves an event to the database, generating all the necessary indexes.

func (*D) SerialCacheStats added in v0.33.0

func (d *D) SerialCacheStats() SerialCacheStats

SerialCacheStats returns statistics about the serial cache.

func (*D) SetLogLevel

func (d *D) SetLogLevel(level string)

func (*D) SetMarker added in v0.6.0

func (d *D) SetMarker(key string, value []byte) (err error)

SetMarker stores an arbitrary marker in the database

func (*D) SetRateLimiter added in v0.35.1

func (d *D) SetRateLimiter(limiter RateLimiterInterface)

SetRateLimiter sets the rate limiter for controlling memory during import/export

func (*D) SetRelayIdentitySecret added in v0.8.0

func (d *D) SetRelayIdentitySecret(skb []byte) (err error)

SetRelayIdentitySecret stores the relay identity secret key bytes (expects 32 bytes).

func (*D) StoreEventIdSerial added in v0.33.0

func (d *D) StoreEventIdSerial(txn *badger.Txn, serial uint64, eventId []byte) error

StoreEventIdSerial stores the mapping from event serial to full event ID. This is called during event save to enable later reconstruction.

func (*D) StoreInviteCode added in v0.27.0

func (d *D) StoreInviteCode(code string, expiresAt time.Time) error

StoreInviteCode stores an invite code with expiry

func (*D) Sync

func (d *D) Sync() (err error)

Sync flushes the database buffers to disk.

func (*D) TraverseFollowers added in v0.34.0

func (d *D) TraverseFollowers(seedPubkey []byte, maxDepth int) (*GraphResult, error)

TraverseFollowers performs BFS traversal to find who follows the seed pubkey. This is the reverse of TraverseFollows - it finds users whose kind-3 lists contain the target pubkey(s).

At each depth: - Depth 1: Users who directly follow the seed - Depth 2: Users who follow anyone at depth 1 (followers of followers) - etc.

func (*D) TraverseFollowersFromHex added in v0.34.0

func (d *D) TraverseFollowersFromHex(seedPubkeyHex string, maxDepth int) (*GraphResult, error)

TraverseFollowersFromHex is a convenience wrapper that accepts hex-encoded pubkey.

func (*D) TraverseFollows added in v0.34.0

func (d *D) TraverseFollows(seedPubkey []byte, maxDepth int) (*GraphResult, error)

TraverseFollows performs BFS traversal of the follow graph starting from a seed pubkey. Returns pubkeys grouped by first-discovered depth (no duplicates across depths).

The traversal works by: 1. Starting with the seed pubkey at depth 0 (not included in results) 2. For each pubkey at the current depth, find their kind-3 contact list 3. Extract p-tags from the contact list to get follows 4. Add new (unseen) follows to the next depth 5. Continue until maxDepth is reached or no new pubkeys are found

Early termination occurs if two consecutive depths yield no new pubkeys.

func (*D) TraverseFollowsFromHex added in v0.34.0

func (d *D) TraverseFollowsFromHex(seedPubkeyHex string, maxDepth int) (*GraphResult, error)

TraverseFollowsFromHex is a convenience wrapper that accepts hex-encoded pubkey.

func (*D) TraverseThread added in v0.34.0

func (d *D) TraverseThread(seedEventID []byte, maxDepth int, direction string) (*GraphResult, error)

TraverseThread performs BFS traversal of thread structure via e-tags. Starting from a seed event, it finds all replies/references at each depth.

The traversal works bidirectionally: - Forward: Events that the seed references (parents, quoted posts) - Backward: Events that reference the seed (replies, reactions, reposts)

Parameters: - seedEventID: The event ID to start traversal from - maxDepth: Maximum depth to traverse - direction: "both" (default), "inbound" (replies to seed), "outbound" (seed's references)

func (*D) TraverseThreadFromHex added in v0.34.0

func (d *D) TraverseThreadFromHex(seedEventIDHex string, maxDepth int, direction string) (*GraphResult, error)

TraverseThreadFromHex is a convenience wrapper that accepts hex-encoded event ID.

func (*D) UpdateExpirationTags

func (d *D) UpdateExpirationTags()

func (*D) UpdateWordIndexes added in v0.9.0

func (d *D) UpdateWordIndexes()

func (*D) ValidateInviteCode added in v0.27.0

func (d *D) ValidateInviteCode(code string) (valid bool, err error)

ValidateInviteCode checks if an invite code is valid and not expired

func (*D) Wipe

func (d *D) Wipe() (err error)

func (*D) WouldReplaceEvent added in v0.10.5

func (d *D) WouldReplaceEvent(ev *event.E) (bool, types.Uint40s, error)

WouldReplaceEvent checks if the provided event would replace existing events based on Nostr's replaceable or parameterized replaceable semantics. It returns true if the candidate is newer-or-equal than existing events. If an existing event is newer, it returns (false, nil, ErrOlderThanExisting). If no conflicts exist, it returns (false, nil, nil).

type Database added in v0.29.1

type Database interface {
	// Core lifecycle methods
	Path() string
	Init(path string) error
	Sync() error
	Close() error
	Wipe() error
	SetLogLevel(level string)
	Ready() <-chan struct{} // Returns a channel that closes when database is ready to serve requests

	// Event storage and retrieval
	SaveEvent(c context.Context, ev *event.E) (exists bool, err error)
	GetSerialsFromFilter(f *filter.F) (serials types.Uint40s, err error)
	WouldReplaceEvent(ev *event.E) (bool, types.Uint40s, error)

	QueryEvents(c context.Context, f *filter.F) (evs event.S, err error)
	QueryAllVersions(c context.Context, f *filter.F) (evs event.S, err error)
	QueryEventsWithOptions(c context.Context, f *filter.F, includeDeleteEvents bool, showAllVersions bool) (evs event.S, err error)
	QueryDeleteEventsByTargetId(c context.Context, targetEventId []byte) (evs event.S, err error)
	QueryForSerials(c context.Context, f *filter.F) (serials types.Uint40s, err error)
	QueryForIds(c context.Context, f *filter.F) (idPkTs []*store.IdPkTs, err error)

	CountEvents(c context.Context, f *filter.F) (count int, approximate bool, err error)

	FetchEventBySerial(ser *types.Uint40) (ev *event.E, err error)
	FetchEventsBySerials(serials []*types.Uint40) (events map[uint64]*event.E, err error)

	GetSerialById(id []byte) (ser *types.Uint40, err error)
	GetSerialsByIds(ids *tag.T) (serials map[string]*types.Uint40, err error)
	GetSerialsByIdsWithFilter(ids *tag.T, fn func(ev *event.E, ser *types.Uint40) bool) (serials map[string]*types.Uint40, err error)
	GetSerialsByRange(idx Range) (serials types.Uint40s, err error)

	GetFullIdPubkeyBySerial(ser *types.Uint40) (fidpk *store.IdPkTs, err error)
	GetFullIdPubkeyBySerials(sers []*types.Uint40) (fidpks []*store.IdPkTs, err error)

	// Event deletion
	DeleteEvent(c context.Context, eid []byte) error
	DeleteEventBySerial(c context.Context, ser *types.Uint40, ev *event.E) error
	DeleteExpired()
	ProcessDelete(ev *event.E, admins [][]byte) error
	CheckForDeleted(ev *event.E, admins [][]byte) error

	// Import/Export
	Import(rr io.Reader)
	Export(c context.Context, w io.Writer, pubkeys ...[]byte)
	ImportEventsFromReader(ctx context.Context, rr io.Reader) error
	ImportEventsFromStrings(ctx context.Context, eventJSONs []string, policyManager interface {
		CheckPolicy(action string, ev *event.E, pubkey []byte, remote string) (bool, error)
	}) error

	// Relay identity
	GetRelayIdentitySecret() (skb []byte, err error)
	SetRelayIdentitySecret(skb []byte) error
	GetOrCreateRelayIdentitySecret() (skb []byte, err error)

	// Markers (metadata key-value storage)
	SetMarker(key string, value []byte) error
	GetMarker(key string) (value []byte, err error)
	HasMarker(key string) bool
	DeleteMarker(key string) error

	// Subscriptions (payment-based access control)
	GetSubscription(pubkey []byte) (*Subscription, error)
	IsSubscriptionActive(pubkey []byte) (bool, error)
	ExtendSubscription(pubkey []byte, days int) error
	RecordPayment(pubkey []byte, amount int64, invoice, preimage string) error
	GetPaymentHistory(pubkey []byte) ([]Payment, error)
	ExtendBlossomSubscription(pubkey []byte, tier string, storageMB int64, daysExtended int) error
	GetBlossomStorageQuota(pubkey []byte) (quotaMB int64, err error)
	IsFirstTimeUser(pubkey []byte) (bool, error)

	// NIP-43 Invite-based ACL
	AddNIP43Member(pubkey []byte, inviteCode string) error
	RemoveNIP43Member(pubkey []byte) error
	IsNIP43Member(pubkey []byte) (isMember bool, err error)
	GetNIP43Membership(pubkey []byte) (*NIP43Membership, error)
	GetAllNIP43Members() ([][]byte, error)
	StoreInviteCode(code string, expiresAt time.Time) error
	ValidateInviteCode(code string) (valid bool, err error)
	DeleteInviteCode(code string) error
	PublishNIP43MembershipEvent(kind int, pubkey []byte) error

	// Migrations (version tracking for schema updates)
	RunMigrations()

	// Query cache methods
	GetCachedJSON(f *filter.F) ([][]byte, bool)
	CacheMarshaledJSON(f *filter.F, marshaledJSON [][]byte)
	GetCachedEvents(f *filter.F) (event.S, bool)
	CacheEvents(f *filter.F, events event.S)
	InvalidateQueryCache()

	// Utility methods
	EventIdsBySerial(start uint64, count int) (evs []uint64, err error)
}

Database defines the interface that all database implementations must satisfy. This allows switching between different storage backends (badger, neo4j, etc.)

func NewDatabase added in v0.29.1

func NewDatabase(
	ctx context.Context,
	cancel context.CancelFunc,
	dbType string,
	dataDir string,
	logLevel string,
) (Database, error)

NewDatabase creates a database instance based on the specified type. Supported types: "badger", "neo4j"

func NewDatabaseWithConfig added in v0.31.8

func NewDatabaseWithConfig(
	ctx context.Context,
	cancel context.CancelFunc,
	dbType string,
	cfg *DatabaseConfig,
) (Database, error)

NewDatabaseWithConfig creates a database instance with full configuration. This is the preferred method when you have access to the app config.

type DatabaseConfig added in v0.31.8

type DatabaseConfig struct {
	// Common settings for all backends
	DataDir  string
	LogLevel string

	// Badger-specific settings
	BlockCacheMB       int           // ORLY_DB_BLOCK_CACHE_MB
	IndexCacheMB       int           // ORLY_DB_INDEX_CACHE_MB
	QueryCacheDisabled bool          // ORLY_QUERY_CACHE_DISABLED - disable query cache to reduce memory usage
	QueryCacheSizeMB   int           // ORLY_QUERY_CACHE_SIZE_MB
	QueryCacheMaxAge   time.Duration // ORLY_QUERY_CACHE_MAX_AGE

	// Serial cache settings for compact event storage
	SerialCachePubkeys  int // ORLY_SERIAL_CACHE_PUBKEYS - max pubkeys to cache (default: 100000)
	SerialCacheEventIds int // ORLY_SERIAL_CACHE_EVENT_IDS - max event IDs to cache (default: 500000)

	// Compression settings
	ZSTDLevel int // ORLY_DB_ZSTD_LEVEL - ZSTD compression level (0=none, 1=fast, 3=default, 9=best)

	// Neo4j-specific settings
	Neo4jURI      string // ORLY_NEO4J_URI
	Neo4jUser     string // ORLY_NEO4J_USER
	Neo4jPassword string // ORLY_NEO4J_PASSWORD
}

DatabaseConfig holds all database configuration options that can be passed to any database backend. Each backend uses the relevant fields for its type. This centralizes configuration instead of having each backend read env vars directly.

type DatabaseSerialResolver added in v0.33.0

type DatabaseSerialResolver struct {
	// contains filtered or unexported fields
}

DatabaseSerialResolver implements SerialResolver using the database and cache.

func NewDatabaseSerialResolver added in v0.33.0

func NewDatabaseSerialResolver(db *D, cache *SerialCache) *DatabaseSerialResolver

NewDatabaseSerialResolver creates a new resolver.

func (*DatabaseSerialResolver) GetEventIdBySerial added in v0.33.0

func (r *DatabaseSerialResolver) GetEventIdBySerial(serial uint64) (eventId []byte, err error)

GetEventIdBySerial implements SerialResolver.

func (*DatabaseSerialResolver) GetEventSerialById added in v0.33.0

func (r *DatabaseSerialResolver) GetEventSerialById(eventId []byte) (serial uint64, found bool, err error)

GetEventSerialById implements SerialResolver.

func (*DatabaseSerialResolver) GetOrCreatePubkeySerial added in v0.33.0

func (r *DatabaseSerialResolver) GetOrCreatePubkeySerial(pubkey []byte) (serial uint64, err error)

GetOrCreatePubkeySerial implements SerialResolver.

func (*DatabaseSerialResolver) GetPubkeyBySerial added in v0.33.0

func (r *DatabaseSerialResolver) GetPubkeyBySerial(serial uint64) (pubkey []byte, err error)

GetPubkeyBySerial implements SerialResolver.

type EventNeedingModeration added in v0.17.0

type EventNeedingModeration struct {
	ID     string    `json:"id"`
	Reason string    `json:"reason,omitempty"`
	Added  time.Time `json:"added"`
}

EventNeedingModeration represents an event that needs moderation

type GraphAdapter added in v0.34.0

type GraphAdapter struct {
	// contains filtered or unexported fields
}

GraphAdapter wraps a database instance and implements graph.GraphDatabase interface. This allows the graph executor to call database traversal methods without the database package importing the graph package.

func NewGraphAdapter added in v0.34.0

func NewGraphAdapter(db *D) *GraphAdapter

NewGraphAdapter creates a new GraphAdapter wrapping the given database.

func (*GraphAdapter) FindMentions added in v0.34.0

func (a *GraphAdapter) FindMentions(pubkey []byte, kinds []uint16) (graph.GraphResultI, error)

FindMentions implements graph.GraphDatabase.

func (*GraphAdapter) TraverseFollowers added in v0.34.0

func (a *GraphAdapter) TraverseFollowers(seedPubkey []byte, maxDepth int) (graph.GraphResultI, error)

TraverseFollowers implements graph.GraphDatabase.

func (*GraphAdapter) TraverseFollows added in v0.34.0

func (a *GraphAdapter) TraverseFollows(seedPubkey []byte, maxDepth int) (graph.GraphResultI, error)

TraverseFollows implements graph.GraphDatabase.

func (*GraphAdapter) TraverseThread added in v0.34.0

func (a *GraphAdapter) TraverseThread(seedEventID []byte, maxDepth int, direction string) (graph.GraphResultI, error)

TraverseThread implements graph.GraphDatabase.

type GraphResult added in v0.34.0

type GraphResult struct {
	// PubkeysByDepth maps depth -> pubkeys first discovered at that depth.
	// Each pubkey appears ONLY in the array for the depth where it was first seen.
	// Depth 1 = direct connections, Depth 2 = connections of connections, etc.
	PubkeysByDepth map[int][]string

	// EventsByDepth maps depth -> event IDs discovered at that depth.
	// Used for thread traversal queries.
	EventsByDepth map[int][]string

	// FirstSeenPubkey tracks which depth each pubkey was first discovered.
	// Key is pubkey hex, value is the depth (1-indexed).
	FirstSeenPubkey map[string]int

	// FirstSeenEvent tracks which depth each event was first discovered.
	// Key is event ID hex, value is the depth (1-indexed).
	FirstSeenEvent map[string]int

	// TotalPubkeys is the count of unique pubkeys discovered across all depths.
	TotalPubkeys int

	// TotalEvents is the count of unique events discovered across all depths.
	TotalEvents int

	// InboundRefs tracks inbound references (events that reference discovered items).
	// Structure: kind -> target_id -> []referencing_event_ids
	InboundRefs map[uint16]map[string][]string

	// OutboundRefs tracks outbound references (events referenced by discovered items).
	// Structure: kind -> source_id -> []referenced_event_ids
	OutboundRefs map[uint16]map[string][]string
}

GraphResult contains depth-organized traversal results for graph queries. It tracks pubkeys and events discovered at each depth level, ensuring each entity appears only at the depth where it was first discovered.

func NewGraphResult added in v0.34.0

func NewGraphResult() *GraphResult

NewGraphResult creates a new initialized GraphResult.

func (*GraphResult) AddEventAtDepth added in v0.34.0

func (r *GraphResult) AddEventAtDepth(eventIDHex string, depth int) bool

AddEventAtDepth adds an event ID to the result at the specified depth if not already seen. Returns true if the event was added (first time seen), false if already exists.

func (*GraphResult) AddInboundRef added in v0.34.0

func (r *GraphResult) AddInboundRef(kind uint16, targetIDHex string, referencingEventIDHex string)

AddInboundRef records an inbound reference from a referencing event to a target.

func (*GraphResult) AddOutboundRef added in v0.34.0

func (r *GraphResult) AddOutboundRef(kind uint16, sourceIDHex string, referencedEventIDHex string)

AddOutboundRef records an outbound reference from a source event to a referenced event.

func (*GraphResult) AddPubkeyAtDepth added in v0.34.0

func (r *GraphResult) AddPubkeyAtDepth(pubkeyHex string, depth int) bool

AddPubkeyAtDepth adds a pubkey to the result at the specified depth if not already seen. Returns true if the pubkey was added (first time seen), false if already exists.

func (*GraphResult) GetAllEvents added in v0.34.0

func (r *GraphResult) GetAllEvents() []string

GetAllEvents returns all event IDs discovered across all depths.

func (*GraphResult) GetAllPubkeys added in v0.34.0

func (r *GraphResult) GetAllPubkeys() []string

GetAllPubkeys returns all pubkeys discovered across all depths.

func (*GraphResult) GetDepthsSorted added in v0.34.0

func (r *GraphResult) GetDepthsSorted() []int

GetDepthsSorted returns all depths that have pubkeys, sorted ascending.

func (*GraphResult) GetEventDepth added in v0.34.0

func (r *GraphResult) GetEventDepth(eventIDHex string) int

GetEventDepth returns the depth at which an event was first discovered. Returns 0 if the event was not found.

func (*GraphResult) GetEventDepthsSorted added in v0.34.0

func (r *GraphResult) GetEventDepthsSorted() []int

GetEventDepthsSorted returns all depths that have events, sorted ascending.

func (*GraphResult) GetEventsAtDepth added in v0.34.0

func (r *GraphResult) GetEventsAtDepth(depth int) []string

GetEventsAtDepth returns events at a specific depth, or empty slice if none.

func (*GraphResult) GetEventsByDepth added in v0.34.0

func (r *GraphResult) GetEventsByDepth() map[int][]string

GetEventsByDepth returns the EventsByDepth map for external access.

func (*GraphResult) GetInboundRefsSorted added in v0.34.0

func (r *GraphResult) GetInboundRefsSorted(kind uint16) []RefAggregation

GetInboundRefsSorted returns inbound refs for a kind, sorted by count descending.

func (*GraphResult) GetOutboundRefsSorted added in v0.34.0

func (r *GraphResult) GetOutboundRefsSorted(kind uint16) []RefAggregation

GetOutboundRefsSorted returns outbound refs for a kind, sorted by count descending.

func (*GraphResult) GetPubkeyDepth added in v0.34.0

func (r *GraphResult) GetPubkeyDepth(pubkeyHex string) int

GetPubkeyDepth returns the depth at which a pubkey was first discovered. Returns 0 if the pubkey was not found.

func (*GraphResult) GetPubkeysAtDepth added in v0.34.0

func (r *GraphResult) GetPubkeysAtDepth(depth int) []string

GetPubkeysAtDepth returns pubkeys at a specific depth, or empty slice if none.

func (*GraphResult) GetPubkeysByDepth added in v0.34.0

func (r *GraphResult) GetPubkeysByDepth() map[int][]string

GetPubkeysByDepth returns the PubkeysByDepth map for external access.

func (*GraphResult) GetTotalEvents added in v0.34.0

func (r *GraphResult) GetTotalEvents() int

GetTotalEvents returns the total event count for external access.

func (*GraphResult) GetTotalPubkeys added in v0.34.0

func (r *GraphResult) GetTotalPubkeys() int

GetTotalPubkeys returns the total pubkey count for external access.

func (*GraphResult) HasEvent added in v0.34.0

func (r *GraphResult) HasEvent(eventIDHex string) bool

HasEvent returns true if the event has been discovered at any depth.

func (*GraphResult) HasPubkey added in v0.34.0

func (r *GraphResult) HasPubkey(pubkeyHex string) bool

HasPubkey returns true if the pubkey has been discovered at any depth.

func (*GraphResult) ToDepthArrays added in v0.34.0

func (r *GraphResult) ToDepthArrays() [][]string

ToDepthArrays converts the result to the response format: array of arrays. Index 0 = depth 1 pubkeys, Index 1 = depth 2 pubkeys, etc. Empty arrays are included for depths with no pubkeys to maintain index alignment.

func (*GraphResult) ToEventDepthArrays added in v0.34.0

func (r *GraphResult) ToEventDepthArrays() [][]string

ToEventDepthArrays converts event results to the response format: array of arrays. Index 0 = depth 1 events, Index 1 = depth 2 events, etc.

type LRUCache added in v0.36.17

type LRUCache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

LRUCache provides a thread-safe LRU cache with configurable max size. It starts empty and grows on demand up to maxSize. When at capacity, the least recently used entry is evicted to make room for new entries.

func NewLRUCache added in v0.36.17

func NewLRUCache[K comparable, V any](maxSize int) *LRUCache[K, V]

NewLRUCache creates a new LRU cache with the given maximum size. The cache starts empty and grows on demand.

func (*LRUCache[K, V]) Clear added in v0.36.17

func (c *LRUCache[K, V]) Clear()

Clear removes all entries from the cache.

func (*LRUCache[K, V]) Contains added in v0.36.17

func (c *LRUCache[K, V]) Contains(key K) bool

Contains returns true if the key exists in the cache without updating LRU order.

func (*LRUCache[K, V]) Delete added in v0.36.17

func (c *LRUCache[K, V]) Delete(key K)

Delete removes an entry from the cache.

func (*LRUCache[K, V]) Get added in v0.36.17

func (c *LRUCache[K, V]) Get(key K) (value V, found bool)

Get retrieves a value by key and marks it as recently used. Returns the value and true if found, zero value and false otherwise.

func (*LRUCache[K, V]) Len added in v0.36.17

func (c *LRUCache[K, V]) Len() int

Len returns the current number of entries in the cache.

func (*LRUCache[K, V]) MaxSize added in v0.36.17

func (c *LRUCache[K, V]) MaxSize() int

MaxSize returns the maximum capacity of the cache.

func (*LRUCache[K, V]) Put added in v0.36.17

func (c *LRUCache[K, V]) Put(key K, value V)

Put adds or updates a value, evicting the LRU entry if at capacity.

type ManagedACL added in v0.17.0

type ManagedACL struct {
	*D
}

ManagedACL database operations

func NewManagedACL added in v0.17.0

func NewManagedACL(db *D) *ManagedACL

NewManagedACL creates a new ManagedACL instance

func (*ManagedACL) GetRelayConfig added in v0.17.0

func (m *ManagedACL) GetRelayConfig() (ManagedACLConfig, error)

GetRelayConfig returns relay configuration

func (*ManagedACL) IsEventAllowed added in v0.17.0

func (m *ManagedACL) IsEventAllowed(eventID string) (bool, error)

Check if an event is explicitly allowed

func (*ManagedACL) IsEventBanned added in v0.17.0

func (m *ManagedACL) IsEventBanned(eventID string) (bool, error)

Check if an event is banned

func (*ManagedACL) IsIPBlocked added in v0.17.0

func (m *ManagedACL) IsIPBlocked(ip string) (bool, error)

Check if an IP is blocked

func (*ManagedACL) IsKindAllowed added in v0.17.0

func (m *ManagedACL) IsKindAllowed(kind int) (bool, error)

Check if a kind is allowed

func (*ManagedACL) IsPubkeyAllowed added in v0.17.0

func (m *ManagedACL) IsPubkeyAllowed(pubkey string) (bool, error)

Check if a pubkey is explicitly allowed

func (*ManagedACL) IsPubkeyBanned added in v0.17.0

func (m *ManagedACL) IsPubkeyBanned(pubkey string) (bool, error)

Check if a pubkey is banned

func (*ManagedACL) ListAllowedEvents added in v0.17.0

func (m *ManagedACL) ListAllowedEvents() ([]AllowedEvent, error)

ListAllowedEvents returns all allowed events

func (*ManagedACL) ListAllowedKinds added in v0.17.0

func (m *ManagedACL) ListAllowedKinds() ([]int, error)

ListAllowedKinds returns all allowed kinds

func (*ManagedACL) ListAllowedPubkeys added in v0.17.0

func (m *ManagedACL) ListAllowedPubkeys() ([]AllowedPubkey, error)

ListAllowedPubkeys returns all allowed pubkeys

func (*ManagedACL) ListBannedEvents added in v0.17.0

func (m *ManagedACL) ListBannedEvents() ([]BannedEvent, error)

ListBannedEvents returns all banned events

func (*ManagedACL) ListBannedPubkeys added in v0.17.0

func (m *ManagedACL) ListBannedPubkeys() ([]BannedPubkey, error)

ListBannedPubkeys returns all banned pubkeys

func (*ManagedACL) ListBlockedIPs added in v0.17.0

func (m *ManagedACL) ListBlockedIPs() ([]BlockedIP, error)

ListBlockedIPs returns all blocked IPs

func (*ManagedACL) ListEventsNeedingModeration added in v0.17.0

func (m *ManagedACL) ListEventsNeedingModeration() ([]EventNeedingModeration, error)

ListEventsNeedingModeration returns all events needing moderation

func (*ManagedACL) RemoveAllowedEvent added in v0.17.0

func (m *ManagedACL) RemoveAllowedEvent(eventID string) error

RemoveAllowedEvent removes an allowed event from the database

func (*ManagedACL) RemoveAllowedKind added in v0.17.0

func (m *ManagedACL) RemoveAllowedKind(kind int) error

RemoveAllowedKind removes an allowed kind from the database

func (*ManagedACL) RemoveAllowedPubkey added in v0.17.0

func (m *ManagedACL) RemoveAllowedPubkey(pubkey string) error

RemoveAllowedPubkey removes an allowed pubkey from the database

func (*ManagedACL) RemoveBannedEvent added in v0.17.0

func (m *ManagedACL) RemoveBannedEvent(eventID string) error

RemoveBannedEvent removes a banned event from the database

func (*ManagedACL) RemoveBannedPubkey added in v0.17.0

func (m *ManagedACL) RemoveBannedPubkey(pubkey string) error

RemoveBannedPubkey removes a banned pubkey from the database

func (*ManagedACL) RemoveBlockedIP added in v0.17.0

func (m *ManagedACL) RemoveBlockedIP(ip string) error

RemoveBlockedIP removes a blocked IP from the database

func (*ManagedACL) RemoveEventNeedingModeration added in v0.17.0

func (m *ManagedACL) RemoveEventNeedingModeration(eventID string) error

RemoveEventNeedingModeration removes an event from moderation queue

func (*ManagedACL) SaveAllowedEvent added in v0.17.0

func (m *ManagedACL) SaveAllowedEvent(eventID string, reason string) error

SaveAllowedEvent saves an allowed event to the database

func (*ManagedACL) SaveAllowedKind added in v0.17.0

func (m *ManagedACL) SaveAllowedKind(kind int) error

SaveAllowedKind saves an allowed kind to the database

func (*ManagedACL) SaveAllowedPubkey added in v0.17.0

func (m *ManagedACL) SaveAllowedPubkey(pubkey string, reason string) error

SaveAllowedPubkey saves an allowed pubkey to the database

func (*ManagedACL) SaveBannedEvent added in v0.17.0

func (m *ManagedACL) SaveBannedEvent(eventID string, reason string) error

SaveBannedEvent saves a banned event to the database

func (*ManagedACL) SaveBannedPubkey added in v0.17.0

func (m *ManagedACL) SaveBannedPubkey(pubkey string, reason string) error

SaveBannedPubkey saves a banned pubkey to the database

func (*ManagedACL) SaveBlockedIP added in v0.17.0

func (m *ManagedACL) SaveBlockedIP(ip string, reason string) error

SaveBlockedIP saves a blocked IP to the database

func (*ManagedACL) SaveEventNeedingModeration added in v0.17.0

func (m *ManagedACL) SaveEventNeedingModeration(eventID string, reason string) error

SaveEventNeedingModeration saves an event that needs moderation

func (*ManagedACL) SaveRelayConfig added in v0.17.0

func (m *ManagedACL) SaveRelayConfig(config ManagedACLConfig) error

SaveRelayConfig saves relay configuration

type ManagedACLConfig added in v0.17.0

type ManagedACLConfig struct {
	RelayName        string `json:"relay_name"`
	RelayDescription string `json:"relay_description"`
	RelayIcon        string `json:"relay_icon"`
}

ManagedACLConfig represents the configuration for managed ACL mode

type NIP43Membership added in v0.27.0

type NIP43Membership struct {
	Pubkey     []byte
	AddedAt    time.Time
	InviteCode string
}

NIP43Membership represents membership metadata for NIP-43

type Payment

type Payment struct {
	Amount    int64     `json:"amount"`
	Timestamp time.Time `json:"timestamp"`
	Invoice   string    `json:"invoice"`
	Preimage  string    `json:"preimage"`
}

Payment represents a recorded payment

type Range

type Range struct {
	Start, End []byte
}

func GetIndexesFromFilter

func GetIndexesFromFilter(f *filter.F) (idxs []Range, err error)

GetIndexesFromFilter returns encoded indexes based on the given filter.

An error is returned if any input values are invalid during encoding.

The indexes are designed so that only one table needs to be iterated, being a complete set of combinations of all fields in the event, thus there is no need to decode events until they are to be delivered.

type RateLimiterInterface added in v0.35.1

type RateLimiterInterface interface {
	IsEnabled() bool
	Wait(ctx context.Context, opType int) time.Duration
}

RateLimiterInterface defines the minimal interface for rate limiting during import

type RefAggregation added in v0.34.0

type RefAggregation struct {
	// TargetEventID is the event ID being referenced (for inbound) or referencing (for outbound)
	TargetEventID string

	// TargetAuthor is the author pubkey of the target event (if known)
	TargetAuthor string

	// TargetDepth is the depth at which this target was discovered in the graph
	TargetDepth int

	// RefKind is the kind of the referencing events
	RefKind uint16

	// RefCount is the number of references to/from this target
	RefCount int

	// RefEventIDs is the list of event IDs that reference this target
	RefEventIDs []string
}

RefAggregation represents aggregated reference data for a single target/source.

type SerialCache added in v0.33.0

type SerialCache struct {
	// contains filtered or unexported fields
}

SerialCache provides LRU caching for pubkey and event ID serial lookups. This is critical for compact event decoding performance since every event requires looking up the author pubkey and potentially multiple tag references.

The cache uses LRU eviction and starts empty, growing on demand up to the configured limits. This provides better memory efficiency than pre-allocation and better hit rates than random eviction.

func NewSerialCache added in v0.33.0

func NewSerialCache(maxPubkeys, maxEventIds int) *SerialCache

NewSerialCache creates a new serial cache with the specified maximum sizes. The cache starts empty and grows on demand up to these limits.

func (*SerialCache) CacheEventId added in v0.33.0

func (c *SerialCache) CacheEventId(serial uint64, eventId []byte)

CacheEventId adds an event ID to the cache in both directions.

func (*SerialCache) CachePubkey added in v0.33.0

func (c *SerialCache) CachePubkey(serial uint64, pubkey []byte)

CachePubkey adds a pubkey to the cache in both directions.

func (*SerialCache) GetEventIdBySerial added in v0.33.0

func (c *SerialCache) GetEventIdBySerial(serial uint64) (eventId []byte, found bool)

GetEventIdBySerial returns the event ID for a serial from cache.

func (*SerialCache) GetPubkeyBySerial added in v0.33.0

func (c *SerialCache) GetPubkeyBySerial(serial uint64) (pubkey []byte, found bool)

GetPubkeyBySerial returns the pubkey for a serial from cache.

func (*SerialCache) GetSerialByEventId added in v0.33.0

func (c *SerialCache) GetSerialByEventId(eventId []byte) (serial uint64, found bool)

GetSerialByEventId returns the serial for an event ID from cache.

func (*SerialCache) GetSerialByPubkey added in v0.33.0

func (c *SerialCache) GetSerialByPubkey(pubkey []byte) (serial uint64, found bool)

GetSerialByPubkey returns the serial for a pubkey from cache.

func (*SerialCache) Stats added in v0.33.0

func (c *SerialCache) Stats() SerialCacheStats

Stats returns statistics about the serial cache.

type SerialCacheStats added in v0.33.0

type SerialCacheStats struct {
	PubkeysCached      int // Number of pubkeys currently cached
	PubkeysMaxSize     int // Maximum pubkey cache size
	EventIdsCached     int // Number of event IDs currently cached
	EventIdsMaxSize    int // Maximum event ID cache size
	PubkeyMemoryBytes  int // Estimated memory usage for pubkey cache
	EventIdMemoryBytes int // Estimated memory usage for event ID cache
	TotalMemoryBytes   int // Total estimated memory usage
}

SerialCacheStats holds statistics about the serial cache.

type SerialResolver added in v0.33.0

type SerialResolver interface {
	// GetOrCreatePubkeySerial returns the serial for a pubkey, creating one if needed.
	GetOrCreatePubkeySerial(pubkey []byte) (serial uint64, err error)

	// GetPubkeyBySerial returns the full pubkey for a serial.
	GetPubkeyBySerial(serial uint64) (pubkey []byte, err error)

	// GetEventSerialById returns the serial for an event ID, or 0 if not found.
	GetEventSerialById(eventId []byte) (serial uint64, found bool, err error)

	// GetEventIdBySerial returns the full event ID for a serial.
	GetEventIdBySerial(serial uint64) (eventId []byte, err error)
}

SerialResolver is an interface for resolving serials during compact encoding/decoding. This allows the encoder/decoder to look up or create serial mappings.

type Subscription

type Subscription struct {
	TrialEnd       time.Time `json:"trial_end"`
	PaidUntil      time.Time `json:"paid_until"`
	BlossomLevel   string    `json:"blossom_level,omitempty"`   // Service level name (e.g., "basic", "premium")
	BlossomStorage int64     `json:"blossom_storage,omitempty"` // Storage quota in MB
}

Subscription represents a user's subscription status

Source Files

  • cleanup-kind3.go
  • compact_event.go
  • compact_stats.go
  • count.go
  • database.go
  • delete-event.go
  • delete-expired.go
  • export.go
  • factory.go
  • fetch-event-by-serial.go
  • fetch-events-by-serials.go
  • filter_utils.go
  • get-fullidpubkey-by-serial.go
  • get-fullidpubkey-by-serials.go
  • get-indexes-for-event.go
  • get-indexes-from-filter.go
  • get-serial-by-id.go
  • get-serials-by-range.go
  • graph-adapter.go
  • graph-follows.go
  • graph-mentions.go
  • graph-refs.go
  • graph-result.go
  • graph-thread.go
  • graph-traversal.go
  • identity.go
  • import.go
  • import_utils.go
  • interface.go
  • logger.go
  • lrucache.go
  • managed-acl.go
  • markers.go
  • migrations.go
  • nip43.go
  • process-delete.go
  • pubkey-serial.go
  • query-events.go
  • query-for-deleted.go
  • query-for-ids.go
  • query-for-ptag-graph.go
  • query-for-serials.go
  • save-event.go
  • serial_cache.go
  • subscriptions.go
  • tokenize.go
  • types.go
  • unicode_normalize.go

Directories

Path Synopsis
Package bufpool provides buffer pools for reducing GC pressure in hot paths.
Package bufpool provides buffer pools for reducing GC pressure in hot paths.

Jump to

Keyboard shortcuts

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