@leejpsd/nextjs-cache-handler 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +67 -2
  2. package/README.md +47 -25
  3. package/dist/cache-components/index.cjs +235 -46
  4. package/dist/cache-components/index.cjs.map +1 -1
  5. package/dist/cache-components/index.d.cts +1 -1
  6. package/dist/cache-components/index.d.ts +1 -1
  7. package/dist/cache-components/index.js +227 -46
  8. package/dist/cache-components/index.js.map +1 -1
  9. package/dist/incremental/index.cjs +231 -41
  10. package/dist/incremental/index.cjs.map +1 -1
  11. package/dist/incremental/index.d.cts +42 -3
  12. package/dist/incremental/index.d.ts +42 -3
  13. package/dist/incremental/index.js +223 -41
  14. package/dist/incremental/index.js.map +1 -1
  15. package/dist/index.cjs +313 -70
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +305 -70
  20. package/dist/index.js.map +1 -1
  21. package/dist/ops/index.d.cts +1 -1
  22. package/dist/ops/index.d.ts +1 -1
  23. package/dist/otel/index.cjs +72 -0
  24. package/dist/otel/index.cjs.map +1 -0
  25. package/dist/otel/index.d.cts +72 -0
  26. package/dist/otel/index.d.ts +72 -0
  27. package/dist/otel/index.js +64 -0
  28. package/dist/otel/index.js.map +1 -0
  29. package/dist/shared/client/adapter-ioredis.cjs +49 -10
  30. package/dist/shared/client/adapter-ioredis.cjs.map +1 -1
  31. package/dist/shared/client/adapter-ioredis.d.cts +5 -2
  32. package/dist/shared/client/adapter-ioredis.d.ts +5 -2
  33. package/dist/shared/client/adapter-ioredis.js +43 -11
  34. package/dist/shared/client/adapter-ioredis.js.map +1 -1
  35. package/dist/shared/client/adapter-redis.cjs +22 -7
  36. package/dist/shared/client/adapter-redis.cjs.map +1 -1
  37. package/dist/shared/client/adapter-redis.d.cts +1 -1
  38. package/dist/shared/client/adapter-redis.d.ts +1 -1
  39. package/dist/shared/client/adapter-redis.js +16 -7
  40. package/dist/shared/client/adapter-redis.js.map +1 -1
  41. package/dist/{types-Dq1q6qXd.d.cts → types-Bl-rkLKX.d.cts} +37 -1
  42. package/dist/{types-Dq1q6qXd.d.ts → types-Bl-rkLKX.d.ts} +37 -1
  43. package/package.json +27 -5
package/CHANGELOG.md CHANGED
@@ -1,11 +1,78 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`f07e91b`](https://github.com/leejpsd/nextjs-cache-handler/commit/f07e91b432be6d52885f2f0a83bfb6c63d519bbe) Thanks [@leejpsd](https://github.com/leejpsd)! - Refresh the npm package description and keywords for the 0.3 feature set:
8
+ Next.js 15/16, built-in compression, Redis Sentinel, OpenTelemetry, and the
9
+ multi-instance AWS validation results.
10
+
11
+ ## 0.3.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [`dc1ac0a`](https://github.com/leejpsd/nextjs-cache-handler/commit/dc1ac0a0b29e73485f4af587f8ec0f4b68d1d54f) Thanks [@leejpsd](https://github.com/leejpsd)! - Reliability fixes (reconnect backoff instead of a permanent connect-failure
16
+ latch, bounded memory fallback, namespace-scoped tag propagation without
17
+ truncation, strict `fallback: "never"` honored by the ISR handler, working
18
+ ESM peer loading) plus new features: Next.js 15 ISR support, request-scoped
19
+ GET deduplication, transparent gzip/brotli value compression, Redis Sentinel
20
+ support, a built-in OpenTelemetry adapter at `/otel`, and `memoryMaxEntries`.
21
+
3
22
  All notable changes to this project are documented here. The format is
4
23
  based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
5
24
  this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
25
 
7
26
  ## [Unreleased]
8
27
 
