@bymax-one/nest-logger 1.0.5 → 1.0.7

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
@@ -11,6 +11,70 @@ heading here.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [1.0.7] - 2026-08-07
15
+
16
+ **Documentation and tooling.** `dist/` differs from `1.0.6` only in the text of the comments
17
+ described below; no runtime code changed.
18
+
19
+ ### Changed
20
+
21
+ - **Equivalent mutants are documented in the source instead of only in the report, and the
22
+ rule against that was retired on a measurement.** The plan forbade inline
23
+ `// Stryker disable` comments on the ground that they would push the server subpath past
24
+ its 13.5 kB brotli budget. Measured: seven directives took the bundle from **12.84 to
25
+ 12.94 kB** — **+0.10 kB** against 0.66 kB of headroom, because brotli compresses their
26
+ repeated prefixes almost for free. The assumed cost was roughly ten times the real one, and
27
+ no budget changed.
28
+
29
+ With the ten survivors now carrying their reason inline, the measured score moves from
30
+ **97.42%** to **100%** — no test and no production logic changed; Stryker excludes an
31
+ ignored mutant from the denominator instead of counting it as one the suite failed to kill.
32
+
33
+ - **One suppression is recorded as what it is, not as an equivalent.** `otel-detector.ts:40`
34
+ is killed by the suite — applying the mutation by hand turns the suite red — but Stryker
35
+ fails to attribute the killing test to it under `perTest` coverage analysis. Its directive
36
+ says exactly that. Calling it equivalent to reach a rounder number would have been false.
37
+
38
+ - Two reasons were corrected after review. `decodeStrings: false` claimed equivalence "for
39
+ every input"; with `true`, Node encodes the string using the write's encoding and this
40
+ stream decodes with `toString('utf-8')`, so a `write(chunk, 'latin1')` would change
41
+ non-ASCII bytes. Nothing writes here but Pino, which emits UTF-8 NDJSON at the default
42
+ encoding, and the reason now says so and names where it stops being true. The
43
+ `{ strict: false }` reason argued from a missing provider; it now gives the actual
44
+ mechanism — `NestApplicationContext.get` branches on `!(options && options.strict)`, so the
45
+ mutant's `{}` leaves `strict` undefined, which is falsy, and takes the same non-strict
46
+ lookup.
47
+
48
+ ### Added
49
+
50
+ - `check:mutants` gate (`scripts/check-mutation-directives.mjs`) — validates every
51
+ `// Stryker` comment against the parser's own regular expression, rejecting a reason written
52
+ after `--` instead of a colon, a reason wrapped onto a second comment line, a stray comma in
53
+ the mutator list, and a mutator name Stryker does not know, which matches nothing and so
54
+ silences nothing. Wired into CI and `prepublishOnly`.
55
+
56
+ ### Fixed
57
+
58
+ - The `[Unreleased]` compare link still pointed at `v1.0.5` after `1.0.6` shipped.
59
+
60
+ ## [1.0.6] - 2026-08-06
61
+
62
+ **Tests and documentation only.** `dist/` is byte-identical to `1.0.5`.
63
+
64
+ An earlier revision of this branch added inline `// Stryker disable` comments and reported a
65
+ 99.73% score off the back of them. That is against this package's own plan, which forbids them
66
+ because they ship in the unminified bundle and eat the server subpath's brotli budget. They are
67
+ gone; the score is the measured 97.42% with the equivalents documented instead.
68
+
69
+ ### Tests
70
+
71
+ - `detectOtelTraceApi` resolves `@opentelemetry/api`, and the specifier was pinned by nothing —
72
+ the spec mocks `createRequire`, so the resolver ignored what it was handed. Renaming the module
73
+ would have kept the suite green while every deployment silently lost trace correlation, because
74
+ a failed resolve is swallowed by design.
75
+ - `useNestLogger` gained a feature-module case, the shape where the provider sits outside the host
76
+ module's own injector.
77
+
14
78
  ## [1.0.5] - 2026-07-30
15
79
 
16
80
  ### Security
@@ -252,7 +316,9 @@ published `dist/` is identical — no runtime behaviour changes for consumers.
252
316
  - Professional CI suite: `ci.yml`, `bench.yml`, `codeql.yml`, `scorecard.yml`,
253
317
  `release.yml`, Dependabot, and issue templates
254
318
 
