cachekit 0.17.0__tar.gz → 0.18.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {cachekit-0.17.0 → cachekit-0.18.0}/Cargo.lock +4 -3
  2. {cachekit-0.17.0 → cachekit-0.18.0}/PKG-INFO +36 -21
  3. {cachekit-0.17.0 → cachekit-0.18.0}/README.md +32 -17
  4. {cachekit-0.17.0 → cachekit-0.18.0}/pyproject.toml +8 -4
  5. {cachekit-0.17.0 → cachekit-0.18.0}/rust/Cargo.toml +7 -3
  6. {cachekit-0.17.0 → cachekit-0.18.0}/rust/README.md +32 -17
  7. {cachekit-0.17.0 → cachekit-0.18.0}/rust/src/lib.rs +2 -5
  8. {cachekit-0.17.0 → cachekit-0.18.0}/rust/src/python_bindings.rs +212 -46
  9. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/__init__.py +8 -7
  10. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/base.py +2 -3
  11. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/cachekitio/backend.py +38 -13
  12. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/file/backend.py +40 -15
  13. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/cache_handler.py +53 -6
  14. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/config/decorator.py +0 -6
  15. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/config/nested.py +0 -2
  16. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/config/settings.py +170 -2
  17. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/wrapper.py +18 -1
  18. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/key_generator.py +14 -8
  19. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/l1_cache.py +3 -200
  20. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/__init__.py +7 -1
  21. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/encryption_wrapper.py +245 -16
  22. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/standard_serializer.py +6 -2
  23. {cachekit-0.17.0 → cachekit-0.18.0}/Cargo.toml +0 -0
  24. {cachekit-0.17.0 → cachekit-0.18.0}/LICENSE +0 -0
  25. {cachekit-0.17.0 → cachekit-0.18.0}/rust/Makefile +0 -0
  26. {cachekit-0.17.0 → cachekit-0.18.0}/rust/TEST_EXPANSION_SUMMARY.md +0 -0
  27. {cachekit-0.17.0 → cachekit-0.18.0}/rust/supply-chain/audits.toml +0 -0
  28. {cachekit-0.17.0 → cachekit-0.18.0}/rust/supply-chain/config.toml +0 -0
  29. {cachekit-0.17.0 → cachekit-0.18.0}/rust/supply-chain/imports.lock +0 -0
  30. {cachekit-0.17.0 → cachekit-0.18.0}/rust/tsan_suppressions.txt +0 -0
  31. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/__init__.py +0 -0
  32. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/base_config.py +0 -0
  33. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/cachekitio/__init__.py +0 -0
  34. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/cachekitio/client.py +0 -0
  35. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/cachekitio/config.py +0 -0
  36. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/cachekitio/error_handler.py +0 -0
  37. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/cachekitio/session.py +0 -0
  38. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/errors.py +0 -0
  39. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/file/__init__.py +0 -0
  40. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/file/config.py +0 -0
  41. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/memcached/__init__.py +0 -0
  42. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/memcached/backend.py +0 -0
  43. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/memcached/config.py +0 -0
  44. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/memcached/error_handler.py +0 -0
  45. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/provider.py +0 -0
  46. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/redis/__init__.py +0 -0
  47. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/redis/backend.py +0 -0
  48. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/redis/client.py +0 -0
  49. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/redis/config.py +0 -0
  50. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/redis/error_handler.py +0 -0
  51. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/backends/redis/provider.py +0 -0
  52. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/config/__init__.py +0 -0
  53. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/config/singleton.py +0 -0
  54. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/config/validation.py +0 -0
  55. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/__init__.py +0 -0
  56. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/intent.py +0 -0
  57. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/local_wrapper.py +0 -0
  58. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/main.py +0 -0
  59. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/orchestrator.py +0 -0
  60. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/session.py +0 -0
  61. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/stats_context.py +0 -0
  62. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/tenant_context.py +0 -0
  63. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/decorators/utils/__init__.py +0 -0
  64. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/di.py +0 -0
  65. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/hash_utils.py +0 -0
  66. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/health.py +0 -0
  67. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/hiredis_compat.py +0 -0
  68. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/imports.py +0 -0
  69. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/interop.py +0 -0
  70. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/logging.py +0 -0
  71. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/monitoring/__init__.py +0 -0
  72. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/monitoring/correlation_tracking.py +0 -0
  73. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/monitoring/pool_monitor.py +0 -0
  74. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/monitoring/protocols.py +0 -0
  75. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/object_cache.py +0 -0
  76. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/py.typed +0 -0
  77. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/reliability/__init__.py +0 -0
  78. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/reliability/async_metrics.py +0 -0
  79. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/reliability/circuit_breaker.py +0 -0
  80. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/reliability/error_classification.py +0 -0
  81. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/reliability/load_control.py +0 -0
  82. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/reliability/metrics_collection.py +0 -0
  83. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/reliability/profiles.py +0 -0
  84. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/arrow_serializer.py +0 -0
  85. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/auto_serializer.py +0 -0
  86. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/base.py +0 -0
  87. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/interop_serializer.py +0 -0
  88. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/orjson_serializer.py +0 -0
  89. {cachekit-0.17.0 → cachekit-0.18.0}/src/cachekit/serializers/wrapper.py +0 -0
@@ -245,9 +245,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
245
245
 
246
246
  [[package]]
247
247
  name = "cachekit-core"