28
+ ### Added
29
+
30
+ - **Next.js 15 support** for the singular `cacheHandler` (ISR): both ctx
31
+ generations accepted (`ctx.revalidate`/`kindHint` and
32
+ `ctx.cacheControl`/`kind`); `peerDependencies.next` widened to
33
+ `>=15.0.0 <17`. Verified end to end against Next 15.5 (build, ISR
34
+ HIT/MISS, tag/path revalidation, fetch-cache TTL, cross-process reads).
35
+ - **Request-scoped GET deduplication** (singular handler):
36
+ `resetRequestCache()` is now a real implementation — duplicate reads of a
37
+ cache key within one request share a single Redis GET. New metric event
38
+ `cache.get.deduped`.
39
+ - **Transparent value compression** (`compression: "gzip" | "brotli"`,
40
+ default off) via node:zlib — marker-prefixed storage with auto-detecting
41
+ reads, safe to enable on a live cache with a mixed fleet. Payloads < 1 KiB
42
+ stay plain.
43
+ - **Redis Sentinel support** (`{ type: "sentinel", sentinels, name }`) via
44
+ ioredis master discovery — verified locally including a live failover.
45
+ - **Built-in OpenTelemetry adapter** at
46
+ `@leejpsd/nextjs-cache-handler/otel` (`createOtelMetricEmitter`);
47
+ `@opentelemetry/api` is an optional peer resolved at runtime.
48
+ - **`memoryMaxEntries` option** (default 1000) bounding the in-memory
49
+ fallback stores with LRU eviction.
50
+
51
+ ### Fixed
52
+
53
+ - **Connect failures no longer latch the process into memory-only mode.**
54
+ Reconnects retry with exponential backoff (1s→30s cap) and dropped
55
+ connections are replaced (dead clients disposed).
56
+ - **`refreshTags` scans only the current build namespace** and processes
57
+ markers chunk-by-chunk — the previous 500-key cap silently left tags
58
+ unpropagated; the local mirror is now rebuilt per complete scan (bounded
59
+ by live markers) and `memTagExp` is capped.
60
+ - **`fallback: "never"` is honored by the singular handler** (it previously
61
+ read/wrote the memory fallback unconditionally, silently degrading strict
62
+ mode to per-process caching).
63
+ - **ESM build can load optional peers**: bare `require()` calls became
64
+ esbuild's throwing `__require` fallback in ESM; now routed through
65
+ `createRequire` with a CWD fallback for symlinked installs (npm file
66
+ installs, pnpm).
67
+
68
+ ### Changed
69
+
70
+ - Multi-tag `updateTags` fans out concurrently (one round trip via
71
+ auto-pipelining) instead of one await per tag; ioredis clients enable
72
+ `enableAutoPipelining`.
73
+ - Removed the declared-but-never-emitted `cache.stale.refresh.skipped`
74
+ metric event type.
75
+
9
76
  ## [0.2.0] - 2026-05-10
10
77
 
11
78
  First minor bump. Three differentiators land in this release.
@@ -117,8 +184,6 @@ runtime cache key shapes.
117
184
  - Provenance attestation is disabled for the local-publish flow; v0.2
118
185
  will switch to GitHub Actions OIDC publish
119
186
 
120
-
121
-
122
187
  ### Added — `cacheHandlers` (plural) for `'use cache'`
123
188
 
124
189
  - `createCacheComponentsHandler(opts)` factory implementing the full
