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