255
- [Unreleased]: https://github.com/bymaxone/nest-logger/compare/v1.0.5...HEAD
319
+ [Unreleased]: https://github.com/bymaxone/nest-logger/compare/v1.0.7...HEAD
320
+ [1.0.7]: https://github.com/bymaxone/nest-logger/compare/v1.0.6...v1.0.7
321
+ [1.0.6]: https://github.com/bymaxone/nest-logger/compare/v1.0.5...v1.0.6
256
322
  [1.0.5]: https://github.com/bymaxone/nest-logger/compare/v1.0.4...v1.0.5
257
323
  [1.0.4]: https://github.com/bymaxone/nest-logger/compare/v1.0.3...v1.0.4
258
324
  [1.0.3]: https://github.com/bymaxone/nest-logger/compare/v1.0.2...v1.0.3
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
  <a href="https://www.npmjs.com/package/@bymax-one/nest-logger"><img src="https://img.shields.io/npm/dm/@bymax-one/nest-logger?style=flat-square&colorA=000000&colorB=000000" alt="npm downloads" /></a>
15
15
  <a href="https://github.com/bymaxone/nest-logger/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/bymaxone/nest-logger/ci.yml?branch=main&style=flat-square&colorA=000000&label=CI" alt="CI status" /></a>
16
16
  <a href="https://github.com/bymaxone/nest-logger/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-logger/blob/main/docs/mutation_testing_results.md"><img src="https://img.shields.io/badge/mutation-97.42%25-brightgreen?style=flat-square&colorA=000000" alt="mutation score" /></a>
17
+ <a href="https://github.com/bymaxone/nest-logger/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-logger"><img src="https://api.scorecard.dev/projects/github.com/bymaxone/nest-logger/badge?style=flat-square" alt="OpenSSF Scorecard" /></a>
19
19
  <a href="https://github.com/bymaxone/nest-logger/blob/main/LICENSE"><img src="https://img.shields.io/github/license/bymaxone/nest-logger?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>
@@ -745,8 +745,12 @@ When integrating `@bymax-one/nest-logger` in production, verify each of the foll
745
745
  A logger runs on every request of every service that installs it, so the suite is held to a bar beyond "it runs" — every behavior is pinned so that a regression **fails a test**.
746
746
 
747
747
  - ✅ **100% line coverage** — statements, branches, functions, and lines, enforced as a release gate across unit + e2e
