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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- **Node Hono middleware (`tricache/hono`)** — first-class `cacheMiddleware` on `CacheService` (ttl/tags/SWR, weak ETag, `If-None-Match` → 304, no cache for non-2xx). Distinct from the edge helper under `tricache/edge`.

## [0.8.0] — 2026-09-16

### Added
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ tricache/
│ ├── nestjs/ # NestJS CacheModule & interceptors
│ ├── prisma/ # Prisma client caching extension
│ ├── drizzle/ # Drizzle ORM query caching helper
│ └── http/ # HTTP reverse-proxy / fetch caching
│ ├── http/ # HTTP reverse-proxy / fetch caching
│ ├── hono/ # Node Hono middleware (CacheService)
├── tests/ # Vitest unit & integration test suites
├── bench/ # Microbenchmark suites
├── bin/ # CLI binaries
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Docs](https://img.shields.io/badge/docs-VitePress-blue.svg)](https://kareem411.github.io/TriCache/)
[![npm version](https://img.shields.io/npm/v/tricache.svg)](https://www.npmjs.com/package/tricache)
[![npm downloads](https://img.shields.io/npm/dm/tricache.svg)](https://www.npmjs.com/package/tricache)
[![Tests](https://img.shields.io/badge/tests-816%20passing-brightgreen)](tests)
[![Tests](https://img.shields.io/badge/tests-822%20passing-brightgreen)](tests)
[![Code Quality](https://img.shields.io/badge/oxlint-0%20warnings-brightgreen)](src)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Node.js ≥ 20](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
Expand Down Expand Up @@ -122,6 +122,7 @@ const cache = CacheService.preset('enterprise-hardened', { redisHost: 'redis.int
| **Prisma ORM** | `tricache/prisma` | `$extends` client extension with query hashing and auto-mutation tag eviction. |
| **Drizzle ORM** | `tricache/drizzle` | `withCache(query, opts)` query wrapper with SQL+parameters hashing and background SWR. |
| **Express & Fastify** | `tricache/http` | Route caching middleware with deterministic query sorting, weak ETag, and `304 Not Modified`. |
| **Hono (Node)** | `tricache/hono` | First-class `cacheMiddleware` on `CacheService` with ttl/tags/SWR, weak ETag, and `304 Not Modified`. |
| **Hono & Edge Isolates** | `tricache/edge` | Zero-Node-dependency implementation for Cloudflare Workers, Fastly Compute, Hono, and Vercel Edge. |
| **SSE Dashboard** | `tricache/dashboard` | Zero-dependency Server-Sent Events real-time admin dashboard. |
| **Live CLI Top** | `npx tricache top` | Real-time terminal ASCII monitor over Unix sockets and Windows named pipes. |
Expand Down
3 changes: 2 additions & 1 deletion docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ export default defineConfig({
{ text: 'NestJS Dynamic Module', link: '/integrations/nestjs' },
{ text: 'Prisma ORM Extension', link: '/integrations/prisma' },
{ text: 'Drizzle ORM Wrapper', link: '/integrations/drizzle' },
{ text: 'Express & Hono Middleware', link: '/integrations/http' },
{ text: 'Express & Fastify Middleware', link: '/integrations/http' },
{ text: 'Hono Node Middleware', link: '/integrations/hono' },
{ text: 'Edge Isolates (Workers)', link: '/integrations/edge' },
{ text: 'Visual Dashboard & CLI', link: '/integrations/dashboard' },
],
Expand Down
2 changes: 1 addition & 1 deletion docs/.vitepress/theme/components/IntegrationGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ withDefaults(defineProps<Props>(), {
</div>
<div class="card-meta">
<span class="card-name">Express / Hono</span>
<span class="card-desc">Edge Middleware</span>
<span class="card-desc">Node + Edge Middleware</span>
</div>
</a>

Expand Down
13 changes: 12 additions & 1 deletion docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ The TriCache engine honors the following environment variables across all enviro

---

## 9. HTTP & Framework Middlewares (`tricache/http` & `tricache/edge`)
## 9. HTTP & Framework Middlewares (`tricache/http`, `tricache/hono` & `tricache/edge`)

### `createExpressMiddleware(cache, options?)`
Creates an Express/Connect route middleware with deterministic query sorting, weak ETag calculation, and RFC 7232 `304 Not Modified` short-circuiting.
Expand All @@ -486,6 +486,17 @@ import { createFastifyPlugin } from 'tricache/http';
await fastify.register(createFastifyPlugin(cache, { ttlSeconds: 120 }));
```

### `cacheMiddleware(options?)` (`tricache/hono`)
Creates Node Hono middleware on `CacheService` with Express-aligned ttl/tags/SWR, weak ETags, and RFC 7232 `304 Not Modified`. Non-2xx responses are not cached.

```typescript
import { cacheMiddleware } from 'tricache/hono';

app.get('/api/posts', cacheMiddleware({ ttl: 300, tags: ['posts'] }), (c) => {
return c.json({ data: '...' });
});
```

### `createHonoEdgeMiddleware(edgeCache, options?)`
Creates a decoupled Hono edge middleware using pure Web Standards (`Request`, `Response`, `crypto.subtle`) with zero Node native dependencies.

Expand Down
5 changes: 5 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- **Node Hono middleware (`tricache/hono`)** — first-class `cacheMiddleware` on `CacheService` (ttl/tags/SWR, weak ETag, `If-None-Match` → 304, no cache for non-2xx). Distinct from the edge helper under `tricache/edge`.

## [0.8.0] — 2026-09-16

### Added
Expand Down
76 changes: 76 additions & 0 deletions docs/integrations/hono.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Hono Node Middleware

> Package entry: `tricache/hono`

First-class **Node.js** Hono middleware backed by `CacheService` (L1 RAM → L1.5 disk → L2 Redis). This is the adapter requested for Hono apps running on Node — not the Web-Crypto edge helper under [`tricache/edge`](/integrations/edge).

```typescript
import { Hono } from 'hono';
import { cacheMiddleware } from 'tricache/hono';

const app = new Hono();

app.get('/api/posts', cacheMiddleware({ ttl: 300, tags: ['posts'] }), (c) => {
return c.json({ data: '...' });
});
```

Pass an explicit `CacheService` when you already have one:

```typescript
import { CacheService } from 'tricache';
import { cacheMiddleware } from 'tricache/hono';

const cache = CacheService.create();

app.get(
'/api/posts',
cacheMiddleware({
cache,
ttl: 300,
swr: 60,
tags: ['posts'],
headerWhitelist: ['accept-language'],
}),
(c) => c.json({ data: '...' }),
);
```

`createHonoMiddleware` is an alias of `cacheMiddleware`.

---

## Node vs edge

| Entry | Runtime | Cache engine | Import |
|:---|:---|:---|:---|
| **`tricache/hono`** | Node.js | `CacheService` | `import { cacheMiddleware } from 'tricache/hono'` |
| **`tricache/edge`** | Workers / edge isolates | `EdgeCacheService` | `import { honoEdgeCache } from 'tricache/edge'` |

`tricache/http` still re-exports the edge helper as `honoCache` for compatibility. New Node Hono apps should import `tricache/hono`.

---

## Behavior

* **Safe methods only**: `GET` and `HEAD` are cached; other methods pass through.
* **Weak ETags**: SHA-1 weak validators (`ETag: W/"…"`) via the same Node helper as Express.
* **304 Not Modified**: matching `If-None-Match` short-circuits with an empty body.
* **Status gate**: non-2xx responses are never kept (4xx/5xx cannot poison a key).
* **Bypass**: `Cache-Control: no-cache` / `no-store` and a custom `skipCache` predicate skip the cache.
* **SWR & tags**: `ttl`, `swr`, and `tags` are forwarded to `CacheService.get`, matching Express middleware.

---

## Options

| Option | Type | Default | Description |
|---|---|---|---|
| `cache` | `CacheService` | singleton | TriCache instance. If omitted, lazily resolves `CacheService.create()` |
| `ttl` | `number` | `300` | Time-to-live in seconds |
| `swr` | `number` | `undefined` | Stale-While-Revalidate window in seconds |
| `etag` | `boolean` | `true` | Generate and evaluate weak ETags (`W/"…"`) |
| `keyGenerator` | `(c) => string` | method + URL + sorted query | Custom cache key from the Hono context |
| `headerWhitelist` | `string[]` | `[]` | Request headers incorporated into the cache key |
| `skipCache` | `(c) => boolean` | `undefined` | Predicate returning true to bypass cache |
| `tags` | `string[] \| ((c) => string[])` | `[]` | Semantic tags for targeted `cache.invalidateTag()` |
2 changes: 2 additions & 0 deletions docs/integrations/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

TriCache provides enterprise-grade HTTP route caching middleware with weak ETag calculation, deterministic query sorting, and RFC 7232 `304 Not Modified` short-circuiting for Express, Fastify, Connect, and Node.js HTTP servers.

For **Node Hono** (`CacheService`, `import { cacheMiddleware } from 'tricache/hono'`), see [Hono Node Middleware](/integrations/hono). The `honoCache` export from this package is the edge helper — prefer [`tricache/edge`](/integrations/edge) for Workers.

### Ready-to-run Express demo

A self-contained microservice lives at [`examples/express-api`](https://github.com/Kareem411/TriCache/tree/main/examples/express-api). It exercises weak ETags, `If-None-Match` → `304`, deterministic query sorting, `headerWhitelist: ['accept-language']`, and `skipCache` for `Authorization`.
Expand Down
3 changes: 2 additions & 1 deletion docs/integrations/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Explore the dedicated guides for your application stack:
| **[NestJS Module](/integrations/nestjs)** | `tricache/nestjs` | Dynamic `TriCacheModule` (`register`/`registerAsync`), `@Cacheable` and `@CacheEvict` decorators. |
| **[Prisma ORM Extension](/integrations/prisma)** | `tricache/prisma` | `$extends(withTriCache())`, automatic mutation invalidation, deterministic query key hashing. |
| **[Drizzle ORM Wrapper](/integrations/drizzle)** | `tricache/drizzle` | `withCache(query)`, SQL + parameterized argument hashing, custom TTL and tag assignment. |
| **[Express & Hono Middleware](/integrations/http)** | `tricache/http` | Route caching middleware, weak ETag calculation, RFC 7232 `304 Not Modified` short-circuiting. |
| **[Express & Fastify Middleware](/integrations/http)** | `tricache/http` | Route caching middleware, weak ETag calculation, RFC 7232 `304 Not Modified` short-circuiting. |
| **[Hono Node Middleware](/integrations/hono)** | `tricache/hono` | First-class `cacheMiddleware` on `CacheService` with ttl/tags/SWR and `304 Not Modified`. |
| **[Edge Isolates (Workers)](/integrations/edge)** | `tricache/edge` | Universal zero-Node runtime for Cloudflare Workers, Fastly Compute, Web Crypto, WASM Bloom. |
| **[Visual Dashboard & CLI](/integrations/dashboard)** | `tricache/dashboard` | Real-time SSE Web UI, Next.js route handlers, standalone management server, CLI. |
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@
"import": "./dist/edge/index.js",
"require": "./dist/edge/index.cjs",
"default": "./dist/edge/index.js"
},
"./hono": {
"types": "./dist/hono/index.d.ts",
"import": "./dist/hono/index.js",
"require": "./dist/hono/index.cjs"
}
},
"files": [
Expand All @@ -93,7 +98,7 @@
"LICENSE"
],
"scripts": {
"build": "tsup src/index.ts src/cli.ts src/serialize-worker.ts src/next/index.ts src/nestjs/index.ts src/prisma/index.ts src/drizzle/index.ts src/http/index.ts src/dashboard/index.ts src/edge/index.ts --format esm,cjs --dts --clean",
"build": "tsup src/index.ts src/cli.ts src/serialize-worker.ts src/next/index.ts src/nestjs/index.ts src/prisma/index.ts src/drizzle/index.ts src/http/index.ts src/dashboard/index.ts src/edge/index.ts src/hono/index.ts --format esm,cjs --dts --clean",
"postbuild": "node --input-type=module -e \"import{readdirSync,rmSync,statSync}from'fs';import{join}from'path';function clean(d){for(const f of readdirSync(d)){const p=join(d,f);if(statSync(p).isDirectory())clean(p);else if(p.endsWith('.d.cts'))rmSync(p,{force:true});}}clean('dist');\"",
"dev": "tsup src/index.ts src/serialize-worker.ts --format esm,cjs --dts --watch",
"typecheck": "tsc --noEmit",
Expand Down
Loading
Loading