@bymax-one/nest-logger 1.0.2 → 1.0.4

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,63 @@ heading here.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [1.0.4] - 2026-07-29
15
+
16
+ ### Fixed
17
+
18
+ - **The published declarations no longer depend on Express's types.** The HTTP
19
+ logging interceptor, the exception filter and the request-id middleware typed
20
+ their signatures with `Request` / `Response` / `NextFunction` from `express`,
21
+ so `dist/server/index.d.ts` imported from `express` and a consumer compiling
22
+ with `skipLibCheck: false` and no express types installed hit
23
+ `error TS2307: Cannot find module 'express'`. Present since 1.0.0; the imports
24
+ were `import type` only, so runtime was never affected and no express code was
25
+ ever bundled.
26
+
27
+ They are now typed by structural contracts declaring exactly the members this
28
+ package reads — `LoggableRequest` (`headers`, `method`, `url`, `ip`,
29
+ `user?.id`), `LoggableResponse` (`statusCode`, `setHeader`, `status().json()`)
30
+ and `NextHandler`. The emitted declarations import only `@nestjs/common`,
31
+ `pino` and `rxjs`, all declared peers.
32
+
33
+ **Not a breaking change:** an Express request and response satisfy the
34
+ contracts structurally, so existing call sites keep compiling with no cast —
35
+ the parameter types only widen what is accepted. The internal
36
+ `RequestWithUser` alias is gone, replaced by `LoggableRequest`; it was never
37
+ exported.
38
+
39
+ ### Added
40
+
41
+ - `LoggableRequest`, `LoggableResponse`, `NextHandler` and `IncomingHeaders` are
42
+ exported from the package root: they type `RequestIdMiddleware.use()`, so a
43
+ consumer invoking it directly (in a test, say) can name them.
44
+
45
+ ### Removed
46
+
47
+ - The `@types/express` optional peer dependency added in 1.0.3. With the
48
+ declarations self-contained it serves no purpose — nothing in the published
49
+ types names an express symbol. It stays a devDependency: the specs build
50
+ express-shaped mocks deliberately, to prove a real express request and
51
+ response still satisfy the contracts.
52
+
53
+ ## [1.0.3] - 2026-07-29
54
+
55
+ ### Fixed
56
+
57
+ - **Declared `@types/express` as an optional peer dependency.** The published
58
+ declarations reference `Request` / `Response` / `NextFunction` from `express`
59
+ (the HTTP interceptor, the exception filter and the request-id middleware all
60
+ type their signatures with them), but the requirement was undeclared. A
61
+ consumer compiling with `skipLibCheck: false` and no express types installed
62
+ hit `error TS2307: Cannot find module 'express'` from inside
63
+ `dist/server/index.d.ts` with nothing in `package.json` pointing at the cause.
64
+ Present since 1.0.0 — the imports are `import type` only, so runtime was never
65
+ affected and no express code is bundled.
66
+
67
+ It is marked optional because nothing in the library needs express at runtime:
68
+ a consumer on a non-express adapter (Fastify) can ignore it, as can anyone
69
+ keeping `skipLibCheck: true` — the default the Nest CLI scaffolds.
70
+
14
71
  ## [1.0.2] - 2026-07-29
15
72
 
16
73
  ### Fixed
@@ -130,7 +187,10 @@ published `dist/` is identical — no runtime behaviour changes for consumers.
130
187
  - Professional CI suite: `ci.yml`, `bench.yml`, `codeql.yml`, `scorecard.yml`,
131
188
  `release.yml`, Dependabot, and issue templates
132
189
 
133
- [Unreleased]: https://github.com/bymaxone/nest-logger/compare/v1.0.1...HEAD
190
+ [Unreleased]: https://github.com/bymaxone/nest-logger/compare/v1.0.4...HEAD
191
+ [1.0.4]: https://github.com/bymaxone/nest-logger/compare/v1.0.3...v1.0.4
192
+ [1.0.3]: https://github.com/bymaxone/nest-logger/compare/v1.0.2...v1.0.3
193
+ [1.0.2]: https://github.com/bymaxone/nest-logger/compare/v1.0.1...v1.0.2
134
194
  [1.0.1]: https://github.com/bymaxone/nest-logger/compare/v1.0.0...v1.0.1
