Enhance Directory Client Library for NIP-XX Protocol
- Introduced a TypeScript client library for the Distributed Directory Consensus Protocol (NIP-XX), providing a high-level API for managing directory events, identity resolution, and trust calculations. - Implemented core functionalities including event parsing, trust score aggregation, and replication filtering, mirroring the Go implementation. - Added comprehensive documentation and development guides for ease of use and integration. - Updated the `.gitignore` to include additional dependencies and build artifacts for the TypeScript client. - Enhanced validation mechanisms for group tag names and trust levels, ensuring robust input handling and security. - Created a new `bun.lock` file to manage package dependencies effectively.
This commit is contained in:
227
pkg/protocol/directory-client/helpers.go
Normal file
227
pkg/protocol/directory-client/helpers.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package directory_client
|
||||
|
||||
import (
|
||||
"next.orly.dev/pkg/encoders/event"
|
||||
"next.orly.dev/pkg/protocol/directory"
|
||||
)
|
||||
|
||||
// EventCollector provides utility methods for collecting specific types of
|
||||
// directory events from a slice.
|
||||
type EventCollector struct {
|
||||
events []*event.E
|
||||
}
|
||||
|
||||
// NewEventCollector creates a new event collector for the given events.
|
||||
func NewEventCollector(events []*event.E) *EventCollector {
|
||||
return &EventCollector{events: events}
|
||||
}
|
||||
|
||||
// RelayIdentities returns all relay identity declarations.
|
||||
func (ec *EventCollector) RelayIdentities() (identities []*directory.RelayIdentityAnnouncement) {
|
||||
identities = make([]*directory.RelayIdentityAnnouncement, 0)
|
||||
for _, ev := range ec.events {
|
||||
if uint16(ev.Kind) == 39100 {
|
||||
if identity, err := directory.ParseRelayIdentityAnnouncement(ev); err == nil {
|
||||
identities = append(identities, identity)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TrustActs returns all trust acts.
|
||||
func (ec *EventCollector) TrustActs() (acts []*directory.TrustAct) {
|
||||
acts = make([]*directory.TrustAct, 0)
|
||||
for _, ev := range ec.events {
|
||||
if uint16(ev.Kind) == 39101 {
|
||||
if act, err := directory.ParseTrustAct(ev); err == nil {
|
||||
acts = append(acts, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GroupTagActs returns all group tag acts.
|
||||
func (ec *EventCollector) GroupTagActs() (acts []*directory.GroupTagAct) {
|
||||
acts = make([]*directory.GroupTagAct, 0)
|
||||
for _, ev := range ec.events {
|
||||
if uint16(ev.Kind) == 39102 {
|
||||
if act, err := directory.ParseGroupTagAct(ev); err == nil {
|
||||
acts = append(acts, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PublicKeyAdvertisements returns all public key advertisements.
|
||||
func (ec *EventCollector) PublicKeyAdvertisements() (ads []*directory.PublicKeyAdvertisement) {
|
||||
ads = make([]*directory.PublicKeyAdvertisement, 0)
|
||||
for _, ev := range ec.events {
|
||||
if uint16(ev.Kind) == 39103 {
|
||||
if ad, err := directory.ParsePublicKeyAdvertisement(ev); err == nil {
|
||||
ads = append(ads, ad)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ReplicationRequests returns all replication requests.
|
||||
func (ec *EventCollector) ReplicationRequests() (requests []*directory.DirectoryEventReplicationRequest) {
|
||||
requests = make([]*directory.DirectoryEventReplicationRequest, 0)
|
||||
for _, ev := range ec.events {
|
||||
if uint16(ev.Kind) == 39104 {
|
||||
if req, err := directory.ParseDirectoryEventReplicationRequest(ev); err == nil {
|
||||
requests = append(requests, req)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ReplicationResponses returns all replication responses.
|
||||
func (ec *EventCollector) ReplicationResponses() (responses []*directory.DirectoryEventReplicationResponse) {
|
||||
responses = make([]*directory.DirectoryEventReplicationResponse, 0)
|
||||
for _, ev := range ec.events {
|
||||
if uint16(ev.Kind) == 39105 {
|
||||
if resp, err := directory.ParseDirectoryEventReplicationResponse(ev); err == nil {
|
||||
responses = append(responses, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FindRelayIdentity finds a relay identity by relay URL.
|
||||
func FindRelayIdentity(events []*event.E, relayURL string) (*directory.RelayIdentityAnnouncement, bool) {
|
||||
normalizedURL := NormalizeRelayURL(relayURL)
|
||||
for _, ev := range events {
|
||||
if uint16(ev.Kind) == 39100 {
|
||||
if identity, err := directory.ParseRelayIdentityAnnouncement(ev); err == nil {
|
||||
if NormalizeRelayURL(identity.RelayURL) == normalizedURL {
|
||||
return identity, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// FindTrustActsForRelay finds all trust acts targeting a specific relay.
|
||||
func FindTrustActsForRelay(events []*event.E, targetPubkey string) (acts []*directory.TrustAct) {
|
||||
acts = make([]*directory.TrustAct, 0)
|
||||
for _, ev := range events {
|
||||
if uint16(ev.Kind) == 39101 {
|
||||
if act, err := directory.ParseTrustAct(ev); err == nil {
|
||||
if act.TargetPubkey == targetPubkey {
|
||||
acts = append(acts, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FindGroupTagActsForRelay finds all group tag acts targeting a specific relay.
|
||||
// Note: This function needs to be updated based on the actual GroupTagAct structure
|
||||
// which doesn't have a Target field. The filtering logic should be clarified.
|
||||
func FindGroupTagActsForRelay(events []*event.E, targetPubkey string) (acts []*directory.GroupTagAct) {
|
||||
acts = make([]*directory.GroupTagAct, 0)
|
||||
for _, ev := range events {
|
||||
if uint16(ev.Kind) == 39102 {
|
||||
if act, err := directory.ParseGroupTagAct(ev); err == nil {
|
||||
// Filter by actor since GroupTagAct doesn't have a Target field
|
||||
if act.Actor == targetPubkey {
|
||||
acts = append(acts, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FindGroupTagActsByGroup finds all group tag acts for a specific group.
|
||||
func FindGroupTagActsByGroup(events []*event.E, groupID string) (acts []*directory.GroupTagAct) {
|
||||
acts = make([]*directory.GroupTagAct, 0)
|
||||
for _, ev := range events {
|
||||
if uint16(ev.Kind) == 39102 {
|
||||
if act, err := directory.ParseGroupTagAct(ev); err == nil {
|
||||
if act.GroupID == groupID {
|
||||
acts = append(acts, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TrustGraph represents a directed graph of trust relationships.
|
||||
type TrustGraph struct {
|
||||
// edges maps source pubkey -> list of trust acts
|
||||
edges map[string][]*directory.TrustAct
|
||||
}
|
||||
|
||||
// NewTrustGraph creates a new trust graph instance.
|
||||
func NewTrustGraph() *TrustGraph {
|
||||
return &TrustGraph{
|
||||
edges: make(map[string][]*directory.TrustAct),
|
||||
}
|
||||
}
|
||||
|
||||
// AddTrustAct adds a trust act to the graph.
|
||||
func (tg *TrustGraph) AddTrustAct(act *directory.TrustAct) {
|
||||
if act == nil {
|
||||
return
|
||||
}
|
||||
source := string(act.Event.Pubkey)
|
||||
tg.edges[source] = append(tg.edges[source], act)
|
||||
}
|
||||
|
||||
// GetTrustActs returns all trust acts from a source pubkey.
|
||||
func (tg *TrustGraph) GetTrustActs(source string) []*directory.TrustAct {
|
||||
return tg.edges[source]
|
||||
}
|
||||
|
||||
// GetTrustedBy returns all pubkeys that trust the given target.
|
||||
func (tg *TrustGraph) GetTrustedBy(target string) []string {
|
||||
trustedBy := make([]string, 0)
|
||||
for source, acts := range tg.edges {
|
||||
for _, act := range acts {
|
||||
if act.TargetPubkey == target {
|
||||
trustedBy = append(trustedBy, source)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return trustedBy
|
||||
}
|
||||
|
||||
// GetTrustTargets returns all pubkeys trusted by the given source.
|
||||
func (tg *TrustGraph) GetTrustTargets(source string) []string {
|
||||
acts := tg.edges[source]
|
||||
targets := make(map[string]bool)
|
||||
for _, act := range acts {
|
||||
targets[act.TargetPubkey] = true
|
||||
}
|
||||
|
||||
result := make([]string, 0, len(targets))
|
||||
for target := range targets {
|
||||
result = append(result, target)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BuildTrustGraph builds a trust graph from a collection of events.
|
||||
func BuildTrustGraph(events []*event.E) *TrustGraph {
|
||||
graph := NewTrustGraph()
|
||||
for _, ev := range events {
|
||||
if uint16(ev.Kind) == 39101 {
|
||||
if act, err := directory.ParseTrustAct(ev); err == nil {
|
||||
graph.AddTrustAct(act)
|
||||
}
|
||||
}
|
||||
}
|
||||
return graph
|
||||
}
|
||||
Reference in New Issue
Block a user