748
- - ✅ **97.42% mutation score** — verified with [Stryker](https://stryker-mutator.io/) against a `break` threshold of 95; 97.42% is the theoretical maximum for this codebase
749
- - ✅ **Every survivor documented** — the 10 remaining mutants are equivalents, each recorded in [docs/mutation_testing_results.md](./docs/mutation_testing_results.md) rather than silenced with an inline comment, so the score is an accounting rather than a number
748
+ - ✅ **100% mutation score** — verified with [Stryker](https://stryker-mutator.io/) against a
749
+ `break` threshold of 95. The ten mutants no test can kill each carry their reason on the line
750
+ they apply to; a rule against those comments was retired once their cost was measured at
751
+ **+0.10 kB brotli** against 0.66 kB of headroom, roughly a tenth of what it had been assumed
752
+ to be (see the [report](./docs/mutation_testing_results.md))
753
+ - ✅ **Every suppression carries its reason** — each `// Stryker disable` names, after the `:` Stryker reads it from, why the mutant it silences cannot be observed; one of them is recorded as what it is, a mutant the suite kills but Stryker fails to attribute, rather than mislabelled an equivalent. `check:mutants` proves those reasons parse, so they reach the report rather than the `Ignored using a comment` fallback, and the score stays an accounting rather than a number
750
754
  - ✅ **No real I/O in unit tests** — the Pino instance and every destination are mocked; e2e tests exercise the wired module through `@nestjs/testing` and supertest
751
755
 
752
756
  ```bash
@@ -849,6 +849,7 @@ function destinationToStream(destination) {
849
849
  // Keep string chunks as strings (Node's default re-encodes them to Buffers
850
850
  // before `_write`): the common Pino path emits NDJSON strings, so this skips
851
851
  // a string→Buffer→string round-trip on the hot logging path.
852
+ // Stryker disable next-line BooleanLiteral: equivalent for every chunk this stream receives — with `true`, Node encodes the string to a Buffer and `write()` below decodes it back with `toString('utf-8')`. Pino writes UTF-8 NDJSON strings at the default encoding, so the round-trip returns the identical string. It is NOT equivalent in general: a `write(chunk, 'latin1')` would round-trip through UTF-8 and change non-ASCII bytes, which is unreachable here because nothing writes to this stream but Pino. The flag stays because it skips the round-trip on the hot logging path.
852
853
  decodeStrings: false,
853
854
  write(chunk, _encoding, callback) {
854
855
  const onFailure = (cause) => {
@@ -843,6 +843,7 @@ function destinationToStream(destination) {
843
843
  // Keep string chunks as strings (Node's default re-encodes them to Buffers
844
844
  // before `_write`): the common Pino path emits NDJSON strings, so this skips
845
845
  // a string→Buffer→string round-trip on the hot logging path.
846
+ // Stryker disable next-line BooleanLiteral: equivalent for every chunk this stream receives — with `true`, Node encodes the string to a Buffer and `write()` below decodes it back with `toString('utf-8')`. Pino writes UTF-8 NDJSON strings at the default encoding, so the round-trip returns the identical string. It is NOT equivalent in general: a `write(chunk, 'latin1')` would round-trip through UTF-8 and change non-ASCII bytes, which is unreachable here because nothing writes to this stream but Pino. The flag stays because it skips the round-trip on the hot logging path.
846
847
  decodeStrings: false,
847
848
  write(chunk, _encoding, callback) {
848
849
  const onFailure = (cause) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bymax-one/nest-logger",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Structured JSON logging for NestJS based on Pino 10, with optional OpenTelemetry correlation.",
5
5
  "author": "Bymax One <support@bymax.one>",
6
6
  "license": "MIT",
@@ -53,6 +53,30 @@
53
53
  ]
54
54
  }
55
55
  },
56
+ "scripts": {
57
+ "bench": "node --expose-gc --import tsx bench/throughput.bench.ts",
58
+ "build": "pnpm clean && tsup",
59
+ "check:exports": "attw --pack .",
60
+ "check:mutants": "node scripts/check-mutation-directives.mjs",
61
+ "check:published": "node scripts/check-published-surface.mjs",
62
+ "clean": "rm -rf dist coverage",
63
+ "lint": "eslint src",
64
+ "lint:fix": "eslint src --fix",
65
+ "mutation": "stryker run",
66
+ "mutation:dry-run": "stryker run --dryRunOnly",
67
+ "mutation:incremental": "stryker run --incremental",
68
+ "prepare": "husky",
69
+ "prepublishOnly": "pnpm clean && pnpm typecheck && pnpm lint && pnpm check:mutants && pnpm test:cov:all && pnpm build && pnpm check:published",
70
+ "release": "npm publish --provenance --access public",
71
+ "size": "node scripts/check-size.mjs",
72
+ "test": "jest",
73
+ "test:all": "pnpm test && pnpm test:e2e",
74
+ "test:cov": "jest --coverage",
75
+ "test:cov:all": "jest --config jest.coverage.config.ts --coverage",
76
+ "test:e2e": "jest --config jest.e2e.config.ts",
77
+ "test:watch": "jest --watch",
78
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.server.json"
79
+ },
56
80
  "lint-staged": {
57
81
  "*.{ts,tsx,js,mjs,cjs}": [
58
82
  "eslint --fix",
@@ -134,32 +158,12 @@
134
158
  "request-id",
135
159
  "pii-redaction"
136
160
  ],
161
+ "packageManager": "pnpm@11.20.0",
137
162
  "engines": {
138
163
  "node": ">=24.0.0"
139
164
  },
140
165
  "publishConfig": {
141
166
  "access": "public",
142
167
  "registry": "https://registry.npmjs.org/"
143
- },
144
- "scripts": {
145
- "bench": "node --expose-gc --import tsx bench/throughput.bench.ts",
146
- "build": "pnpm clean && tsup",
147
- "check:exports": "attw --pack .",
148
- "check:published": "node scripts/check-published-surface.mjs",
149
- "clean": "rm -rf dist coverage",
150
- "lint": "eslint src",
151
- "lint:fix": "eslint src --fix",
152
- "mutation": "stryker run",
153
- "mutation:dry-run": "stryker run --dryRunOnly",
154
- "mutation:incremental": "stryker run --incremental",
155
- "release": "pnpm publish --provenance",
156
- "size": "node scripts/check-size.mjs",
157
- "test": "jest",
158
- "test:all": "pnpm test && pnpm test:e2e",
159
- "test:cov": "jest --coverage",
160
- "test:cov:all": "jest --config jest.coverage.config.ts --coverage",
161
- "test:e2e": "jest --config jest.e2e.config.ts",
162
- "test:watch": "jest --watch",
163
- "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.server.json"
164
168
  }
165
- }
169
+ }