feat: Memcached + File backends (Node-only subpath exports) (LAB-430)#76
Conversation
…-430) Two new backends bring the (Node-runtime) TypeScript backend menu to parity with Python's, per the backend-agnostic core principle: - backends/file.ts — FileBackend implements Backend + TTLBackend. On-disk compatible with cachekit-py's File backend: blake2b(key, digestSize=16) hex filenames and the same 14-byte header (magic, version, flags, u64 BE expiry), pinned by python-generated golden vectors in the tests, so py and ts can share a cache directory. Atomic write-to-temp/fsync/rename, expired+corrupt entries unlinked on read, O_NOFOLLOW everywhere. Deliberate deltas from py (documented in the class doc): no LRU size eviction, no flock. - backends/memcached.ts — MemcachedBackend implements Backend via memjs (binary protocol, multi-server). Matches py's capability choices: base backend + directly-callable refreshTTL (touch), deliberately NOT TTLBackend because the protocol cannot read a key's remaining TTL. 30-day TTL clamp, client-side 1 MiB item-size guard, GET-based exists, client-side keyPrefix exposed for the interop guard. Dependency boundaries: both backends live behind subpath exports (./backends/file, ./backends/memcached) and are NOT re-exported from the root index; memjs is an optional peerDependency loaded lazily on first use. Browser/edge bundles importing the package root never see memjs or node:fs (verified: dist/index.js graph has no reference). Tests: 59 unit tests (File against real fs incl. py golden vectors; Memcached against a documented protocol-faithful memjs mock) plus a Testcontainers integration suite run against real memcached 1.6 (9 tests, green locally). Config types exported type-only from the root for discoverability. Co-authored-by: multica-agent <github@multica.ai>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 20 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (12)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Resolve against the LAB-595 entrypoint split: the Memcached/File config type exports land in index.ts's Node-only section (the backends stay behind subpath exports, unchanged), package.json keeps both new export maps (./backends/* from this branch, ./workers from main), and pnpm-lock.yaml is regenerated from main's lockfile plus this branch's memjs/@types-memjs additions.
|
Un-dirtied per LAB-761: merged main (the LAB-595 entrypoint split) into this branch. The Memcached/File config type exports moved into Verified locally: type-check, lint, format, full vitest (620 passed incl. memcached/file suites), and |
Co-authored-by: multica-agent <github@multica.ai>
🤖 I have created a release *beep* *boop* --- <details><summary>cachekit: 0.1.4</summary> ## [0.1.4](cachekit-v0.1.3...cachekit-v0.1.4) (2026-07-24) ### Features * Cloudflare Workers entrypoint on wasm32 cachekit-core (LAB-595) ([#78](#78)) ([d70d225](d70d225)) * Memcached + File backends (Node-only subpath exports) (LAB-430) ([#76](#76)) ([e22928d](e22928d)) </details> <details><summary>cachekit-core-wasm: 0.1.1</summary> ## [0.1.1](cachekit-core-wasm-v0.1.0...cachekit-core-wasm-v0.1.1) (2026-07-24) ### Features * Cloudflare Workers entrypoint on wasm32 cachekit-core (LAB-595) ([#78](#78)) ([d70d225](d70d225)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: cachekit-release-bot[bot] <247960786+cachekit-release-bot[bot]@users.noreply.github.com>
Summary
Implements the two missing backends that bring the (Node-runtime) TypeScript backend menu to parity with Python's — backend-agnostic is a core CacheKit principle, and until now a Node user of cachekit-ts had a smaller menu than a Python user for no principled reason.
FileBackend(backends/file.ts) — implementsBackend+TTLBackendblake2b(key, digestSize=16)hex (32 chars, flat layout) and every file carries the same 14-byte header (magicCK, version, flags, u64 BE expiry; 0 = never expire) — py and ts processes can share a cache directory. Pinned by python-generated golden vectors in the unit tests (filename hashes for 3 keys incl. unicode, plus full py-struct-packed file images parsed by ts, plus ts-written headers verified field-by-field).O_NOFOLLOWon every open, orphaned-temp-file sweep on init, 10-year TTL ceiling,maxValueBytesguard (100 MiB default, matching py).getTTL/refreshTTLread/rewrite the on-disk expiry header in place (payload untouched → cross-SDK readers stay compatible).refreshTTLthrows onttl <= 0per the ts-wideTTLBackendcontract (deliberate divergence from py'srefresh_ttl(0)= permanent — zero-semantics stay uniform across ts backends).MemcachedBackend(backends/memcached.ts) — implementsBackendrefreshTTL(viatouch, trivially free), deliberately notTTLBackend— the memcached protocol cannot read a key's remaining TTL, sogetTTLcannot exist and capability checks correctly exclude it.exists, client-sidekeyPrefixexposed for the interop fail-closed guard.Dependency boundaries (acceptance criterion)
@cachekit-io/cachekit/backends/file,…/backends/memcached) and are not re-exported from the root index — verified thatdist/index.js's module graph has no reference to either module or memjs.memjsis an optional peerDependency (dev-dep for tests), loaded lazily via dynamic import on first use with a clearConfigurationErrorif missing. Config interfaces are exported type-only from the root.Tests
pnpm test).createCache({ backend: file({...}) })round-trips through the full stack (L1 + MessagePack + reliability) on the built dist, both ESM and CJS subpaths load.Docs (matrix + README updated in sibling PRs)
protocol/sdk-feature-matrix.mdand docs.cachekit.io updated in sibling LAB-430 PRs (ts Memcached/File cells → ✅ with module evidence; stale LAB-427/LAB-446 capability cells refreshed).Closes LAB-430.