248
- version = "0.4.0"
248
+ version = "0.5.0"
249
249
  source = "registry+https://github.com/rust-lang/crates.io-index"
250
- checksum = "6aba1513135a7b92a124ad6983f7e80e5f5c78c4f9c74384079efa3fbf491eab"
250
+ checksum = "12089baacc5ff661a62d2071588c895973bc48e42ed359178afaee22decb5559"
251
251
  dependencies = [
252
252
  "aes",
253
253
  "aes-gcm",
@@ -271,7 +271,7 @@ dependencies = [
271
271
 
272
272
  [[package]]
273
273
  name = "cachekit-rs"
274
- version = "0.17.0"
274
+ version = "0.18.0"
275
275
  dependencies = [
276
276
  "cachekit-core",
277
277
  "criterion",
@@ -282,6 +282,7 @@ dependencies = [
282
282
  "pprof",
283
283
  "proptest",
284
284
  "pyo3",
285
+ "zeroize",
285
286
  ]
286
287
 
287
288
  [[package]]
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cachekit
3
- Version: 0.17.0
4
- Classifier: Development Status :: 3 - Alpha
3
+ Version: 0.18.0
4
+ Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
7
7
  Classifier: Operating System :: OS Independent
@@ -21,7 +21,7 @@ Classifier: Framework :: AsyncIO
21
21
  Classifier: Typing :: Typed
22
22
  Requires-Dist: redis[hiredis]>=4.0.0
23
23
  Requires-Dist: pydantic>=2.0.0
24
- Requires-Dist: pydantic-settings>=2.0.0
24
+ Requires-Dist: pydantic-settings>=2.7.0
25
25
  Requires-Dist: prometheus-client>=0.22.1
26
26
  Requires-Dist: psutil>=7.0.0
27
27
  Requires-Dist: blake3>=1.0.5
@@ -37,7 +37,7 @@ Provides-Extra: data
37
37
  Provides-Extra: json
38
38
  Provides-Extra: memcached
39
39
  License-File: LICENSE
40
- Summary: Production-ready Redis caching for Python with intelligent reliability features and Rust-powered performance
40
+ Summary: Backend-agnostic caching for Python — intent-based decorators with circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge AES-256-GCM encryption, on a Rust-powered core. Zero-config L1 in-memory; scales to Redis, Memcached, File, or CachekitIO.
41
41
  Keywords: redis,cache,caching,decorator,rust,performance,reliability,production,encryption,security,circuit-breaker,prometheus,messagepack,distributed-locking
42
42
  Home-Page: https://github.com/cachekit-io/cachekit-py
43
43
  Author-email: cachekit Contributors <noreply@cachekit.io>
@@ -57,7 +57,7 @@ Project-URL: Repository, https://github.com/cachekit-io/cachekit-py.git
57
57
 
58
58
  > **Python caching, batteries included**
59
59
 
60
- Production-ready caching for Python with intelligent reliability features and Rust-powered performance.
60
+ Backend-agnostic caching with intent-based decorators circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge encryption on a Rust-powered core. Zero config to start, any backend when you scale.
61
61
 
62
62
  [![PyPI Version][pypi-badge]][pypi-url]
63
63
  [![Python Versions][python-badge]][pypi-url]
@@ -68,20 +68,16 @@ Production-ready caching for Python with intelligent reliability features and Ru
68
68
 
69
69
  ---
70
70
 
71
- > [!WARNING]
72
- > **Alpha Software** — cachekit is under active development. While we've been building and testing for ~6 months, the API is not yet stable and **breaking changes may occur** between releases. We're committed to making this library rock-solid, but we need your help!
73
- >
74
- > 🐛 **Found a bug?** Please [open an issue][issues-url] — even small ones help us improve.
75
- >
76
- > 💡 **Something feel off?** We want to hear about rough edges, confusing APIs, or missing features.
71
+ > [!NOTE]
72
+ > **Status: beta** — CacheKit is in closed beta ahead of 1.0. APIs are stabilising; minor breaking changes may still occur between 0.x releases.
77
73
  >
78
- > Your feedback directly shapes the path to 1.0. Cheers!
74
+ > 🐛 **Found a bug or a rough edge?** Please [open an issue][issues-url] — your feedback directly shapes the path to 1.0.
79
75
 
80
76
  ---
81
77
 
82
78
  ## Why cachekit?
83
79
 
84
- **Simple to use, production-ready out of the box.**
80
+ **Simple to use, works out of the box.**
85
81
 
86
82
  ```python
87
83
  from cachekit import cache
@@ -125,7 +121,7 @@ backend that fits your infrastructure — they're peers behind the same `@cache`
125
121
  | Backend | Best for | Select with |
126
122
  |---------|----------|-------------|
127
123
  | Redis | Self-hosted, full control | `REDIS_URL` / `CACHEKIT_REDIS_URL` |
128
- | CachekitIO | Managed, zero-ops (alpha) | `CACHEKIT_API_KEY` |
124
+ | CachekitIO | Managed, zero-ops (beta) | `CACHEKIT_API_KEY` |
129
125
  | Memcached | High-throughput, existing infra | `CACHEKIT_MEMCACHED_SERVERS` |
130
126
  | File / L1-only | Local dev, tests, no external deps | `CACHEKIT_FILE_CACHE_DIR` / `backend=None` |
131
127
 
@@ -148,7 +144,7 @@ def expensive_api_call(user_id: int):
148
144
  ### More Backends
149
145
 
150
146
  <details>
151
- <summary><strong>CachekitIO — Managed SaaS (Alpha)</strong></summary>
147
+ <summary><strong>CachekitIO — Managed SaaS (Beta)</strong></summary>
152
148
 
153
149
  ```python notest
154
150
  import os
@@ -162,7 +158,7 @@ def expensive_api_call(user_id: int):
162
158
  return fetch_user_data(user_id)
163
159
  ```
164
160
 
165
- *cachekit.io is in closed alpha — [request access](https://cachekit.io) to get started.*
161
+ *cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
166
162
 
167
163
  </details>
168
164
 
@@ -188,9 +184,9 @@ def expensive_api_call(user_id: int):
188
184
 
189
185
  ---
190
186
 
191
- > **CachekitIO Cloud (Alpha)**
187
+ > **CachekitIO Cloud (Beta)**
192
188
  > Managed caching with zero infrastructure. L1+L2 caching, circuit breaker, and automatic failover — no Redis to manage.
193
- > *cachekit.io is in closed alpha — [request access](https://cachekit.io) to get started.*
189
+ > *cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
194
190
 
195
191
  ---
196
192
 
@@ -221,9 +217,8 @@ def get_user_profile(user_id: int):
221
217
  | Backpressure | ✅ | ✅ | - | ✅ | ✅ |
222
218
  | Integrity Checking | - | ✅ | - | ✅ | ✅ 🔒 |
223
219
  | Encryption | - | - | - | - | ✅ Required |
224
- | L1 SWR | - | ✅ | - | ✅ | ✅ |
220
+ | L1 SWR (L1-only mode) | - | ✅ | - | ✅ | ✅ |
225
221
  | L1 Invalidation | - | - | - | ✅ | ✅ |
226
- | L1 Namespace Index | - | - | - | ✅ | ✅ |
227
222
  | Prometheus Metrics | - | - | - | ✅ | ✅ |
228
223
  | Tracing | - | ✅ | - | ✅ | ✅ |
229
224
  | Structured Logging | - | ✅ | - | ✅ | ✅ |
@@ -231,6 +226,8 @@ def get_user_profile(user_id: int):
231
226
 
232
227
  > 🔒 `@cache.secure` forces `integrity_checking=True` — it cannot be overridden.
233
228
  >
229
+ > **L1 SWR** (within-TTL background refresh) runs only in L1-only mode (`backend=None`) — with a backend configured it has no effect. `@cache.io` additionally ships past-TTL SWR via `stale_ttl` ([docs](docs/configuration.md#stale-while-revalidate-stale_ttl)).
230
+ >
234
231
  > **`@cache.io()`** mirrors `@cache.production` (full reliability + observability) but routes to the managed CachekitIO SaaS backend instead of Redis. **`@cache.local()`** is a separate in-process path backed by `ObjectCache` (raw object references, entry-count LRU, no serialization) — the reliability and encryption features listed above do not apply to it.
235
232
 
236
233
  <details>
@@ -346,6 +343,12 @@ def get_patient_data(hospital_id: int):
346
343
  > [!CAUTION]
347
344
  > When handling PII, medical, or financial data, always use `@cache.secure` to enforce encryption.
348
345
 
346
+ **Zero-downtime key rotation**: promote a new `CACHEKIT_MASTER_KEY` and keep the
347
+ retiring key readable via `CACHEKIT_PREVIOUS_MASTER_KEYS` (comma-separated hex,
348
+ max 3 decrypt-only keys). Entries are selected by exact key fingerprint — never
349
+ trial decryption — and old entries age out via TTL, no cache flush required. See
350
+ [Zero-Knowledge Encryption](docs/features/zero-knowledge-encryption.md#key-rotation-pattern).
351
+
349
352
  cachekit employs comprehensive security tooling:
350
353
 
351
354
  - **Supply Chain Security**: cargo-deny for license compliance + RustSec scanning
@@ -443,6 +446,7 @@ info = expensive_func.cache_info()
443
446
  | [Comparison Guide][comparison-url] | How cachekit compares to lru_cache, aiocache, cachetools |
444
447
  | [Getting Started][getting-started-url] | Progressive tutorial from basics to advanced |
445
448
  | [API Reference][api-reference-url] | Complete API documentation |
449
+ | [Skyline (live example)][skyline-url] | Canonical example project: this SDK ingests the Bluesky firehose and writes the analytics entries a TypeScript edge Worker serves live, on one shared interop namespace |
446
450
 
447
451
  ### Feature Deep Dives
448
452
 
@@ -453,6 +457,11 @@ info = expensive_func.cache_info()
453
457
  | [Distributed Locking][distributed-locking-url] | Cache stampede prevention |
454
458
  | [Prometheus Metrics][prometheus-url] | Built-in observability |
455
459
  | [Zero-Knowledge Encryption][encryption-url] | Client-side security |
460
+ | [Interop Mode][interop-url] | Cross-SDK cache sharing with cachekit-ts/rs |
461
+ | [L1 Invalidation & SWR][l1-invalidation-url] | Process-local invalidation, stale-while-revalidate |
462
+ | [Reference Caching][reference-caching-url] | `@cache.local()` for non-serializable objects |
463
+ | [Rust Serialization][rust-serialization-url] | ByteStorage layer: LZ4, xxHash3, AES-256-GCM |
464
+ | [SSRF Protection][ssrf-url] | URL allowlisting for the CachekitIO backend |
456
465
 
457
466
  ---
458
467
 
@@ -465,7 +474,7 @@ info = expensive_func.cache_info()
465
474
  CACHEKIT_REDIS_URL="redis://localhost:6379" # Primary (preferred)
466
475
  REDIS_URL="redis://localhost:6379" # Fallback
467
476
 
468
- # CachekitIO SaaS Backend (closed alpha — request access at cachekit.io)
477
+ # CachekitIO SaaS Backend (closed beta — request access at cachekit.io)
469
478
  CACHEKIT_API_KEY="your-api-key" # Required for @cache.io() # pragma: allowlist secret
470
479
  CACHEKIT_API_URL="https://api.cachekit.io" # Default SaaS endpoint
471
480
 
@@ -528,6 +537,7 @@ MIT License - see [LICENSE][license-file-url] for details.
528
537
  [uv-url]: https://github.com/astral-sh/uv
529
538
  [security-url]: SECURITY.md
530
539
  [comparison-url]: docs/comparison.md
540
+ [skyline-url]: https://github.com/cachekit-io/bluesky-thinking
531
541
  [getting-started-url]: docs/getting-started.md
532
542
  [api-reference-url]: docs/api-reference.md
533
543
  [serializer-guide-url]: docs/serializers/index.md
@@ -535,6 +545,11 @@ MIT License - see [LICENSE][license-file-url] for details.
535
545
  [distributed-locking-url]: docs/features/distributed-locking.md
536
546
  [prometheus-url]: docs/features/prometheus-metrics.md
537
547
  [encryption-url]: docs/features/zero-knowledge-encryption.md
548
+ [interop-url]: docs/features/interop-mode.md
549
+ [l1-invalidation-url]: docs/features/l1-invalidation.md
550
+ [reference-caching-url]: docs/features/reference-caching.md
551
+ [rust-serialization-url]: docs/features/rust-serialization.md
552
+ [ssrf-url]: docs/features/ssrf-protection.md
538
553
  [contributing-url]: CONTRIBUTING.md
539
554
  [license-file-url]: LICENSE
540
555
  [github-url]: https://github.com/cachekit-io/cachekit-py
@@ -4,7 +4,7 @@
4
4
 
5
5
  > **Python caching, batteries included**
6
6
 
7
- Production-ready caching for Python with intelligent reliability features and Rust-powered performance.
7
+ Backend-agnostic caching with intent-based decorators circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge encryption on a Rust-powered core. Zero config to start, any backend when you scale.
8
8
 
9
9
  [![PyPI Version][pypi-badge]][pypi-url]
10
10
  [![Python Versions][python-badge]][pypi-url]
@@ -15,20 +15,16 @@ Production-ready caching for Python with intelligent reliability features and Ru
15
15
 
16
16
  ---
17
17
 
18
- > [!WARNING]
19
- > **Alpha Software** — cachekit is under active development. While we've been building and testing for ~6 months, the API is not yet stable and **breaking changes may occur** between releases. We're committed to making this library rock-solid, but we need your help!
20
- >
21
- > 🐛 **Found a bug?** Please [open an issue][issues-url] — even small ones help us improve.
22
- >
23
- > 💡 **Something feel off?** We want to hear about rough edges, confusing APIs, or missing features.
18
+ > [!NOTE]
19
+ > **Status: beta** — CacheKit is in closed beta ahead of 1.0. APIs are stabilising; minor breaking changes may still occur between 0.x releases.
24
20
  >
25
- > Your feedback directly shapes the path to 1.0. Cheers!
21
+ > 🐛 **Found a bug or a rough edge?** Please [open an issue][issues-url] — your feedback directly shapes the path to 1.0.
26
22
 
27
23
  ---
28
24
 
29
25
  ## Why cachekit?
30
26
 
31
- **Simple to use, production-ready out of the box.**
27
+ **Simple to use, works out of the box.**
32
28
 
33
29
  ```python
34
30
  from cachekit import cache
@@ -72,7 +68,7 @@ backend that fits your infrastructure — they're peers behind the same `@cache`
72
68
  | Backend | Best for | Select with |
73
69
  |---------|----------|-------------|
74
70
  | Redis | Self-hosted, full control | `REDIS_URL` / `CACHEKIT_REDIS_URL` |
75
- | CachekitIO | Managed, zero-ops (alpha) | `CACHEKIT_API_KEY` |
71
+ | CachekitIO | Managed, zero-ops (beta) | `CACHEKIT_API_KEY` |
76
72
  | Memcached | High-throughput, existing infra | `CACHEKIT_MEMCACHED_SERVERS` |
77
73
  | File / L1-only | Local dev, tests, no external deps | `CACHEKIT_FILE_CACHE_DIR` / `backend=None` |
78
74
 
@@ -95,7 +91,7 @@ def expensive_api_call(user_id: int):
95
91
  ### More Backends
96
92
 
97
93
  <details>
98
- <summary><strong>CachekitIO — Managed SaaS (Alpha)</strong></summary>
94
+ <summary><strong>CachekitIO — Managed SaaS (Beta)</strong></summary>
99
95
 
100
96
  ```python notest
101
97
  import os
@@ -109,7 +105,7 @@ def expensive_api_call(user_id: int):
109
105
  return fetch_user_data(user_id)
110
106
  ```
111
107
 
112
- *cachekit.io is in closed alpha — [request access](https://cachekit.io) to get started.*
108
+ *cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
113
109
 
114
110
  </details>
115
111
 
@@ -135,9 +131,9 @@ def expensive_api_call(user_id: int):
135
131
 
136
132
  ---
137
133
 
138
- > **CachekitIO Cloud (Alpha)**
134
+ > **CachekitIO Cloud (Beta)**
139
135
  > Managed caching with zero infrastructure. L1+L2 caching, circuit breaker, and automatic failover — no Redis to manage.
140
- > *cachekit.io is in closed alpha — [request access](https://cachekit.io) to get started.*
136
+ > *cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
141
137
 
142
138
  ---
143
139
 
@@ -168,9 +164,8 @@ def get_user_profile(user_id: int):
168
164
  | Backpressure | ✅ | ✅ | - | ✅ | ✅ |
169
165
  | Integrity Checking | - | ✅ | - | ✅ | ✅ 🔒 |
170
166
  | Encryption | - | - | - | - | ✅ Required |
171
- | L1 SWR | - | ✅ | - | ✅ | ✅ |
167
+ | L1 SWR (L1-only mode) | - | ✅ | - | ✅ | ✅ |
172
168
  | L1 Invalidation | - | - | - | ✅ | ✅ |
173
- | L1 Namespace Index | - | - | - | ✅ | ✅ |
174
169
  | Prometheus Metrics | - | - | - | ✅ | ✅ |
175
170
  | Tracing | - | ✅ | - | ✅ | ✅ |
176
171
  | Structured Logging | - | ✅ | - | ✅ | ✅ |
@@ -178,6 +173,8 @@ def get_user_profile(user_id: int):
178
173
 
179
174
  > 🔒 `@cache.secure` forces `integrity_checking=True` — it cannot be overridden.
180
175
  >
176
+ > **L1 SWR** (within-TTL background refresh) runs only in L1-only mode (`backend=None`) — with a backend configured it has no effect. `@cache.io` additionally ships past-TTL SWR via `stale_ttl` ([docs](docs/configuration.md#stale-while-revalidate-stale_ttl)).
177
+ >
181
178
  > **`@cache.io()`** mirrors `@cache.production` (full reliability + observability) but routes to the managed CachekitIO SaaS backend instead of Redis. **`@cache.local()`** is a separate in-process path backed by `ObjectCache` (raw object references, entry-count LRU, no serialization) — the reliability and encryption features listed above do not apply to it.
182
179
 
183
180
  <details>
@@ -293,6 +290,12 @@ def get_patient_data(hospital_id: int):
293
290
  > [!CAUTION]
294
291
  > When handling PII, medical, or financial data, always use `@cache.secure` to enforce encryption.
295
292
 
293
+ **Zero-downtime key rotation**: promote a new `CACHEKIT_MASTER_KEY` and keep the
294
+ retiring key readable via `CACHEKIT_PREVIOUS_MASTER_KEYS` (comma-separated hex,
295
+ max 3 decrypt-only keys). Entries are selected by exact key fingerprint — never
296
+ trial decryption — and old entries age out via TTL, no cache flush required. See
297
+ [Zero-Knowledge Encryption](docs/features/zero-knowledge-encryption.md#key-rotation-pattern).
298
+
296
299
  cachekit employs comprehensive security tooling:
297
300
 
298
301
  - **Supply Chain Security**: cargo-deny for license compliance + RustSec scanning
@@ -390,6 +393,7 @@ info = expensive_func.cache_info()
390
393
  | [Comparison Guide][comparison-url] | How cachekit compares to lru_cache, aiocache, cachetools |
391
394
  | [Getting Started][getting-started-url] | Progressive tutorial from basics to advanced |
392
395
  | [API Reference][api-reference-url] | Complete API documentation |
396
+ | [Skyline (live example)][skyline-url] | Canonical example project: this SDK ingests the Bluesky firehose and writes the analytics entries a TypeScript edge Worker serves live, on one shared interop namespace |
393
397
 
394
398
  ### Feature Deep Dives
395
399
 
@@ -400,6 +404,11 @@ info = expensive_func.cache_info()
400
404
  | [Distributed Locking][distributed-locking-url] | Cache stampede prevention |
401
405
  | [Prometheus Metrics][prometheus-url] | Built-in observability |
402
406
  | [Zero-Knowledge Encryption][encryption-url] | Client-side security |
407
+ | [Interop Mode][interop-url] | Cross-SDK cache sharing with cachekit-ts/rs |
408
+ | [L1 Invalidation & SWR][l1-invalidation-url] | Process-local invalidation, stale-while-revalidate |
409
+ | [Reference Caching][reference-caching-url] | `@cache.local()` for non-serializable objects |
410
+ | [Rust Serialization][rust-serialization-url] | ByteStorage layer: LZ4, xxHash3, AES-256-GCM |
411
+ | [SSRF Protection][ssrf-url] | URL allowlisting for the CachekitIO backend |
403
412
 
404
413
  ---
405
414
 
@@ -412,7 +421,7 @@ info = expensive_func.cache_info()
412
421
  CACHEKIT_REDIS_URL="redis://localhost:6379" # Primary (preferred)
413
422
  REDIS_URL="redis://localhost:6379" # Fallback
414
423
 
415
- # CachekitIO SaaS Backend (closed alpha — request access at cachekit.io)
424
+ # CachekitIO SaaS Backend (closed beta — request access at cachekit.io)
416
425
  CACHEKIT_API_KEY="your-api-key" # Required for @cache.io() # pragma: allowlist secret
417
426
  CACHEKIT_API_URL="https://api.cachekit.io" # Default SaaS endpoint
418
427
 
@@ -475,6 +484,7 @@ MIT License - see [LICENSE][license-file-url] for details.
475
484
  [uv-url]: https://github.com/astral-sh/uv
476
485
  [security-url]: SECURITY.md
477
486
  [comparison-url]: docs/comparison.md
487
+ [skyline-url]: https://github.com/cachekit-io/bluesky-thinking
478
488
  [getting-started-url]: docs/getting-started.md
479
489
  [api-reference-url]: docs/api-reference.md
480
490
  [serializer-guide-url]: docs/serializers/index.md
@@ -482,6 +492,11 @@ MIT License - see [LICENSE][license-file-url] for details.
482
492
  [distributed-locking-url]: docs/features/distributed-locking.md
483
493
  [prometheus-url]: docs/features/prometheus-metrics.md
484
494
  [encryption-url]: docs/features/zero-knowledge-encryption.md
495
+ [interop-url]: docs/features/interop-mode.md
496
+ [l1-invalidation-url]: docs/features/l1-invalidation.md
497
+ [reference-caching-url]: docs/features/reference-caching.md
498
+ [rust-serialization-url]: docs/features/rust-serialization.md
499
+ [ssrf-url]: docs/features/ssrf-protection.md
485
500
  [contributing-url]: CONTRIBUTING.md
486
501
  [license-file-url]: LICENSE
487
502
  [github-url]: https://github.com/cachekit-io/cachekit-py
@@ -4,8 +4,8 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "cachekit"
7
- version = "0.17.0"
8
- description = "Production-ready Redis caching for Python with intelligent reliability features and Rust-powered performance"
7
+ version = "0.18.0"
8
+ description = "Backend-agnostic caching for Python — intent-based decorators with circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge AES-256-GCM encryption, on a Rust-powered core. Zero-config L1 in-memory; scales to Redis, Memcached, File, or CachekitIO."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
11
11
  authors = [
@@ -31,7 +31,7 @@ keywords = [
31
31
  "distributed-locking",
32
32
  ]
33
33
  classifiers = [
34
- "Development Status :: 3 - Alpha",
34
+ "Development Status :: 4 - Beta",
35
35
  "Intended Audience :: Developers",
36
36
  "License :: OSI Approved :: MIT License",
37
37
  "Operating System :: OS Independent",
@@ -56,7 +56,7 @@ dependencies = [
56
56
  "redis[hiredis]>=4.0.0",
57
57
  # Configuration and validation
58
58
  "pydantic>=2.0.0",
59
- "pydantic-settings>=2.0.0",
59
+ "pydantic-settings>=2.7.0", # NoDecode (previous_master_keys env parsing) first shipped in 2.7.0
60
60
  # Monitoring and observability
61
61
  "prometheus-client>=0.22.1",
62
62
  "psutil>=7.0.0",
@@ -251,4 +251,8 @@ constraint-dependencies = [
251
251
  # PYSEC-2026-196 (entry-point path traversal), GHSA-58qw-9mgm-455v (tar/zip
252
252
  # confusion) and GHSA-jp4c-xjxw-mgf9 (self-update import ordering).
253
253
  "pip>=26.1.2",
254
+ # h2 is a transitive dep (httpx[http2] -> h2). 4.4.1 fixes
255
+ # GHSA-6hr6-w5qg-qmwg (duplicate Host headers forwarded on HTTP/2 ->
256
+ # HTTP/1.1 downgrade — request smuggling primitive).
257
+ "h2>=4.4.1",
254
258
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "cachekit-rs"
3
- version = "0.17.0"
3
+ version = "0.18.0"
4
4
  edition = "2021"
5
5
  authors = ["cachekit Contributors"]
6
6
  description = "High-performance storage engine for caching with compression and encryption"
@@ -20,11 +20,15 @@ crate-type = ["cdylib", "rlib"]
20
20
 
21
21
  [dependencies]
22
22
  # Compression, checksums, encryption (https://crates.io/crates/cachekit-core)
23
- cachekit-core = { version = "0.4.0", features = ["compression", "checksum", "messagepack", "encryption"] }
23
+ cachekit-core = { version = "0.5.0", features = ["compression", "checksum", "messagepack", "encryption"] }
24
24
 
25
25
  # Python integration - optional for Rust-only builds
26
26
  pyo3 = { workspace = true, optional = true }
27
27
 
28
+ # Wipe the PyO3-side copies of master key material on drop. Only used behind
29
+ # the encryption feature, so gated the same way pyo3 is.
30
+ zeroize = { version = "1", optional = true }
31
+
28
32
  # Feature flags
29
33
  [features]
30
34
  default = ["python", "compression", "checksum", "messagepack", "encryption"]
@@ -36,7 +40,7 @@ python = ["dep:pyo3"]
36
40
  compression = []
37
41
  checksum = []
38
42
  messagepack = []
39
- encryption = []
43
+ encryption = ["dep:zeroize"]
40
44
 
41
45
  [dev-dependencies]
42
46
  criterion = { version = "0.5", features = ["html_reports"] }
@@ -4,7 +4,7 @@
4
4
 
5
5
  > **Python caching, batteries included**
6
6
 
7
- Production-ready caching for Python with intelligent reliability features and Rust-powered performance.
7
+ Backend-agnostic caching with intent-based decorators circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge encryption on a Rust-powered core. Zero config to start, any backend when you scale.
8
8
 
9
9
  [![PyPI Version][pypi-badge]][pypi-url]
10
10
  [![Python Versions][python-badge]][pypi-url]
@@ -15,20 +15,16 @@ Production-ready caching for Python with intelligent reliability features and Ru
15
15
 
16
16
  ---
17
17
 
18
- > [!WARNING]
19
- > **Alpha Software** — cachekit is under active development. While we've been building and testing for ~6 months, the API is not yet stable and **breaking changes may occur** between releases. We're committed to making this library rock-solid, but we need your help!
20
- >
21
- > 🐛 **Found a bug?** Please [open an issue][issues-url] — even small ones help us improve.
22
- >
23
- > 💡 **Something feel off?** We want to hear about rough edges, confusing APIs, or missing features.
18
+ > [!NOTE]
19
+ > **Status: beta** — CacheKit is in closed beta ahead of 1.0. APIs are stabilising; minor breaking changes may still occur between 0.x releases.
24
20
  >
25
- > Your feedback directly shapes the path to 1.0. Cheers!
21
+ > 🐛 **Found a bug or a rough edge?** Please [open an issue][issues-url] — your feedback directly shapes the path to 1.0.
26
22
 
27
23
  ---
28
24
 
29
25
  ## Why cachekit?
30
26
 
31
- **Simple to use, production-ready out of the box.**
27
+ **Simple to use, works out of the box.**
32
28
 
33
29
  ```python
34
30
  from cachekit import cache
@@ -72,7 +68,7 @@ backend that fits your infrastructure — they're peers behind the same `@cache`
72
68
  | Backend | Best for | Select with |
73
69
  |---------|----------|-------------|
74
70
  | Redis | Self-hosted, full control | `REDIS_URL` / `CACHEKIT_REDIS_URL` |
75
- | CachekitIO | Managed, zero-ops (alpha) | `CACHEKIT_API_KEY` |
71
+ | CachekitIO | Managed, zero-ops (beta) | `CACHEKIT_API_KEY` |
76
72
  | Memcached | High-throughput, existing infra | `CACHEKIT_MEMCACHED_SERVERS` |
77
73
  | File / L1-only | Local dev, tests, no external deps | `CACHEKIT_FILE_CACHE_DIR` / `backend=None` |
78
74
 
@@ -95,7 +91,7 @@ def expensive_api_call(user_id: int):
95
91
  ### More Backends
96
92
 
97
93
  <details>
98
- <summary><strong>CachekitIO — Managed SaaS (Alpha)</strong></summary>
94
+ <summary><strong>CachekitIO — Managed SaaS (Beta)</strong></summary>
99
95
 
100
96
  ```python notest
101
97
  import os
@@ -109,7 +105,7 @@ def expensive_api_call(user_id: int):
109
105
  return fetch_user_data(user_id)
110
106
  ```
111
107
 
112
- *cachekit.io is in closed alpha — [request access](https://cachekit.io) to get started.*
108
+ *cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
113
109
 
114
110
  </details>
115
111
 
@@ -135,9 +131,9 @@ def expensive_api_call(user_id: int):
135
131
 
136
132
  ---
137
133
 
138
- > **CachekitIO Cloud (Alpha)**
134
+ > **CachekitIO Cloud (Beta)**
139
135
  > Managed caching with zero infrastructure. L1+L2 caching, circuit breaker, and automatic failover — no Redis to manage.
140
- > *cachekit.io is in closed alpha — [request access](https://cachekit.io) to get started.*
136
+ > *cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
141
137
 
142
138
  ---
143
139
 
@@ -168,9 +164,8 @@ def get_user_profile(user_id: int):
168
164
  | Backpressure | ✅ | ✅ | - | ✅ | ✅ |
169
165
  | Integrity Checking | - | ✅ | - | ✅ | ✅ 🔒 |
170
166
  | Encryption | - | - | - | - | ✅ Required |
171
- | L1 SWR | - | ✅ | - | ✅ | ✅ |
167
+ | L1 SWR (L1-only mode) | - | ✅ | - | ✅ | ✅ |
172
168
  | L1 Invalidation | - | - | - | ✅ | ✅ |
173
- | L1 Namespace Index | - | - | - | ✅ | ✅ |
174
169
  | Prometheus Metrics | - | - | - | ✅ | ✅ |
175
170
  | Tracing | - | ✅ | - | ✅ | ✅ |
176
171
  | Structured Logging | - | ✅ | - | ✅ | ✅ |
@@ -178,6 +173,8 @@ def get_user_profile(user_id: int):
178
173
 
179
174
  > 🔒 `@cache.secure` forces `integrity_checking=True` — it cannot be overridden.
180
175
  >
176
+ > **L1 SWR** (within-TTL background refresh) runs only in L1-only mode (`backend=None`) — with a backend configured it has no effect. `@cache.io` additionally ships past-TTL SWR via `stale_ttl` ([docs](docs/configuration.md#stale-while-revalidate-stale_ttl)).
177
+ >
181
178
  > **`@cache.io()`** mirrors `@cache.production` (full reliability + observability) but routes to the managed CachekitIO SaaS backend instead of Redis. **`@cache.local()`** is a separate in-process path backed by `ObjectCache` (raw object references, entry-count LRU, no serialization) — the reliability and encryption features listed above do not apply to it.
182
179
 
183
180
  <details>
@@ -293,6 +290,12 @@ def get_patient_data(hospital_id: int):
293
290
  > [!CAUTION]
294
291
  > When handling PII, medical, or financial data, always use `@cache.secure` to enforce encryption.
295
292
 
293
+ **Zero-downtime key rotation**: promote a new `CACHEKIT_MASTER_KEY` and keep the
294
+ retiring key readable via `CACHEKIT_PREVIOUS_MASTER_KEYS` (comma-separated hex,
295
+ max 3 decrypt-only keys). Entries are selected by exact key fingerprint — never
296
+ trial decryption — and old entries age out via TTL, no cache flush required. See
297
+ [Zero-Knowledge Encryption](docs/features/zero-knowledge-encryption.md#key-rotation-pattern).
298
+
296
299
  cachekit employs comprehensive security tooling:
297
300
 
298
301
  - **Supply Chain Security**: cargo-deny for license compliance + RustSec scanning
@@ -390,6 +393,7 @@ info = expensive_func.cache_info()
390
393
  | [Comparison Guide][comparison-url] | How cachekit compares to lru_cache, aiocache, cachetools |
391
394
  | [Getting Started][getting-started-url] | Progressive tutorial from basics to advanced |
392
395
  | [API Reference][api-reference-url] | Complete API documentation |
396
+ | [Skyline (live example)][skyline-url] | Canonical example project: this SDK ingests the Bluesky firehose and writes the analytics entries a TypeScript edge Worker serves live, on one shared interop namespace |
393
397
 
394
398
  ### Feature Deep Dives
395
399
 
@@ -400,6 +404,11 @@ info = expensive_func.cache_info()
400
404
  | [Distributed Locking][distributed-locking-url] | Cache stampede prevention |
401
405
  | [Prometheus Metrics][prometheus-url] | Built-in observability |
402
406
  | [Zero-Knowledge Encryption][encryption-url] | Client-side security |
407
+ | [Interop Mode][interop-url] | Cross-SDK cache sharing with cachekit-ts/rs |
408
+ | [L1 Invalidation & SWR][l1-invalidation-url] | Process-local invalidation, stale-while-revalidate |
409
+ | [Reference Caching][reference-caching-url] | `@cache.local()` for non-serializable objects |
410
+ | [Rust Serialization][rust-serialization-url] | ByteStorage layer: LZ4, xxHash3, AES-256-GCM |
411
+ | [SSRF Protection][ssrf-url] | URL allowlisting for the CachekitIO backend |
403
412
 
404
413
  ---
405
414
 
@@ -412,7 +421,7 @@ info = expensive_func.cache_info()
412
421
  CACHEKIT_REDIS_URL="redis://localhost:6379" # Primary (preferred)
413
422
  REDIS_URL="redis://localhost:6379" # Fallback
414
423
 
415
- # CachekitIO SaaS Backend (closed alpha — request access at cachekit.io)
424
+ # CachekitIO SaaS Backend (closed beta — request access at cachekit.io)
416
425
  CACHEKIT_API_KEY="your-api-key" # Required for @cache.io() # pragma: allowlist secret
417
426
  CACHEKIT_API_URL="https://api.cachekit.io" # Default SaaS endpoint
418
427
 
@@ -475,6 +484,7 @@ MIT License - see [LICENSE][license-file-url] for details.
475
484
  [uv-url]: https://github.com/astral-sh/uv
476
485
  [security-url]: SECURITY.md
477
486
  [comparison-url]: docs/comparison.md
487
+ [skyline-url]: https://github.com/cachekit-io/bluesky-thinking
478
488
  [getting-started-url]: docs/getting-started.md
479
489
  [api-reference-url]: docs/api-reference.md
480
490
  [serializer-guide-url]: docs/serializers/index.md
@@ -482,6 +492,11 @@ MIT License - see [LICENSE][license-file-url] for details.
482
492
  [distributed-locking-url]: docs/features/distributed-locking.md
483
493
  [prometheus-url]: docs/features/prometheus-metrics.md
484
494
  [encryption-url]: docs/features/zero-knowledge-encryption.md
495
+ [interop-url]: docs/features/interop-mode.md
496
+ [l1-invalidation-url]: docs/features/l1-invalidation.md
497
+ [reference-caching-url]: docs/features/reference-caching.md
498
+ [rust-serialization-url]: docs/features/rust-serialization.md
499
+ [ssrf-url]: docs/features/ssrf-protection.md
485
500
  [contributing-url]: CONTRIBUTING.md
486
501
  [license-file-url]: LICENSE
487
502
  [github-url]: https://github.com/cachekit-io/cachekit-py
@@ -9,11 +9,8 @@ pub use cachekit_core::{ByteStorage, OperationMetrics, StorageEnvelope};
9
9
  #[cfg(feature = "encryption")]
10
10
  pub use cachekit_core::{
11
11
  derive_domain_key,
12
- encryption::{
13
- key_derivation::{derive_tenant_keys, key_fingerprint, TenantKeys},
14
- key_rotation::KeyRotationState,
15
- },
16
- EncryptionError, ZeroKnowledgeEncryptor,
12
+ encryption::key_derivation::{derive_tenant_keys, key_fingerprint, TenantKeys},
13
+ EncryptionError, Keyring, ZeroKnowledgeEncryptor,
17
14
  };
18
15
 
19
16
  // Python bindings (gated behind python feature)