diff options
Diffstat (limited to 'proto/nostr/v1/nostr.proto')
| -rw-r--r-- | proto/nostr/v1/nostr.proto | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/proto/nostr/v1/nostr.proto b/proto/nostr/v1/nostr.proto new file mode 100644 index 0000000..7e8eacb --- /dev/null +++ b/proto/nostr/v1/nostr.proto | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | syntax = "proto3"; | ||
| 2 | |||
| 3 | package nostr.v1; | ||
| 4 | |||
| 5 | option go_package = "northwest.io/nostr-grpc/api/nostr/v1;nostrv1"; | ||
| 6 | |||
| 7 | // Core Nostr event as defined in NIP-01 | ||
| 8 | message Event { | ||
| 9 | string id = 1; | ||
| 10 | string pubkey = 2; | ||
| 11 | int64 created_at = 3; | ||
| 12 | int32 kind = 4; | ||
| 13 | repeated Tag tags = 5; | ||
| 14 | string content = 6; | ||
| 15 | string sig = 7; | ||
| 16 | |||
| 17 | // Optional: only populated if client requests verification | ||
| 18 | // Contains exact canonical JSON bytes that were signed | ||
| 19 | optional bytes canonical_json = 8; | ||
| 20 | } | ||
| 21 | |||
| 22 | // Tag is an array of strings (e.g., ["e", "event_id", "relay_url"]) | ||
| 23 | message Tag { | ||
| 24 | repeated string values = 1; | ||
| 25 | } | ||
| 26 | |||
| 27 | // Nostr filter for querying events (REQ) | ||
| 28 | message Filter { | ||
| 29 | repeated string ids = 1; | ||
| 30 | repeated string authors = 2; // pubkeys | ||
| 31 | repeated int32 kinds = 3; | ||
| 32 | repeated string e_tags = 4; // #e tag values | ||
| 33 | repeated string p_tags = 5; // #p tag values | ||
| 34 | optional int64 since = 6; | ||
| 35 | optional int64 until = 7; | ||
| 36 | optional int32 limit = 8; | ||
| 37 | |||
| 38 | // Extension: support for arbitrary tag filters | ||
| 39 | map<string, TagFilter> tag_filters = 9; | ||
| 40 | } | ||
| 41 | |||
| 42 | // Filter for arbitrary tags | ||
| 43 | message TagFilter { | ||
| 44 | repeated string values = 1; | ||
| 45 | } | ||
| 46 | |||
| 47 | // Request to publish a single event | ||
| 48 | message PublishEventRequest { | ||
| 49 | Event event = 1; | ||
| 50 | } | ||
| 51 | |||
| 52 | // Response after publishing an event | ||
| 53 | message PublishEventResponse { | ||
| 54 | bool accepted = 1; | ||
| 55 | string message = 2; // Error message or "duplicate" or "success" | ||
| 56 | |||
| 57 | // Always include canonical JSON so client can verify | ||
| 58 | // what the relay stored | ||
| 59 | bytes canonical_json = 3; | ||
| 60 | } | ||
| 61 | |||
| 62 | // Request to subscribe to events matching filters | ||
| 63 | message SubscribeRequest { | ||
| 64 | repeated Filter filters = 1; | ||
| 65 | |||
| 66 | // If true, include canonical_json in streamed Event messages | ||
| 67 | // Allows client-side signature verification | ||
| 68 | // Default: false (most clients trust the relay) | ||
| 69 | bool include_canonical_json = 2; | ||
| 70 | |||
| 71 | // Optional client-provided subscription ID for tracking | ||
| 72 | string subscription_id = 3; | ||
| 73 | } | ||
| 74 | |||
| 75 | // Request to unsubscribe from an active subscription | ||
| 76 | message UnsubscribeRequest { | ||
| 77 | string subscription_id = 1; | ||
| 78 | } | ||
| 79 | |||
| 80 | // Batch publish request | ||
| 81 | message PublishBatchRequest { | ||
| 82 | repeated Event events = 1; | ||
| 83 | } | ||
| 84 | |||
| 85 | // Batch publish response | ||
| 86 | message PublishBatchResponse { | ||
| 87 | repeated PublishEventResponse results = 1; | ||
| 88 | } | ||
| 89 | |||
| 90 | // Paginated query request | ||
| 91 | message QueryRequest { | ||
| 92 | repeated Filter filters = 1; | ||
| 93 | bool include_canonical_json = 2; | ||
| 94 | |||
| 95 | // Pagination | ||
| 96 | string cursor = 3; // Opaque cursor from previous response | ||
| 97 | int32 page_size = 4; // Default: 100 | ||
| 98 | } | ||
| 99 | |||
| 100 | // Paginated query response | ||
| 101 | message QueryResponse { | ||
| 102 | repeated Event events = 1; | ||
| 103 | string next_cursor = 2; // Empty if no more results | ||
| 104 | int32 total_count = 3; // Optional: total matching events | ||
| 105 | } | ||
| 106 | |||
| 107 | // Event count request (NIP-45) | ||
| 108 | message CountRequest { | ||
| 109 | repeated Filter filters = 1; | ||
| 110 | } | ||
| 111 | |||
| 112 | // Event count response | ||
| 113 | message CountResponse { | ||
| 114 | int64 count = 1; | ||
| 115 | } | ||
| 116 | |||
| 117 | // Empty message | ||
| 118 | message Empty {} | ||
| 119 | |||
| 120 | // Main relay service | ||
| 121 | service NostrRelay { | ||
| 122 | // Publish a single event | ||
| 123 | rpc PublishEvent(PublishEventRequest) returns (PublishEventResponse); | ||
| 124 | |||
| 125 | // Subscribe to events matching filters (streaming) | ||
| 126 | rpc Subscribe(SubscribeRequest) returns (stream Event); | ||
| 127 | |||
| 128 | // Unsubscribe from an active subscription | ||
| 129 | rpc Unsubscribe(UnsubscribeRequest) returns (Empty); | ||
| 130 | |||
| 131 | // gRPC-specific: batch publish | ||
| 132 | rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse); | ||
| 133 | |||
| 134 | // gRPC-specific: paginated query (non-streaming) | ||
| 135 | rpc QueryEvents(QueryRequest) returns (QueryResponse); | ||
| 136 | |||
| 137 | // Event counts (NIP-45) | ||
| 138 | rpc CountEvents(CountRequest) returns (CountResponse); | ||
| 139 | } | ||
| 140 | |||
| 141 | // Admin service (optional, secured separately) | ||
| 142 | service RelayAdmin { | ||
| 143 | rpc GetStats(Empty) returns (RelayStats); | ||
| 144 | rpc GetConnections(Empty) returns (ConnectionList); | ||
| 145 | rpc BanPublicKey(BanRequest) returns (Empty); | ||
| 146 | rpc GetStorageInfo(Empty) returns (StorageStats); | ||
| 147 | } | ||
| 148 | |||
| 149 | // Relay statistics | ||
| 150 | message RelayStats { | ||
| 151 | int64 total_events = 1; | ||
| 152 | int64 total_subscriptions = 2; | ||
| 153 | int64 connected_clients = 3; | ||
| 154 | int64 events_per_second = 4; | ||
| 155 | int64 uptime_seconds = 5; | ||
| 156 | } | ||
| 157 | |||
| 158 | // List of active connections | ||
| 159 | message ConnectionList { | ||
| 160 | repeated Connection connections = 1; | ||
| 161 | } | ||
| 162 | |||
| 163 | // Single connection info | ||
| 164 | message Connection { | ||
| 165 | string client_id = 1; | ||
| 166 | string protocol = 2; // "websocket" or "grpc" | ||
| 167 | int64 connected_at = 3; | ||
| 168 | int32 active_subscriptions = 4; | ||
| 169 | } | ||
| 170 | |||
| 171 | // Request to ban a public key | ||
| 172 | message BanRequest { | ||
| 173 | string pubkey = 1; | ||
| 174 | int64 until = 2; // Unix timestamp, 0 for permanent | ||
| 175 | string reason = 3; | ||
| 176 | } | ||
| 177 | |||
| 178 | // Storage statistics | ||
| 179 | message StorageStats { | ||
| 180 | int64 total_bytes = 1; | ||
| 181 | int64 total_events = 2; | ||
| 182 | int64 db_size_bytes = 3; | ||
| 183 | } | ||
