summaryrefslogtreecommitdiffstats
path: root/internal/handler/websocket/handler.go
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-13 19:12:28 -0800
committerbndw <ben@bdw.to>2026-02-13 19:12:28 -0800
commit656748ea286ff7eac6cbe1b241ad31212892ba61 (patch)
treee9685b4a585809463bdf51a4d1ecb7f7c5efaf70 /internal/handler/websocket/handler.go
parent83876eae868bd1e4fb6b9a823a6e8173919f290d (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/websocket/handler.go')
-rw-r--r--internal/handler/websocket/handler.go13
1 files changed, 13 insertions, 0 deletions
diff --git a/internal/handler/websocket/handler.go b/internal/handler/websocket/handler.go
index cef83dd..4a7db0d 100644
--- a/internal/handler/websocket/handler.go
+++ b/internal/handler/websocket/handler.go
@@ -17,6 +17,7 @@ import (
17type EventStore interface { 17type EventStore interface {
18 StoreEvent(context.Context, *storage.EventData) error 18 StoreEvent(context.Context, *storage.EventData) error
19 QueryEvents(context.Context, []*pb.Filter, *storage.QueryOptions) ([]*pb.Event, error) 19 QueryEvents(context.Context, []*pb.Filter, *storage.QueryOptions) ([]*pb.Event, error)
20 ProcessDeletion(context.Context, *pb.Event) error
20} 21}
21 22
22type Handler struct { 23type Handler struct {
@@ -32,6 +33,11 @@ func NewHandler(store EventStore, subs *subscription.Manager) *Handler {
32} 33}
33 34
34func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 35func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
36 if r.Method == "GET" && r.Header.Get("Accept") == "application/nostr+json" {
37 h.ServeNIP11(w, r)
38 return
39 }
40
35 conn, err := websocket.Accept(w, r) 41 conn, err := websocket.Accept(w, r)
36 if err != nil { 42 if err != nil {
37 log.Printf("WebSocket accept failed: %v", err) 43 log.Printf("WebSocket accept failed: %v", err)
@@ -125,6 +131,13 @@ func (h *Handler) handleEvent(ctx context.Context, conn *websocket.Conn, raw []j
125 return nil 131 return nil
126 } 132 }
127 133
134 if pbEvent.Kind == 5 {
135 if err := h.store.ProcessDeletion(ctx, pbEvent); err != nil {
136 h.sendOK(ctx, conn, event.ID, false, fmt.Sprintf("deletion failed: %v", err))
137 return nil
138 }
139 }
140
128 h.subs.MatchAndFan(pbEvent) 141 h.subs.MatchAndFan(pbEvent)
129 142
130 h.sendOK(ctx, conn, event.ID, true, "") 143 h.sendOK(ctx, conn, event.ID, true, "")