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;
}