# API Reference

## Public API Contract

- Public surface is the `kyrodb` package exports in `src/kyrodb/__init__.py`.
- Public client methods return SDK models, not generated protobuf classes.
- Generated protobuf modules (`kyrodb._generated.*`) are internal implementation details.

## Core Clients

- `KyroDBClient`: synchronous gRPC client
- `AsyncKyroDBClient`: asynchronous gRPC client

Both clients expose the same operational surface.

Constructor options (both clients):

- `target="127.0.0.1:50051"`
- `api_key: str | None = None`
- `tls: TLSConfig | None = None`
- `default_namespace: str = ""`
- `default_timeout_s: float | None = 30.0`
- `retry_policy: RetryPolicy | None = None`
- `circuit_breaker_policy: CircuitBreakerPolicy | None = None`
- `channel_options: Sequence[tuple[str, int | str]] | None = None`
- `lb_policy_name: str | None = None`
- `compression: grpc.Compression | None = None`
- `max_unary_batch_size: int = 10000`

## Connection + Lifecycle

- `wait_for_ready(timeout_s=...) -> None`
- `close() -> None` (sync)
- `close() -> Awaitable[None]` (async)
- `set_api_key(api_key: str | None) -> None`
- `set_api_key_provider(provider: Callable[[], str | None]) -> None`
- `set_api_key_provider_async(provider: Callable[[], Awaitable[str | None]]) -> Awaitable[None]` (async client)

Timeout semantics for all methods:

- Omitted `timeout_s`: use client default timeout (`default_timeout_s`, default `30.0`).
- `timeout_s=None`: explicit unbounded timeout.
- `timeout_s>0`: explicit per-call timeout override.

Transport defaults:

- keepalive and message-size channel options are applied by default
- user-supplied `channel_options` override matching defaults by key

## Write Operations

- `insert(...) -> InsertAck`
- `bulk_insert(...) -> InsertAck`
- `bulk_load_hnsw(...) -> BulkLoadResult`
- `delete(...) -> DeleteResult`
- `update_metadata(...) -> UpdateMetadataResult`
- `batch_delete_ids(...) -> BatchDeleteResult`

Batch behavior notes:

- `bulk_query(...)` and `batch_delete_ids(...)` auto-split large ID lists using `max_unary_batch_size`.
- Result models are aggregated and returned as a single response object.

## Read Operations

- `query(...) -> QueryResult`
- `search(..., filter: MetadataFilter | None = None, ...) -> SearchResponse`
- `bulk_search(requests: Iterable[SearchQuery] | AsyncIterable[SearchQuery], ...) -> Iterator[SearchResponse] / AsyncIterator[SearchResponse]`
- `bulk_query(...) -> BulkQueryResult`

## Health + Admin

- `health(...) -> HealthResult`
- `metrics(...) -> MetricsResult`
- `flush_hot_tier(...) -> FlushResult`
- `create_snapshot(...) -> SnapshotResult`
- `get_config(...) -> ConfigResult`

## Models

- `InsertItem`
- `InsertAck`
- `MetadataFilter`
- `SearchQuery`
- `BulkLoadResult`
- `DeleteResult`
- `UpdateMetadataResult`
- `BulkQueryResult`
- `BatchDeleteResult`
- `QueryResult`
- `SearchHit`
- `SearchResponse`
- `HealthResult`
- `MetricsResult`
- `FlushResult`
- `SnapshotResult`
- `ConfigResult`

## Auth + TLS

- `TLSConfig(root_certificates=None, private_key=None, certificate_chain=None)`
- API key is passed via `x-api-key` metadata

## Retry

- `RetryPolicy(max_attempts=3, initial_backoff_s=0.05, max_backoff_s=0.5, multiplier=2.0, jitter_ratio=0.2, max_elapsed_time_s=2.0, retryable_codes=...)`
- `CircuitBreakerPolicy(failure_threshold=8, recovery_timeout_s=30.0, half_open_success_threshold=2, tracked_codes=...)`
- Read-only calls retry; writes do not retry by default.

## Filter Builders

- `exact(key, value)`
- `in_values(key, values)`
- `range_match(key, gte=None, lte=None, gt=None, lt=None)`
- `all_of(filters)`
- `any_of(filters)`
- `negate(filter_value)`

Notes:

- `RangeMatch` in protobuf has a `oneof` bound; when multiple bounds are provided to
  `range_match(...)`, the SDK composes them as `all_of([single-bound-filters...])`.
- Filter builders return SDK `MetadataFilter` wrappers; protobuf internals remain private.