package/README.md CHANGED
@@ -3,17 +3,20 @@
3
3
  [![npm](https://img.shields.io/npm/v/@leejpsd/nextjs-cache-handler.svg)](https://www.npmjs.com/package/@leejpsd/nextjs-cache-handler)
4
4
  [![license](https://img.shields.io/npm/l/@leejpsd/nextjs-cache-handler.svg)](./LICENSE)
5
5
 
6
- > **`v0.2.0`** — install with
6
+ > **`v0.3.0`** — install with
7
7
  > `npm install @leejpsd/nextjs-cache-handler`. Production-validated against
8
- > AWS ECS Fargate with multi-instance Redis (24h live-traffic soak: 0
9
- > errors, 0 leaks, 2ms Redis ping, namespace isolation working).
8
+ > AWS ECS Fargate with multi-instance Redis (v0.1: 24h live-traffic soak;
9
+ > v0.3: fresh multi-instance verification incl. a live Redis-reboot drill
10
+ > with zero 5xx — see
11
+ > [`docs/staging-verification-2026-08-01.md`](./docs/staging-verification-2026-08-01.md)).
10
12
  >
11
- > v0.2 adds: optional **single-flight refresh lock** for cache-stampede
12
- > protection at the SWR boundary, a reference **OpenTelemetry** wrapper,
13
- > and **integration tests** (21 scenarios) running against real Redis 7
14
- > over both `redis@5` and `ioredis` adapters.
13
+ > v0.3 adds: **Next.js 15 support** (ISR handler), **reconnect with
14
+ > exponential backoff** (no more permanent memory-only latch), **request-scoped
15
+ > GET deduplication**, transparent **gzip/brotli compression**, **Redis
16
+ > Sentinel** support, a built-in **OpenTelemetry emitter** at `/otel`, and an
17
+ > LRU-bounded memory fallback.
15
18
 
16
- The Redis cache handler for **Next.js 16** that ships **both** `cacheHandler`
19
+ The Redis cache handler for **Next.js 15/16** that ships **both** `cacheHandler`
17
20
  (ISR / Pages Router) **and** `cacheHandlers` (`'use cache'` directive,
18
21
  `cacheComponents: true`) — the area where
19
22
  [`@fortedigital/nextjs-cache-handler`](https://github.com/fortedigital/nextjs-cache-handler)
@@ -54,18 +57,19 @@ As of 2026-05, the leading OSS Redis handler `@fortedigital/nextjs-cache-handler
54
57
  declares `peerDependencies.next: ">=16.1.5"` but the README marks the new
55
58
  plural interface as ❌ **"Not yet supported - Help needed"**:
56
59
 
57
- > 📅 **Compatibility matrix verified 2026-05-10.** The OSS Next.js cache
60
+ > 📅 **Compatibility matrix re-verified 2026-07-31** (from each project's
61
+ > published README/registry metadata). The OSS Next.js cache
58
62
  > handler ecosystem moves quickly — please verify
59
63
  > [`@fortedigital`](https://github.com/fortedigital/nextjs-cache-handler#compatibility)
60
64
  > and
61
65
  > [`nextjs-turbo-redis-cache`](https://github.com/trieb-work/nextjs-turbo-redis-cache#features)
62
66
  > directly before relying on this comparison.
63
67
 
64
- | Next 16 feature | this | @fortedigital 3.2.0 | nextjs-turbo-redis-cache 1.13 |
68
+ | Feature | this (0.3.0) | @fortedigital 3.2.1 | nextjs-turbo-redis-cache 1.15 |
65
69
  |---|---|---|---|
66
70
  | `cacheHandlers` config (plural) | ✅ | ❌ Help needed | ✅ since 1.11 |
67
71
  | `'use cache'` directive | ✅ | ❌ Help needed | ✅ since 1.11 |
68
- | `'use cache: remote'` | ✅ | ❌ Help needed | partial |
72
+ | `'use cache: remote'` | ✅ default handler (dedicated multi-tier: roadmap) | ❌ Help needed | partial |
69
73
  | `'use cache: private'` | n/a (uncustomizable) | n/a | n/a |
70
74
  | `cacheComponents: true` | ✅ | ❌ Help needed | ✅ |
71
75
  | Build-phase skip (`PHASE_PRODUCTION_BUILD`) | ✅ | ✅ (singular only) | ✅ |
@@ -75,13 +79,17 @@ plural interface as ❌ **"Not yet supported - Help needed"**:
75
79
  | Redis Cluster | ✅ (cluster adapter, see Production checklist) | ✅ | ✅ |
76
80
  | ioredis support | ✅ | ✅ | ✅ |
77
81
  | In-memory fallback (TTL-aware) | ✅ | partial | ✅ L1 + Redis L2 |
78
- | OpenTelemetry hook | ✅ `onMetric` | ❌ | ❌ |
82
+ | Next 15 support (ISR handler) | ✅ `>=15.0.0` | ✅ (legacy 2.x line) | ✅ `>=15.0.3` |
83
+ | Request-scoped GET dedup | ✅ | ❌ | ✅ |
84
+ | Built-in value compression | ✅ gzip/brotli option | example only | example only |
85
+ | Redis Sentinel | ✅ (local failover drill) | ❌ | ❌ |
86
+ | OpenTelemetry | ✅ built-in `/otel` emitter + `onMetric` hook | ❌ | ❌ |
87
+ | Reconnect strategy | ✅ exponential backoff | client-level | error-threshold restart |
79
88
  | Live-traffic dogfood (24h+) | ✅ AWS ECS Fargate | not published | not published |
80
89
 
81
90
  PR [#207](https://github.com/fortedigital/nextjs-cache-handler/pull/207) on
82
- `@fortedigital` has been stalled for 3+ months on the same issue: the
83
- upstream review insisted on `PHASE_PRODUCTION_BUILD` handling, which this
84
- package has from the start.
91
+ `@fortedigital` (their `cacheHandlers` attempt) was held up in review over
92
+ `PHASE_PRODUCTION_BUILD` handling — which this package has from the start.
85
93
 
86
94
  ---
87
95
 
@@ -185,6 +193,8 @@ interface CacheHandlerOptions {
185
193
  singleFlightLockTtlSec?: number; // default: 10
186
194
  isBuildPhase?: () => boolean; // override PHASE_PRODUCTION_BUILD detection
187
195
  hashTag?: boolean; // default: false (set true on Redis Cluster)
196
+ memoryMaxEntries?: number; // default: 1000 — LRU cap for the in-memory fallback
197
+ compression?: "gzip" | "brotli"; // default: off — transparent value compression (node:zlib)
188
198
  onMetric?: (event: MetricEvent) => void;
189
199
  logger?: Logger;
190
200
  }
@@ -192,10 +202,12 @@ interface CacheHandlerOptions {
192
202
  type RedisClientConfig =
193
203
  | { type: "redis"; url: string; password?: string; tls?: boolean; connectTimeout?: number }
194
204
  | { type: "ioredis"; url: string; password?: string; tls?: boolean; connectTimeout?: number }
195
- | { type: "cluster"; nodes: { host: string; port: number }[]; password?: string; tls?: boolean };
205
+ | { type: "cluster"; nodes: { host: string; port: number }[]; password?: string; tls?: boolean }
206
+ | { type: "sentinel"; sentinels: { host: string; port: number }[]; name: string;
207
+ password?: string; sentinelPassword?: string; tls?: boolean; connectTimeout?: number };
196
208
  ```
197
209
 
198
- Full reference: [`docs/api.md`](./docs/api.md) (auto-generated).
210
+ Full reference: [`docs/api.md`](./docs/api.md).
199
211
 
200
212
  ---
201
213
 
@@ -234,8 +246,9 @@ Full reference: [`docs/api.md`](./docs/api.md) (auto-generated).
234
246
  | **Self-hosted Redis 7+** | `{ type: "redis", url }` or `{ type: "ioredis", url }` | ✅ AWS ElastiCache 24h soak |
235
247
  | **Redis Cluster** | `{ type: "cluster", nodes }` + `hashTag: true` | unit-tested, not yet load-tested at scale |
236
248
  | **Upstash Redis** | `{ type: "redis", url: "rediss://..." }` (TLS auto-detected) | not yet validated, expected to work via the standard Redis protocol |
237
- | **AWS ElastiCache (replication group)** | `{ type: "redis", url: "rediss://..." }` | ✅ reference deployment |
238
- | **Vercel KV** | not yet supported — `@vercel/kv` adapter ships in v0.3 | — |
249
+ | **AWS ElastiCache (replication group)** | `{ type: "redis", url: "rediss://..." }` | ✅ reference deployment (re-verified 2026-08-01, Seoul) |
250
+ | **Redis Sentinel** | `{ type: "sentinel", sentinels, name }` | ✅ local master/replica failover drill |
251
+ | **Vercel KV** | not yet supported — dedicated adapter on the roadmap | — |
239
252
  | **DragonflyDB / KeyDB** | Redis-protocol compatible — `{ type: "redis", url }` should work | not validated |
240
253
 
241
254
  ---
@@ -337,10 +350,16 @@ eventual implementation should converge on the same behavior.
337
350
 
338
351
  ## Compatibility
339
352
 
340
- - **Next.js**: `>=16.1.5 <17`
353
+ - **Next.js**: `>=15.0.0 <17`
354
+ - `cacheHandler` (singular, ISR): Next **15 and 16** — the handler accepts
355
+ both ctx shapes (Next 15's `ctx.revalidate` / `kindHint`, Next 16's
356
+ `ctx.cacheControl` / `kind`)
357
+ - `cacheHandlers` (plural, `'use cache'`): Next **>=16.1.5** only — the
358
+ interface does not exist before 16
341
359
  - **Node.js**: `>=20`
342
360
  - **redis**: `>=5.0.0` (peer, optional)
343
- - **ioredis**: `>=5.0.0` (peer, optional)
361
+ - **ioredis**: `>=5.0.0` (peer, optional) — also powers `type: "cluster"` and
362
+ `type: "sentinel"` (Sentinel master discovery with automatic failover)
344
363
 
345
364
  ESM and CJS dual-published, full TypeScript types, validated via
346
365
  [`arethetypeswrong`](https://arethetypeswrong.github.io) and
@@ -357,10 +376,13 @@ ESM and CJS dual-published, full TypeScript types, validated via
357
376
  metrics, OpenTelemetry reference adapter, integration tests against
358
377
  real Redis 7 (21 scenarios over `redis@5` + `ioredis`), GitHub Actions
359
378
  OIDC publish path with provenance attestation ✅
360
- - **v0.3.0** — Vercel KV / Upstash Redis adapter, `'use cache: remote'`
361
- multi-tier setup, Redis Cluster load testing
362
- - **v0.4.0** — Cache stampede protection beyond single-flight,
363
- request-scoped memoization
379
+ - **v0.3.0** *(2026-08)* — Next.js 15 ISR support, reconnect backoff (no
380
+ permanent connect-failure latch), request-scoped GET deduplication,
381
+ gzip/brotli compression, Redis Sentinel, built-in OpenTelemetry emitter
382
+ (`/otel`), LRU-bounded memory fallback, ESM peer-loading fixes ✅
383
+ - **v0.4.0** — Build-phase cache seeding (prepopulate prebuilt pages),
384
+ pub/sub-based tag propagation, Redis Cluster e2e validation, Vercel KV /
385
+ Upstash adapter, `'use cache: remote'` multi-tier setup
364
386
 
365
387
  ---
366
388