135
195
  [1.0.0]: https://github.com/bymaxone/nest-logger/compare/v0.1.0...v1.0.0
136
196
  [0.1.0]: https://github.com/bymaxone/nest-logger/releases/tag/v0.1.0
package/README.md CHANGED
@@ -143,11 +143,15 @@ pnpm add -D pino-pretty
143
143
 
144
144
  # Optional — OpenTelemetry trace correlation
145
145
  pnpm add @opentelemetry/api @opentelemetry/sdk-node
146
+
146
147
  ```
147
148
 
148
149
  > [!NOTE]
149
150
  > `@opentelemetry/api` is resolved lazily when the Pino instance is built. When it is absent the trace mixin silently steps aside — the logger never fails to start, and never warns, over an optional peer.
150
151
 
152
+ > [!NOTE]
153
+ > The published declarations depend on no HTTP framework's types. The HTTP interceptor, the exception filter and the request-id middleware are typed by structural contracts (`LoggableRequest`, `LoggableResponse`, `NextHandler`) that an Express request and response satisfy as-is, so nothing extra is needed even when you compile with `skipLibCheck: false`. The emitted `.d.ts` imports only `@nestjs/common`, `pino` and `rxjs`.
154
+
151
155
  ### 2. Register the module
152
156
 
153
157
  ```typescript
