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