diff options
| author | bndw <ben@bdw.to> | 2026-02-13 19:12:28 -0800 |
|---|---|---|
| committer | bndw <ben@bdw.to> | 2026-02-13 19:12:28 -0800 |
| commit | 656748ea286ff7eac6cbe1b241ad31212892ba61 (patch) | |
| tree | e9685b4a585809463bdf51a4d1ecb7f7c5efaf70 /internal/handler/grpc | |
| parent | 83876eae868bd1e4fb6b9a823a6e8173919f290d (diff) | |
feat: implement NIP-09 (deletions) and NIP-11 (relay info)
NIP-11 (Relay Information Document):
- Serves relay metadata at GET / with Accept: application/nostr+json
- Returns name, description, supported NIPs, limitations
- CORS headers for browser compatibility
NIP-09 (Event Deletion):
- Kind 5 events delete events referenced in 'e' tags
- Only authors can delete their own events
- Soft delete (marks deleted=1)
- Records deletion in deletions table
- Works across all protocols (gRPC, Connect, WebSocket)
Fixed deletions schema:
- deleted_event_id as PRIMARY KEY (not deletion_event_id)
- Allows one deletion event to delete multiple events
3 new tests, 44 total tests passing
Supported NIPs now: 1, 9, 11
Diffstat (limited to 'internal/handler/grpc')
| -rw-r--r-- | internal/handler/grpc/server.go | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/internal/handler/grpc/server.go b/internal/handler/grpc/server.go index b65b527..b1ffd96 100644 --- a/internal/handler/grpc/server.go +++ b/internal/handler/grpc/server.go | |||
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | type EventStore interface { | 13 | type EventStore interface { |
| 14 | StoreEvent(context.Context, *storage.EventData) error | 14 | StoreEvent(context.Context, *storage.EventData) error |
| 15 | QueryEvents(context.Context, []*pb.Filter, *storage.QueryOptions) ([]*pb.Event, error) | 15 | QueryEvents(context.Context, []*pb.Filter, *storage.QueryOptions) ([]*pb.Event, error) |
| 16 | ProcessDeletion(context.Context, *pb.Event) error | ||
| 16 | } | 17 | } |
| 17 | 18 | ||
| 18 | type Server struct { | 19 | type Server struct { |
| @@ -75,6 +76,16 @@ func (s *Server) PublishEvent(ctx context.Context, req *pb.PublishEventRequest) | |||
| 75 | return nil, fmt.Errorf("failed to store event: %w", err) | 76 | return nil, fmt.Errorf("failed to store event: %w", err) |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 79 | if req.Event.Kind == 5 { | ||
| 80 | if err := s.store.ProcessDeletion(ctx, req.Event); err != nil { | ||
| 81 | return &pb.PublishEventResponse{ | ||
| 82 | Accepted: false, | ||
| 83 | Message: fmt.Sprintf("deletion processing failed: %v", err), | ||
| 84 | CanonicalJson: canonicalJSON, | ||
| 85 | }, nil | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 78 | s.subs.MatchAndFan(req.Event) | 89 | s.subs.MatchAndFan(req.Event) |
| 79 | 90 | ||
| 80 | return &pb.PublishEventResponse{ | 91 | return &pb.PublishEventResponse{ |
