@bymax-one/nest-cache 1.0.6 → 1.1.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 CHANGED
@@ -4,7 +4,29 @@ All notable changes to this project are documented in this file. The format is
4
4
  based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
5
5
  project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [1.1.0] - 2026-08-11
8
+
9
+ ### Changed
10
+
11
+ - **BREAKING: peer dependency `ioredis` migrated `^5` → `^6`.** A consumer must move to
12
+ ioredis 6, which aligns this package with `@bymax-one/nest-queue` so a single ioredis copy
13
+ resolves across a workspace that uses both. ioredis 6 negotiates **RESP3** on the wire by
14
+ default — the protocol changes at runtime — but its `'legacy'` reply mapping preserves every
15
+ reply shape this cache relies on (GET/SET/TTL, EVALSHA, Pub/Sub message events, cluster and
16
+ sentinel commands), so observable behaviour is unchanged; the only source change is the
17
+ compile-time typing narrowing below. ioredis 6 requires Node.js ≥ 20, already covered by
18
+ this package's `engines` (Node ≥ 24).
19
+
20
+ ### Internal
21
+
22
+ - `ConnectionManager` narrows the options handed to the `Redis` and `Cluster` constructors
23
+ to a local shape (`OwnedRedisOptions` / `OwnedClusterOptions`). ioredis 6's constructor
24
+ overloads intersect `replyMapping` with a non-`undefined` variant to infer the
25
+ reply-mapping generic, which makes a plain `RedisOptions`/`ClusterOptions` value
26
+ unassignable under `exactOptionalPropertyTypes`. The narrowing drops only that `undefined`;
27
+ the runtime object is untouched.
28
+ - Mutation gate tightened: Stryker `break`/`high`/`low` raised to **100** (the run is at
29
+ 100%, 0 survivors).
8
30
 
9
31
  ## [1.0.6] - 2026-08-06
10
32
 
@@ -168,6 +190,7 @@ type or export moved.
168
190
  - Published with npm OIDC provenance — no long-lived tokens
169
191
  - Zero direct runtime dependencies (`dependencies: {}`) — `ioredis` and NestJS via peer deps
170
192
 
193
+ [1.1.0]: https://github.com/bymaxone/nest-cache/compare/v1.0.6...v1.1.0
171
194
  [1.0.6]: https://github.com/bymaxone/nest-cache/compare/v1.0.5...v1.0.6
172
195
  [1.0.5]: https://github.com/bymaxone/nest-cache/compare/v1.0.4...v1.0.5
173
196
  [1.0.4]: https://github.com/bymaxone/nest-cache/compare/v1.0.3...v1.0.4
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p align="center">
8
8
  <strong>Typed Redis cache for NestJS</strong><br />
9
- <sub>ioredis 5 · Namespacing · Pub/Sub · Lua Scripts · Multi-Tenant · Zero Runtime Dependencies</sub>
9
+ <sub>ioredis 6 · Namespacing · Pub/Sub · Lua Scripts · Multi-Tenant · Zero Runtime Dependencies</sub>
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -14,7 +14,7 @@
14
14
  <a href="https://www.npmjs.com/package/@bymax-one/nest-cache"><img src="https://img.shields.io/npm/dm/@bymax-one/nest-cache?style=flat-square&colorA=000000&colorB=000000" alt="npm downloads" /></a>
15
15
  <a href="https://github.com/bymaxone/nest-cache/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/bymaxone/nest-cache/ci.yml?branch=main&style=flat-square&colorA=000000&label=CI" alt="CI status" /></a>
16
16
  <a href="https://github.com/bymaxone/nest-cache/actions/workflows/ci.yml"><img src="https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square&colorA=000000" alt="coverage" /></a>
