Documentation
¶
Overview ¶
Package wasmdb provides a WebAssembly-compatible database implementation using IndexedDB as the storage backend. It replicates the Badger database's index schema for full query compatibility.
This implementation uses aperturerobotics/go-indexeddb (a fork of hack-pad/go-indexeddb) which provides full IndexedDB bindings with cursor/range support and transaction retry mechanisms to handle IndexedDB's transaction expiration issues in Go WASM.
Architecture:
- Each index type (evt, eid, kc-, pc-, etc.) maps to an IndexedDB object store
- Keys are binary-encoded using the same format as the Badger implementation
- Range queries use IndexedDB cursors with KeyRange bounds
- Serial numbers are managed using a dedicated "meta" object store
Index ¶
- Constants
- Variables
- func CheckExpiration(ev *event.E) (expired bool)
- func NewLogger(level int) *logger
- func RegisterJSBridge(db *W, ctx context.Context, cancel context.CancelFunc)
- type JSBridge
- type W
- func (w *W) AddNIP43Member(pubkey []byte, inviteCode string) error
- func (w *W) CacheEvents(f *filter.F, events event.S)
- func (w *W) CacheMarshaledJSON(f *filter.F, marshaledJSON [][]byte)
- func (w *W) CheckForDeleted(ev *event.E, admins [][]byte) (err error)
- func (w *W) Close() error
- func (w *W) CountEvents(c context.Context, f *filter.F) (count int, approx bool, err error)
- func (w *W) DeleteEvent(c context.Context, eid []byte) (err error)
- func (w *W) DeleteEventBySerial(c context.Context, ser *types.Uint40, ev *event.E) (err error)
- func (w *W) DeleteExpired()
- func (w *W) DeleteInviteCode(code string) error
- func (w *W) DeleteMarker(key string) error
- func (w *W) EventIdsBySerial(start uint64, count int) ([]uint64, error)
- func (w *W) Export(c context.Context, wr io.Writer, pubkeys ...[]byte)
- func (w *W) ExtendBlossomSubscription(pubkey []byte, level string, storageMB int64, days int) error
- func (w *W) ExtendSubscription(pubkey []byte, days int) error
- func (w *W) FetchEventBySerial(ser *types.Uint40) (ev *event.E, err error)
- func (w *W) FetchEventsBySerials(serials []*types.Uint40) (events map[uint64]*event.E, err error)
- func (w *W) GetAllNIP43Members() ([][]byte, error)
- func (w *W) GetBlossomStorageQuota(pubkey []byte) (quotaMB int64, err error)
- func (w *W) GetCachedEvents(f *filter.F) (event.S, bool)
- func (w *W) GetCachedJSON(f *filter.F) ([][]byte, bool)
- func (w *W) GetEventAccessInfo(serial uint64) (lastAccess int64, accessCount uint32, err error)
- func (w *W) GetFullIdPubkeyBySerial(ser *types.Uint40) (fidpk *store.IdPkTs, err error)
- func (w *W) GetFullIdPubkeyBySerials(sers []*types.Uint40) (fidpks []*store.IdPkTs, err error)
- func (w *W) GetLeastAccessedEvents(limit int, minAgeSec int64) (serials []uint64, err error)
- func (w *W) GetMarker(key string) (value []byte, err error)
- func (w *W) GetNIP43Membership(pubkey []byte) (*database.NIP43Membership, error)
- func (w *W) GetOrCreateRelayIdentitySecret() (skb []byte, err error)
- func (w *W) GetPaymentHistory(pubkey []byte) ([]database.Payment, error)
- func (w *W) GetRelayIdentitySecret() (skb []byte, err error)
- func (w *W) GetSerialById(id []byte) (ser *types.Uint40, err error)
- func (w *W) GetSerialsByIds(ids *tag.T) (serials map[string]*types.Uint40, err error)
- func (w *W) GetSerialsByIdsWithFilter(ids *tag.T, fn func(ev *event.E, ser *types.Uint40) bool) (serials map[string]*types.Uint40, err error)
- func (w *W) GetSerialsByPubkey(pubkey []byte) ([]*types.Uint40, error)
- func (w *W) GetSerialsByRange(idx database.Range) (sers types.Uint40s, err error)
- func (w *W) GetSerialsFromFilter(f *filter.F) (serials types.Uint40s, err error)
- func (w *W) GetSubscription(pubkey []byte) (*database.Subscription, error)
- func (w *W) HasMarker(key string) bool
- func (w *W) Import(rr io.Reader)
- func (w *W) ImportEventsFromReader(ctx context.Context, rr io.Reader) error
- func (w *W) ImportEventsFromStrings(ctx context.Context, eventJSONs []string, policyManager interface{ ... }) error
- func (w *W) Init(path string) error
- func (w *W) InvalidateQueryCache()
- func (w *W) IsFirstTimeUser(pubkey []byte) (bool, error)
- func (w *W) IsNIP43Member(pubkey []byte) (isMember bool, err error)
- func (w *W) IsSubscriptionActive(pubkey []byte) (bool, error)
- func (w *W) Path() string
- func (w *W) ProcessDelete(ev *event.E, admins [][]byte) (err error)
- func (w *W) PublishNIP43MembershipEvent(kind int, pubkey []byte) error
- func (w *W) QueryAllVersions(c context.Context, f *filter.F) (evs event.S, err error)
- func (w *W) QueryDeleteEventsByTargetId(c context.Context, targetEventId []byte) (evs event.S, err error)
- func (w *W) QueryEvents(c context.Context, f *filter.F) (evs event.S, err error)
- func (w *W) QueryEventsWithOptions(c context.Context, f *filter.F, includeDeleteEvents bool, showAllVersions bool) (evs event.S, err error)
- func (w *W) QueryForIds(c context.Context, f *filter.F) (idPkTs []*store.IdPkTs, err error)
- func (w *W) QueryForSerials(c context.Context, f *filter.F) (sers types.Uint40s, err error)
- func (w *W) Ready() <-chan struct{}
- func (w *W) RecordEventAccess(serial uint64, connectionID string) error
- func (w *W) RecordPayment(pubkey []byte, amount int64, invoice, preimage string) error
- func (w *W) RemoveNIP43Member(pubkey []byte) error
- func (w *W) RunMigrations()
- func (w *W) SaveEvent(c context.Context, ev *event.E) (replaced bool, err error)
- func (w *W) SetLogLevel(level string)
- func (w *W) SetMarker(key string, value []byte) error
- func (w *W) SetRelayIdentitySecret(skb []byte) error
- func (w *W) StoreInviteCode(code string, expiresAt time.Time) error
- func (w *W) Sync() error
- func (w *W) ValidateInviteCode(code string) (valid bool, err error)
- func (w *W) Wipe() error
- func (w *W) WouldReplaceEvent(ev *event.E) (bool, types.Uint40s, error)
Constants ¶
const ( // NIP43StoreName is the object store for NIP-43 membership NIP43StoreName = "nip43" // InvitesStoreName is the object store for invite codes InvitesStoreName = "invites" )
const ( // SubscriptionsStoreName is the object store for payment subscriptions SubscriptionsStoreName = "subscriptions" // PaymentsPrefix is the key prefix for payment records PaymentsPrefix = "payment:" )
const ( // DatabaseName is the IndexedDB database name DatabaseName = "orly-nostr-relay" // DatabaseVersion is incremented when schema changes require migration DatabaseVersion = 1 // MetaStoreName holds metadata like serial counters MetaStoreName = "meta" // EventSerialKey is the key for the event serial counter in meta store EventSerialKey = "event_serial" // PubkeySerialKey is the key for the pubkey serial counter in meta store PubkeySerialKey = "pubkey_serial" // RelayIdentityKey is the key for the relay identity secret RelayIdentityKey = "relay_identity" )
Variables ¶
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 CheckExpiration ¶
CheckExpiration checks if an event has expired based on its "expiration" tag
Types ¶
type JSBridge ¶ added in v0.48.9
type JSBridge struct {
// contains filtered or unexported fields
}
JSBridge wraps the WasmDB instance for JavaScript interop Exposes a relay protocol interface (NIP-01) rather than direct database access
type W ¶
type W struct {
Logger *logger
// contains filtered or unexported fields
}
W implements the database.Database interface using IndexedDB
func New ¶
New creates a new IndexedDB-based database instance with default configuration
func NewWithConfig ¶
func NewWithConfig( ctx context.Context, cancel context.CancelFunc, cfg *database.DatabaseConfig, ) (*W, error)
NewWithConfig creates a new IndexedDB-based database instance
func (*W) AddNIP43Member ¶
AddNIP43Member adds a pubkey as a NIP-43 member with the given invite code
func (*W) CheckForDeleted ¶
CheckForDeleted checks if the event has been deleted, and returns an error with prefix "blocked:" if it is. This function also allows designating admin pubkeys that may also delete the event.
func (*W) CountEvents ¶
CountEvents counts events matching a filter
func (*W) DeleteEvent ¶
DeleteEvent removes an event from the database identified by `eid`.
func (*W) DeleteEventBySerial ¶
DeleteEventBySerial removes an event and all its indexes by serial number.
func (*W) DeleteExpired ¶
func (w *W) DeleteExpired()
DeleteExpired scans for events with expiration timestamps that have passed and deletes them.
func (*W) DeleteInviteCode ¶
DeleteInviteCode removes an invite code
func (*W) EventIdsBySerial ¶
EventIdsBySerial retrieves event IDs by serial range
func (*W) Export ¶
Export writes events to a JSONL writer, optionally filtered by pubkeys
func (*W) ExtendBlossomSubscription ¶
ExtendBlossomSubscription extends a blossom subscription with storage quota
func (*W) ExtendSubscription ¶
ExtendSubscription extends a subscription by the given number of days
func (*W) FetchEventBySerial ¶
FetchEventBySerial retrieves an event by its serial number
func (*W) FetchEventsBySerials ¶
FetchEventsBySerials retrieves multiple events by their serial numbers
func (*W) GetAllNIP43Members ¶
GetAllNIP43Members returns all NIP-43 member pubkeys
func (*W) GetBlossomStorageQuota ¶
GetBlossomStorageQuota returns the storage quota for a pubkey
func (*W) GetCachedJSON ¶
Query cache methods (simplified for WASM - no caching)
func (*W) GetEventAccessInfo ¶ added in v0.46.0
GetEventAccessInfo is a stub for WasmDB.
func (*W) GetFullIdPubkeyBySerial ¶
GetFullIdPubkeyBySerial retrieves the ID, pubkey hash, and timestamp for a serial
func (*W) GetFullIdPubkeyBySerials ¶
GetFullIdPubkeyBySerials retrieves ID/pubkey/timestamp for multiple serials
func (*W) GetLeastAccessedEvents ¶ added in v0.46.0
GetLeastAccessedEvents is a stub for WasmDB.
func (*W) GetNIP43Membership ¶
func (w *W) GetNIP43Membership(pubkey []byte) (*database.NIP43Membership, error)
GetNIP43Membership returns the full membership details for a pubkey
func (*W) GetOrCreateRelayIdentitySecret ¶
func (*W) GetPaymentHistory ¶
GetPaymentHistory retrieves all payments for a pubkey
func (*W) GetSerialById ¶
GetSerialById looks up the serial number for an event ID
func (*W) GetSerialsByIds ¶
GetSerialsByIds looks up serial numbers for multiple event IDs
func (*W) GetSerialsByIdsWithFilter ¶
func (w *W) GetSerialsByIdsWithFilter(ids *tag.T, fn func(ev *event.E, ser *types.Uint40) bool) (serials map[string]*types.Uint40, err error)
GetSerialsByIdsWithFilter looks up serial numbers with a filter function
func (*W) GetSerialsByPubkey ¶
GetSerialsByPubkey returns all event serials for a given pubkey
func (*W) GetSerialsByRange ¶
GetSerialsByRange retrieves serials from an index range using cursor iteration. The index keys must end with a 5-byte serial number.
func (*W) GetSerialsFromFilter ¶
GetSerialsFromFilter is an alias for QueryForSerials for interface compatibility
func (*W) GetSubscription ¶
func (w *W) GetSubscription(pubkey []byte) (*database.Subscription, error)
GetSubscription retrieves a subscription for a pubkey
func (*W) Import ¶
Import reads events from a JSONL reader and imports them into the database
func (*W) ImportEventsFromReader ¶
ImportEventsFromReader imports events from a JSONL reader with context support
func (*W) ImportEventsFromStrings ¶
func (w *W) 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 JSON strings with policy checking
func (*W) Init ¶
Init initializes the database (no-op, done in New)
func (*W) IsFirstTimeUser ¶
IsFirstTimeUser checks if a pubkey is a first-time user (no subscription history)
func (*W) IsNIP43Member ¶
IsNIP43Member checks if a pubkey is a NIP-43 member
func (*W) IsSubscriptionActive ¶
IsSubscriptionActive checks if a pubkey has an active subscription If no subscription exists, creates a 30-day trial
func (*W) ProcessDelete ¶
ProcessDelete processes a kind 5 deletion event, deleting referenced events.
func (*W) PublishNIP43MembershipEvent ¶
PublishNIP43MembershipEvent is a no-op in WASM (events are handled by the relay)
func (*W) QueryAllVersions ¶
QueryAllVersions queries events and returns all versions of replaceable events
func (*W) QueryDeleteEventsByTargetId ¶
func (w *W) QueryDeleteEventsByTargetId(c context.Context, targetEventId []byte) (evs event.S, err error)
QueryDeleteEventsByTargetId queries for delete events targeting a specific event ID
func (*W) QueryEvents ¶
QueryEvents queries events based on a filter
func (*W) QueryEventsWithOptions ¶
func (w *W) QueryEventsWithOptions(c context.Context, f *filter.F, includeDeleteEvents bool, showAllVersions bool) (evs event.S, err error)
QueryEventsWithOptions queries events with additional options for deletion and versioning
func (*W) QueryForIds ¶
QueryForIds retrieves IdPkTs records based on a filter. Results are sorted by timestamp in reverse chronological order.
func (*W) QueryForSerials ¶
QueryForSerials takes a filter and returns matching event serials
func (*W) Ready ¶
func (w *W) Ready() <-chan struct{}
Ready returns a channel that closes when the database is ready
func (*W) RecordEventAccess ¶ added in v0.46.0
RecordEventAccess is a stub for WasmDB. Access tracking is not implemented for the WebAssembly backend as it's primarily used for client-side applications where storage management is handled differently.
func (*W) RecordPayment ¶
RecordPayment records a payment for a pubkey
func (*W) RemoveNIP43Member ¶
RemoveNIP43Member removes a pubkey from NIP-43 membership
func (*W) RunMigrations ¶
func (w *W) RunMigrations()
RunMigrations runs database migrations (handled by IndexedDB upgrade)
func (*W) SaveEvent ¶
SaveEvent saves an event to the database, generating all necessary indexes.
func (*W) StoreInviteCode ¶
StoreInviteCode stores an invite code with expiration time
func (*W) Sync ¶
Sync flushes pending writes (IndexedDB handles persistence automatically)
func (*W) ValidateInviteCode ¶
ValidateInviteCode checks if an invite code is valid (exists and not expired)
Source Files
¶
- access_tracking.go
- delete-event.go
- fetch-event.go
- helpers.go
- import-export.go
- jsbridge.go
- logger.go
- nip43.go
- query-events.go
- save-event.go
- subscriptions.go
- wasmdb.go