diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 4b10d29..9ff627e 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -6,7 +6,7 @@ **Feature parity and compliance status across all CacheKit SDK implementations.** -*Last updated: 2026-07-28 — LAB-998: interop/v1 ship-status corrected — the row no longer reads `unreleased`; all three SDKs have published it (PyPI 0.14.0+, crates.io 0.4.0+, npm 0.1.3+), stated as floors per footnote ⁴, aligned with docs.cachekit.io (LAB-996). LAB-729: rs backpressure flipped ❌ → ✅ (semaphore + bounded queue in the rs reliability stack; decision footnote records why the LAB-519 ts rationale doesn't transfer to tokio). LAB-430 shipped TypeScript Node-only Memcached and File backends; the protocol-owned File format and vectors now define fail-closed flag negotiation. LAB-446: Python File backend gains full TTL inspection/refresh; Memcached gains `refresh_ttl` (touch) only (see [TTL management note](#reliability-features)). LAB-595 shipped: ts Cloudflare Workers flipped ❌ → ✅ via the `@cachekit-io/cachekit/workers` entrypoint on a wasm32 cachekit-core build (~55 KB gz measured); footnote ¹ records the phase-1 surface and semantics deltas. LAB-519: ts cold-miss single-flight (in-process, always on) + LockableBackend wired into `wrap()`'s miss path (opt-in); ts backpressure decision recorded; ts Redis lock/TTL capability cells refreshed for LAB-427. LAB-272 code-verified protocol-adherence audit (2026-07-22): interop/v1 merged in Python ([cachekit-py#220](https://github.com/cachekit-io/cachekit-py/pull/220)), TypeScript ([cachekit-ts#71](https://github.com/cachekit-io/cachekit-ts/pull/71)), and Rust ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)); test-vector CI coverage corrected* +*Last updated: 2026-07-28 — LAB-998: interop/v1 ship-status corrected — the row no longer reads `unreleased`; all three SDKs have published it (PyPI 0.14.0+, crates.io 0.4.0+, npm 0.1.3+), stated as floors per footnote ⁴, aligned with docs.cachekit.io (LAB-996). LAB-750: ts Workers gains native edge storage — Workers KV + Cache API backend rows added (footnote ¹ updated: phase-1 CachekitIO-only surface superseded; backend instances now accepted by the `minimal`/`production`/`secure` intents in every ts entrypoint). LAB-729: rs backpressure flipped ❌ → ✅ (semaphore + bounded queue in the rs reliability stack; decision footnote records why the LAB-519 ts rationale doesn't transfer to tokio). LAB-430 shipped TypeScript Node-only Memcached and File backends; the protocol-owned File format and vectors now define fail-closed flag negotiation. LAB-446: Python File backend gains full TTL inspection/refresh; Memcached gains `refresh_ttl` (touch) only (see [TTL management note](#reliability-features)). LAB-595 shipped: ts Cloudflare Workers flipped ❌ → ✅ via the `@cachekit-io/cachekit/workers` entrypoint on a wasm32 cachekit-core build (~55 KB gz measured); footnote ¹ records the phase-1 surface and semantics deltas. LAB-519: ts cold-miss single-flight (in-process, always on) + LockableBackend wired into `wrap()`'s miss path (opt-in); ts backpressure decision recorded; ts Redis lock/TTL capability cells refreshed for LAB-427. LAB-272 code-verified protocol-adherence audit (2026-07-22): interop/v1 merged in Python ([cachekit-py#220](https://github.com/cachekit-io/cachekit-py/pull/220)), TypeScript ([cachekit-ts#71](https://github.com/cachekit-io/cachekit-ts/pull/71)), and Rust ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)); test-vector CI coverage corrected* @@ -76,9 +76,11 @@ | File (local) | ✅ `backends/file` (stdlib + mmap) | ✅ `file` feature (byte-compatible with py)³ | ✅ `backends/file.ts` (Node-only; [format](spec/file-backend-format.md))⁴ | ❌ | | CacheKit SaaS (HTTP) | ✅ `backends/cachekitio` (httpx) | ✅ `cachekitio` feature (reqwest, default) | ✅ `backends/cachekitio.ts` (fetch) | 🔜 Planned | | Cloudflare Workers | N/A | ✅ `workers` feature (`worker::Fetch`) | ✅ `@cachekit-io/cachekit/workers` (wasm32 core)¹ | N/A | +| Workers KV (Cloudflare) | N/A | ❌ | ✅ `workersKV` on the `/workers` entry (LAB-750)¹ | N/A | +| Cache API (Cloudflare) | N/A | ❌ | ✅ `workersCacheAPI` on the `/workers` entry (LAB-750)¹ | N/A | | DynamoDB | ❌² | ❌ | ❌ | ❌ | -> ¹ Shipped in LAB-595 (2026-07-24), following spike LAB-431's GO verdict: the `@cachekit-io/cachekit/workers` subpath (also the `workerd` condition on the root export) runs crypto and the ByteStorage envelope on a **wasm32 build of cachekit-core** (`@cachekit-io/cachekit-core-wasm`, 137 KB raw / ~55 KB gzipped + ~10 KB JS glue, wasm-bindgen `--target web` + wasm-opt `-Oz`) — counter nonces and the envelope carry over unchanged and the crypto stays single-touchpoint in the Rust core; byte-verified against the Python-ground-truth `test-vectors/encryption.json` and `wire-format.json` suites inside real workerd. Phase-1 surface: CachekitIO backend (pure `fetch`) or a custom `Backend` instance; Redis-URL intents, Redis Pub/Sub invalidation, and Prometheus metrics stay Node-only and are excluded from the edge bundle (CI-guarded: no `node:*`, no NAPI, no ioredis/prom-client — no `nodejs_compat` flag needed); SWR background refresh is forced off (fire-and-forget refreshes aren't tied to `ctx.waitUntil` yet and workerd cancels them at response return). Semantics delta: keys live in wasm linear memory (a host-readable ArrayBuffer), weaker isolation than NAPI's Rust heap but ~JS-heap-equivalent on Workers where the host is your own isolate; zeroized deterministically on `dispose()`. WebCrypto (AES-256-GCM + HKDF-SHA256, random-nonce fallback per [encryption.md → Nonce Generation](spec/encryption.md#nonce-generation)) remains the documented fallback if the wasm path ever hits a wall. +> ¹ Shipped in LAB-595 (2026-07-24), following spike LAB-431's GO verdict: the `@cachekit-io/cachekit/workers` subpath (also the `workerd` condition on the root export) runs crypto and the ByteStorage envelope on a **wasm32 build of cachekit-core** (`@cachekit-io/cachekit-core-wasm`, 137 KB raw / ~55 KB gzipped + ~10 KB JS glue, wasm-bindgen `--target web` + wasm-opt `-Oz`) — counter nonces and the envelope carry over unchanged and the crypto stays single-touchpoint in the Rust core; byte-verified against the Python-ground-truth `test-vectors/encryption.json` and `wire-format.json` suites inside real workerd. Backend surface (phase 2, LAB-750): CachekitIO (pure `fetch`), **Workers KV** (`workersKV({ kv })` over a `KVNamespace` binding; native `expirationTtl` with its 60s floor — shorter TTLs clamp up, `ttl <= 0` stores without expiry; eventually consistent ~60s), the **Cache API** (`workersCacheAPI()` over `caches.default`/named caches; per-data-center only, `Cache-Control: max-age` to the second, best-effort eviction, keys mapped to synthetic never-fetched URLs), or a custom `Backend` instance — all storage transports over the unchanged opaque ByteStorage payload (encryption above the backend; secure caches store ciphertext only). Backend instances are accepted by the `minimal`/`production`/`secure` intents (`{ backend }` in place of `{ url }`, both entrypoints); Redis-URL intents, Redis Pub/Sub invalidation, and Prometheus metrics stay Node-only and are excluded from the edge bundle (CI-guarded: no `node:*`, no NAPI, no ioredis/prom-client — no `nodejs_compat` flag needed); SWR background refresh is forced off (fire-and-forget refreshes aren't tied to `ctx.waitUntil` yet and workerd cancels them at response return). Semantics delta: keys live in wasm linear memory (a host-readable ArrayBuffer), weaker isolation than NAPI's Rust heap but ~JS-heap-equivalent on Workers where the host is your own isolate; zeroized deterministically on `dispose()`. WebCrypto (AES-256-GCM + HKDF-SHA256, random-nonce fallback per [encryption.md → Nonce Generation](spec/encryption.md#nonce-generation)) remains the documented fallback if the wasm path ever hits a wall. > > ² DynamoDB has never shipped in any SDK. The previous Python ✅ traced to the [custom-backend tutorial](https://github.com/cachekit-io/cachekit-py/blob/main/docs/backends/custom.md), which shows how a *user* can implement the backend protocol against DynamoDB — that is an extension point, not shipped support (LAB-273).