@@ -1363,8 +1363,8 @@ exports.RequestIdMiddleware = class RequestIdMiddleware {
1363
1363
  * Echo or mint the `x-request-id`, expose it on the response, and run the
1364
1364
  * remainder of the request inside a fresh log-context scope.
1365
1365
  *
1366
- * @param req - The incoming Express request.
1367
- * @param res - The outgoing Express response.
1366
+ * @param req - The incoming request (Express satisfies the contract).
1367
+ * @param res - The outgoing response (Express satisfies the contract).
1368
1368
  * @param next - The next handler in the chain.
1369
1369
  */
1370
1370
  use(req, res, next) {
@@ -2,7 +2,6 @@ import * as _nestjs_common from '@nestjs/common';
2
2
  import { ModuleMetadata, Type, DynamicModule, INestApplication, LoggerService, OnApplicationShutdown, ExceptionFilter, ArgumentsHost, NestInterceptor, ExecutionContext, CallHandler, MiddlewareConsumer, NestMiddleware, CustomDecorator } from '@nestjs/common';
3
3
  import { Logger } from 'pino';
4
4
  import { Observable } from 'rxjs';
5
- import { Request, Response, NextFunction } from 'express';
6
5
 
7
6
  /**
8
7
  * Pino log levels (mirrored to NestJS-compatible names).
@@ -753,6 +752,66 @@ declare class HttpLoggingInterceptor implements NestInterceptor {
753
752
  */
754
753
  declare function applyRequestIdMiddleware(consumer: MiddlewareConsumer, routes?: string): void;
755
754
 
755
+ /**
756
+ * Minimal HTTP request/response contracts the logging layer reads.
757
+ *
758
+ * Layer: server/interfaces — exported structural contracts shared by the HTTP
759
+ * logging interceptor, the exception filter and the request-id middleware. They
760
+ * are part of the public API: they appear in those components' published
761
+ * signatures, so a consumer calling `RequestIdMiddleware.use()` directly needs
762
+ * to be able to name them. Declared structurally, listing only the members
763
+ * those three actually touch, so the published declarations depend on no HTTP
764
+ * framework's types. Naming Express's
765
+ * `Request`/`Response` here would make the emitted `.d.ts` import from
766
+ * `express`, forcing every consumer that compiles with `skipLibCheck: false` to
767
+ * install `@types/express` whether or not they use those signatures.
768
+ *
769
+ * The shapes mirror what the Express adapter provides — `status().json()` and
770
+ * `setHeader()` are Express/Node response methods — so this is not an
771
+ * adapter-agnostic abstraction; a Fastify adapter remains unsupported. An
772
+ * Express request and response satisfy these contracts structurally, with no
773
+ * cast at the call site.
774
+ */
775
+ /** Raw inbound headers, as the HTTP layer delivers them. */
776
+ type IncomingHeaders = Record<string, string | string[] | undefined>;
777
+ /**
778
+ * The inbound request members the logging layer reads.
779
+ *
780
+ * `user` is populated by upstream auth in the consumer app (a guard or
781
+ * middleware); only `id` is ever read, for the acting-user log field.
782
+ */
783
+ interface LoggableRequest {
784
+ /** Inbound headers — read for correlation ids and the user agent. */
785
+ readonly headers: IncomingHeaders;
786
+ /** HTTP verb, logged as-is. */
787
+ readonly method: string;
788
+ /** Request target, normalized and query-stripped before it reaches a log. */
789
+ readonly url: string;
790
+ /** Client address when the adapter resolves one. */
791
+ readonly ip?: string | undefined;
792
+ /** Authenticated principal, when upstream auth attached one. */
793
+ readonly user?: {
794
+ readonly id?: string | undefined;
795
+ } | undefined;
796
+ }
797
+ /**
798
+ * The outbound response members the logging layer writes or reads: the status
799
+ * for the terminal log entry, `setHeader` to echo the correlation id, and the
800
+ * chainable `status().json()` used by the exception filter to emit a body.
801
+ */
802
+ interface LoggableResponse {
803
+ /** Status code, read when logging the completed request. */
804
+ readonly statusCode: number;
805
+ /** Sets a response header (used for the correlation id). */
806
+ setHeader(name: string, value: string): void;
807
+ /** Selects the status code and returns the chainable body writer. */
808
+ status(code: number): {
809
+ json(body: unknown): unknown;
810
+ };
811
+ }
812
+ /** Continuation passed to a middleware; invoked with no arguments here. */
813
+ type NextHandler = () => void;
814
+
756
815
  /**
757
816
  * Reads (or generates) the correlation id and starts the per-request log
758
817
  * context scope.
@@ -783,11 +842,11 @@ declare class RequestIdMiddleware implements NestMiddleware {
783
842
  * Echo or mint the `x-request-id`, expose it on the response, and run the
784
843
  * remainder of the request inside a fresh log-context scope.
785
844
  *
786
- * @param req - The incoming Express request.
787
- * @param res - The outgoing Express response.
845
+ * @param req - The incoming request (Express satisfies the contract).
846
+ * @param res - The outgoing response (Express satisfies the contract).
788
847
  * @param next - The next handler in the chain.
789
848
  */
790
- use(req: Request, res: Response, next: NextFunction): void;
849
+ use(req: LoggableRequest, res: LoggableResponse, next: NextHandler): void;
791
850
  }
792
851
 
793
852
  /**
@@ -950,4 +1009,4 @@ declare const RESERVED_LOG_KEYS: Readonly<{
950
1009
  readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
951
1010
  }>;
952
1011
 
953
- export { BymaxLoggerModule, type BymaxLoggerModuleAsyncOptions, type BymaxLoggerModuleOptions, type BymaxLoggerModuleOptionsFactory, DEFAULT_REDACT_PATHS, DefaultStdoutDestination, HttpExceptionFilter, HttpLoggingInterceptor, type HttpOptions, type ILogDestination, InjectLogger, LOGGER_DESTINATIONS_TOKEN, LOGGER_OPTIONS_TOKEN, LOGGER_PINO_INSTANCE_TOKEN, LOG_CONTEXT_METADATA_KEY, LOG_CONTEXT_TOKEN, LOG_KEYS_CONVENTION_REGEX, LogContext, type LogContext$1 as LogContextBag, LogContextService, type LogEntry, type LogLevel, LogPerformance, type OtelOptions, PinoLoggerService, PrettyDevDestination, RESERVED_LOG_KEYS, RequestIdMiddleware, type ResolvedBymaxLoggerModuleOptions, type ServiceMetadata, applyRequestIdMiddleware };
1012
+ export { BymaxLoggerModule, type BymaxLoggerModuleAsyncOptions, type BymaxLoggerModuleOptions, type BymaxLoggerModuleOptionsFactory, DEFAULT_REDACT_PATHS, DefaultStdoutDestination, HttpExceptionFilter, HttpLoggingInterceptor, type HttpOptions, type ILogDestination, type IncomingHeaders, InjectLogger, LOGGER_DESTINATIONS_TOKEN, LOGGER_OPTIONS_TOKEN, LOGGER_PINO_INSTANCE_TOKEN, LOG_CONTEXT_METADATA_KEY, LOG_CONTEXT_TOKEN, LOG_KEYS_CONVENTION_REGEX, LogContext, type LogContext$1 as LogContextBag, LogContextService, type LogEntry, type LogLevel, LogPerformance, type LoggableRequest, type LoggableResponse, type NextHandler, type OtelOptions, PinoLoggerService, PrettyDevDestination, RESERVED_LOG_KEYS, RequestIdMiddleware, type ResolvedBymaxLoggerModuleOptions, type ServiceMetadata, applyRequestIdMiddleware };
@@ -2,7 +2,6 @@ import * as _nestjs_common from '@nestjs/common';
2
2
  import { ModuleMetadata, Type, DynamicModule, INestApplication, LoggerService, OnApplicationShutdown, ExceptionFilter, ArgumentsHost, NestInterceptor, ExecutionContext, CallHandler, MiddlewareConsumer, NestMiddleware, CustomDecorator } from '@nestjs/common';
3
3
  import { Logger } from 'pino';
4
4
  import { Observable } from 'rxjs';
5
- import { Request, Response, NextFunction } from 'express';
6
5
 
7
6
  /**
8
7
  * Pino log levels (mirrored to NestJS-compatible names).
@@ -753,6 +752,66 @@ declare class HttpLoggingInterceptor implements NestInterceptor {
753
752
  */
754
753
  declare function applyRequestIdMiddleware(consumer: MiddlewareConsumer, routes?: string): void;
755
754
 
755
+ /**
756
+ * Minimal HTTP request/response contracts the logging layer reads.
757
+ *
758
+ * Layer: server/interfaces — exported structural contracts shared by the HTTP
759
+ * logging interceptor, the exception filter and the request-id middleware. They
760
+ * are part of the public API: they appear in those components' published
761
+ * signatures, so a consumer calling `RequestIdMiddleware.use()` directly needs
762
+ * to be able to name them. Declared structurally, listing only the members
763
+ * those three actually touch, so the published declarations depend on no HTTP
764
+ * framework's types. Naming Express's
765
+ * `Request`/`Response` here would make the emitted `.d.ts` import from
766
+ * `express`, forcing every consumer that compiles with `skipLibCheck: false` to
767
+ * install `@types/express` whether or not they use those signatures.
768
+ *
769
+ * The shapes mirror what the Express adapter provides — `status().json()` and
770
+ * `setHeader()` are Express/Node response methods — so this is not an
771
+ * adapter-agnostic abstraction; a Fastify adapter remains unsupported. An
772
+ * Express request and response satisfy these contracts structurally, with no
773
+ * cast at the call site.
774
+ */
775
+ /** Raw inbound headers, as the HTTP layer delivers them. */
776
+ type IncomingHeaders = Record<string, string | string[] | undefined>;
777
+ /**
778
+ * The inbound request members the logging layer reads.
779
+ *
780
+ * `user` is populated by upstream auth in the consumer app (a guard or
781
+ * middleware); only `id` is ever read, for the acting-user log field.
782
+ */
783
+ interface LoggableRequest {
784
+ /** Inbound headers — read for correlation ids and the user agent. */
785
+ readonly headers: IncomingHeaders;
786
+ /** HTTP verb, logged as-is. */
787
+ readonly method: string;
788
+ /** Request target, normalized and query-stripped before it reaches a log. */
789
+ readonly url: string;
790
+ /** Client address when the adapter resolves one. */
791
+ readonly ip?: string | undefined;
792
+ /** Authenticated principal, when upstream auth attached one. */
793
+ readonly user?: {
794
+ readonly id?: string | undefined;
795
+ } | undefined;
796
+ }
797
+ /**
798
+ * The outbound response members the logging layer writes or reads: the status
799
+ * for the terminal log entry, `setHeader` to echo the correlation id, and the
800
+ * chainable `status().json()` used by the exception filter to emit a body.
801
+ */
802
+ interface LoggableResponse {
803
+ /** Status code, read when logging the completed request. */
804
+ readonly statusCode: number;
805
+ /** Sets a response header (used for the correlation id). */
806
+ setHeader(name: string, value: string): void;
807
+ /** Selects the status code and returns the chainable body writer. */
808
+ status(code: number): {
809
+ json(body: unknown): unknown;
810
+ };
811
+ }
812
+ /** Continuation passed to a middleware; invoked with no arguments here. */
813
+ type NextHandler = () => void;
814
+
756
815
  /**
757
816
  * Reads (or generates) the correlation id and starts the per-request log
758
817
  * context scope.
@@ -783,11 +842,11 @@ declare class RequestIdMiddleware implements NestMiddleware {
783
842
  * Echo or mint the `x-request-id`, expose it on the response, and run the
784
843
  * remainder of the request inside a fresh log-context scope.
785
844
  *
786
- * @param req - The incoming Express request.
787
- * @param res - The outgoing Express response.
845
+ * @param req - The incoming request (Express satisfies the contract).
846
+ * @param res - The outgoing response (Express satisfies the contract).
788
847
  * @param next - The next handler in the chain.
789
848
  */
790
- use(req: Request, res: Response, next: NextFunction): void;
849
+ use(req: LoggableRequest, res: LoggableResponse, next: NextHandler): void;
791
850
  }
