summaryrefslogtreecommitdiffstats
path: root/proto/nostr/v1/nostr.proto
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-13 17:35:32 -0800
committerbndw <ben@bdw.to>2026-02-13 17:35:32 -0800
commit6c840f03524187d1f056fdaa70e5f1f9b24cf793 (patch)
tree9b068d5125e79320321ac1a35df30f43482d4aba /proto/nostr/v1/nostr.proto
parent581ceecbf046f99b39885c74e2780a5320e5b15e (diff)
feat: add Protocol Buffer definitions and build tooling
Diffstat (limited to 'proto/nostr/v1/nostr.proto')
-rw-r--r--proto/nostr/v1/nostr.proto183
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 @@
1syntax = "proto3";
2
3package nostr.v1;
4
5option go_package = "northwest.io/nostr-grpc/api/nostr/v1;nostrv1";
6
7// Core Nostr event as defined in NIP-01
8message 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"])
23message Tag {
24 repeated string values = 1;
25}
26
27// Nostr filter for querying events (REQ)
28message 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
43message TagFilter {
44 repeated string values = 1;
45}
46
47// Request to publish a single event
48message PublishEventRequest {
49 Event event = 1;
50}
51
52// Response after publishing an event
53message 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
63message 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
76message UnsubscribeRequest {
77 string subscription_id = 1;
78}
79
80// Batch publish request
81message PublishBatchRequest {
82 repeated Event events = 1;
83}
84
85// Batch publish response
86message PublishBatchResponse {
87 repeated PublishEventResponse results = 1;
88}
89
90// Paginated query request
91message 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
101message 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)
108message CountRequest {
109 repeated Filter filters = 1;
110}
111
112// Event count response
113message CountResponse {
114 int64 count = 1;
115}
116
117// Empty message
118message Empty {}
119
120// Main relay service
121service 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)
142service 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
150message 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
159message ConnectionList {
160 repeated Connection connections = 1;
161}
162
163// Single connection info
164message 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
172message BanRequest {
173 string pubkey = 1;
174 int64 until = 2; // Unix timestamp, 0 for permanent
175 string reason = 3;
176}
177
178// Storage statistics
179message StorageStats {
180 int64 total_bytes = 1;
181 int64 total_events = 2;
182 int64 db_size_bytes = 3;
183}