capri

Manage Khepri stores and typed, versioned repositories.

Define a repository with the initial decoder, bind it to a non-root path, and use it for record operations. Migrations are atomically reversible transformations for schema and values.

Values

pub fn add_migration(
  repository: types.Repository(from),
  to_version: Int,
  decoder: types.Decoder(to),
  forward: fn(types.Entry(from)) -> Result(
    types.Entry(to),
    types.MigrationFailure,
  ),
  reverse: fn(types.Entry(to)) -> Result(
    types.Entry(from),
    types.MigrationFailure,
  ),
) -> Result(types.Repository(to), types.Error)

Append a reversible per-entry migration to the repository definition.

to_version must increment the current version by exactly one. The returned repository carries the new record type. During safe execution, reversing every transformed entry must reproduce the exact original keys and payloads.

pub fn add_unsafe_migration(
  repository: types.Repository(from),
  to_version: Int,
  decoder: types.Decoder(to),
  forward: fn(types.Entry(from)) -> Result(
    types.Entry(to),
    types.MigrationFailure,
  ),
) -> Result(types.Repository(to), types.Error)

Append a forward-only per-entry migration to the repository definition.

to_version must increment the current version by exactly one. Safe migration execution rejects this step; execute it only through unsafe_migrate_to_current, which permits irreversible changes and data loss.

pub fn all(
  store: types.StoreHandle,
  prefix: types.Prefix(record),
) -> yielder.Yielder(
  Result(types.Child(record), types.OperationError),
)

Lazily yield every decoded direct child beneath a repository prefix.

Descendants below those children are not included. Each item is a Result, and iteration stops after the first page or decode error. Internal pages use separate Khepri snapshots, so concurrent changes may appear between pages.

pub fn bind(
  store: types.StoreHandle,
  path: types.Path,
  repository: types.Repository(record),
) -> Result(types.Prefix(record), types.Error)

Open an existing repository at path, or register it when absent.

Existing metadata must match the repository identity and version. New registration validates and canonicalizes existing direct child payloads. Registration races are resolved by reopening after another caller wins.

pub fn child(
  prefix: types.Prefix(record),
  key: types.Key,
) -> types.TypedPath(record)

Return the repository-bound path of a direct child.

pub fn cluster_nodes(
  store: types.StoreHandle,
) -> Result(List(node.Node), khepri_error.Error)

Return the nodes currently belonging to the store’s cluster.

pub fn connect(
  id: atom.Atom,
) -> Result(types.StoreHandle, khepri_error.Error)

Connect to an existing running store and return its handle.

Returns StoreNotRunning when the named store is unavailable. Prefer init when the store may need to be started.

pub fn delete(
  store: types.StoreHandle,
  record_path: types.TypedPath(record),
) -> Result(option.Option(record), types.OperationError)

Atomically delete and return a repository-bound record.

Missing records return None. Returning the deleted value makes single-use resources safe without exposing a separate destructive transaction API.

pub fn get(
  store: types.StoreHandle,
  record_path: types.TypedPath(record),
) -> Result(option.Option(record), types.OperationError)

Read and decode a repository-bound record.

Returns Ok(None) when the exact node is absent. A node with invalid or structurally corrupt data returns an error rather than being treated as missing.

pub fn init(
  id: atom.Atom,
  directory: String,
) -> Result(types.StoreHandle, khepri_error.Error)

Connect to a named running store, or start it in directory.

The returned handle identifies the store for subsequent operations.

pub fn insert(
  store: types.StoreHandle,
  record_path: types.TypedPath(record),
  value: record,
) -> Result(Nil, types.OperationError)

Insert a record only when its exact node is absent.

Returns AlreadyExists without replacing an existing node. The value is validated through the repository decoder before persistence.

pub fn is_running(store: types.StoreHandle) -> Bool

Return whether the store represented by store is running locally.

pub fn migrate_to_current(
  store: types.StoreHandle,
  prefix_path: types.Path,
  repository: types.Repository(record),
) -> Result(Nil, types.Error)

Atomically migrate a registered repository to its declared version.

Every applied step must include a reverse callback that reproduces the exact original keys and payloads. All callbacks and validation complete before the commit; any failed proof or callback leaves the repository unchanged. An already-current repository returns Ok(Nil).

pub fn open(
  store: types.StoreHandle,
  path: types.Path,
  repository: types.Repository(record),
) -> Result(types.Prefix(record), types.Error)

Open and validate an existing repository-bound prefix.

The path must be non-root and non-reserved. Metadata must exist and match the repository identity and version; child payloads are not decoded, rewritten, or canonicalized.

pub fn put(
  store: types.StoreHandle,
  record_path: types.TypedPath(record),
  value: record,
) -> Result(Nil, types.OperationError)

Insert or replace a repository-bound record.

The value is encoded and decoded through the repository decoder before it is persisted. Existing corrupt data is reported instead of overwritten.

pub fn register(
  store: types.StoreHandle,
  path: types.Path,
  repository: types.Repository(record),
) -> Result(types.Prefix(record), types.Error)

Register repository metadata at an unregistered prefix.

The path must be non-root and non-reserved. Existing direct child payloads are decoded and canonicalized before the atomic commit. Registration fails if metadata already exists; use open for an existing repository or bind when either state is acceptable.

pub fn repository(
  id: String,
  version: Int,
  decoder: types.Decoder(record),
) -> Result(types.Repository(record), types.Error)

Define the initial version of a typed repository.

The identifier must be non-empty and version must be at least one. This only builds a definition; use bind, register, or open to obtain a capability for a store path.

pub fn reset_and_join_cluster(
  store: types.StoreHandle,
  peer: node.Node,
) -> Result(types.StoreHandle, khepri_error.Error)

Erase local data, leave the current cluster, and join peer’s cluster.

This is the primary way to join a cluster. It is destructive: local data may already be erased even when the function returns an error.

pub fn reset_local_member(
  store: types.StoreHandle,
) -> Result(Nil, khepri_error.Error)

Leave the cluster and erase all data for this local member.

This operation is destructive and cannot be undone by Capri.

pub fn stop(
  store: types.StoreHandle,
) -> Result(Nil, khepri_error.Error)

Stop the store represented by store.

pub fn unsafe_migrate_to_current(
  store: types.StoreHandle,
  prefix_path: types.Path,
  repository: types.Repository(record),
) -> Result(Nil, types.Error)

Atomically migrate while permitting irreversible changes and data loss.

This may execute forward-only steps and skips reversibility proofs. All callbacks and validation still complete before the commit. Use only when loss is intentional. An already-current repository returns Ok(Nil).

pub fn wait_until_ready(
  store: types.StoreHandle,
  timeout_ms: Int,
) -> Result(types.StoreHandle, khepri_error.Error)

Wait up to timeout_ms for leader election to complete.

Returns the same store handle when the store becomes ready.

Search Document