waymaker-client/proto/kv.proto

208 lines
5.5 KiB
Protocol Buffer

syntax = "proto3";
package waymaker.kv;
option go_package = "/apis/waymaker_kv";
// ============================================================
// WaymakerKvService — distributed key-value store implemented
// as a thin façade over the streams subsystem. Each KV bucket
// is backed by a stream named `kv:<bucket>`; KV revisions are
// stream sequence numbers; KV deletes are tombstones (per the
// WIRE_SPEC.md tombstone header convention).
//
// The service lives in its own proto so the wire surface is
// composable: an operator could ship a KV-only build, or layer
// KV on top of someone else's streams implementation.
// ============================================================
service WaymakerKvService {
// ----- Bucket lifecycle -------------------------------------
rpc CreateBucket (KvCreateBucketRequest) returns (KvCreateBucketResponse);
rpc DeleteBucket (KvDeleteBucketRequest) returns (KvDeleteBucketResponse);
// ----- Mutations --------------------------------------------
rpc Put (KvPutRequest) returns (KvPutResponse);
// CAS create — succeeds only when the key has never been
// written or its current value is a tombstone.
rpc Create (KvCreateRequest) returns (KvPutResponse);
// CAS update — succeeds only when `expected_revision`
// matches the server-side revision.
rpc Update (KvUpdateRequest) returns (KvPutResponse);
rpc Delete (KvDeleteRequest) returns (KvDeleteResponse);
// ----- Reads ------------------------------------------------
rpc Get (KvGetRequest) returns (KvGetResponse);
rpc Keys (KvKeysRequest) returns (KvKeysResponse);
rpc History (KvHistoryRequest) returns (KvHistoryResponse);
// ----- TTL refresh ------------------------------------------
rpc Touch (KvTouchRequest) returns (KvPutResponse);
// ----- Watch ------------------------------------------------
// Server-streamed event flow for a single bucket. When `key`
// is empty, every put/delete in the bucket fans out; when
// `key` is set, only events at that key are emitted.
rpc Watch (KvWatchRequest) returns (stream KvWatchEvent);
}
message KvCreateBucketRequest {
string bucket = 1;
uint64 max_bytes = 2; // 0 = unbounded
uint64 max_value_size = 3; // 0 = no per-value cap
// Bucket-level TTL (ms). 0 = no time-based eviction.
// Independent of per-key TTL set via Put.
uint64 max_age_ms = 4;
bool ephemeral = 5;
// Per-key revision cap. 0 (default) = unbounded — history depth
// is then bounded only by the bucket's stream-level retention
// (max_age_ms / max_bytes). When N > 0, after each successful
// write to a key, older revisions of *that key* beyond the N
// most recent are dropped via per-message pruning. Useful when
// one bucket hosts many keys with very different write rates —
// a fast-churning key won't crowd out older revisions of a
// slow-changing key. NATS JetStream's "MaxRevisions" semantic.
uint64 max_revisions = 6;
}
message KvCreateBucketResponse {
bool success = 1;
string result_code = 2; // "ok" | "already_exists" | "invalid_config" | "internal"
string message = 3;
}
message KvDeleteBucketRequest { string bucket = 1; }
message KvDeleteBucketResponse {
bool success = 1;
string result_code = 2; // "ok" | "no_such_bucket" | "internal"
string message = 3;
}
message KvPutRequest {
string bucket = 1;
string key = 2;
bytes value = 3;
uint64 ttl_ms = 4; // per-key TTL; 0 = no TTL
}
message KvCreateRequest {
string bucket = 1;
string key = 2;
bytes value = 3;
uint64 ttl_ms = 4;
}
message KvUpdateRequest {
string bucket = 1;
string key = 2;
bytes value = 3;
// The revision the caller believes is current. Server returns
// wrong_revision if mismatch.
uint64 expected_revision = 4;
uint64 ttl_ms = 5;
}
message KvPutResponse {
bool success = 1;
// "ok" | "no_such_bucket" | "wrong_revision" | "invalid_key" | "internal"
string result_code = 2;
string message = 3;
uint64 revision = 4;
}
message KvGetRequest {
string bucket = 1;
string key = 2;
}
message KvGetResponse {
bool success = 1;
string result_code = 2;
string message = 3;
optional KvEntry entry = 4;
}
message KvEntry {
bytes value = 1;
uint64 revision = 2;
int64 ts_ms = 3;
}
message KvDeleteRequest {
string bucket = 1;
string key = 2;
}
message KvDeleteResponse {
bool success = 1;
string result_code = 2;
string message = 3;
uint64 revision = 4;
}
message KvKeysRequest { string bucket = 1; }
message KvKeysResponse {
bool success = 1;
string result_code = 2;
string message = 3;
repeated KvKeyEntry entries = 4;
}
message KvKeyEntry {
string key = 1;
uint64 revision = 2;
bool deleted = 3;
}
message KvHistoryRequest {
string bucket = 1;
string key = 2;
uint64 from_revision = 3; // 0 = from beginning
uint64 limit = 4; // 0 = server default
}
message KvHistoryResponse {
bool success = 1;
string result_code = 2;
string message = 3;
repeated KvHistoryEntry entries = 4;
}
message KvHistoryEntry {
bytes value = 1;
uint64 revision = 2;
int64 ts_ms = 3;
bool deleted = 4;
}
message KvTouchRequest {
string bucket = 1;
string key = 2;
uint64 ttl_ms = 3;
}
message KvWatchRequest {
string bucket = 1;
string key = 2; // empty = whole bucket
}
message KvWatchEvent {
oneof event {
KvPutEvent put = 1;
KvDeleteEvent delete = 2;
}
}
message KvPutEvent {
string key = 1;
bytes value = 2;
uint64 revision = 3;
int64 ts_ms = 4;
}
message KvDeleteEvent {
string key = 1;
uint64 revision = 2;
int64 ts_ms = 3;
}