17
- <a href="https://github.com/bymaxone/nest-cache/blob/main/docs/mutation_testing_results.md"><img src="https://img.shields.io/badge/mutation-99.78%25-brightgreen?style=flat-square&colorA=000000" alt="mutation score" /></a>
17
+ <a href="https://github.com/bymaxone/nest-cache/blob/main/docs/mutation_testing_results.md"><img src="https://img.shields.io/badge/mutation-100%25-brightgreen?style=flat-square&colorA=000000" alt="mutation score" /></a>
18
18
  <a href="https://scorecard.dev/viewer/?uri=github.com/bymaxone/nest-cache"><img src="https://api.scorecard.dev/projects/github.com/bymaxone/nest-cache/badge?style=flat-square" alt="OpenSSF Scorecard" /></a>
19
19
  <a href="https://github.com/bymaxone/nest-cache/blob/main/LICENSE"><img src="https://img.shields.io/github/license/bymaxone/nest-cache?style=flat-square&colorA=000000&colorB=000000" alt="license" /></a>
20
20
  <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-strict-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" /></a>
@@ -101,7 +101,7 @@ One package, two entry points — import only what your app needs:
101
101
 
102
102
  | Subpath | Import | Purpose | Dependencies |
103
103
  | ---------- | ------------------------------ | -------------------------------------------------------------------------------------------------------- | :------------------------------------: |
104
- | **Server** | `@bymax-one/nest-cache` | `BymaxCacheModule`, `CacheService`, `PubSubService`, `ScriptManagerService`, DI tokens, `CacheException` | NestJS 11, ioredis 5, reflect-metadata |
104
+ | **Server** | `@bymax-one/nest-cache` | `BymaxCacheModule`, `CacheService`, `PubSubService`, `ScriptManagerService`, DI tokens, `CacheException` | NestJS 11, ioredis 6, reflect-metadata |
105
105
  | **Shared** | `@bymax-one/nest-cache/shared` | Types + constants — `CACHE_ERROR_CODES`, `CacheEventName`, config types | None |
106
106
 
107
107
  ```
@@ -511,7 +511,7 @@ When integrating `@bymax-one/nest-cache` in production, verify each of the follo
511
511
  ## 🧱 Tech Stack
512
512
 
513
513
  [![NestJS](https://img.shields.io/badge/NestJS-11-E0234E?style=flat-square&logo=nestjs&logoColor=white)](https://nestjs.com)
514
- [![ioredis](https://img.shields.io/badge/ioredis-5-DC382D?style=flat-square&logo=redis&logoColor=white)](https://github.com/redis/ioredis)
514
+ [![ioredis](https://img.shields.io/badge/ioredis-6-DC382D?style=flat-square&logo=redis&logoColor=white)](https://github.com/redis/ioredis)
515
515
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
516
516
  [![Node.js](https://img.shields.io/badge/Node.js-24-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
517
517
  [![Jest](https://img.shields.io/badge/Jest-30-C21325?style=flat-square&logo=jest)](https://jestjs.io)
@@ -526,8 +526,8 @@ When integrating `@bymax-one/nest-cache` in production, verify each of the follo
526
526
  A cache is consulted on the hot path of every request that touches it, so the suite is held to a bar beyond "it runs" — every behavior is pinned so that a regression **fails a test**.
527
527
 
528
528
  - ✅ **100% line coverage** — statements, branches, functions, and lines, enforced by `jest.coverage.config.ts` as a pre-publish gate, not a target
529
- - ✅ **99.78% mutation score** — verified with [Stryker](https://stryker-mutator.io/) at `break: 95` and `ignoreStatic: false`; the single survivor is `configurable: false` on the withheld connection accessor, equivalent here because the resolved options are frozen on the way out, and [documented as such](./docs/mutation_testing_results.md)
530
- - ✅ **Zero suppressions** — the production source carries no coverage or mutation directives; the one would-be equivalent mutant was refactored away rather than silenced, so the score is an accounting rather than a number
529
+ - ✅ **100% mutation score** — verified with [Stryker](https://stryker-mutator.io/) at `break: 100` and `ignoreStatic: false`; 441 killed, 6 timed out, **0 survived**, and [documented in full](./docs/mutation_testing_results.md)
530
+ - ✅ **One documented equivalent** — the production source carries a single `// Stryker disable` directive, on `configurable: false` of the withheld connection accessor, genuinely equivalent because the resolved options are frozen on the way out (freezing already makes every property non-configurable); `check:mutants` proves it parses and carries its reason, so the score is an accounting rather than a number
531
531
  - ✅ **No real Redis in unit tests** — `ioredis-mock` throughout; e2e tests exercise the wired module through `@nestjs/testing` and Testcontainers against a real Redis for connection lifecycle, Pub/Sub, and Lua scripts
