Initial scaffold for kestrove-core

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-15 18:30:14 +09:00
co-authored by Claude Opus 5.5
commit 462fbbc523
34 changed files with 2063 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "kv-store"
description = "Local encrypted replica (SQLite). Holds ciphertext only."
version.workspace = true
edition.workspace = true
license.workspace = true
publish.workspace = true
[dependencies]
kv-proto.workspace = true
uuid.workspace = true
thiserror.workspace = true
+42
View File
@@ -0,0 +1,42 @@
//! Local encrypted replica (milestone M1, kestrove-spec/docs/07).
//!
//! The store holds the same `Envelope` bytes the server holds, plus sync
//! bookkeeping. It never sees plaintext. Planned schema (rusqlite, bundled):
//!
//! ```sql
//! CREATE TABLE vault (vault_id BLOB PRIMARY KEY, sealed_key TEXT, meta TEXT, cursor INTEGER, manifest_version INTEGER, manifest_hash BLOB);
//! CREATE TABLE item (vault_id BLOB, item_id BLOB, revision INTEGER, deleted INTEGER,
//! wrapped_item_key TEXT, payload TEXT,
//! state TEXT CHECK(state IN ('clean','pending')), base_revision INTEGER, base_payload TEXT,
//! PRIMARY KEY (vault_id, item_id));
//! CREATE TABLE history (vault_id BLOB, item_id BLOB, revision INTEGER, wrapped_item_key TEXT, payload TEXT);
//! ```
use kv_proto::ItemRecord;
use uuid::Uuid;
#[derive(Debug, thiserror::Error)]
pub enum StoreError {
#[error("storage I/O: {0}")]
Io(String),
#[error("not found")]
NotFound,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SyncState {
Clean,
/// Edited locally; `base_revision` is what the edit was made against.
Pending { base_revision: u64 },
}
/// Storage backend. The SQLite implementation and an in-memory one for tests come in M1.
pub trait Store: Send + Sync {
fn cursor(&self, vault: Uuid) -> Result<u64, StoreError>;
fn set_cursor(&self, vault: Uuid, revision: u64) -> Result<(), StoreError>;
fn put_remote(&self, vault: Uuid, record: &ItemRecord) -> Result<(), StoreError>;
fn put_local(&self, vault: Uuid, record: &ItemRecord, state: SyncState) -> Result<(), StoreError>;
fn pending(&self, vault: Uuid) -> Result<Vec<(ItemRecord, u64)>, StoreError>;
fn get(&self, vault: Uuid, item: Uuid) -> Result<(ItemRecord, SyncState), StoreError>;
fn list(&self, vault: Uuid) -> Result<Vec<ItemRecord>, StoreError>;
}