792
851
 
793
852
  /**
@@ -950,4 +1009,4 @@ declare const RESERVED_LOG_KEYS: Readonly<{
950
1009
  readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
951
1010
  }>;
952
1011
 
953
- export { BymaxLoggerModule, type BymaxLoggerModuleAsyncOptions, type BymaxLoggerModuleOptions, type BymaxLoggerModuleOptionsFactory, DEFAULT_REDACT_PATHS, DefaultStdoutDestination, HttpExceptionFilter, HttpLoggingInterceptor, type HttpOptions, type ILogDestination, InjectLogger, LOGGER_DESTINATIONS_TOKEN, LOGGER_OPTIONS_TOKEN, LOGGER_PINO_INSTANCE_TOKEN, LOG_CONTEXT_METADATA_KEY, LOG_CONTEXT_TOKEN, LOG_KEYS_CONVENTION_REGEX, LogContext, type LogContext$1 as LogContextBag, LogContextService, type LogEntry, type LogLevel, LogPerformance, type OtelOptions, PinoLoggerService, PrettyDevDestination, RESERVED_LOG_KEYS, RequestIdMiddleware, type ResolvedBymaxLoggerModuleOptions, type ServiceMetadata, applyRequestIdMiddleware };
1012
+ export { BymaxLoggerModule, type BymaxLoggerModuleAsyncOptions, type BymaxLoggerModuleOptions, type BymaxLoggerModuleOptionsFactory, DEFAULT_REDACT_PATHS, DefaultStdoutDestination, HttpExceptionFilter, HttpLoggingInterceptor, type HttpOptions, type ILogDestination, type IncomingHeaders, InjectLogger, LOGGER_DESTINATIONS_TOKEN, LOGGER_OPTIONS_TOKEN, LOGGER_PINO_INSTANCE_TOKEN, LOG_CONTEXT_METADATA_KEY, LOG_CONTEXT_TOKEN, LOG_KEYS_CONVENTION_REGEX, LogContext, type LogContext$1 as LogContextBag, LogContextService, type LogEntry, type LogLevel, LogPerformance, type LoggableRequest, type LoggableResponse, type NextHandler, type OtelOptions, PinoLoggerService, PrettyDevDestination, RESERVED_LOG_KEYS, RequestIdMiddleware, type ResolvedBymaxLoggerModuleOptions, type ServiceMetadata, applyRequestIdMiddleware };
@@ -1357,8 +1357,8 @@ var RequestIdMiddleware = class {
1357
1357
  * Echo or mint the `x-request-id`, expose it on the response, and run the
1358
1358
  * remainder of the request inside a fresh log-context scope.
1359
1359
  *
1360
- * @param req - The incoming Express request.
1361
- * @param res - The outgoing Express response.
1360
+ * @param req - The incoming request (Express satisfies the contract).
1361
+ * @param res - The outgoing response (Express satisfies the contract).
1362
1362
  * @param next - The next handler in the chain.
1363
1363
  */
1364
1364
  use(req, res, next) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bymax-one/nest-logger",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
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",
@@ -73,10 +73,10 @@
73
73
  "rxjs": "^7.8.0"
74
74
  },
75
75
  "peerDependenciesMeta": {
76
- "pino-pretty": {
76
+ "@opentelemetry/api": {
77
77
  "optional": true
78
78
  },
79
- "@opentelemetry/api": {
79
+ "pino-pretty": {
80
80
  "optional": true
81
81
  }
82
82
  },