@bymax-one/nest-logger 1.1.0 → 1.2.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.
@@ -5,7 +5,7 @@ import pino from 'pino';
5
5
  import { createRequire } from 'module';
6
6
  import { join } from 'path';
7
7
  import { Writable } from 'stream';
8
- import { AsyncLocalStorage } from 'async_hooks';
8
+ import { AsyncLocalStorage, AsyncResource } from 'async_hooks';
9
9
  import { randomUUID } from 'crypto';
10
10
 
11
11
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -58,6 +58,7 @@ function applyDefaults(options) {
58
58
  isGlobal: options.isGlobal ?? true,
59
59
  shouldUseAsNestLogger: options.shouldUseAsNestLogger ?? true,
60
60
  redactPaths: Object.freeze([...options.redactPaths ?? []]),
61
+ redactStrategy: options.redactStrategy ?? "names",
61
62
  redactCensor: options.redactCensor ?? "[REDACTED]",
62
63
  shouldDisableDefaultRedact: options.shouldDisableDefaultRedact ?? false,
63
64
  destinations: Object.freeze([...options.destinations ?? []]),
@@ -83,7 +84,7 @@ var PINO_LEVEL_NUMBERS = Object.freeze({
83
84
  debug: 20,
84
85
  trace: 10
85
86
  });
86
- Object.freeze(
87
+ var PINO_LEVEL_NAMES = Object.freeze(
87
88
  Object.fromEntries(
88
89
  Object.entries(PINO_LEVEL_NUMBERS).map(([name, num]) => [num, name])
89
90
  // keys of PINO_LEVEL_NUMBERS are always LogLevel
@@ -120,16 +121,105 @@ function validateOptions(options) {
120
121
  if (options.maxEntrySizeBytes !== void 0 && options.maxEntrySizeBytes <= 0) {
121
122
  throw new Error("[BymaxLoggerModule] options.maxEntrySizeBytes must be > 0");
122
123
  }
124
+ if (options.redactStrategy !== void 0 && options.redactStrategy !== "names" && options.redactStrategy !== "paths") {
125
+ throw new Error(
126
+ `[BymaxLoggerModule] options.redactStrategy must be 'names' or 'paths'. Got: ${String(
127
+ options.redactStrategy
128
+ )}`
129
+ );
130
+ }
123
131
  }
124
132
 
125
133
  // src/server/constants/injection-tokens.constants.ts
126
134
  var LOGGER_OPTIONS_TOKEN = /* @__PURE__ */ Symbol("BYMAX_LOGGER_OPTIONS");
127
135
  var LOGGER_PINO_INSTANCE_TOKEN = /* @__PURE__ */ Symbol("BYMAX_LOGGER_PINO_INSTANCE");
128
136
  var LOGGER_DESTINATIONS_TOKEN = /* @__PURE__ */ Symbol("BYMAX_LOGGER_DESTINATIONS");
137
+ var LOGGER_REDACTOR_TOKEN = /* @__PURE__ */ Symbol("BYMAX_LOGGER_REDACTOR");
129
138
  var LOG_CONTEXT_TOKEN = /* @__PURE__ */ Symbol("BYMAX_LOGGER_LOG_CONTEXT");
139
+
140
+ // src/shared/constants/reserved-log-keys.constants.ts
141
+ var RESERVED_LOG_KEYS = Object.freeze({
142
+ LOGGER_BOOTSTRAP_OK: "LOGGER_BOOTSTRAP_OK",
143
+ LOGGER_BOOTSTRAP_WARNING: "LOGGER_BOOTSTRAP_WARNING",
144
+ LOGGER_SHUTDOWN_OK: "LOGGER_SHUTDOWN_OK",
145
+ HTTP_REQUEST_START: "HTTP_REQUEST_START",
146
+ HTTP_REQUEST_SUCCESS: "HTTP_REQUEST_SUCCESS",
147
+ HTTP_REQUEST_REDIRECT: "HTTP_REQUEST_REDIRECT",
148
+ HTTP_REQUEST_CLIENT_ERROR: "HTTP_REQUEST_CLIENT_ERROR",
149
+ HTTP_REQUEST_SERVER_ERROR: "HTTP_REQUEST_SERVER_ERROR",
150
+ HTTP_REQUEST_COMPLETED: "HTTP_REQUEST_COMPLETED",
151
+ HTTP_REQUEST_ABORTED: "HTTP_REQUEST_ABORTED",
152
+ HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED",
153
+ HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED",
154
+ METHOD_EXECUTION: "METHOD_EXECUTION",
155
+ METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION",
156
+ LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED",
157
+ LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED",
158
+ LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED",
159
+ LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED"
160
+ });
161
+ var RESERVED_LOG_KEYS_NOT_EMITTED = Object.freeze({
162
+ /**
163
+ * Superseded before it was ever used. The request lifecycle terminates in one
164
+ * of `HTTP_REQUEST_SUCCESS` / `_REDIRECT` / `_CLIENT_ERROR` / `_SERVER_ERROR`,
165
+ * each carrying the same `duration` a generic "completed" entry would. Emitting
166
+ * it as well would double the terminal access-log volume to say nothing new.
167
+ * It stays claimed so an application cannot repurpose a name that reads like a
168
+ * library event.
169
+ */
170
+ HTTP_REQUEST_COMPLETED: "reserved: superseded by the four status-specific terminal keys"
171
+ });
172
+
173
+ // src/server/constants/prototype-polluting-keys.constants.ts
174
+ var PROTOTYPE_POLLUTING_KEYS = /* @__PURE__ */ new Set([
175
+ "__proto__",
176
+ "constructor",
177
+ "prototype"
178
+ ]);
179
+
180
+ // src/server/services/pino-logger.service.ts
181
+ var OWNED_PAYLOAD_KEYS = ["logKey", "userId", "context"];
182
+ function withoutOwnedKeys(metadata) {
183
+ if (metadata === void 0) {
184
+ return {};
185
+ }
186
+ try {
187
+ const safe = {};
188
+ for (const key of Object.keys(metadata)) {
189
+ if (!OWNED_PAYLOAD_KEYS.includes(key) && !PROTOTYPE_POLLUTING_KEYS.has(key)) {
190
+ Reflect.set(safe, key, Reflect.get(metadata, key));
191
+ }
192
+ }
193
+ return safe;
194
+ } catch {
195
+ return {
196
+ _redactionFailed: true,
197
+ _logKey: RESERVED_LOG_KEYS.LOGGER_REDACTION_FAILED
198
+ };
199
+ }
200
+ }
201
+ function safeErrorMessage(error) {
202
+ try {
203
+ return String(error.message);
204
+ } catch {
205
+ return "Unreadable error message";
206
+ }
207
+ }
208
+ function assignIfDefined(payload, key, value) {
209
+ if (value !== void 0) {
210
+ Reflect.defineProperty(payload, key, { value, enumerable: true });
211
+ }
212
+ }
130
213
  var PinoLoggerService = class {
131
- constructor(pino2) {
214
+ /**
215
+ * @param pino - The wrapped Pino instance.
216
+ * @param redact - The DEFAULT-coverage redactor, applied to `child()` bindings.
217
+ * Defaults to the identity so a hand-built instance (benchmarks, unit tests)
218
+ * still works; the module always injects the configured one.
219
+ */
220
+ constructor(pino2, redact = (value) => value) {
132
221
  this.pino = pino2;
222
+ this.redact = redact;
133
223
  }
134
224
  // ─── NestJS LoggerService variadic interface ──────────────────────────────
135
225
  /**
@@ -152,18 +242,16 @@ var PinoLoggerService = class {
152
242
  */
153
243
  error(message, ...optionalParams) {
154
244
  if (message instanceof Error) {
155
- this.pino.error(
156
- { context: this.resolveContext(optionalParams), err: this.serializeError(message) },
157
- message.message
158
- );
245
+ const payload2 = { err: this.serializeError(message) };
246
+ assignIfDefined(payload2, "context", this.resolveContext(optionalParams));
247
+ this.pino.error(payload2, safeErrorMessage(message));
159
248
  return;
160
249
  }
161
250
  const stack = typeof optionalParams[0] === "string" ? optionalParams[0] : void 0;
162
251
  const context = typeof optionalParams[1] === "string" ? optionalParams[1] : this.context;
163
- const payload = { context };
164
- if (stack !== void 0) {
165
- payload["stack"] = stack;
166
- }
252
+ const payload = {};
253
+ assignIfDefined(payload, "context", context);
254
+ assignIfDefined(payload, "stack", stack);
167
255
  this.pino.error(payload, typeof message === "string" ? message : String(message));
168
256
  }
169
257
  /**
@@ -238,10 +326,14 @@ var PinoLoggerService = class {
238
326
  * @param metadata - Optional extra structured fields.
239
327
  */
240
328
  errorStructured(logKey, error, userId, metadata) {
241
- this.pino.error(
242
- { ...metadata, logKey, userId, context: this.context, err: this.serializeError(error) },
243
- error.message
244
- );
329
+ const payload = {
330
+ ...withoutOwnedKeys(metadata),
331
+ logKey,
332
+ err: this.serializeError(error)
333
+ };
334
+ assignIfDefined(payload, "userId", userId);
335
+ assignIfDefined(payload, "context", this.context);
336
+ this.pino.error(payload, safeErrorMessage(error));
245
337
  }
246
338
  // ─── Helpers / escape hatches ─────────────────────────────────────────────
247
339
  /**
@@ -274,7 +366,8 @@ var PinoLoggerService = class {
274
366
  * @returns A new `PinoLoggerService` wrapping the Pino child.
275
367
  */
276
368
  child(bindings) {
277
- const childService = new PinoLoggerService(this.pino.child(bindings));
369
+ const safeBindings = this.redact(bindings, true);
370
+ const childService = new PinoLoggerService(this.pino.child(safeBindings), this.redact);
278
371
  if (this.context !== void 0) {
279
372
  childService.setContext(this.context);
280
373
  }
@@ -299,7 +392,11 @@ var PinoLoggerService = class {
299
392
  * dashboards for every exception logged through `HttpExceptionFilter`.
300
393
  */
301
394
  serializeError(error) {
302
- return { type: error.name, message: error.message, stack: error.stack };
395
+ try {
396
+ return { type: error.name, message: error.message, stack: error.stack };
397
+ } catch {
398
+ return { type: "SanitizeFailed", message: "Failed to read the thrown value" };
399
+ }
303
400
  }
304
401
  /** Resolve the context: last string param wins, else the instance context. */
305
402
  resolveContext(optionalParams) {
@@ -308,12 +405,9 @@ var PinoLoggerService = class {
308
405
  }
309
406
  /** Emit a structured payload at info or warn level. */
310
407
  emitStructured(level, logKey, message, userId, metadata) {
311
- const payload = {
312
- ...metadata,
313
- logKey,
314
- userId,
315
- context: this.context
316
- };
408
+ const payload = { ...withoutOwnedKeys(metadata), logKey };
409
+ assignIfDefined(payload, "userId", userId);
410
+ assignIfDefined(payload, "context", this.context);
317
411
  if (level === "info") {
318
412
  this.pino.info(payload, message);
319
413
  } else {
@@ -322,7 +416,8 @@ var PinoLoggerService = class {
322
416
  }
323
417
  /** Emit a NestJS-style variadic log, dispatching by level without computed indexing. */
324
418
  emitNestStyle(level, message, optionalParams) {
325
- const payload = { context: this.resolveContext(optionalParams) };
419
+ const payload = {};
420
+ assignIfDefined(payload, "context", this.resolveContext(optionalParams));
326
421
  const msg = typeof message === "string" ? message : String(message);
327
422
  switch (level) {
328
423
  case "info":
@@ -345,7 +440,8 @@ var PinoLoggerService = class {
345
440
  };
346
441
  PinoLoggerService = __decorateClass([
347
442
  Injectable(),
348
- __decorateParam(0, Inject(LOGGER_PINO_INSTANCE_TOKEN))
443
+ __decorateParam(0, Inject(LOGGER_PINO_INSTANCE_TOKEN)),
444
+ __decorateParam(1, Inject(LOGGER_REDACTOR_TOKEN))
349
445
  ], PinoLoggerService);
350
446
 
351
447
  // src/server/decorators/inject-logger.provider.ts
@@ -395,26 +491,6 @@ DefaultStdoutDestination = __decorateClass([
395
491
  Injectable()
396
492
  ], DefaultStdoutDestination);
397
493
 
398
- // src/shared/constants/reserved-log-keys.constants.ts
399
- var RESERVED_LOG_KEYS = Object.freeze({
400
- LOGGER_BOOTSTRAP_OK: "LOGGER_BOOTSTRAP_OK",
401
- LOGGER_BOOTSTRAP_WARNING: "LOGGER_BOOTSTRAP_WARNING",
402
- LOGGER_SHUTDOWN_OK: "LOGGER_SHUTDOWN_OK",
403
- HTTP_REQUEST_START: "HTTP_REQUEST_START",
404
- HTTP_REQUEST_SUCCESS: "HTTP_REQUEST_SUCCESS",
405
- HTTP_REQUEST_REDIRECT: "HTTP_REQUEST_REDIRECT",
406
- HTTP_REQUEST_CLIENT_ERROR: "HTTP_REQUEST_CLIENT_ERROR",
407
- HTTP_REQUEST_SERVER_ERROR: "HTTP_REQUEST_SERVER_ERROR",
408
- HTTP_REQUEST_COMPLETED: "HTTP_REQUEST_COMPLETED",
409
- HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED",
410
- HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED",
411
- METHOD_EXECUTION: "METHOD_EXECUTION",
412
- METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION",
413
- LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED",
414
- LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED",
415
- LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED"
416
- });
417
-
418
494
  // src/server/utils/normalize-url.util.ts
419
495
  var UUID_REGEX = /\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?![0-9a-f])/gi;
420
496
  var ULID_REGEX = /\/[0-9A-HJKMNP-TV-Z]{26}(?![0-9A-HJKMNP-TV-Z])/g;
@@ -555,11 +631,39 @@ HttpExceptionFilter = __decorateClass([
555
631
  Catch(),
556
632
  __decorateParam(0, Inject(PinoLoggerService))
557
633
  ], HttpExceptionFilter);
558
- var HTTP_SUCCESS_MIN = 200;
634
+
635
+ // src/server/utils/http-log-state.util.ts
559
636
  var HTTP_REDIRECT_MIN = 300;
560
637
  var HTTP_CLIENT_ERROR_MIN = 400;
561
638
  var HTTP_SERVER_ERROR_MIN = 500;
562
639
  var UNKNOWN_USER_AGENT = "unknown";
640
+ var RECORDER_ACTIVE = /* @__PURE__ */ Symbol("bymax-one/nest-logger:recorder");
641
+ var RECORDED_ERROR = /* @__PURE__ */ Symbol("bymax-one/nest-logger:error");
642
+ function markRecorderActive(req) {
643
+ Reflect.set(req, RECORDER_ACTIVE, true);
644
+ }
645
+ function isRecorderActive(req) {
646
+ return Reflect.get(req, RECORDER_ACTIVE) === true;
647
+ }
648
+ function recordError(req, error) {
649
+ Reflect.set(req, RECORDED_ERROR, { error });
650
+ }
651
+ function readRecordedError(req) {
652
+ return Reflect.get(req, RECORDED_ERROR);
653
+ }
654
+ function toError(thrown) {
655
+ return thrown instanceof Error ? thrown : new Error(String(thrown));
656
+ }
657
+ function readUserId(req) {
658
+ return req.user?.sub ?? req.user?.id;
659
+ }
660
+ function readUserAgent(req) {
661
+ const raw = req.headers["user-agent"];
662
+ return typeof raw === "string" ? raw : UNKNOWN_USER_AGENT;
663
+ }
664
+
665
+ // src/server/interceptors/http-logging.interceptor.ts
666
+ var HTTP_SUCCESS_MIN = 200;
563
667
  var HttpLoggingInterceptor = class {
564
668
  /**
565
669
  * @param logger - The structured logger the lifecycle entries are written to.
@@ -593,13 +697,15 @@ var HttpLoggingInterceptor = class {
593
697
  const http = context.switchToHttp();
594
698
  const req = http.getRequest();
595
699
  const res = http.getResponse();
700
+ if (isRecorderActive(req)) {
701
+ return this.recordOnly(req, next);
702
+ }
596
703
  const { method, url, ip } = req;
597
704
  if (this.isExcluded(stripQueryString(url))) {
598
705
  return next.handle();
599
706
  }
600
- const rawUserAgent = req.headers["user-agent"];
601
- const userAgent = typeof rawUserAgent === "string" ? rawUserAgent : UNKNOWN_USER_AGENT;
602
- const userId = req.user?.sub ?? req.user?.id;
707
+ const userAgent = readUserAgent(req);
708
+ const userId = readUserId(req);
603
709
  const normalizedUrl = normalizeUrl(url);
604
710
  const start = Date.now();
605
711
  this.logger.info(RESERVED_LOG_KEYS.HTTP_REQUEST_START, `${method} ${normalizedUrl}`, userId, {
@@ -622,6 +728,28 @@ var HttpLoggingInterceptor = class {
622
728
  })
623
729
  );
624
730
  }
731
+ /**
732
+ * Hand the lifecycle to the access-log middleware, recording only the thrown
733
+ * error for its terminal entry.
734
+ *
735
+ * The interceptor cannot be the recorder: it never runs for a request a guard
736
+ * rejected or one that matched no route. It also cannot judge DELIVERY — at the
737
+ * moment it completes, the response has not been flushed yet, which is why an
738
+ * aborted request used to be logged as the 200 the handler intended. What it
739
+ * uniquely has is the thrown value, so that is all it contributes.
740
+ *
741
+ * @param req - The request whose lifecycle the middleware owns.
742
+ * @param next - The downstream call handler.
743
+ * @returns The response stream, unmodified and with exceptions re-thrown.
744
+ */
745
+ recordOnly(req, next) {
746
+ return next.handle().pipe(
747
+ catchError((err) => {
748
+ recordError(req, toError(err));
749
+ return throwError(() => err);
750
+ })
751
+ );
752
+ }
625
753
  /**
626
754
  * Log a non-throwing completion: SUCCESS for 2xx, REDIRECT for 3xx, nothing
627
755
  * for any other status (those are surfaced via the error path instead).
@@ -680,12 +808,12 @@ var HttpLoggingInterceptor = class {
680
808
  }
681
809
  return;
682
810
  }
683
- this.logger.errorStructured(
684
- RESERVED_LOG_KEYS.HTTP_REQUEST_SERVER_ERROR,
685
- err instanceof Error ? err : new Error(String(err)),
686
- userId,
687
- { method, url, statusCode: HttpStatus.INTERNAL_SERVER_ERROR, duration }
688
- );
811
+ this.logger.errorStructured(RESERVED_LOG_KEYS.HTTP_REQUEST_SERVER_ERROR, toError(err), userId, {
812
+ method,
813
+ url,
814
+ statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
815
+ duration
816
+ });
689
817
  }
690
818
  };
691
819
  HttpLoggingInterceptor = __decorateClass([
@@ -720,48 +848,6 @@ var {
720
848
  // disabled" without a dead nullish branch.
721
849
  global: extras.isGlobal !== false
722
850
  })).build();
723
- function detectOtelTraceApi() {
724
- try {
725
- const requireFromCwd = createRequire(join(process.cwd(), "noop.cjs"));
726
- const mod = requireFromCwd("@opentelemetry/api");
727
- return mod.trace;
728
- } catch {
729
- return void 0;
730
- }
731
- }
732
- function isValidTraceId(traceId) {
733
- return /^[0-9a-f]{32}$/.test(traceId) && !/^0+$/.test(traceId);
734
- }
735
- function isValidSpanId(spanId) {
736
- return /^[0-9a-f]{16}$/.test(spanId) && !/^0+$/.test(spanId);
737
- }
738
-
739
- // src/server/mixins/trace-context.mixin.ts
740
- function createTraceContextMixin(logContext, opts) {
741
- const traceApi = opts.shouldAutoInjectTraceContext ? detectOtelTraceApi() : void 0;
742
- return function mixin(_mergeObject, _level, _logger) {
743
- const merged = {};
744
- const store = logContext.getStore();
745
- if (store) {
746
- Object.assign(merged, store);
747
- }
748
- if (traceApi) {
749
- const span = traceApi.getActiveSpan();
750
- if (span) {
751
- const ctx = span.spanContext();
752
- if (isValidTraceId(ctx.traceId) && isValidSpanId(ctx.spanId)) {
753
- Reflect.set(merged, opts.traceIdField, ctx.traceId);
754
- Reflect.set(merged, opts.spanIdField, ctx.spanId);
755
- if (typeof ctx.traceFlags === "number") {
756
- const flagsByte = ctx.traceFlags & 255;
757
- Reflect.set(merged, opts.traceFlagsField, flagsByte.toString(16).padStart(2, "0"));
758
- }
759
- }
760
- }
761
- }
762
- return merged;
763
- };
764
- }
765
851
 
766
852
  // src/server/constants/default-redact-paths.constants.ts
767
853
  var REDACT_MAX_DEPTH = 4;
@@ -804,7 +890,20 @@ var REDACT_COMMON_FIELDS = [
804
890
  "signingSecret",
805
891
  "privateKey",
806
892
  // Conservative PII (1) — consumer can disable if logging email is justified
807
- "email"
893
+ "email",
894
+ // Credential-bearing HTTP header names (5). These also appear in
895
+ // {@link REDACT_ABSOLUTE_PATHS}, pinned to the `req.headers` / `res.headers`
896
+ // shapes — which covered ONLY those two shapes. A headers bag logged under any
897
+ // other key (`logger.info(k, m, u, { headers: req.headers })`, one of the most
898
+ // common things written while debugging an integration) wrote the bearer token
899
+ // in clear. Listed here as bare names, they are caught wherever they appear.
900
+ // Node lower-cases inbound header names, so the lower-case spelling is the one
901
+ // that can actually reach a log.
902
+ "authorization",
903
+ "cookie",
904
+ "set-cookie",
905
+ "x-api-key",
906
+ "x-auth-token"
808
907
  ];
809
908
  var REDACT_ABSOLUTE_PATHS = [
810
909
  "req.headers.authorization",
@@ -818,6 +917,48 @@ var DEFAULT_REDACT_PATHS = [
818
917
  ...REDACT_COMMON_FIELDS.flatMap((field) => depth(field)),
819
918
  ...REDACT_ABSOLUTE_PATHS
820
919
  ];
920
+ function detectOtelTraceApi() {
921
+ try {
922
+ const requireFromCwd = createRequire(join(process.cwd(), "noop.cjs"));
923
+ const mod = requireFromCwd("@opentelemetry/api");
924
+ return mod.trace;
925
+ } catch {
926
+ return void 0;
927
+ }
928
+ }
929
+ function isValidTraceId(traceId) {
930
+ return /^[0-9a-f]{32}$/.test(traceId) && !/^0+$/.test(traceId);
931
+ }
932
+ function isValidSpanId(spanId) {
933
+ return /^[0-9a-f]{16}$/.test(spanId) && !/^0+$/.test(spanId);
934
+ }
935
+
936
+ // src/server/mixins/trace-context.mixin.ts
937
+ function createTraceContextMixin(logContext, opts) {
938
+ const traceApi = opts.shouldAutoInjectTraceContext ? detectOtelTraceApi() : void 0;
939
+ return function mixin(_mergeObject, _level, _logger) {
940
+ const merged = {};
941
+ const store = logContext.getStore();
942
+ if (store) {
943
+ Object.assign(merged, store);
944
+ }
945
+ if (traceApi) {
946
+ const span = traceApi.getActiveSpan();
947
+ if (span) {
948
+ const ctx = span.spanContext();
949
+ if (isValidTraceId(ctx.traceId) && isValidSpanId(ctx.spanId)) {
950
+ Reflect.set(merged, opts.traceIdField, ctx.traceId);
951
+ Reflect.set(merged, opts.spanIdField, ctx.spanId);
952
+ if (typeof ctx.traceFlags === "number") {
953
+ const flagsByte = ctx.traceFlags & 255;
954
+ Reflect.set(merged, opts.traceFlagsField, flagsByte.toString(16).padStart(2, "0"));
955
+ }
956
+ }
957
+ }
958
+ }
959
+ return merged;
960
+ };
961
+ }
821
962
 
822
963
  // src/server/utils/compile-redact-paths.util.ts
823
964
  function compileRedactPaths(extraPaths, shouldSkipDefaults) {
@@ -866,6 +1007,120 @@ function destinationToStream(destination) {
866
1007
  });
867
1008
  }
868
1009
 
1010
+ // src/server/utils/redact-by-name.util.ts
1011
+ var REDACT_MAX_TRAVERSAL_DEPTH = 100;
1012
+ var REDACT_DEPTH_EXCEEDED = "[REDACTION_DEPTH_EXCEEDED]";
1013
+ var REDACT_CIRCULAR = "[Circular]";
1014
+ function resolveToJson(value) {
1015
+ let getter;
1016
+ let candidate;
1017
+ let current = value;
1018
+ while (current !== null) {
1019
+ const descriptor = Object.getOwnPropertyDescriptor(current, "toJSON");
1020
+ if (descriptor !== void 0) {
1021
+ getter = descriptor.get;
1022
+ candidate = getter === void 0 ? descriptor.value : getter.call(value);
1023
+ break;
1024
+ }
1025
+ current = Object.getPrototypeOf(current);
1026
+ }
1027
+ return {
1028
+ method: typeof candidate === "function" ? candidate : void 0,
1029
+ fromAccessor: getter !== void 0
1030
+ };
1031
+ }
1032
+ function cloneError(error) {
1033
+ const clone = Object.create(
1034
+ Object.getPrototypeOf(error),
1035
+ Object.getOwnPropertyDescriptors(error)
1036
+ );
1037
+ const { stack } = error;
1038
+ if (typeof stack === "string") {
1039
+ Reflect.defineProperty(clone, "stack", { value: stack, enumerable: false });
1040
+ }
1041
+ return clone;
1042
+ }
1043
+ var BUFFER_TO_JSON = Buffer.prototype.toJSON;
1044
+ var WRITE_FAILED = new Error();
1045
+ function defineOwn(target, key, value) {
1046
+ if (!Reflect.defineProperty(target, key, { value, enumerable: true })) {
1047
+ throw WRITE_FAILED;
1048
+ }
1049
+ }
1050
+ function walkArray(value, sensitive, censor, depth2, ancestors) {
1051
+ const length = value.length;
1052
+ const copy = [];
1053
+ for (let index = 0; index < length; index++) {
1054
+ Reflect.set(
1055
+ copy,
1056
+ index,
1057
+ walk(Reflect.get(value, index), sensitive, censor, depth2 + 1, ancestors)
1058
+ );
1059
+ }
1060
+ return copy;
1061
+ }
1062
+ function walk(value, sensitive, censor, depth2, ancestors, honorToJson = true) {
1063
+ if (value === null) {
1064
+ return value;
1065
+ }
1066
+ if (typeof value !== "object" && typeof value !== "function") {
1067
+ return value;
1068
+ }
1069
+ if (depth2 > REDACT_MAX_TRAVERSAL_DEPTH) {
1070
+ return REDACT_DEPTH_EXCEEDED;
1071
+ }
1072
+ if (ancestors.has(value)) {
1073
+ return REDACT_CIRCULAR;
1074
+ }
1075
+ const resolvedToJson = resolveToJson(value);
1076
+ if (!resolvedToJson.fromAccessor && resolvedToJson.method === BUFFER_TO_JSON) {
1077
+ return value;
1078
+ }
1079
+ ancestors.add(value);
1080
+ try {
1081
+ const toJson = honorToJson ? resolvedToJson.method : void 0;
1082
+ if (toJson !== void 0) {
1083
+ if (Object.keys(value).some((key) => sensitive.has(key.toLowerCase()))) {
1084
+ return censor;
1085
+ }
1086
+ return walk(toJson.call(value), sensitive, censor, depth2 + 1, ancestors);
1087
+ }
1088
+ if (typeof value === "function") {
1089
+ return value;
1090
+ }
1091
+ if (Array.isArray(value)) {
1092
+ return walkArray(value, sensitive, censor, depth2, ancestors);
1093
+ }
1094
+ const source = value;
1095
+ const keys = Object.keys(source);
1096
+ const copy = value instanceof Error ? cloneError(value) : {};
1097
+ for (const key of keys) {
1098
+ const current = Reflect.get(source, key);
1099
+ defineOwn(
1100
+ copy,
1101
+ key,
1102
+ sensitive.has(key.toLowerCase()) ? censor : walk(current, sensitive, censor, depth2 + 1, ancestors)
1103
+ );
1104
+ }
1105
+ return copy;
1106
+ } finally {
1107
+ ancestors.delete(value);
1108
+ }
1109
+ }
1110
+ function createNameRedactor(fieldNames, censor) {
1111
+ const sensitive = new Set(fieldNames.map((name) => name.toLowerCase()));
1112
+ return (value, isRecordRoot = false) => {
1113
+ try {
1114
+ return walk(value, sensitive, censor, 0, /* @__PURE__ */ new Set(), !isRecordRoot);
1115
+ } catch {
1116
+ return {
1117
+ _redactionFailed: true,
1118
+ _logKey: RESERVED_LOG_KEYS.LOGGER_REDACTION_FAILED
1119
+ };
1120
+ }
1121
+ };
1122
+ }
1123
+
869
1124
  // src/server/utils/truncate-large-entries.ts
870
1125
  var PREVIEW_LENGTH = 200;
871
1126
  function createSizeBoundedSerializer(baseSerializer, maxBytes) {
@@ -894,25 +1149,56 @@ function createSizeBoundedSerializer(baseSerializer, maxBytes) {
894
1149
  }
895
1150
 
896
1151
  // src/server/pino-factory.ts
1152
+ var PATH_SEGMENT = /\[\s*['"]([^'"]+)['"]\s*\]|([^.[\]]+)/g;
1153
+ var INDEX_SEGMENT = /^\d+$/;
1154
+ function leafNameOf(path) {
1155
+ let leaf;
1156
+ for (const match of path.matchAll(PATH_SEGMENT)) {
1157
+ const quoted = match[1];
1158
+ const name = quoted ?? (match[2] !== void 0 && INDEX_SEGMENT.test(match[2]) ? void 0 : match[2]);
1159
+ if (name !== void 0 && name !== "*") {
1160
+ leaf = name;
1161
+ }
1162
+ }
1163
+ return leaf;
1164
+ }
1165
+ var PASS_THROUGH = (value) => value;
1166
+ function resolveNameRedactor(options) {
1167
+ if (options.redactStrategy !== "names") {
1168
+ return PASS_THROUGH;
1169
+ }
1170
+ const names = [
1171
+ ...options.shouldDisableDefaultRedact ? [] : REDACT_COMMON_FIELDS,
1172
+ ...options.redactPaths.flatMap((path) => leafNameOf(path) ?? [])
1173
+ ];
1174
+ if (names.length === 0) {
1175
+ return PASS_THROUGH;
1176
+ }
1177
+ return createNameRedactor(names, options.redactCensor);
1178
+ }
1179
+ function resolveRedactOption(options) {
1180
+ const paths = options.redactStrategy === "paths" ? compileRedactPaths(options.redactPaths, options.shouldDisableDefaultRedact) : [...new Set(options.redactPaths)];
1181
+ if (paths.length === 0) {
1182
+ return void 0;
1183
+ }
1184
+ return { paths, censor: options.redactCensor };
1185
+ }
897
1186
  function buildPinoInstance(options, logContext, destinations) {
898
1187
  const maxBytes = options.maxEntrySizeBytes;
1188
+ const redact = resolveNameRedactor(options);
1189
+ const bound = (serializer) => createSizeBoundedSerializer((input) => redact(serializer(input)), maxBytes);
899
1190
  const serializers = {
900
- err: createSizeBoundedSerializer(pino.stdSerializers.err, maxBytes),
1191
+ err: bound(pino.stdSerializers.err),
901
1192
  ...Object.fromEntries(
902
1193
  Object.entries(options.serializers).map(
903
- ([key, serializer]) => [
904
- key,
905
- createSizeBoundedSerializer(serializer, maxBytes)
906
- ]
1194
+ ([key, serializer]) => [key, bound(serializer)]
907
1195
  )
908
1196
  )
909
1197
  };
1198
+ const redactOption = resolveRedactOption(options);
910
1199
  const pinoOptions = {
911
1200
  level: options.level,
912
- redact: {
913
- paths: compileRedactPaths(options.redactPaths, options.shouldDisableDefaultRedact),
914
- censor: options.redactCensor
915
- },
1201
+ ...redactOption === void 0 ? {} : { redact: redactOption },
916
1202
  base: { service: options.service },
917
1203
  // Pino requires the timestamp fn to emit the `,"time":"..."` fragment.
918
1204
  timestamp: () => `,"time":"${options.timestamp()}"`,
@@ -920,10 +1206,42 @@ function buildPinoInstance(options, logContext, destinations) {
920
1206
  // Emit the level as a string label instead of the numeric code — easier
921
1207
  // for log aggregators. Trace context is injected via `mixin`, never via
922
1208
  // `formatters.log` (which cannot see ambient ALS / OTel state).
923
- level: (label) => ({ level: label })
1209
+ level: (label) => ({ level: label }),
1210
+ // `base` bindings never reach `formatters.log` — Pino pre-serializes them
1211
+ // into the instance's `chindings`, the same reason `child()` has to redact
1212
+ // its own. That matters because `service` is CONSUMER-supplied and
1213
+ // `applyDefaults` keeps whatever it was given: a `{ name, version, apiKey }`
1214
+ // went out in clear, where the path expansion had covered it via `*.*.apiKey`.
1215
+ // Redacting here rather than trimming to the two declared fields keeps a
1216
+ // consumer's extra metadata instead of silently dropping it. Runs ONCE, at
1217
+ // logger construction — no per-entry cost. `true`: bindings are a record
1218
+ // root, iterated rather than serialized.
1219
+ bindings: (bindings) => redact(bindings, true),
1220
+ // The name-walk redactor runs here, on the merged record (mixin output +
1221
+ // the caller's object), which is exactly the surface a caller controls.
1222
+ // `base` and child bindings are NOT visible at this hook — they are
1223
+ // library-owned (`service`, the `@InjectLogger` context) and carry nothing
1224
+ // sensitive, which `pino-factory.spec.ts` pins.
1225
+ log: (record) => redact(record, true)
924
1226
  },
925
1227
  serializers,
926
- mixin: createTraceContextMixin(logContext, options.otel)
1228
+ mixin: createTraceContextMixin(logContext, options.otel),
1229
+ // `formatters.log` is NOT the first code to touch the caller's object: Pino
1230
+ // merges the mixin result with it first, and the default strategy's
1231
+ // `Object.assign` invokes every own getter. A throwing getter therefore
1232
+ // crashed the log call before the redactor could return its fail-closed
1233
+ // envelope. Owning the merge moves that boundary inside the guarantee.
1234
+ mixinMergeStrategy: (mergeObject, mixinObject) => {
1235
+ try {
1236
+ return Object.assign({}, mixinObject, mergeObject);
1237
+ } catch {
1238
+ return {
1239
+ ...mixinObject,
1240
+ _redactionFailed: true,
1241
+ _logKey: RESERVED_LOG_KEYS.LOGGER_REDACTION_FAILED
1242
+ };
1243
+ }
1244
+ }
927
1245
  };
928
1246
  const streams = destinations.map((destination) => ({
929
1247
  level: destination.minLevel ?? options.level,
@@ -939,9 +1257,10 @@ var DestinationRegistry = class {
939
1257
  * @param logger - Structured logger used to report init failures. Injected by
940
1258
  * token explicitly for the same bundling reason.
941
1259
  */
942
- constructor(registered, logger) {
1260
+ constructor(registered, logger, options) {
943
1261
  this.registered = registered;
944
1262
  this.logger = logger;
1263
+ this.options = options;
945
1264
  /**
946
1265
  * Destinations that initialized successfully, in registration order.
947
1266
  *
@@ -973,6 +1292,35 @@ var DestinationRegistry = class {
973
1292
  );
974
1293
  }
975
1294
  }
1295
+ this.announceBootstrap();
1296
+ }
1297
+ /**
1298
+ * Emit the one-shot bootstrap entries, AFTER every destination has been
1299
+ * initialized.
1300
+ *
1301
+ * Ordering is the whole point of doing this here rather than from an eagerly
1302
+ * instantiated provider factory: a provider factory runs while Nest is still
1303
+ * building the graph, before `onModuleInit`, so a sink that only accepts
1304
+ * writes once its own `onInit()` has run would drop these entries — including
1305
+ * `LOGGER_BOOTSTRAP_WARNING`, which exists precisely so a security review can
1306
+ * see that PII redaction was turned off. A signal that a custom destination
1307
+ * can silently swallow is not an audit trail. Emitting from the registry that
1308
+ * owns destination initialization makes the ordering structural instead of a
1309
+ * cross-provider hook-order assumption.
1310
+ */
1311
+ announceBootstrap() {
1312
+ this.logger.info(RESERVED_LOG_KEYS.LOGGER_BOOTSTRAP_OK, "BymaxLoggerModule initialized");
1313
+ if (this.options.shouldDisableDefaultRedact) {
1314
+ this.logger.warnStructured(
1315
+ RESERVED_LOG_KEYS.LOGGER_BOOTSTRAP_WARNING,
1316
+ "Default PII redaction is DISABLED \u2014 sensitive fields will be logged verbatim unless every one of them is listed in options.redactPaths",
1317
+ void 0,
1318
+ {
1319
+ shouldDisableDefaultRedact: true,
1320
+ redactPathCount: this.options.redactPaths.length
1321
+ }
1322
+ );
1323
+ }
976
1324
  }
977
1325
  /**
978
1326
  * Flush and close active destinations in REVERSE registration order, so a
@@ -981,6 +1329,15 @@ var DestinationRegistry = class {
981
1329
  * point in the shutdown sequence.
982
1330
  */
983
1331
  async onApplicationShutdown() {
1332
+ this.logger.info(
1333
+ RESERVED_LOG_KEYS.LOGGER_SHUTDOWN_OK,
1334
+ "BymaxLoggerModule shutting down",
1335
+ void 0,
1336
+ { destinations: this.active.length }
1337
+ );
1338
+ await new Promise((resolve) => {
1339
+ setImmediate(resolve);
1340
+ });
984
1341
  for (const destination of [...this.active].reverse()) {
985
1342
  try {
986
1343
  await destination.onShutdown?.();
@@ -1005,9 +1362,10 @@ var DestinationRegistry = class {
1005
1362
  DestinationRegistry = __decorateClass([
1006
1363
  Injectable(),
1007
1364
  __decorateParam(0, Inject(LOGGER_DESTINATIONS_TOKEN)),
1008
- __decorateParam(1, Inject(PinoLoggerService))
1365
+ __decorateParam(1, Inject(PinoLoggerService)),
1366
+ __decorateParam(2, Inject(LOGGER_OPTIONS_TOKEN))
1009
1367
  ], DestinationRegistry);
1010
- var FORBIDDEN_CONTEXT_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1368
+ var FORBIDDEN_CONTEXT_KEYS = PROTOTYPE_POLLUTING_KEYS;
1011
1369
  var LogContextService = class {
1012
1370
  constructor() {
1013
1371
  this.als = new AsyncLocalStorage();
@@ -1093,24 +1451,21 @@ LogContextService = __decorateClass([
1093
1451
  ], LogContextService);
1094
1452
 
1095
1453
  // src/server/logger.module.ts
1096
- var LOGGER_BOOTSTRAP_TOKEN = /* @__PURE__ */ Symbol("BYMAX_LOGGER_BOOTSTRAP");
1097
1454
  function resolveDestinations(options) {
1098
1455
  return options.destinations.length > 0 ? options.destinations : [new DefaultStdoutDestination()];
1099
1456
  }
1100
- function bootstrapProvider() {
1101
- return {
1102
- provide: LOGGER_BOOTSTRAP_TOKEN,
1103
- useFactory: (logger) => {
1104
- logger.info(RESERVED_LOG_KEYS.LOGGER_BOOTSTRAP_OK, "BymaxLoggerModule initialized");
1105
- return true;
1106
- },
1107
- inject: [PinoLoggerService]
1108
- };
1109
- }
1110
1457
  function buildCommonProviders() {
1111
1458
  return [
1112
1459
  LogContextService,
1113
1460
  { provide: LOG_CONTEXT_TOKEN, useExisting: LogContextService },
1461
+ {
1462
+ // The DEFAULT-coverage redactor, shared by the Pino factory's hooks and by
1463
+ // `PinoLoggerService.child()`. The latter needs it as a provider because
1464
+ // Pino pre-serializes child bindings before `formatters.log` can see them.
1465
+ provide: LOGGER_REDACTOR_TOKEN,
1466
+ useFactory: (options) => resolveNameRedactor(options),
1467
+ inject: [LOGGER_OPTIONS_TOKEN]
1468
+ },
1114
1469
  {
1115
1470
  provide: LOGGER_PINO_INSTANCE_TOKEN,
1116
1471
  useFactory: (options, logContext, destinations) => buildPinoInstance(options, logContext, destinations),
@@ -1126,8 +1481,7 @@ function buildCommonProviders() {
1126
1481
  // exported — consumers never inject it directly.
1127
1482
  DestinationRegistry,
1128
1483
  // One child-logger provider per context discovered from @InjectLogger(context).
1129
- ...collectContextLoggerProviders(),
1130
- bootstrapProvider()
1484
+ ...collectContextLoggerProviders()
1131
1485
  ];
1132
1486
  }
1133
1487
  function asyncHttpInterceptorProvider() {
@@ -1147,6 +1501,7 @@ function augmentLoggerModule(base, providers) {
1147
1501
  LOGGER_OPTIONS_TOKEN,
1148
1502
  LOGGER_PINO_INSTANCE_TOKEN,
1149
1503
  LOGGER_DESTINATIONS_TOKEN,
1504
+ LOGGER_REDACTOR_TOKEN,
1150
1505
  LOG_CONTEXT_TOKEN,
1151
1506
  LogContextService,
1152
1507
  PinoLoggerService,
@@ -1337,6 +1692,119 @@ var PrettyDevDestination = class {
1337
1692
  });
1338
1693
  }
1339
1694
  };
1695
+ var HttpAccessLogMiddleware = class {
1696
+ /**
1697
+ * @param logger - The structured logger the access entries are written to.
1698
+ * Injected by token explicitly: the package is bundled without
1699
+ * `emitDecoratorMetadata`, so implicit class-type injection would not resolve.
1700
+ * @param options - Resolved module options (read for `http.excludePaths`).
1701
+ */
1702
+ constructor(logger, options) {
1703
+ this.logger = logger;
1704
+ this.isEnabled = options.http.isEnabled;
1705
+ this.excludePaths = options.http.excludePaths;
1706
+ }
1707
+ /**
1708
+ * Emit START, arm the terminal entry on `'close'`, and continue the chain.
1709
+ *
1710
+ * @param req - The incoming request (Express satisfies the contract).
1711
+ * @param res - The outgoing response (Express satisfies the contract).
1712
+ * @param next - The next handler in the chain.
1713
+ */
1714
+ use(req, res, next) {
1715
+ if (!this.isEnabled) {
1716
+ next();
1717
+ return;
1718
+ }
1719
+ const target = req.originalUrl ?? req.url;
1720
+ const path = stripQueryString(target);
1721
+ if (this.excludePaths.some((pattern) => pattern.test(path))) {
1722
+ next();
1723
+ return;
1724
+ }
1725
+ markRecorderActive(req);
1726
+ const method = req.method;
1727
+ const url = normalizeUrl(target);
1728
+ const start = Date.now();
1729
+ this.logger.info(RESERVED_LOG_KEYS.HTTP_REQUEST_START, `${method} ${url}`, readUserId(req), {
1730
+ method,
1731
+ url,
1732
+ // Query string stripped: it may carry secrets (reset tokens, OAuth codes)
1733
+ // that no key-name redaction can scrub out of a string VALUE.
1734
+ fullUrl: path,
1735
+ // Conventional for an access log and personal data under GDPR/LGPD. Its
1736
+ // fidelity is the app's to establish: behind a proxy it is only the real
1737
+ // client when the app configures `trust proxy`, and a value the app has not
1738
+ // established is attacker-chosen. Suppress with `redactPaths: ['ip']`.
1739
+ ip: req.ip,
1740
+ userAgent: readUserAgent(req)
1741
+ });
1742
+ res.on(
1743
+ "close",
1744
+ AsyncResource.bind(() => {
1745
+ this.logTerminal(req, res, method, url, Date.now() - start);
1746
+ })
1747
+ );
1748
+ next();
1749
+ }
1750
+ /**
1751
+ * Emit the terminal entry for a closed request.
1752
+ *
1753
+ * `userId` is read HERE rather than at START because authentication runs in a
1754
+ * guard, downstream of this middleware — at START there is no principal yet.
1755
+ *
1756
+ * @param req - The request, carrying any error the interceptor recorded.
1757
+ * @param res - The closed response.
1758
+ * @param method - The HTTP method.
1759
+ * @param url - The normalized request URL.
1760
+ * @param duration - Elapsed milliseconds.
1761
+ */
1762
+ logTerminal(req, res, method, url, duration) {
1763
+ const statusCode = res.statusCode;
1764
+ const userId = readUserId(req);
1765
+ const meta = { method, url, statusCode, duration };
1766
+ if (!res.writableFinished) {
1767
+ this.logger.warnStructured(
1768
+ RESERVED_LOG_KEYS.HTTP_REQUEST_ABORTED,
1769
+ `${method} ${url} \u2192 ${statusCode} not delivered (${duration}ms)`,
1770
+ userId,
1771
+ meta
1772
+ );
1773
+ return;
1774
+ }
1775
+ if (statusCode >= HTTP_SERVER_ERROR_MIN) {
1776
+ const recorded = readRecordedError(req);
1777
+ this.logger.errorStructured(
1778
+ RESERVED_LOG_KEYS.HTTP_REQUEST_SERVER_ERROR,
1779
+ recorded?.error ?? new Error(`${method} ${url} \u2192 ${statusCode}`),
1780
+ userId,
1781
+ meta
1782
+ );
1783
+ return;
1784
+ }
1785
+ if (statusCode >= HTTP_CLIENT_ERROR_MIN) {
1786
+ const recorded = readRecordedError(req);
1787
+ this.logger.warnStructured(
1788
+ RESERVED_LOG_KEYS.HTTP_REQUEST_CLIENT_ERROR,
1789
+ `${method} ${url} \u2192 ${statusCode}`,
1790
+ userId,
1791
+ recorded === void 0 ? meta : { ...meta, errorMessage: recorded.error.message }
1792
+ );
1793
+ return;
1794
+ }
1795
+ this.logger.info(
1796
+ statusCode >= HTTP_REDIRECT_MIN ? RESERVED_LOG_KEYS.HTTP_REQUEST_REDIRECT : RESERVED_LOG_KEYS.HTTP_REQUEST_SUCCESS,
1797
+ `${method} ${url} \u2192 ${statusCode} (${duration}ms)`,
1798
+ userId,
1799
+ meta
1800
+ );
1801
+ }
1802
+ };
1803
+ HttpAccessLogMiddleware = __decorateClass([
1804
+ Injectable(),
1805
+ __decorateParam(0, Inject(PinoLoggerService)),
1806
+ __decorateParam(1, Inject(LOGGER_OPTIONS_TOKEN))
1807
+ ], HttpAccessLogMiddleware);
1340
1808
  var REQUEST_ID_HEADER = "x-request-id";
1341
1809
  var MAX_CORRELATION_ID_LENGTH = 256;
1342
1810
  var CORRELATION_ID_CHARSET = /^[A-Za-z0-9._:/+=-]+$/;
@@ -1387,9 +1855,9 @@ RequestIdMiddleware = __decorateClass([
1387
1855
  ], RequestIdMiddleware);
1388
1856
 
1389
1857
  // src/server/middlewares/apply-request-id-middleware.ts
1390
- var ALL_ROUTES = "*";
1858
+ var ALL_ROUTES = "/";
1391
1859
  function applyRequestIdMiddleware(consumer, routes = ALL_ROUTES) {
1392
- consumer.apply(RequestIdMiddleware).forRoutes(routes);
1860
+ consumer.apply(RequestIdMiddleware, HttpAccessLogMiddleware).forRoutes(routes);
1393
1861
  }
1394
1862
  var INJECT_LOGGER_CONTEXT_METADATA_KEY = "bymax_logger:context";
1395
1863
  function InjectLogger(context) {
@@ -1452,4 +1920,4 @@ function LogPerformance(thresholdMs = DEFAULT_THRESHOLD_MS) {
1452
1920
  // src/shared/constants/log-keys-convention.constants.ts
1453
1921
  var LOG_KEYS_CONVENTION_REGEX = /^[A-Z][A-Z0-9_]+_[A-Z][A-Z0-9_]+(_[A-Z][A-Z0-9_]+)?$/;
1454
1922
 
1455
- export { BymaxLoggerModule, DEFAULT_REDACT_PATHS, DefaultStdoutDestination, HttpExceptionFilter, HttpLoggingInterceptor, InjectLogger, LOGGER_DESTINATIONS_TOKEN, LOGGER_OPTIONS_TOKEN, LOGGER_PINO_INSTANCE_TOKEN, LOG_CONTEXT_METADATA_KEY, LOG_CONTEXT_TOKEN, LOG_KEYS_CONVENTION_REGEX, LogContext, LogContextService, LogPerformance, PinoLoggerService, PrettyDevDestination, RESERVED_LOG_KEYS, RequestIdMiddleware, applyRequestIdMiddleware };
1923
+ export { BymaxLoggerModule, DEFAULT_REDACT_PATHS, DefaultStdoutDestination, HttpExceptionFilter, HttpLoggingInterceptor, InjectLogger, LOGGER_DESTINATIONS_TOKEN, LOGGER_OPTIONS_TOKEN, LOGGER_PINO_INSTANCE_TOKEN, LOG_CONTEXT_METADATA_KEY, LOG_CONTEXT_TOKEN, LOG_KEYS_CONVENTION_REGEX, LogContext, LogContextService, LogPerformance, PINO_LEVEL_NAMES, PINO_LEVEL_NUMBERS, PinoLoggerService, PrettyDevDestination, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, RequestIdMiddleware, applyRequestIdMiddleware };