532
532
  - ✅ **Published-package smoke test** — `scripts/dogfood-smoke-test.mjs` validates exports, tarball shape, and a consumer install before tagging
533
533
 
@@ -376,7 +376,7 @@ exports.ConnectionManager = class ConnectionManager {
376
376
  sentinelPassword: sentinel.sentinelPassword
377
377
  },
378
378
  ...sentinel.password !== void 0 && { password: sentinel.password },
379
- // Normalize 'replica' → 'slave' — ioredis 5 only accepts 'slave' at the
379
+ // Normalize 'replica' → 'slave' — ioredis only accepts 'slave' at the
380
380
  // wire level; our public interface accepts 'replica' per Redis 7 naming.
381
381
  ...sentinel.role !== void 0 && {
382
382
  role: sentinel.role === "replica" ? "slave" : sentinel.role
@@ -374,7 +374,7 @@ var ConnectionManager = class {
374
374
  sentinelPassword: sentinel.sentinelPassword
375
375
  },
376
376
  ...sentinel.password !== void 0 && { password: sentinel.password },
377
- // Normalize 'replica' → 'slave' — ioredis 5 only accepts 'slave' at the
377
+ // Normalize 'replica' → 'slave' — ioredis only accepts 'slave' at the
378
378
  // wire level; our public interface accepts 'replica' per Redis 7 naming.
379
379
  ...sentinel.role !== void 0 && {
380
380
  role: sentinel.role === "replica" ? "slave" : sentinel.role
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bymax-one/nest-cache",
3
- "version": "1.0.6",
4
- "description": "Typed Redis cache for NestJS based on ioredis 5, with namespace strategy, Pub/Sub and Lua script management.",
3
+ "version": "1.1.0",
4
+ "description": "Typed Redis cache for NestJS based on ioredis 6, with namespace strategy, Pub/Sub and Lua script management.",
5
5
  "author": "Bymax One <support@bymax.one>",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/bymaxone/nest-cache#readme",
@@ -62,8 +62,8 @@
62
62
  "lint": "eslint src scripts",
63
63
  "lint:fix": "eslint src scripts --fix",
64
64
  "mutation": "stryker run",
65
+ "mutation:full": "node -e \"require('node:fs').rmSync('reports/stryker-incremental.json',{force:true,recursive:true})\" && stryker run",
65
66
  "mutation:dry-run": "stryker run --dryRunOnly",
66
- "mutation:incremental": "stryker run --incremental",
67
67
  "prepare": "husky",
68
68
  "prepublishOnly": "pnpm clean && pnpm typecheck && pnpm test:types && pnpm lint && pnpm check:mutants && pnpm test:cov:all && pnpm build && pnpm check:published",
69
69
  "release": "npm publish --provenance --access public",
@@ -90,7 +90,7 @@
90
90
  "peerDependencies": {
91
91
  "@nestjs/common": "^11.0.16",
92
92
  "@nestjs/core": "^11.1.18",
93
- "ioredis": "^5.0.0",
93
+ "ioredis": "^6.0.0",
94
94
  "reflect-metadata": "^0.2.0"
95
95
  },
96
96
  "devDependencies": {
@@ -116,7 +116,7 @@
116
116
  "eslint-plugin-security": "^4.0.0",
117
117
  "globals": "^17.6.0",
118
118
  "husky": "^9.1.7",
119
- "ioredis": "^5.10.1",
119
+ "ioredis": "^6.0.0",
120
120
  "ioredis-mock": "^8.13.1",
121
121
  "jest": "^30.4.2",
122
122
  "lint-staged": "^17.2.0",