Skip to content

feat(universal-cache): add universal cache middleware package#1764

Open
lord007tn wants to merge 4 commits intohonojs:mainfrom
lord007tn:feat/universal-cache
Open

feat(universal-cache): add universal cache middleware package#1764
lord007tn wants to merge 4 commits intohonojs:mainfrom
lord007tn:feat/universal-cache

Conversation

@lord007tn
Copy link

@lord007tn lord007tn commented Feb 24, 2026

Summary

This PR introduces @hono/universal-cache as a new third-party middleware package for Hono.

It is the implementation path discussed in honojs/hono#3857:
honojs/hono#3857

This middleware has been running internally in our production systems for a while. After validating behavior under real traffic and edge cases, we are open-sourcing it so it can be reviewed and improved with community feedback.

Dependency Model

@hono/universal-cache depends on unstorage as the storage abstraction.

That gives us:

  • in-memory cache by default
  • adapter-based backends through unstorage drivers (Redis, KV, filesystem, and others)
  • one consistent cache API across runtimes

Major Features

  • response caching for Hono handlers via cacheMiddleware()
  • function-level caching via cacheFunction()
  • request-scoped defaults via cacheDefaults()
  • stale-while-revalidate (SWR) with background refresh
  • in-flight deduplication for revalidation/refresh paths
  • configurable cache keys (getKey) and integrity (integrity/hash)
  • custom serialize / deserialize hooks for response and function entries
  • cache control hooks: shouldBypassCache, shouldInvalidateCache, validate
  • configurable HTTP methods and varies support for cache key variation
  • configurable revalidation header (x-cache-revalidate by default)
  • keepPreviousOn5xx behavior for safer refresh failures
  • global helpers for cache defaults and storage instance management

Test Coverage

Added extensive tests for:

  • middleware caching behavior across methods
  • bypass/invalidation flows
  • SWR stale serving and background refresh behavior
  • vary-based keying
  • custom serialization/deserialization
  • function cache deduplication and validation
  • global defaults/storage helpers

Validation

  • corepack yarn eslint packages/universal-cache/src --cache --cache-location .cache/.eslintcache
  • corepack yarn workspace @hono/universal-cache typecheck
  • corepack yarn workspace @hono/universal-cache test --run
  • corepack yarn prettier --check packages/universal-cache/src/cache.ts packages/universal-cache/src/types.ts packages/universal-cache/src/index.test.ts

Related

Merge Note

Please merge this together with the docs PR above.

The author should do the following, if applicable

  • Add tests
  • Run tests
  • yarn changeset at the top of this repo and push the changeset
  • Follow the contribution guide

@changeset-bot
Copy link

changeset-bot bot commented Feb 24, 2026

🦋 Changeset detected

Latest commit: d79c864

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@hono/universal-cache Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codecov
Copy link

codecov bot commented Feb 26, 2026

Codecov Report

❌ Patch coverage is 93.78238% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.90%. Comparing base (8a0d4ea) to head (d79c864).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
packages/universal-cache/src/cache.ts 93.16% 21 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1764      +/-   ##
==========================================
+ Coverage   91.71%   91.90%   +0.19%     
==========================================
  Files         113      115       +2     
  Lines        3778     4164     +386     
  Branches      954     1067     +113     
==========================================
+ Hits         3465     3827     +362     
- Misses        281      302      +21     
- Partials       32       35       +3     
Flag Coverage Δ
universal-cache 93.78% <93.78%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@lord007tn
Copy link
Author

Addressed the Codecov coverage gaps with additional targeted tests.

What I added

  • New utility test suite:
    • packages/universal-cache/src/utils.test.ts
    • Covers all utils.ts branches and lines (normalizePathToName, stableStringify, TTL logic, expiry helpers).
  • Expanded index.test.ts with cache edge-case scenarios:
    • malformed path decoding fallback key path
    • cache entry rejection on integrity mismatch
    • cache entry rejection via validate()
    • rejection of cached headers containing etag: "undefined" / last-modified: "undefined"
    • invalidation behavior for non-cacheable no-store responses
    • function cache default key hashing path (without getKey)
    • removal of malformed function cache entries

Validation run

  • corepack yarn eslint packages/universal-cache/src --cache --cache-location .cache/.eslintcache
  • corepack yarn workspace @hono/universal-cache typecheck
  • corepack yarn workspace @hono/universal-cache test --run

All passed locally.

The new commit is: d79c864

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant