{"id":49828899,"url":"https://github.com/cachekit-io/cachekit-rs","last_synced_at":"2026-05-13T19:30:44.829Z","repository":{"id":353877659,"uuid":"1183048148","full_name":"cachekit-io/cachekit-rs","owner":"cachekit-io","description":"Production-ready Rust caching SDK for CacheKit protocol","archived":false,"fork":false,"pushed_at":"2026-04-26T02:48:13.000Z","size":145,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-26T03:09:51.310Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cachekit-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-16T08:12:26.000Z","updated_at":"2026-04-26T02:48:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cachekit-io/cachekit-rs","commit_stats":null,"previous_names":["cachekit-io/cachekit-rs"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/cachekit-io/cachekit-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cachekit-io%2Fcachekit-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cachekit-io%2Fcachekit-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cachekit-io%2Fcachekit-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cachekit-io%2Fcachekit-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cachekit-io","download_url":"https://codeload.github.com/cachekit-io/cachekit-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cachekit-io%2Fcachekit-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32997421,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"ssl_error","status_checked_at":"2026-05-13T13:14:51.610Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-13T19:30:39.959Z","updated_at":"2026-05-13T19:30:44.818Z","avatar_url":"https://github.com/cachekit-io.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cachekit-rs\n\n\u003cdiv align=\"center\"\u003e\n\n**Production-ready caching for Rust — dual-layer L1/L2, zero-knowledge encryption, multi-backend.**\n\n[![Crates.io](https://img.shields.io/crates/v/cachekit-rs.svg)](https://crates.io/crates/cachekit-rs)\n[![docs.rs](https://docs.rs/cachekit-rs/badge.svg)](https://docs.rs/cachekit-rs)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![MSRV](https://img.shields.io/badge/MSRV-1.85-blue.svg)](https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html)\n\n[Features](#features) · [Quick Start](#quick-start) · [Encryption](#zero-knowledge-encryption) · [Backends](#backends) · [Architecture](#architecture)\n\n\u003c/div\u003e\n\n---\n\n## Overview\n\n`cachekit-rs` is the Rust SDK for [cachekit.io](https://cachekit.io). Plug in a backend, get dual-layer caching with optional client-side encryption. Bytes never leave your process unencrypted unless you say so.\n\n| Component | What it does |\n|:----------|:-------------|\n| **CacheKit** | `get` / `set` / `delete` / `exists` with automatic L1 → L2 layering |\n| **SecureCache** | Transparent AES-256-GCM encryption before storage (zero-knowledge) |\n| **Backend** | Pluggable trait — cachekit.io SaaS, Redis, Cloudflare Workers |\n| **L1 Cache** | In-process [moka](https://crates.io/crates/moka) cache with write-through + backfill |\n\n\u003e [!TIP]\n\u003e For the Python SDK with decorators, see [`cachekit`](https://github.com/cachekit-io/cachekit).\n\u003e For the low-level compression/encryption primitives, see [`cachekit-core`](https://crates.io/crates/cachekit-core).\n\n---\n\n## Features\n\n| Feature | Default | Description |\n|:--------|:-------:|:------------|\n| `cachekitio` | ✅ | HTTP backend for [api.cachekit.io](https://api.cachekit.io) via [reqwest](https://crates.io/crates/reqwest) + rustls |\n| `encryption` | ✅ | Zero-knowledge AES-256-GCM via [cachekit-core](https://crates.io/crates/cachekit-core) |\n| `l1` | ✅ | In-process L1 cache via [moka](https://crates.io/crates/moka) |\n| `redis` | ❌ | Redis backend via [fred](https://crates.io/crates/fred) (native only) |\n| `workers` | ❌ | Cloudflare Workers backend via [worker](https://crates.io/crates/worker) |\n| `macros` | ❌ | `#[cachekit]` proc-macro decorator |\n\n```toml\n# Defaults: SaaS + encryption + L1\n[dependencies]\ncachekit-rs = \"0.2\"\n\n# With Redis backend\n[dependencies]\ncachekit-rs = { version = \"0.2\", features = [\"redis\"] }\n\n# For Cloudflare Workers (no L1, no Redis)\n[dependencies]\ncachekit-rs = { version = \"0.2\", default-features = false, features = [\"workers\", \"encryption\"] }\n```\n\n\u003e [!WARNING]\n\u003e **Mutually exclusive features:**\n\u003e - `workers` + `redis` — Workers runtime cannot use fred\n\u003e - `workers` + `l1` — moka requires std threads unavailable in wasm32\n\n---\n\n## Quick Start\n\n### From Environment Variables\n\n```rust\nuse cachekit::prelude::*;\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), CachekitError\u003e {\n    let cache = CacheKit::from_env()?.build()?;\n\n    cache.set(\"greeting\", \u0026\"Hello, world!\").await?;\n    let val: String = cache.get(\"greeting\").await?.unwrap();\n    println!(\"{val}\");\n\n    Ok(())\n}\n```\n\n### Builder API\n\n```rust\nuse std::sync::Arc;\nuse std::time::Duration;\nuse cachekit::prelude::*;\nuse cachekit::backend::cachekitio::CachekitIO;\n\nlet backend = CachekitIO::builder()\n    .api_key(\"ck_live_...\")\n    .build()?;\n\nlet cache = CacheKit::builder()\n    .backend(Arc::new(backend))\n    .default_ttl(Duration::from_secs(600))\n    .namespace(\"myapp\")\n    .l1_capacity(5000)\n    .build()?;\n```\n\n\u003e [!IMPORTANT]\n\u003e Never hardcode API keys or master keys. Use environment variables or a secrets manager.\n\n---\n\n## Zero-Knowledge Encryption\n\nCall `.secure()` to get an encrypted cache handle. All values are encrypted client-side with AES-256-GCM before hitting any backend. The backend only ever sees ciphertext.\n\n```rust\nlet cache = CacheKit::from_env()?.build()?;\nlet secure = cache.secure()?;\n\n// Encrypt → store (backend sees only ciphertext)\nsecure.set(\"user:42:ssn\", \u0026\"123-45-6789\").await?;\n\n// Retrieve → decrypt (transparent to caller)\nlet ssn: String = secure.get(\"user:42:ssn\").await?.unwrap();\n```\n\n```\n┌──────────────┐     ┌──────────────┐     ┌──────────────┐\n│  Your Code   │────\u003e│  SecureCache  │────\u003e│   Backend    │\n│              │     │  AES-256-GCM  │     │  (cachekit.io│\n│  plaintext   │     │  encrypt /    │     │   or Redis)  │\n│              │\u003c────│  decrypt      │\u003c────│              │\n└──────────────┘     └──────────────┘     └──────────────┘\n                      L1 stores ciphertext\n                      (zero-knowledge preserved)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eSecurity Properties\u003c/strong\u003e\u003c/summary\u003e\n\n| Property | Implementation |\n|:---------|:---------------|\n| **Encryption** | AES-256-GCM (AEAD) via [cachekit-core](https://crates.io/crates/cachekit-core) (`ring` on native, `aes-gcm` on wasm32) |\n| **Key Derivation** | HKDF-SHA256 — per-tenant cryptographic isolation |\n| **AAD Binding** | Cache key bound to ciphertext (prevents substitution attacks) |\n| **Memory Safety** | [zeroize](https://crates.io/crates/zeroize) on drop for all key material |\n| **L1 Guarantee** | L1 stores ciphertext, never plaintext |\n\n**AAD v0x03 wire format:**\n\n```text\n[version(0x03)][len(4)][tenant_id][len(4)][cache_key][len(4)][format][len(4)][compressed]\n```\n\nEach field is length-prefixed with a 4-byte big-endian u32 to prevent boundary-confusion attacks.\nCross-SDK compatible — ciphertext produced by the Python SDK decrypts with the Rust SDK and vice versa.\n\n\u003c/details\u003e\n\n---\n\n## Backends\n\n### cachekit.io SaaS (default)\n\nHTTP backend targeting [api.cachekit.io](https://api.cachekit.io) with session tracking, L1 metrics headers, SSRF-safe URL validation, distributed locking, and TTL inspection.\n\n```rust\nuse cachekit::backend::cachekitio::CachekitIO;\n\nlet backend = CachekitIO::builder()\n    .api_key(\"ck_live_...\")\n    .api_url(\"https://api.cachekit.io\")  // optional, this is the default\n    .build()?;\n```\n\n### Redis\n\nNative Redis via [fred](https://crates.io/crates/fred) with cluster support. Requires the `redis` feature flag.\n\n```toml\ncachekit-rs = { version = \"0.2\", features = [\"redis\"] }\n```\n\n```rust\nuse cachekit::backend::redis::RedisBackend;\n\nlet backend = RedisBackend::builder()\n    .url(\"redis://localhost:6379\")\n    .build()?;\nbackend.connect().await?;  // explicit connect required\n```\n\n### Cloudflare Workers\n\n`wasm32-unknown-unknown` backend using `worker::Fetch`. Requires the `workers` feature with default features disabled.\n\n```toml\ncachekit-rs = { version = \"0.2\", default-features = false, features = [\"workers\", \"encryption\"] }\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCustom Backend\u003c/strong\u003e\u003c/summary\u003e\n\nImplement the `Backend` trait to plug in any storage:\n\n```rust\nuse async_trait::async_trait;\nuse cachekit::backend::{Backend, HealthStatus};\nuse cachekit::error::BackendError;\nuse std::time::Duration;\n\nstruct MyBackend;\n\n#[async_trait]\nimpl Backend for MyBackend {\n    async fn get(\u0026self, key: \u0026str) -\u003e Result\u003cOption\u003cVec\u003cu8\u003e\u003e, BackendError\u003e { todo!() }\n    async fn set(\u0026self, key: \u0026str, value: Vec\u003cu8\u003e, ttl: Option\u003cDuration\u003e) -\u003e Result\u003c(), BackendError\u003e { todo!() }\n    async fn delete(\u0026self, key: \u0026str) -\u003e Result\u003cbool, BackendError\u003e { todo!() }\n    async fn exists(\u0026self, key: \u0026str) -\u003e Result\u003cbool, BackendError\u003e { todo!() }\n    async fn health(\u0026self) -\u003e Result\u003cHealthStatus, BackendError\u003e { todo!() }\n}\n```\n\nOptional extension traits: `TtlInspectable` (TTL queries), `LockableBackend` (distributed locking).\n\n\u003c/details\u003e\n\n---\n\n## Dual-Layer Caching\n\nWhen the `l1` feature is enabled (default), CacheKit maintains an in-process [moka](https://crates.io/crates/moka) cache in front of the backend:\n\n```\n┌─────────────────────────────────────────────────────────┐\n│                     CacheKit Client                     │\n├─────────────────────────────────────────────────────────┤\n│                                                         │\n│  GET path:                                              │\n│  L1 hit (~50ns) ──► return immediately                  │\n│  L1 miss ──► L2 backend ──► backfill L1 (30s cap)      │\n│                                                         │\n│  SET path:                                              │\n│  write to L2 backend ──► write-through to L1            │\n│                                                         │\n│  DELETE path:                                           │\n│  invalidate L1 first ──► delete from L2 backend         │\n│                                                         │\n├─────────────┬───────────────────────────────────────────┤\n│  L1 (moka)  │  L2 (cachekit.io / Redis / Workers)      │\n│  ~50ns      │  ~2–50ms                                  │\n└─────────────┴───────────────────────────────────────────┘\n```\n\n| Behavior | Detail |\n|:---------|:-------|\n| **Write-through** | `set()` writes to L2 first, then L1 |\n| **Backfill on miss** | L2 hits populate L1 with a capped 30s TTL |\n| **Invalidate-first** | `delete()` evicts L1 before touching L2 |\n| **Encrypted L1** | `SecureCache` stores ciphertext in L1 (never plaintext) |\n| **Default capacity** | 1,000 entries (configurable via `.l1_capacity()`) |\n\n---\n\n## Environment Variables\n\n| Variable | Required | Description |\n|:---------|:--------:|:------------|\n| `CACHEKIT_API_KEY` | ✅ | API key for cachekit.io |\n| `CACHEKIT_API_URL` | ❌ | Override API endpoint (default: `https://api.cachekit.io`) |\n| `CACHEKIT_MASTER_KEY` | ❌ | Hex-encoded master key (min 32 bytes) for encryption |\n| `CACHEKIT_DEFAULT_TTL` | ❌ | Default TTL in seconds (min 1, default: 300) |\n\n\u003e [!CAUTION]\n\u003e `CACHEKIT_API_URL` must use HTTPS and must not point to a private IP address.\n\u003e Both constraints are enforced at configuration time.\n\n---\n\n## Architecture\n\n```\ncachekit-rs/\n├── crates/\n│   ├── cachekit/              # Main SDK crate\n│   │   └── src/\n│   │       ├── lib.rs         # Public API + prelude\n│   │       ├── client.rs      # CacheKit, SecureCache, CacheKitBuilder\n│   │       ├── config.rs      # CachekitConfig + from_env()\n│   │       ├── encryption.rs  # AES-256-GCM + AAD v0x03\n│   │       ├── error.rs       # CachekitError, BackendError\n│   │       ├── key.rs         # Blake2b-256 cache key generation\n│   │       ├── metrics.rs     # L1 hit-rate metrics headers\n│   │       ├── session.rs     # SDK session tracking\n│   │       ├── url_validator.rs # SSRF-safe URL validation\n│   │       ├── serializer/    # MessagePack serialization\n│   │       ├── l1/            # moka-based L1 cache (feature = \"l1\")\n│   │       └── backend/\n│   │           ├── mod.rs     # Backend + TtlInspectable + LockableBackend traits\n│   │           ├── cachekitio.rs      # cachekit.io HTTP backend\n│   │           ├── cachekitio_lock.rs # Distributed locking\n│   │           ├── cachekitio_ttl.rs  # TTL inspection\n│   │           ├── redis.rs           # Redis backend (feature = \"redis\")\n│   │           └── workers.rs         # Workers backend (feature = \"workers\")\n│   │\n│   └── cachekit-macros/       # Proc-macro crate\n│       └── src/lib.rs         # #[cachekit] decorator\n│\n├── Cargo.toml                 # Workspace root\n└── Makefile                   # Development commands\n```\n\n---\n\n## Development\n\n```bash\nmake quick-check   # fmt + clippy + test (run before every commit)\nmake test          # cargo test --all-features\nmake build         # cargo build --release\nmake build-wasm    # wasm32-unknown-unknown (workers feature)\n```\n\n## Minimum Supported Rust Version\n\n**Rust 1.85** or later (Edition 2021).\n\n## License\n\nMIT — see [LICENSE](LICENSE) for details.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**[Documentation](https://docs.rs/cachekit-rs)** · **[cachekit.io](https://cachekit.io)** · **[GitHub](https://github.com/cachekit-io/cachekit-rs)**\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcachekit-io%2Fcachekit-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcachekit-io%2Fcachekit-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcachekit-io%2Fcachekit-rs/lists"}