1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//! CacheKit — caching for Rust.
//!
//! Supports cachekit.io SaaS, Redis, Memcached, local File, and Cloudflare
//! Workers backends. Zero-knowledge encryption via AES-256-GCM with HKDF key
//! derivation.
//!
//! # Getting started: intent presets
//!
//! The intent presets are the primary entry point — one call that names your
//! use case and returns a pre-configured [`CacheKitBuilder`] you can still
//! override before [`build()`](CacheKitBuilder::build):
//!
//! | Intent | Backend | L1 | Encryption | Auto-reconnect² | Reliability¹ | Default TTL |
//! |------------|-----------|------|------------|-----------------|--------------|-------------|
//! | `CacheKit::minimal`³ | Redis | On (no SWR) | No | No | Off | 300 s |
//! | `CacheKit::production`³ | Redis | On | No | Yes | On | 600 s |
//! | `CacheKit::secure`³ ⁵ | Redis | On | AES-256-GCM | Yes | On | 600 s |
//! | [`io`](CacheKit::io)⁴ | cachekit.io | On | No | n/a (HTTP) | On | 3 600 s |
//!
//! ¹ Retry with backoff + jitter, a circuit breaker, and backpressure around
//! backend ops — see [`reliability`]. Requires the default-on `reliability`
//! cargo feature.
//! ² `production`/`secure` re-establish a dropped Redis connection with
//! exponential backoff (100 ms → 30 s, retrying indefinitely); `minimal` is
//! fail-fast (a dropped connection stays dead). **Initial** connections fail
//! fast for every Redis preset — `io` opens no connection at construction: an
//! empty API key fails at construction, while an invalid key or unreachable
//! endpoint surfaces at the first request.
//! Auto-reconnect is connection-level repair, distinct from the per-operation
//! reliability stack.
//! ³ Requires the `redis` cargo feature; `secure` also needs the
//! default-on `encryption` feature.
//! ⁴ API key by argument, or from `CACHEKIT_API_KEY` via
//! [`io_from_env`](CacheKit::io_from_env). Neither reads
//! `CACHEKIT_MASTER_KEY`; unlike [`from_env`](CacheKit::from_env), the `io`
//! preset never activates encryption from the environment.
//! ⁵ Master key as a hex string, `secure(url, master_key_hex)`, or from
//! `CACHEKIT_MASTER_KEY` via `secure_from_env(url)` — the same hex decoding
//! either way, so one key value derives the same key bytes in every CacheKit
//! SDK. Use exactly 32 bytes (64 hex chars), the only length every SDK
//! accepts. `secure_from_env` also reads decrypt-only rotation keys from
//! `CACHEKIT_PREVIOUS_MASTER_KEYS`, validated as `from_env` validates them.
//! A missing, non-hex or short key fails at construction, before any Redis
//! I/O; `secure` never falls back to plaintext.
//!
//! ```no_run
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let cache = cachekit::CacheKit::io_from_env()?
//! .namespace("myapp")
//! .build()?;
//!
//! cache.set("greeting", &"Hello, world!").await?;
//! let val: Option<String> = cache.get("greeting").await?;
//! # Ok(())
//! # }
//! ```
//!
//! For full control, drop down to [`CacheKit::builder`] or
//! [`CacheKit::from_env`].
//!
//! # Observability
//!
//! Every client counts its reads: [`CacheKit::stats`] answers "is my cache
//! hitting?" (L1 hits / L2 hits / misses), [`CacheKit::l1_entry_count`]
//! reports L1 occupancy, and with `reliability` on,
//! [`CacheKit::circuit_state`] reports the breaker. The same counters feed the
//! cachekit.io backends' `X-CacheKit-*` telemetry headers automatically. Enable
//! the `tracing` cargo feature for a `debug` event per operation on the
//! `cachekit` target (`op`, `outcome`, `key_hash` — never the key) and
//! breaker transitions on `cachekit::reliability` — see [`metrics`].
// Production code lints — these only fire in src/, not tests/
// Mutually exclusive feature guards
compile_error!;
compile_error!;
compile_error!;
compile_error!;
compile_error!;
/// Pluggable cache backend trait and implementations (CachekitIO, Redis,
/// Memcached, File, Workers).
/// High-level cache client with dual-layer (L1/L2) support.
/// Configuration types and environment variable parsing.
/// Error types for cache operations and backend communication.
/// Cold-miss single-flight: dedup concurrent fills of the same key.
/// Interop mode (interop/v1): cross-SDK cache keys and plain-MessagePack values.
/// Live hit/miss counters, the SaaS telemetry headers built from them, and
/// (feature `tracing`) structured events for cache operations.
/// Serialization and deserialization of cached values via MessagePack.
/// SDK session tracking (session ID and start timestamp).
/// SSRF-safe URL validation for CachekitIO endpoints.
/// Intent-based cache presets (`CacheKit::minimal`, `::production`, `::secure`, `::io`).
/// Client-side AES-256-GCM encryption with HKDF key derivation.
/// In-process L1 cache backed by [`moka`] with per-entry TTL.
/// Reliability tier: retry with backoff + jitter, circuit breaker.
// Re-exports
pub use ;
pub use CachekitConfig;
pub use ;
pub use L1Stats;
pub use SecureCache;
pub use EncryptionLayer;
pub use cachekit;
pub use SingleFlight;
pub use ;
// ── Shared jitter source ─────────────────────────────────────────────────────
/// Uniform random in `[0, 1)`. uuid v4 is the crate's existing entropy source
/// (getrandom-backed); jitter needs decorrelation across clients, not crypto
/// quality — 53 bits is plenty. Used by retry backoff (`reliability`) and the
/// L1 SWR freshness threshold at entry insertion (`l1`).
pub
// ── SWR background-refresh spawn (macro plumbing) ───────────────────────────
/// Spawn a stale-while-revalidate background refresh onto the ambient tokio
/// runtime. Macro plumbing for `#[cachekit]` — not public API.
///
/// Without a tokio runtime on the current thread the refresh is skipped: the
/// caller has already been served the stale value, and a later stale read
/// simply retries. Panicking here would turn a cache optimisation into an
/// availability bug on non-tokio executors.
/// No-op variant: under `unsync`, on wasm32, or without the `l1` feature the
/// client never classifies a hit as stale (`SwrRead::Stale` is unreachable),
/// so the refresh future handed here is dead code by construction. The stub
/// exists so `#[cachekit]`-generated code compiles under every configuration.
/// Convenient glob import for the most common types.