@loipv/nestjs-cache 0.0.0-stage → 1.0.0
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.
- package/CHANGELOG.md +81 -0
- package/LICENSE +21 -0
- package/README.md +118 -2
- package/dist/index.cjs +5777 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1861 -0
- package/dist/index.d.ts +1861 -0
- package/dist/index.js +5737 -0
- package/dist/index.js.map +1 -0
- package/package.json +131 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- First release on npm.
|
|
8
|
+
|
|
9
|
+
`@loipv/nestjs-cache` 1.0.0 is the first published version. The public API is frozen and follows
|
|
10
|
+
[semver](https://github.com/loipv/nestjs-cache/blob/main/docs/semver.md) from here.
|
|
11
|
+
|
|
12
|
+
- Requirements: Node 22 or later; TypeScript 5.4 or later with `experimentalDecorators`; peers `@nestjs/common` and `@nestjs/core` `^11.0.0 || ^12.0.0`, `rxjs` `^7.1.0`, `reflect-metadata` `^0.2.0`, and the optional `ioredis` `^5.0.0 || ^6.0.0` or `redis` `^5.0.0 || ^6.0.0`.
|
|
13
|
+
- `escapeKeyArgs` defaults to `false`: template arguments are not escaped unless you enable it, see [security](https://github.com/loipv/nestjs-cache/blob/main/docs/security.md).
|
|
14
|
+
- Decorators: `@Cacheable`, `@CachePut`, `@CacheEvict` and the `CacheService` API, see [decorators](https://github.com/loipv/nestjs-cache/blob/main/docs/decorators.md) and [the service](https://github.com/loipv/nestjs-cache/blob/main/docs/cache-service.md).
|
|
15
|
+
- Stores: memory, Redis (ioredis or node-redis v5/v6, Cluster, Sentinel) and tiered L1/L2 with invalidation, see [stores](https://github.com/loipv/nestjs-cache/blob/main/docs/stores.md).
|
|
16
|
+
- Resilience: distributed locks, circuit breaker, `swr` and `sliding` strategies, `softTimeout`, see [resilience](https://github.com/loipv/nestjs-cache/blob/main/docs/resilience.md).
|
|
17
|
+
- Namespaces and tags: versioned namespaces with O(1) `clear`, batch API, tag invalidation, see [namespaces and tags](https://github.com/loipv/nestjs-cache/blob/main/docs/namespaces-and-tags.md).
|
|
18
|
+
- HTTP caching: `@HttpCache` on Express and Fastify, see [HTTP caching](https://github.com/loipv/nestjs-cache/blob/main/docs/http-caching.md).
|
|
19
|
+
- Serializers and compression: JSON serializer and gzip or brotli `compressedSerializer` (with a `level` option; brotli defaults to quality 4), see [serializers](https://github.com/loipv/nestjs-cache/blob/main/docs/serializers.md).
|
|
20
|
+
- Observability: Prometheus metrics, `@nestjs/terminus` health indicator and OpenTelemetry tracing, see [observability](https://github.com/loipv/nestjs-cache/blob/main/docs/observability.md).
|
|
21
|
+
- Security and migration: see [security](https://github.com/loipv/nestjs-cache/blob/main/docs/security.md) and [migrating from `@nestjs/cache-manager`](https://github.com/loipv/nestjs-cache/blob/main/docs/migration-from-cache-manager.md).
|
|
22
|
+
|
|
23
|
+
Versions 0.1.0 to 0.3.0 below were never published to npm.
|
|
24
|
+
|
|
25
|
+
## [0.3.0] - 2026-11-10
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- `CachePrometheusModule` (`forRoot` and `forRootAsync`) that records cache metrics through a Prometheus client you pass in (`@prometheus-io/client` or `prom-client`), with the `PrometheusClientLike`, `RegistryLike` and `CachePrometheusOptions` types.
|
|
30
|
+
- `CacheHealthIndicator` and `CacheHealthResult`, a health check in the shape `@nestjs/terminus` expects.
|
|
31
|
+
- `CacheStore.ping` (optional), implemented by the memory, Redis, tiered and circuit breaker stores.
|
|
32
|
+
- `logging.level` (`'off'`, `'error'` or `'debug'`) and the `CacheLogLevel` type.
|
|
33
|
+
- Log lines when a circuit breaker opens (`warn`) or closes (`log`).
|
|
34
|
+
- Sample Grafana dashboard in `grafana/dashboard.json` (in the repository, not in the npm package).
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- Metrics and health ship from the main entry point, not from the `/prometheus` and `/terminus` subpaths planned earlier. The CommonJS build would otherwise bundle a second copy of the `CacheEvents` class into each entry point, and the metrics collector and the module would then use different classes.
|
|
39
|
+
- Prometheus clients are passed in by the user; there is no new peer dependency.
|
|
40
|
+
- `IoredisLike` gained a required `ping()`. Real ioredis clients are unaffected, but hand-written stubs must add it.
|
|
41
|
+
- `CacheEventSink` gained an optional `logLevel` field. This is additive.
|
|
42
|
+
- `CacheOperation` gained the value `'metrics'`, used for logs only; `error` events never carry it.
|
|
43
|
+
|
|
44
|
+
## [0.2.0] - 2026-11-10
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- Expiry strategies `fixed`, `swr` (stale-while-revalidate, with `staleTtl`) and `sliding` (with optional `maxTtl`) for `@Cacheable`, `@CachePut`, `CacheService.getOrSet`, `CacheService.set` and `CacheService.get`.
|
|
49
|
+
- Optional distributed lock (`defaults.lock`, per-call `lock`) that coalesces concurrent misses across instances; `LockProvider`, `LockHandle` and `CacheStore.lock`, implemented by the Redis store and by a tiered store whose L2 has a lock.
|
|
50
|
+
- `circuitBreaker(store, options)`, `CircuitBreakerStore`, `CircuitOpenError` and the `CircuitBreakerOptions` and `BreakerState` types.
|
|
51
|
+
- `lock` and `breaker` events; `hit.stale` is `true` for `swr` stale reads.
|
|
52
|
+
- `getAndTouch` (already optional on `CacheStore` and implemented by `RedisStore` in 0.1) is now also implemented by the memory and tiered stores.
|
|
53
|
+
- `MemoryStoreOptions` type export; `CacheLockDefaults` type export.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- `WriteOptions` is now a type alias containing a union, so `interface X extends WriteOptions` no longer compiles; use `type X = WriteOptions & { ... }`.
|
|
58
|
+
- `IoredisLike` gained a required `eval` and a `set ... 'NX'` overload. Real ioredis clients are unaffected, but hand-written fakes must add them.
|
|
59
|
+
- Repeated `error` log lines are throttled to one per 30 seconds for each (store, operation) pair, with a `(+N similar errors suppressed)` suffix. Events are still emitted for every occurrence.
|
|
60
|
+
- `package.json` now has `repository`, `homepage`, `bugs` and more keywords.
|
|
61
|
+
- `defaults.lock` must be an object: `null`, a string, a number, a boolean or an array throws `CacheConfigError` (`undefined` still means the defaults).
|
|
62
|
+
|
|
63
|
+
### Fixed
|
|
64
|
+
|
|
65
|
+
- Decorators on `static` methods are rejected with `CacheConfigError`.
|
|
66
|
+
- `@CacheEvict({ key: [] })` is rejected with `CacheConfigError`.
|
|
67
|
+
- Lock-unavailable warnings are de-duplicated once per class, method and store, so a method that names two stores without a lock warns for each.
|
|
68
|
+
|
|
69
|
+
## [0.1.0] - 2026-11-10
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- `@Cacheable`, `@CachePut` and `@CacheEvict` decorators and a `CacheService` for direct calls.
|
|
74
|
+
- Named stores: in-memory LRU, Redis (ioredis) and a two-tier L1/L2 store with Pub/Sub invalidation.
|
|
75
|
+
- In-process coalescing of concurrent misses, optional null caching and TTL jitter.
|
|
76
|
+
- Dynamic keys from templates or callbacks, a `CacheEvents` emitter, and a pluggable serializer.
|
|
77
|
+
- Dual ESM and CommonJS build with no runtime dependencies.
|
|
78
|
+
|
|
79
|
+
[0.3.0]: https://github.com/loipv/nestjs-cache/compare/v0.2.0...v0.3.0
|
|
80
|
+
[0.2.0]: https://github.com/loipv/nestjs-cache/compare/v0.1.0...v0.2.0
|
|
81
|
+
[0.1.0]: https://github.com/loipv/nestjs-cache/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 loipv
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,119 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @loipv/nestjs-cache
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Decorator-based caching for NestJS: Redis (ioredis or node-redis, Cluster, Sentinel) and two-tier stores, tags, stale-while-revalidate, stampede protection, HTTP caching and Prometheus metrics
|
|
4
|
+
|
|
5
|
+
- `@Cacheable`, `@CachePut` and `@CacheEvict` decorators, plus a `CacheService` for direct calls.
|
|
6
|
+
- `@HttpCache` for opt-in caching of controller routes (Express and Fastify).
|
|
7
|
+
- Named stores: in-memory, Redis (ioredis or node-redis, standalone, Cluster or Sentinel) and a two-tier L1/L2 store synced over Pub/Sub.
|
|
8
|
+
- Concurrent misses on the same key are coalesced into one load (per process), or across instances with the optional distributed lock.
|
|
9
|
+
- Expiry strategies: `fixed`, `swr` (stale-while-revalidate) and `sliding`.
|
|
10
|
+
- Per-store circuit breaker for Redis outages.
|
|
11
|
+
- Optional gzip or brotli compression of large payloads (`compressedSerializer`).
|
|
12
|
+
- Optional null caching and TTL jitter, both off by default.
|
|
13
|
+
- No runtime dependencies. Dual ESM and CommonJS build.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @loipv/nestjs-cache
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Peer dependencies: `@nestjs/common`, `@nestjs/core` (`^11 || ^12`), `reflect-metadata` (`^0.2`) and `rxjs` (`^7.1`, which
|
|
22
|
+
Nest itself requires, so a Nest app already has it).
|
|
23
|
+
`ioredis` (`^5 || ^6`) and `redis` (`^5 || ^6`, node-redis) are optional peers; install the one you use for the Redis store.
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
With no options the module uses an in-memory store named `default`. No Redis is needed.
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { Injectable, Module } from '@nestjs/common';
|
|
31
|
+
import { CacheModule, Cacheable } from '@loipv/nestjs-cache';
|
|
32
|
+
|
|
33
|
+
@Injectable()
|
|
34
|
+
export class UserService {
|
|
35
|
+
@Cacheable({ namespace: 'users', key: 'user:{0}', ttl: 60_000 })
|
|
36
|
+
async findById(id: string): Promise<{ id: string } | null> {
|
|
37
|
+
return { id }; // for example, a database call
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Module({
|
|
42
|
+
imports: [CacheModule.forRoot({ isGlobal: true })],
|
|
43
|
+
providers: [UserService],
|
|
44
|
+
})
|
|
45
|
+
export class AppModule {}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
With memory only, the cache is private to each process: it is not shared between instances and is lost on restart.
|
|
49
|
+
All durations are in milliseconds and must be finite numbers greater than 0.
|
|
50
|
+
|
|
51
|
+
For Redis, Redis Cluster or Sentinel and the two-tier store, see [Stores](docs/stores.md). A runnable NestJS 12 app
|
|
52
|
+
with tags, `@HttpCache`, optional Redis and Prometheus is in [`examples/basic`](examples/basic/README.md).
|
|
53
|
+
|
|
54
|
+
## Documentation
|
|
55
|
+
|
|
56
|
+
- [Configuration](docs/configuration.md): module options and defaults, null caching, TTL jitter and the expiry
|
|
57
|
+
strategies (`fixed`, `swr` with `softTimeout`, `sliding`).
|
|
58
|
+
- [Decorators](docs/decorators.md): `@Cacheable`, `@CachePut` and `@CacheEvict`, their options, and dynamic keys.
|
|
59
|
+
- [HTTP caching](docs/http-caching.md): `@HttpCache` on controller routes, on Express and Fastify.
|
|
60
|
+
- [`CacheService`](docs/cache-service.md): `get`, `set`, `delete`, `clear`, `getOrSet` and the batch methods
|
|
61
|
+
`getMany`, `setMany` and `getOrSetMany`.
|
|
62
|
+
- [Stores](docs/stores.md): memory, Redis (ioredis or node-redis; standalone, Cluster or Sentinel), the two-tier
|
|
63
|
+
store, custom stores and invalidation buses.
|
|
64
|
+
- [Versioned namespaces and tags](docs/namespaces-and-tags.md): an O(1) namespace `clear`, and tag invalidation with
|
|
65
|
+
`invalidateTags` and `@CacheEvict({ tags })`.
|
|
66
|
+
- [Serializers](docs/serializers.md): custom serializers and gzip or brotli compression (`compressedSerializer`).
|
|
67
|
+
- [Resilience](docs/resilience.md): the distributed lock, the circuit breaker, and how errors are handled.
|
|
68
|
+
- [Events and observability](docs/observability.md): events, Prometheus metrics, the `@nestjs/terminus` health check,
|
|
69
|
+
logging and a sample Grafana dashboard.
|
|
70
|
+
- [Tracing](docs/observability.md#tracing): opt-in OpenTelemetry spans for every cache call, with `CacheTracingModule`.
|
|
71
|
+
- [Security](docs/security.md) and [Caveats](docs/caveats.md).
|
|
72
|
+
- [Stability and semver](docs/semver.md): what 1.x keeps stable, and what counts as a major, minor or patch change.
|
|
73
|
+
- [Migrating from `@nestjs/cache-manager`](docs/migration-from-cache-manager.md).
|
|
74
|
+
|
|
75
|
+
## Compatibility
|
|
76
|
+
|
|
77
|
+
The semver contract is in [Stability and semver](docs/semver.md).
|
|
78
|
+
|
|
79
|
+
| Component | Supported |
|
|
80
|
+
| ------------------ | ---------------------------------------------------------- |
|
|
81
|
+
| NestJS | 11 (CommonJS) and 12 (ESM) |
|
|
82
|
+
| Node.js | `>=22` (LTS 22, 24, 26) |
|
|
83
|
+
| TypeScript | `>=5.4` (the published `.d.ts` is checked against 5.4) |
|
|
84
|
+
| ioredis | `^5 \|\| ^6` (optional peer; Cluster needs 5.6.0 or later) |
|
|
85
|
+
| redis (node-redis) | `^5 \|\| ^6` (optional peer; Sentinel supported) |
|
|
86
|
+
| rxjs | `^7.1` (peer, as for `@nestjs/common`) |
|
|
87
|
+
| Redis server | 6.2 or later (Cluster: 7 or later) |
|
|
88
|
+
|
|
89
|
+
The decorators (`@Cacheable`, `@CachePut`, `@CacheEvict`, `@HttpCache`) are legacy decorators: consumers need
|
|
90
|
+
`experimentalDecorators: true` in `tsconfig.json`. Standard (TC39) decorators are not supported.
|
|
91
|
+
|
|
92
|
+
The package ships both ESM and CommonJS builds. The injection tokens use `Symbol.for('@loipv/nestjs-cache:...')`,
|
|
93
|
+
so they are shared when both builds are loaded in one process, and `instanceof CacheConfigError` matches errors
|
|
94
|
+
from either build. Classes are not shared: `CacheService`, `CacheEvents` and the other classes are injected by
|
|
95
|
+
class, so import the package from one build only (do not mix `import` and `require` of it in one app).
|
|
96
|
+
The library does not rely on `emitDecoratorMetadata`.
|
|
97
|
+
|
|
98
|
+
## Roadmap
|
|
99
|
+
|
|
100
|
+
- **0.2 - Resilience (done):** distributed lock (cross-instance stampede protection), per-store circuit breaker, `'swr'` (stale-while-revalidate) and `'sliding'` TTL strategies.
|
|
101
|
+
- **0.3 - Observability (done):** Prometheus metrics (`CachePrometheusModule`) with a sample Grafana dashboard, configurable log level with debug logs, circuit breaker logs, and a `@nestjs/terminus` health indicator (`CacheHealthIndicator`). All from the main entry point.
|
|
102
|
+
- **0.4 - Versioned namespaces and batches (done):** O(1) `clear` for opt-in versioned namespaces, `getMany`/`setMany`/`getOrSetMany`, `escapeKeyArgs`, lock keys under the prefix, and an optional `ping`.
|
|
103
|
+
- **0.5 - Redis Cluster and node-redis (done):** Redis Cluster through ioredis, `nodeRedisAdapter` for `redis` v5 (standalone and cluster), `CacheStore.getStrict`/`setStrict`, `RedisClientAdapter.scanIterator`, and the tiered-store fix for versioned namespaces while L2 is down.
|
|
104
|
+
- **0.6 - HTTP caching (done):** `@HttpCache` and `HttpCacheInterceptor` for opt-in route caching on Express and Fastify, and a [migration guide](docs/migration-from-cache-manager.md) from `@nestjs/cache-manager`.
|
|
105
|
+
- **0.7 - Tags (done):** `tags` on `@Cacheable`, `@CachePut`, `@HttpCache` and the `CacheService` writes, `CacheService.invalidateTags` and `@CacheEvict({ tags })`.
|
|
106
|
+
- **0.8 - Compression, Sentinel and `softTimeout` (done):** `compressedSerializer` (gzip and brotli), swr `softTimeout`, Redis Sentinel (ioredis and node-redis), and the tag token re-read.
|
|
107
|
+
- **0.9 - Redis v6, docs and example (done):** `redis` v6 support, the docs split into `docs/`, an [example app](examples/basic/README.md), and an API tidy-up (see the changelog for the breaking changes).
|
|
108
|
+
- **0.10 - Tracing (done):** opt-in OpenTelemetry tracing (`CacheTracingModule`).
|
|
109
|
+
- **1.0 - API freeze (done):** the public API is frozen and follows [semver](docs/semver.md) from there.
|
|
110
|
+
- **After 1.0 - Replica reads (planned):** reads from Redis replicas.
|
|
111
|
+
|
|
112
|
+
## Changelog and releasing
|
|
113
|
+
|
|
114
|
+
Each version's changes are listed in [CHANGELOG.md](CHANGELOG.md). [RELEASING.md](RELEASING.md) describes how
|
|
115
|
+
releases are published and the rules the CI workflows follow.
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT
|