Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/fuzzy-garlic-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@hono/universal-cache': minor
---

Add `@hono/universal-cache`, a universal cache toolkit for Hono with:

- `cacheMiddleware()` for response caching
- `cacheDefaults()` for scoped defaults
- `cacheFunction()` for caching async function results
- stale-while-revalidate support
- storage/default accessors (`set/getCacheStorage`, `set/getCacheDefaults`)
- custom keying, serialization, validation, and invalidation hooks
1 change: 1 addition & 0 deletions deno.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
// "packages/tsyringe",
"packages/typebox-validator",
"packages/typia-validator",
// "packages/universal-cache",
"packages/valibot-validator",
// "packages/zod-openapi",
"packages/zod-validator",
Expand Down
1 change: 1 addition & 0 deletions packages/universal-cache/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# @hono/universal-cache
81 changes: 81 additions & 0 deletions packages/universal-cache/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# @hono/universal-cache

[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=universal-cache)](https://codecov.io/github/honojs/middleware)

Universal cache utilities for Hono.

## Features

- Response caching with `cacheMiddleware()`
- Function result caching with `cacheFunction()`
- Stale-while-revalidate support
- Cache defaults via middleware `cacheDefaults()`
- Custom keying, storage, serialization, and validation

## Usage

```ts
import { Hono } from 'hono'
import { cacheMiddleware } from '@hono/universal-cache'

const app = new Hono()

app.get('/items', cacheMiddleware(60), (c) => c.json({ ok: true }))
```

## Configure defaults

```ts
import { Hono } from 'hono'
import { cacheDefaults } from '@hono/universal-cache'
import { createStorage } from 'unstorage'
import memoryDriver from 'unstorage/drivers/memory'

const app = new Hono()

app.use(
cacheDefaults({
storage: createStorage({ driver: memoryDriver() }),
maxAge: 60,
staleMaxAge: 30,
swr: true,
})
)
```

## Cached function

```ts
import { cacheFunction } from '@hono/universal-cache'

const getStats = cacheFunction(async (id: string) => ({ id, ts: Date.now() }), {
maxAge: 60,
getKey: (id) => id,
})
```

## API

- `cacheMiddleware(options | maxAge)`
- `cacheDefaults(options)`
- `cacheFunction(fn, options | maxAge)`
- `setCacheStorage(storage)` / `getCacheStorage()`
- `setCacheDefaults(options)` / `getCacheDefaults()`
- `createCacheStorage()`

## Notes

- Cached responses drop `set-cookie` and hop-by-hop headers.
- Manual cache revalidation is disabled by default. Set `revalidateHeader` to opt in.
- Use `shouldRevalidate` to gate manual revalidation requests.
- Middleware cache defaults to `GET` and `HEAD`.
- Default `maxAge` is `60` seconds.
- On `workerd`, stale middleware entries are refreshed synchronously instead of using background self-fetch.

## Author

Raed B. <https://github.com/lord007tn>

## License

MIT
15 changes: 15 additions & 0 deletions packages/universal-cache/deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "@hono/universal-cache",
"version": "0.0.0",
"license": "MIT",
"exports": {
".": "./src/index.ts"
},
"imports": {
"hono": "jsr:@hono/hono@^4.8.3"
},
"publish": {
"include": ["deno.json", "README.md", "src/**/*.ts"],
"exclude": ["src/**/*.test.ts"]
}
}
60 changes: 60 additions & 0 deletions packages/universal-cache/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"name": "@hono/universal-cache",
"version": "0.0.0",
"description": "Universal cache middleware and helpers for Hono",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsdown",
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint",
"typecheck": "tsc -b tsconfig.json",
"test": "vitest",
"test:workerd": "vitest --config vitest.workerd.config.ts",
"version:jsr": "yarn version:set $npm_package_version"
},
"license": "MIT",
"publishConfig": {
"registry": "https://registry.npmjs.org",
"access": "public",
"provenance": true
},
"repository": {
"type": "git",
"url": "git+https://github.com/honojs/middleware.git",
"directory": "packages/universal-cache"
},
"homepage": "https://github.com/honojs/middleware",
"peerDependencies": {
"hono": ">=4.0.0"
},
"dependencies": {
"ohash": "^2.0.11",
"unstorage": "^1.17.0"
},
"devDependencies": {
"@cloudflare/vitest-pool-workers": "https://pkg.pr.new/@cloudflare/vitest-pool-workers@7143d5d",
"@cloudflare/workers-types": "^4.20250612.0",
"hono": "^4.11.5",
"tsdown": "^0.15.9",
"typescript": "^5.9.3",
"vitest": "^4.1.0-beta.1"
}
}
Loading