logixia 2.0.0 → 2.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/README.md +46 -29
- package/dist/async-context-B05ArHgM.mjs +134 -0
- package/dist/async-context-B05ArHgM.mjs.map +1 -0
- package/dist/async-context-DTQgi8f7.js +150 -0
- package/dist/async-context-DTQgi8f7.js.map +1 -0
- package/dist/{azure-monitor.transport-CHnjVRF-.mjs → azure-monitor.transport-BPbgjATu.mjs} +27 -15
- package/dist/azure-monitor.transport-BPbgjATu.mjs.map +1 -0
- package/dist/{azure-monitor.transport-Cn_3Usvu.d.ts → azure-monitor.transport-C7kYyZUW.d.mts} +3 -6
- package/dist/azure-monitor.transport-C7kYyZUW.d.mts.map +1 -0
- package/dist/{azure-monitor.transport-CrvfHd9C.js → azure-monitor.transport-CwbOLZHB.js} +32 -20
- package/dist/azure-monitor.transport-CwbOLZHB.js.map +1 -0
- package/dist/{azure-monitor.transport-D7Da4RAb.d.mts → azure-monitor.transport-DV03Z5P4.d.ts} +3 -6
- package/dist/azure-monitor.transport-DV03Z5P4.d.ts.map +1 -0
- package/dist/azure.d.mts +1 -2
- package/dist/azure.d.ts +1 -2
- package/dist/azure.js +3 -6
- package/dist/azure.mjs +1 -6
- package/dist/{batch-buffer-PGvSgbmd.mjs → batch-buffer-0fgLmIPn.mjs} +21 -7
- package/dist/batch-buffer-0fgLmIPn.mjs.map +1 -0
- package/dist/{batch-buffer-BY-mRWIK.js → batch-buffer-DT4gdXmf.js} +53 -40
- package/dist/batch-buffer-DT4gdXmf.js.map +1 -0
- package/dist/browser.d.mts +45 -25
- package/dist/browser.d.mts.map +1 -1
- package/dist/browser.d.ts +45 -25
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +420 -53
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +421 -56
- package/dist/browser.mjs.map +1 -1
- package/dist/{builder-0gEzRopq.mjs → builder-D70z6kjj.mjs} +212 -104
- package/dist/builder-D70z6kjj.mjs.map +1 -0
- package/dist/{builder-D44QktIo.js → builder-M7NoaugM.js} +355 -249
- package/dist/builder-M7NoaugM.js.map +1 -0
- package/dist/cli/index.js +59 -59
- package/dist/cloudwatch.d.mts +1 -2
- package/dist/cloudwatch.d.ts +1 -2
- package/dist/cloudwatch.js +3 -7
- package/dist/cloudwatch.mjs +1 -7
- package/dist/{cloudwatch.transport-BO1ahxw-.js → cloudwatch.transport-B2wKQFF7.js} +61 -36
- package/dist/cloudwatch.transport-B2wKQFF7.js.map +1 -0
- package/dist/{cloudwatch.transport-DZ6ies7g.mjs → cloudwatch.transport-BTvYfLs9.mjs} +54 -28
- package/dist/cloudwatch.transport-BTvYfLs9.mjs.map +1 -0
- package/dist/{cloudwatch.transport-DsEq633o.d.ts → cloudwatch.transport-Bf7L4I59.d.ts} +2 -6
- package/dist/cloudwatch.transport-Bf7L4I59.d.ts.map +1 -0
- package/dist/{cloudwatch.transport-UlyZFWMn.d.mts → cloudwatch.transport-Rj4yTpRn.d.mts} +2 -6
- package/dist/cloudwatch.transport-Rj4yTpRn.d.mts.map +1 -0
- package/dist/{coerce.utils-Cu6IUTgX.mjs → coerce.utils-B_rEudCn.mjs} +3 -4
- package/dist/{coerce.utils-Cu6IUTgX.mjs.map → coerce.utils-B_rEudCn.mjs.map} +1 -1
- package/dist/{coerce.utils-B-LilukN.js → coerce.utils-C1C5sIX0.js} +8 -10
- package/dist/{coerce.utils-B-LilukN.js.map → coerce.utils-C1C5sIX0.js.map} +1 -1
- package/dist/correlation.d.mts +13 -16
- package/dist/correlation.d.mts.map +1 -1
- package/dist/correlation.d.ts +13 -16
- package/dist/correlation.d.ts.map +1 -1
- package/dist/correlation.js +58 -9
- package/dist/correlation.js.map +1 -1
- package/dist/correlation.mjs +56 -6
- package/dist/correlation.mjs.map +1 -1
- package/dist/{entry-fields-BJkuPnIg.mjs → entry-fields-CGuvT2R0.mjs} +5 -6
- package/dist/entry-fields-CGuvT2R0.mjs.map +1 -0
- package/dist/{entry-fields-BvOLFlJ4.js → entry-fields-RLd1jCoR.js} +10 -12
- package/dist/entry-fields-RLd1jCoR.js.map +1 -0
- package/dist/gcp.d.mts +1 -2
- package/dist/gcp.d.ts +1 -2
- package/dist/gcp.js +3 -7
- package/dist/gcp.mjs +1 -7
- package/dist/{gcp.transport-B7oc97sG.d.ts → gcp.transport-C5D72b1g.d.mts} +3 -6
- package/dist/gcp.transport-C5D72b1g.d.mts.map +1 -0
- package/dist/{gcp.transport-GrJurKo8.d.mts → gcp.transport-CFQfdAOK.d.ts} +3 -6
- package/dist/gcp.transport-CFQfdAOK.d.ts.map +1 -0
- package/dist/{gcp.transport-DBX5TPIy.mjs → gcp.transport-CGKopAhQ.mjs} +55 -16
- package/dist/gcp.transport-CGKopAhQ.mjs.map +1 -0
- package/dist/{gcp.transport-CHV8MGgz.js → gcp.transport-KZe9hCAR.js} +60 -22
- package/dist/gcp.transport-KZe9hCAR.js.map +1 -0
- package/dist/{index-DhIoploR.d.ts → index-DwozbmB4.d.ts} +3 -8
- package/dist/index-DwozbmB4.d.ts.map +1 -0
- package/dist/{index-3mw5gaCw.d.mts → index-xqaJtAZn.d.mts} +3 -8
- package/dist/index-xqaJtAZn.d.mts.map +1 -0
- package/dist/index.d.mts +106 -165
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +105 -164
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +164 -261
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +147 -243
- package/dist/index.mjs.map +1 -1
- package/dist/internal-log-b0Vp4qrB.js +183 -0
- package/dist/internal-log-b0Vp4qrB.js.map +1 -0
- package/dist/internal-log-uCSd1PMc.mjs +142 -0
- package/dist/internal-log-uCSd1PMc.mjs.map +1 -0
- package/dist/{logitron-logger-UVeN-mQm.d.ts → logitron-logger-D2B75Oc7.d.ts} +116 -8
- package/dist/logitron-logger-D2B75Oc7.d.ts.map +1 -0
- package/dist/{logitron-logger-BFDSO8Io.d.mts → logitron-logger-oEd6wNhf.d.mts} +116 -8
- package/dist/logitron-logger-oEd6wNhf.d.mts.map +1 -0
- package/dist/middleware.d.mts +10 -12
- package/dist/middleware.d.mts.map +1 -1
- package/dist/middleware.d.ts +10 -12
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +16 -47
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +13 -45
- package/dist/middleware.mjs.map +1 -1
- package/dist/nest.d.mts +26 -44
- package/dist/nest.d.mts.map +1 -1
- package/dist/nest.d.ts +26 -44
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +116 -132
- package/dist/nest.js.map +1 -1
- package/dist/nest.mjs +59 -73
- package/dist/nest.mjs.map +1 -1
- package/dist/{trace.utils-CvXgaiQT.mjs → request-trace-C_fvIDv4.mjs} +44 -9
- package/dist/request-trace-C_fvIDv4.mjs.map +1 -0
- package/dist/{trace.utils-DpBOLDtq.js → request-trace-wTJdKp6-.js} +121 -77
- package/dist/request-trace-wTJdKp6-.js.map +1 -0
- package/dist/rolldown-runtime-D3PmRqjj.mjs +4 -0
- package/dist/{safe-stringify-DJ66tW5I.mjs → safe-stringify-BMRl3EX3.mjs} +3 -4
- package/dist/safe-stringify-BMRl3EX3.mjs.map +1 -0
- package/dist/{safe-stringify-DWo3aZp_.js → safe-stringify-DLz1Kz3o.js} +23 -25
- package/dist/safe-stringify-DLz1Kz3o.js.map +1 -0
- package/dist/{search-CNh9uVwR.d.ts → search-BH33XhuU.d.mts} +2 -22
- package/dist/search-BH33XhuU.d.mts.map +1 -0
- package/dist/{search-BFbu_oVn.mjs → search-CWMVYC-R.mjs} +22 -39
- package/dist/search-CWMVYC-R.mjs.map +1 -0
- package/dist/{search-DXANsQ2n.d.mts → search-CazwyX5Z.d.ts} +2 -22
- package/dist/search-CazwyX5Z.d.ts.map +1 -0
- package/dist/{search-C4V0OMEn.js → search-DUfWuzFP.js} +52 -69
- package/dist/search-DUfWuzFP.js.map +1 -0
- package/dist/search.d.mts +2 -4
- package/dist/search.d.ts +2 -4
- package/dist/search.js +3 -4
- package/dist/search.mjs +1 -4
- package/dist/secret-config-BegMLkYl.mjs +209 -0
- package/dist/secret-config-BegMLkYl.mjs.map +1 -0
- package/dist/secret-config-CBZBs0p1.js +271 -0
- package/dist/secret-config-CBZBs0p1.js.map +1 -0
- package/dist/{slack.transport-Bzw7sucI.mjs → slack.transport-Ce96JBDk.mjs} +212 -31
- package/dist/slack.transport-Ce96JBDk.mjs.map +1 -0
- package/dist/{slack.transport-BfJRouB2.js → slack.transport-Dlx3xvb7.js} +234 -41
- package/dist/slack.transport-Dlx3xvb7.js.map +1 -0
- package/dist/{slack.transport-BZzoXDPn.d.mts → slack.transport-DrirgDNy.d.ts} +56 -9
- package/dist/slack.transport-DrirgDNy.d.ts.map +1 -0
- package/dist/{slack.transport-CXjQYOes.d.ts → slack.transport-DxHOXlLu.d.mts} +56 -9
- package/dist/slack.transport-DxHOXlLu.d.mts.map +1 -0
- package/dist/testing.d.mts +3 -8
- package/dist/testing.d.mts.map +1 -1
- package/dist/testing.d.ts +3 -8
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +3 -4
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +2 -3
- package/dist/testing.mjs.map +1 -1
- package/dist/{transport.manager-CXbKKdVE.js → transport.manager-DkcEOlqV.js} +164 -160
- package/dist/transport.manager-DkcEOlqV.js.map +1 -0
- package/dist/{transport.manager-BiuCAJd2.mjs → transport.manager-eZ_EeC00.mjs} +108 -99
- package/dist/transport.manager-eZ_EeC00.mjs.map +1 -0
- package/dist/{transport.types-CGoHpWQR.d.ts → transport.types-BJVL1QQl.d.mts} +1 -3
- package/dist/transport.types-BJVL1QQl.d.mts.map +1 -0
- package/dist/{transport.types-BMnurPcc.d.mts → transport.types-BJVL1QQl.d.ts} +1 -3
- package/dist/transport.types-BJVL1QQl.d.ts.map +1 -0
- package/dist/transports.d.mts +22 -36
- package/dist/transports.d.mts.map +1 -1
- package/dist/transports.d.ts +22 -36
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +10 -13
- package/dist/transports.mjs +7 -13
- package/dist/worker-entry.js +337 -87
- package/dist/worker.d.mts +1 -2
- package/dist/worker.d.ts +1 -2
- package/dist/worker.js +3 -4
- package/dist/worker.mjs +1 -4
- package/dist/{worker.transport-CdzSZJmw.d.ts → worker.transport-BuPwBi3d.d.ts} +2 -6
- package/dist/worker.transport-BuPwBi3d.d.ts.map +1 -0
- package/dist/{worker.transport-BdPxu3PN.js → worker.transport-C6GNl_r2.js} +44 -14
- package/dist/worker.transport-C6GNl_r2.js.map +1 -0
- package/dist/{worker.transport-lPxO2MVL.mjs → worker.transport-DLVA4y2e.mjs} +39 -9
- package/dist/worker.transport-DLVA4y2e.mjs.map +1 -0
- package/dist/{worker.transport-JvGPog3C.d.mts → worker.transport-hJay1wxA.d.mts} +2 -6
- package/dist/worker.transport-hJay1wxA.d.mts.map +1 -0
- package/package.json +19 -11
- package/dist/async-context-BzJrbfQs.mjs +0 -72
- package/dist/async-context-BzJrbfQs.mjs.map +0 -1
- package/dist/async-context-DyQQYq3I.js +0 -92
- package/dist/async-context-DyQQYq3I.js.map +0 -1
- package/dist/azure-monitor.transport-CHnjVRF-.mjs.map +0 -1
- package/dist/azure-monitor.transport-Cn_3Usvu.d.ts.map +0 -1
- package/dist/azure-monitor.transport-CrvfHd9C.js.map +0 -1
- package/dist/azure-monitor.transport-D7Da4RAb.d.mts.map +0 -1
- package/dist/batch-buffer-BY-mRWIK.js.map +0 -1
- package/dist/batch-buffer-PGvSgbmd.mjs.map +0 -1
- package/dist/builder-0gEzRopq.mjs.map +0 -1
- package/dist/builder-D44QktIo.js.map +0 -1
- package/dist/chunk-DLSkYcPk.mjs +0 -7
- package/dist/chunk-nOFOJqeH.js +0 -30
- package/dist/cloudwatch.transport-BO1ahxw-.js.map +0 -1
- package/dist/cloudwatch.transport-DZ6ies7g.mjs.map +0 -1
- package/dist/cloudwatch.transport-DsEq633o.d.ts.map +0 -1
- package/dist/cloudwatch.transport-UlyZFWMn.d.mts.map +0 -1
- package/dist/entry-fields-BJkuPnIg.mjs.map +0 -1
- package/dist/entry-fields-BvOLFlJ4.js.map +0 -1
- package/dist/gcp.transport-B7oc97sG.d.ts.map +0 -1
- package/dist/gcp.transport-CHV8MGgz.js.map +0 -1
- package/dist/gcp.transport-DBX5TPIy.mjs.map +0 -1
- package/dist/gcp.transport-GrJurKo8.d.mts.map +0 -1
- package/dist/index-3mw5gaCw.d.mts.map +0 -1
- package/dist/index-DhIoploR.d.ts.map +0 -1
- package/dist/internal-log-BUJYMZbE.js +0 -70
- package/dist/internal-log-BUJYMZbE.js.map +0 -1
- package/dist/internal-log-Cm8SOWSV.mjs +0 -52
- package/dist/internal-log-Cm8SOWSV.mjs.map +0 -1
- package/dist/logitron-logger-BFDSO8Io.d.mts.map +0 -1
- package/dist/logitron-logger-UVeN-mQm.d.ts.map +0 -1
- package/dist/safe-stringify-DJ66tW5I.mjs.map +0 -1
- package/dist/safe-stringify-DWo3aZp_.js.map +0 -1
- package/dist/search-BFbu_oVn.mjs.map +0 -1
- package/dist/search-C4V0OMEn.js.map +0 -1
- package/dist/search-CNh9uVwR.d.ts.map +0 -1
- package/dist/search-DXANsQ2n.d.mts.map +0 -1
- package/dist/slack.transport-BZzoXDPn.d.mts.map +0 -1
- package/dist/slack.transport-BfJRouB2.js.map +0 -1
- package/dist/slack.transport-Bzw7sucI.mjs.map +0 -1
- package/dist/slack.transport-CXjQYOes.d.ts.map +0 -1
- package/dist/trace.utils-CvXgaiQT.mjs.map +0 -1
- package/dist/trace.utils-DpBOLDtq.js.map +0 -1
- package/dist/transport.manager-BiuCAJd2.mjs.map +0 -1
- package/dist/transport.manager-CXbKKdVE.js.map +0 -1
- package/dist/transport.types-BMnurPcc.d.mts.map +0 -1
- package/dist/transport.types-CGoHpWQR.d.ts.map +0 -1
- package/dist/worker.transport-BdPxu3PN.js.map +0 -1
- package/dist/worker.transport-CdzSZJmw.d.ts.map +0 -1
- package/dist/worker.transport-JvGPog3C.d.mts.map +0 -1
- package/dist/worker.transport-lPxO2MVL.mjs.map +0 -1
package/dist/nest.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest.mjs","names":["LogixiaLoggerService","errorData: Record<string, string>","KafkaTraceInterceptor","config?: TraceIdConfig","requireTraceId: boolean","traceId: string | undefined","inner: { unsubscribe(): void } | undefined","TraceMiddleware","config?: TraceIdConfig","traceId: string | undefined","WebSocketTraceInterceptor","config?: TraceIdConfig","traceId: string | undefined","inner: { unsubscribe(): void } | undefined","DEFAULT_ROUTES: RouteInfo[]","LogixiaLoggerModule","resolvedTraceConfig: TraceIdConfig | undefined","traceConfig","defaultConfig: LoggerConfig","errLog: unknown","logger: LogixiaLoggerService | undefined","entry: Record<string, unknown>","exit: Record<string, unknown>","result","result: unknown","LogixiaExceptionFilter","logger?: LogixiaLoggerService","loggerConfig?: Partial<LoggerConfig>","options?: LogixiaExceptionFilterOptions","requestMeta: Record<string, unknown>","logPromise: Promise<void> | void"],"sources":["../src/core/logitron-nestjs.service.ts","../src/core/kafka-trace.interceptor.ts","../src/core/trace.middleware.ts","../src/core/websocket-trace.interceptor.ts","../src/core/logitron-logger.module.ts","../src/core/nestjs-extras.ts","../src/nest.ts"],"sourcesContent":["/**\n * NestJS Service integration for Logixia Logger\n *\n * Implements NestJS's `LoggerService` interface for framework compat, while\n * simultaneously exposing native async overloads that accept structured data:\n *\n * // NestJS compat — void, string context\n * logger.warn('message', 'AuthService');\n *\n * // Native async — Promise<void>, structured metadata\n * await logger.warn('message', { userId: 'u_abc', action: 'login' });\n *\n * TypeScript resolves the correct overload automatically based on the type of\n * the second argument:\n * - second arg is `Record<string, unknown>` → native path (returns Promise<void>)\n * - second arg is `string | undefined` → NestJS compat (returns void)\n *\n * No wrapper, no casting required on the calling side.\n */\n\nimport type { LoggerService } from '@nestjs/common';\nimport { Injectable, Scope } from '@nestjs/common';\n\nimport type { LoggerConfig, LogLevelString } from '../types';\nimport { LogLevel } from '../types';\n\n// ── Custom-level IntelliSense helpers ─────────────────────────────────────────\n\n/**\n * Level names that already have proper typed implementations on LogixiaLoggerService.\n * These are excluded from the auto-generated method type so we don't produce\n * duplicate / conflicting signatures.\n */\ntype _ServiceBuiltinLevels =\n 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'trace' | 'log' | 'logLevel';\n\n/**\n * Mapped type that adds one method per *custom* level (i.e. every key in TLevels\n * that is not already a built-in method on LogixiaLoggerService).\n *\n * @example\n * ServiceCustomLevelMethods<{ kafka: 3; mysql: 4; payment: 5 }>\n * // → { kafka(msg, data?): Promise<void>; mysql(...): …; payment(...): … }\n */\ntype ServiceCustomLevelMethods<TLevels extends Record<string, number>> = {\n readonly [K in keyof TLevels as K extends _ServiceBuiltinLevels ? never : K & string]: (\n message: string,\n data?: Record<string, unknown>\n ) => Promise<void>;\n};\n\n/**\n * The return type of `LogixiaLoggerService.create<T>(config)`.\n *\n * When `T` carries `levelOptions.levels`, this type intersects\n * `LogixiaLoggerService` with a method for every *custom* level so the IDE\n * suggests `service.kafka(...)`, `service.payment(...)`, etc.\n */\nexport type LogixiaServiceWithLevels<T extends LoggerConfig<Record<string, number>>> =\n T['levelOptions'] extends { levels: infer L }\n ? L extends Record<string, number>\n ? LogixiaLoggerService & ServiceCustomLevelMethods<L>\n : LogixiaLoggerService\n : LogixiaLoggerService;\n\n/**\n * Helper — extracts custom level names from a config object's `levelOptions.levels`.\n */\ntype _ExtractCustomLevelNames<T> = T extends { levelOptions?: { levels?: infer L } }\n ? L extends Record<string, number>\n ? Exclude<keyof L & string, _ServiceBuiltinLevels>\n : never\n : never;\n\n/**\n * Typed `LogixiaLoggerService` with autocomplete for custom levels.\n *\n * Accepts either:\n * - **string union** of custom level names: `LogixiaServiceWith<'kafka' | 'payment'>`\n * - **config object type** (via `typeof`): `LogixiaServiceWith<typeof logixiaConfig>`\n *\n * Define your config with `as const` once, derive the type everywhere:\n *\n * @example\n * ```ts\n * // logger.config.ts — define once\n * export const logixiaConfig = {\n * levelOptions: {\n * levels: { error: 0, warn: 1, info: 2, debug: 3, verbose: 4, kafka: 5, payment: 6 },\n * },\n * } as const;\n * export type AppLogger = LogixiaServiceWith<typeof logixiaConfig>;\n *\n * // any.controller.ts — use everywhere, no casting\n * constructor(private readonly logger: AppLogger) {}\n * // this.logger.kafka('msg') ← fully typed\n * // this.logger.payment('msg') ← fully typed\n * ```\n *\n * @example\n * ```ts\n * // Or use string union directly:\n * type AppLogger = LogixiaServiceWith<'kafka' | 'payment'>;\n * ```\n */\nexport type LogixiaServiceWith<T extends string | Record<string, unknown>> =\n LogixiaLoggerService & {\n readonly [\n K in T extends string ? Exclude<T, _ServiceBuiltinLevels> : _ExtractCustomLevelNames<T>\n ]: (message: string, data?: Record<string, unknown>) => Promise<void>;\n };\nimport { safeToString } from '../utils/coerce.utils';\nimport { internalError } from '../utils/internal-log';\nimport { getTraceContextKey, TraceContext } from '../utils/trace.utils';\nimport { LogixiaLogger } from './logitron-logger';\n\n@Injectable({ scope: Scope.TRANSIENT })\nexport class LogixiaLoggerService implements LoggerService {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- index signature required for dynamic custom-level methods\n [K: string]: any;\n\n private logger: LogixiaLogger;\n private context?: string;\n private _mergedConfig: LoggerConfig;\n\n constructor(config?: LoggerConfig) {\n const defaultConfig: LoggerConfig = {\n appName: 'NestJS-App',\n environment: 'development',\n traceId: true,\n format: {\n timestamp: true,\n colorize: true,\n json: false,\n },\n silent: false,\n levelOptions: {\n level: LogLevel.INFO,\n levels: {\n error: 0,\n warn: 1,\n log: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n log: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n fields: {\n timestamp: '[yyyy-mm-dd HH:MM:ss.MS]',\n level: '[log_level]',\n appName: '[app_name]',\n traceId: '[trace_id]',\n message: '[message]',\n payload: '[payload]',\n timeTaken: '[time_taken_MS]',\n },\n };\n\n this._mergedConfig = { ...defaultConfig, ...config };\n this.logger = new LogixiaLogger(this._mergedConfig);\n this._createCustomLevelMethods();\n }\n\n // Dynamically adds a proxy method for every custom level defined in levelOptions.levels\n // so that `service.payment('msg')` works the same as `service.logLevel('payment', 'msg')`.\n private _createCustomLevelMethods(): void {\n const levels = this._mergedConfig.levelOptions?.levels;\n if (!levels) return;\n for (const levelName of Object.keys(levels)) {\n const lower = levelName.toLowerCase();\n // Skip levels that already have a built-in implementation on this class\n if (typeof (this as Record<string, unknown>)[lower] !== 'undefined') continue;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this as any)[lower] = async (\n message: string,\n data?: Record<string, unknown>\n ): Promise<void> => {\n return this.logger.logLevel(lower, message, data);\n };\n }\n }\n\n // ── log / info ──────────────────────────────────────────────────────────────\n\n /**\n * NestJS `LoggerService.log` — void, string context.\n * Maps internally to `info`.\n *\n * @example `logger.log('User signed up', 'AuthService')`\n */\n log(message: unknown, context?: string): void {\n this.setContextIfProvided(context);\n this.logger\n .info(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.log failed', err));\n }\n\n /**\n * Native async `info` — structured data, returns `Promise<void>`.\n *\n * @example `await logger.info('User signed up', { userId: 'u_abc' })`\n */\n async info(message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.info(message, data);\n }\n\n // ── error ──────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.error(new Error('DB timeout'), { requestId: 'req_abc' })`\n * @example `await logger.error('Login failed', { userId: 'u_abc' })`\n */\n error(message: string | Error, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — string trace + optional context, returns `void`.\n *\n * @example `logger.error('Something failed', err.stack, 'AuthService')`\n */\n error(message: unknown, trace?: string, context?: string): void;\n\n error(\n message: unknown,\n dataOrTrace?: Record<string, unknown> | string,\n context?: string\n ): void | Promise<void> {\n // ── Native path: second arg is a structured-data object ──────────────────\n if (typeof dataOrTrace === 'object' && dataOrTrace !== null) {\n return message instanceof Error\n ? this.logger.error(message, dataOrTrace)\n : this.logger.error(this.formatMessage(message), dataOrTrace);\n }\n\n // ── NestJS compat path: second arg is trace string or undefined ──────────\n this.setContextIfProvided(context);\n const errorData: Record<string, string> = {};\n if (typeof dataOrTrace === 'string' && dataOrTrace) {\n errorData.stack = dataOrTrace;\n }\n\n const logPromise =\n message instanceof Error\n ? this.logger.error(message, errorData)\n : this.logger.error(this.formatMessage(message), errorData);\n\n logPromise.catch((err: unknown) => internalError('LogixiaLoggerService.error failed', err));\n }\n\n // ── warn ───────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.warn('Rate limit approaching', { userId: 'u_abc', count: 90 })`\n */\n warn(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.warn('Deprecated API used', 'PaymentService')`\n */\n warn(message: unknown, context?: string): void;\n\n warn(message: unknown, dataOrContext?: Record<string, unknown> | string): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.warn(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .warn(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.warn failed', err));\n }\n\n // ── debug ──────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.debug('Cache miss', { key: 'user:abc', ttl: 300 })`\n */\n debug(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.debug('Processing request', 'OrderService')`\n */\n debug(message: unknown, context?: string): void;\n\n debug(message: unknown, dataOrContext?: Record<string, unknown> | string): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.debug(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .debug(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.debug failed', err));\n }\n\n // ── verbose ────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n * Maps to `trace` level internally.\n *\n * @example `await logger.verbose('Socket message received', { event: 'ping', size: 42 })`\n */\n verbose(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.verbose('Connection established', 'WebSocketGateway')`\n */\n verbose(message: unknown, context?: string): void;\n\n verbose(\n message: unknown,\n dataOrContext?: Record<string, unknown> | string\n ): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.trace(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .trace(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.verbose failed', err));\n }\n\n // ── trace / logLevel ───────────────────────────────────────────────────────\n\n /**\n * Native async `trace` — lowest verbosity level, structured data.\n */\n async trace(message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.trace(message, data);\n }\n\n /**\n * Log at any named level with structured data.\n */\n logLevel(level: string, message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.logLevel(level, message, data);\n }\n\n // ── Timing ─────────────────────────────────────────────────────────────────\n\n time(label: string): void {\n this.logger.time(label);\n }\n\n async timeEnd(label: string): Promise<number | undefined> {\n return this.logger.timeEnd(label);\n }\n\n async timeAsync<T>(label: string, fn: () => Promise<T>): Promise<T> {\n return this.logger.timeAsync(label, fn);\n }\n\n // ── Context / level management ─────────────────────────────────────────────\n\n setContext(context: string): void {\n const coerced = typeof context === 'string' ? context : safeToString(context);\n this.context = coerced;\n this.logger.setContext(coerced);\n }\n\n getContext(): string | undefined {\n return this.context;\n }\n\n setLevel(level: LogLevelString): void {\n this.logger.setLevel(level);\n }\n\n getLevel(): LogLevelString {\n return this.logger.getLevel();\n }\n\n // ── Child logger ───────────────────────────────────────────────────────────\n\n child(context: string, data?: Record<string, unknown>): LogixiaLoggerService {\n const childService = new LogixiaLoggerService(this._mergedConfig);\n childService.logger = this.logger.child(context, data) as LogixiaLogger;\n childService.context = context;\n return childService;\n }\n\n // ── Misc ───────────────────────────────────────────────────────────────────\n\n getCurrentTraceId(): string | undefined {\n return TraceContext.instance.getCurrentTraceId();\n }\n\n /** Returns the AsyncLocalStorage key currently used to store the trace ID. */\n get traceContextKey(): string {\n return getTraceContextKey();\n }\n\n async close(): Promise<void> {\n return this.logger.close();\n }\n\n static create<T extends LoggerConfig<Record<string, number>>>(\n config?: T\n ): LogixiaServiceWithLevels<T> {\n return new LogixiaLoggerService(config) as unknown as LogixiaServiceWithLevels<T>;\n }\n\n getLogger(): LogixiaLogger {\n return this.logger;\n }\n\n // ── Private helpers ────────────────────────────────────────────────────────\n\n private setContextIfProvided(context?: unknown): void {\n // NestJS framework occasionally passes non-string values (ExecutionContext,\n // arguments host, etc.) in the context slot. Silently ignore those — we\n // only want an explicit string label to override `this.context`.\n if (typeof context !== 'string' || context.length === 0) return;\n if (context !== this.context) {\n this.setContext(context);\n }\n }\n\n private formatMessage(message: unknown): string {\n if (typeof message === 'string') return message;\n // Use safeToString rather than raw JSON.stringify: NestJS passes arbitrary\n // values here, and JSON.stringify both THROWS on circular structures (which\n // would crash the log call) and RETURNS undefined for some inputs (e.g. a\n // toJSON returning undefined). safeToString handles both safely.\n return safeToString(message);\n }\n}\n","/** @format */\n\nimport type { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';\nimport { Injectable } from '@nestjs/common';\nimport { EMPTY, Observable } from 'rxjs';\n\nimport type { TraceIdConfig } from '../types';\nimport { extractTraceId, TraceContext } from '../utils/trace.utils';\nimport { LogixiaLoggerModule } from './logitron-logger.module';\n\n/**\n * Observable counters exposed for monitoring Kafka consumer trace hygiene.\n *\n * Usage:\n * import { KafkaTraceInterceptor } from 'logixia/nest';\n * setInterval(() => {\n * myMetrics.gauge('kafka.trace.dropped', KafkaTraceInterceptor.metrics.dropped);\n * }, 10_000);\n */\nexport interface KafkaTraceMetrics {\n /** Messages processed where a traceId was successfully resolved (body/header/ALS). */\n accepted: number;\n /** Messages handled without any traceId — `requireTraceId: false`. */\n acceptedWithoutTrace: number;\n /** Messages dropped because `requireTraceId: true` and no traceId was found. */\n dropped: number;\n}\n\n@Injectable()\nexport class KafkaTraceInterceptor implements NestInterceptor {\n /**\n * Process-wide counters. Readable from anywhere — scrape into your metrics\n * system (Prometheus, Datadog, CloudWatch) on an interval.\n */\n static readonly metrics: KafkaTraceMetrics = {\n accepted: 0,\n acceptedWithoutTrace: 0,\n dropped: 0,\n };\n\n /** Reset counters (tests). */\n static resetMetrics(): void {\n KafkaTraceInterceptor.metrics.accepted = 0;\n KafkaTraceInterceptor.metrics.acceptedWithoutTrace = 0;\n KafkaTraceInterceptor.metrics.dropped = 0;\n }\n\n private readonly ctx = TraceContext.instance;\n\n /**\n * @param config - TraceIdConfig options (extractor keys, contextKey, etc.)\n * @param requireTraceId - When true, messages with no traceId are silently skipped\n * (EMPTY Observable — message is ack'd, consumer stays alive).\n * A WARN is logged AND `KafkaTraceInterceptor.metrics.dropped`\n * increments so the missing traceId is observable end-to-end.\n * Default: false (handler runs without trace context).\n */\n constructor(\n private readonly config?: TraceIdConfig,\n private readonly requireTraceId: boolean = false\n ) {\n this.config = {\n enabled: true,\n contextKey: 'traceId',\n extractor: {\n body: ['traceId', 'trace_id', 'x-trace-id'],\n header: ['x-trace-id', 'trace-id'],\n },\n ...config,\n };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- NestJS interceptor interface requires Observable<any>\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n if (!this.config?.enabled) {\n return next.handle();\n }\n\n const rpcContext = context.switchToRpc();\n const data = rpcContext.getData();\n const rpcData = rpcContext.getContext();\n\n let traceId: string | undefined;\n\n if (this.config.extractor) {\n traceId = extractTraceId(\n { body: data, headers: rpcData?.headers ?? {}, query: {}, params: {} },\n this.config.extractor\n );\n }\n\n if (!traceId) {\n traceId = this.ctx.getCurrentTraceId();\n }\n\n if (!traceId) {\n if (this.requireTraceId) {\n // Warn via global logger (set when LogixiaLoggerModule boots) and ack\n // the message by returning EMPTY — consumer stays alive, no retry loop.\n KafkaTraceInterceptor.metrics.dropped++;\n LogixiaLoggerModule.getGlobalLogger()?.warn(\n `[KafkaTraceInterceptor] Missing traceId on topic \"${rpcData?.topic}\" — message skipped.`\n );\n return EMPTY;\n }\n KafkaTraceInterceptor.metrics.acceptedWithoutTrace++;\n return next.handle();\n }\n\n KafkaTraceInterceptor.metrics.accepted++;\n\n const kafkaContext = {\n messageType: 'kafka',\n topic: rpcData?.topic,\n partition: rpcData?.partition,\n offset: rpcData?.offset,\n key: rpcData?.key,\n timestamp: rpcData?.timestamp,\n };\n\n return new Observable((subscriber) => {\n // Capture the inner subscription so it is torn down when the outer\n // subscriber unsubscribes (consumer shutdown, upstream takeUntil/timeout).\n // Without returning it, the handler subscription leaked and kept running\n // after cancellation.\n let inner: { unsubscribe(): void } | undefined;\n this.ctx.run(\n traceId!,\n () => {\n inner = next.handle().subscribe({\n next: (value) => subscriber.next(value),\n error: (err) => subscriber.error(err),\n complete: () => subscriber.complete(),\n });\n },\n kafkaContext\n );\n return () => inner?.unsubscribe();\n });\n }\n}\n","/**\n * Trace ID middleware for NestJS integration\n */\n\nimport type { NestMiddleware } from '@nestjs/common';\nimport { Injectable, Optional } from '@nestjs/common';\nimport type { NextFunction, Request, Response } from 'express';\n\nimport type { TraceIdConfig } from '../types';\nimport { internalWarn } from '../utils/internal-log';\nimport { DEFAULT_TRACE_HEADERS, extractTraceId, TraceContext } from '../utils/trace.utils';\n\n/** Default response header used to echo the resolved traceId back to the caller. */\nexport const DEFAULT_TRACE_RESPONSE_HEADER = 'X-Trace-Id';\n\n/**\n * Resolve the response header name from config.\n * - `undefined` → default `'X-Trace-Id'`\n * - `string` → user's custom header\n * - `false` → `null` (suppress entirely)\n */\nexport function resolveResponseHeader(config?: TraceIdConfig): string | null {\n if (config?.responseHeader === false) return null;\n return config?.responseHeader ?? DEFAULT_TRACE_RESPONSE_HEADER;\n}\n\n/**\n * Echo the trace ID on the response, tolerating non-Express responses and\n * already-sent headers. NestJS can run on Fastify (reply.header() instead of\n * res.setHeader()), and on a closed/sent response setHeader throws — neither\n * should crash the request. The trace ID is still propagated via async context.\n */\nfunction writeTraceHeader(res: unknown, header: string, traceId: string): void {\n const r = res as {\n setHeader?: (k: string, v: string) => void;\n header?: (k: string, v: string) => void;\n headersSent?: boolean;\n };\n if (r.headersSent) return;\n try {\n if (typeof r.setHeader === 'function') r.setHeader(header, traceId);\n else if (typeof r.header === 'function') r.header(header, traceId);\n } catch {\n /* response not in a header-settable state — context propagation still works */\n }\n}\n\n// Extend Express Request interface — requires namespace to augment Express typings\n/* eslint-disable @typescript-eslint/no-namespace */\ndeclare global {\n namespace Express {\n interface Request {\n traceId?: string;\n }\n }\n}\n/* eslint-enable @typescript-eslint/no-namespace */\n\n@Injectable()\nexport class TraceMiddleware implements NestMiddleware {\n private readonly ctx = TraceContext.instance;\n\n constructor(@Optional() private readonly config?: TraceIdConfig) {\n const defaultExtractor = {\n header: DEFAULT_TRACE_HEADERS,\n query: ['traceId', 'trace_id'],\n };\n this.config = {\n enabled: true,\n generator: () => this.ctx.generate(),\n contextKey: 'traceId',\n ...config,\n extractor: config?.extractor\n ? { ...defaultExtractor, ...config.extractor }\n : defaultExtractor,\n };\n // Only mutate the process-wide context key when tracing is actually enabled —\n // otherwise a disabled middleware would still change global state.\n if (this.config.enabled) {\n this.ctx.setContextKey(this.config.contextKey ?? 'traceId');\n }\n }\n\n use(req: Request, res: Response, next: NextFunction): void {\n if (!this.config?.enabled) {\n return next();\n }\n\n let traceId: string | undefined;\n\n if (this.config.extractor) {\n traceId = extractTraceId(req, this.config.extractor);\n }\n\n if (!traceId && this.config.generator) {\n const candidate = this.config.generator();\n // Guard against a user-supplied generator that returns a bad value —\n // fall back to the built-in UUID generator so the request always has\n // a valid, non-empty traceId downstream.\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n traceId = candidate;\n } else {\n internalWarn(\n 'TraceIdConfig.generator returned a non-string/empty value — using built-in generator.'\n );\n }\n }\n if (!traceId) {\n traceId = this.ctx.generate();\n }\n\n req.traceId = traceId;\n\n const header = resolveResponseHeader(this.config);\n if (header) writeTraceHeader(res, header, traceId);\n\n this.ctx.run(traceId, () => next(), {\n method: req.method,\n url: req.url,\n userAgent: req.get('User-Agent'),\n ip: req.ip || req.socket?.remoteAddress || req.connection?.remoteAddress,\n });\n }\n}\n\n/**\n * Factory function to create trace middleware with configuration\n */\nexport function createTraceMiddleware(config?: TraceIdConfig): TraceMiddleware {\n return new TraceMiddleware(config);\n}\n\n/**\n * Functional middleware for Express-style usage\n */\nexport function traceMiddleware(config?: TraceIdConfig) {\n const ctx = TraceContext.instance;\n const defaultExtractor = {\n header: DEFAULT_TRACE_HEADERS,\n query: ['traceId', 'trace_id'],\n };\n const traceConfig = {\n enabled: true,\n generator: () => ctx.generate(),\n contextKey: 'traceId',\n ...config,\n extractor: config?.extractor ? { ...defaultExtractor, ...config.extractor } : defaultExtractor,\n };\n\n // Only mutate the process-wide context key when the middleware is actually\n // enabled — otherwise a disabled instance would still change global state.\n if (traceConfig.enabled) {\n ctx.setContextKey(traceConfig.contextKey ?? 'traceId');\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (!traceConfig.enabled) {\n return next();\n }\n\n let traceId: string | undefined;\n\n if (traceConfig.extractor) {\n traceId = extractTraceId(req, traceConfig.extractor);\n }\n\n if (!traceId && traceConfig.generator) {\n const candidate = traceConfig.generator();\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n traceId = candidate;\n } else {\n internalWarn(\n 'TraceIdConfig.generator returned a non-string/empty value — using built-in generator.'\n );\n }\n }\n if (!traceId) {\n traceId = ctx.generate();\n }\n\n req.traceId = traceId;\n\n const header = resolveResponseHeader(traceConfig);\n if (header) writeTraceHeader(res, header, traceId);\n\n ctx.run(traceId, () => next(), {\n method: req.method,\n url: req.url,\n userAgent: req.get('User-Agent'),\n ip: req.ip || req.socket?.remoteAddress || req.connection?.remoteAddress,\n });\n };\n}\n","/** @format */\n\nimport type { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';\nimport { Injectable } from '@nestjs/common';\nimport { Observable } from 'rxjs';\n\nimport type { TraceIdConfig } from '../types';\nimport { extractTraceId, TraceContext } from '../utils/trace.utils';\n\n@Injectable()\nexport class WebSocketTraceInterceptor implements NestInterceptor {\n private readonly ctx = TraceContext.instance;\n\n constructor(private readonly config?: TraceIdConfig) {\n this.config = {\n enabled: true,\n contextKey: 'traceId',\n extractor: {\n body: ['traceId', 'trace_id', 'x-trace-id'],\n header: ['x-trace-id', 'trace-id'],\n query: ['traceId', 'trace_id'],\n },\n ...config,\n };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- NestJS interceptor interface requires Observable<any>\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n // Check if trace ID is enabled\n if (!this.config?.enabled) {\n return next.handle();\n }\n\n const wsContext = context.switchToWs();\n const data = wsContext.getData();\n const client = wsContext.getClient();\n\n let traceId: string | undefined;\n\n // Try to extract existing trace ID using extractor\n if (this.config.extractor) {\n // Create a request-like object for extractTraceId\n const requestLike = {\n body: data,\n headers: client?.handshake?.headers || {},\n query: client?.handshake?.query || {},\n params: {},\n };\n traceId = extractTraceId(requestLike, this.config.extractor);\n }\n\n // Only use current trace ID if no extraction happened and we have one\n if (!traceId) {\n traceId = this.ctx.getCurrentTraceId();\n }\n\n // If still no trace ID and enabled, skip (don't generate)\n if (!traceId) {\n return next.handle();\n }\n\n // Set up WebSocket-specific context data\n const wsContextData = {\n messageType: 'websocket',\n event: data?.event,\n socketId: client?.id,\n rooms: client?.rooms ? Array.from(client.rooms) : [],\n clientAddress: client?.handshake?.address,\n };\n\n // Run the handler with trace ID context\n return new Observable((observer) => {\n // Capture the inner subscription so it is torn down when the outer observer\n // unsubscribes — otherwise the handler subscription leaks after the socket\n // disconnects or an upstream operator cancels.\n let inner: { unsubscribe(): void } | undefined;\n this.ctx.run(\n traceId!,\n () => {\n inner = next.handle().subscribe({\n next: (value) => observer.next(value),\n error: (err) => observer.error(err),\n complete: () => observer.complete(),\n });\n },\n wsContextData\n );\n return () => inner?.unsubscribe();\n });\n }\n}\n","import type {\n InjectionToken,\n MiddlewareConsumer,\n ModuleMetadata,\n NestModule,\n OptionalFactoryDependency,\n Type,\n} from '@nestjs/common';\nimport { Module, RequestMethod } from '@nestjs/common';\nimport type { RouteInfo } from '@nestjs/common/interfaces/middleware/middleware-configuration.interface';\nimport type { NextFunction, Request, Response } from 'express';\n\nimport type { LoggerConfig, TraceIdConfig } from '../types';\nimport { internalWarn } from '../utils/internal-log';\nimport { TraceContext } from '../utils/trace.utils';\nimport { KafkaTraceInterceptor } from './kafka-trace.interceptor';\nimport { LogixiaLoggerService } from './logitron-nestjs.service';\nimport { TraceMiddleware } from './trace.middleware';\nimport { WebSocketTraceInterceptor } from './websocket-trace.interceptor';\n\nconst DEFAULT_ROUTES: RouteInfo[] = [{ path: '*', method: RequestMethod.ALL }];\n\n// Constants for provider tokens\nexport const LOGIXIA_LOGGER_CONFIG = 'LOGIXIA_LOGGER_CONFIG';\nexport const LOGIXIA_TRACE_CONFIG = 'TRACE_CONFIG';\nexport const LOGIXIA_LOGGER_PREFIX = 'LOGIXIA_LOGGER_';\n\n// Export the service and interceptors for external use\nexport { KafkaTraceInterceptor } from './kafka-trace.interceptor';\nexport { LogixiaLoggerService } from './logitron-nestjs.service';\nexport { WebSocketTraceInterceptor } from './websocket-trace.interceptor';\n\n// Interface for module configuration\ninterface LogixiaModuleConfig {\n forRoutes?: RouteInfo[];\n exclude?: RouteInfo[];\n}\n\n// Interface for async configuration\nexport interface LogixiaAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n useExisting?: Type<LogixiaOptionsFactory>;\n useClass?: Type<LogixiaOptionsFactory>;\n useFactory?: (...args: unknown[]) => Promise<Partial<LoggerConfig>> | Partial<LoggerConfig>;\n inject?: Array<InjectionToken | OptionalFactoryDependency>;\n}\n\n// Interface for options factory\nexport interface LogixiaOptionsFactory {\n createLogixiaOptions(): Promise<Partial<LoggerConfig>> | Partial<LoggerConfig>;\n}\n\n/**\n * Logixia Logger Module for NestJS dependency injection\n */\n@Module({})\nexport class LogixiaLoggerModule implements NestModule {\n private config: LogixiaModuleConfig = {};\n private static loggerConfig: Partial<LoggerConfig> = {};\n\n /**\n * @internal Backing field for the global logger. Do not read or write\n * directly — use {@link getGlobalLogger} / {@link _setGlobalLogger} which\n * enforce single-init semantics.\n */\n // Retained for backwards compatibility with internal callers that read the\n // field directly (e.g. nestjs-extras). Treat as read-only — writes must go\n // through _setGlobalLogger / _resetGlobalLogger.\n // eslint-disable-next-line sonarjs/public-static-readonly -- intentional: we need to swap this in tests via _resetGlobalLogger, so `readonly` is too strict\n static _globalLogger: LogixiaLoggerService | null = null;\n\n /**\n * @internal Set the global logger exactly once.\n *\n * Called from the module's forRoot / forRootAsync factory. If the module is\n * initialised more than once in the same process (nested DI context, test\n * harness creating multiple apps, hot reload, etc.) a warning is written to\n * stderr and the first logger wins — silently overwriting would allow the\n * newer instance's transport config to replace the live one while the old\n * one is still being used by registered shutdown hooks, decorators, etc.\n *\n * Use {@link _resetGlobalLogger} in tests to reset between runs.\n */\n static _setGlobalLogger(service: LogixiaLoggerService): void {\n if (LogixiaLoggerModule._globalLogger !== null) {\n internalWarn(\n 'LogixiaLoggerModule.forRoot() was called more than once — ignoring the second init. ' +\n 'If this is intentional (e.g. in tests), call LogixiaLoggerModule._resetGlobalLogger() first.'\n );\n return;\n }\n LogixiaLoggerModule._globalLogger = service;\n }\n\n /** @internal Clear the global logger. Tests only. */\n static _resetGlobalLogger(): void {\n LogixiaLoggerModule._globalLogger = null;\n }\n\n /**\n * Returns the global LogixiaLoggerService instance that was created when the\n * module booted. Useful for logging outside of NestJS DI — utility functions,\n * plain scripts, decorators — without injecting the service everywhere.\n *\n * Returns `null` if called before `LogixiaLoggerModule.forRoot[Async]()` has\n * been initialised (i.e. before the NestJS app has started).\n *\n * @example\n * ```ts\n * // some-util.ts\n * import { LogixiaLoggerModule } from 'logixia/nest';\n *\n * export function doSomething() {\n * LogixiaLoggerModule.getGlobalLogger()?.info('doing something');\n * }\n * ```\n */\n static getGlobalLogger(): LogixiaLoggerService | null {\n return LogixiaLoggerModule._globalLogger;\n }\n\n configure(consumer: MiddlewareConsumer) {\n const { forRoutes = DEFAULT_ROUTES, exclude } = this.config;\n\n // Resolve the trace config ONCE at configure() time — it does not change\n // per request, so constructing a fresh TraceMiddleware on every invocation\n // (the old behaviour) was just allocation churn.\n let resolvedTraceConfig: TraceIdConfig | undefined;\n if (typeof LogixiaLoggerModule.loggerConfig.traceId === 'object') {\n resolvedTraceConfig = LogixiaLoggerModule.loggerConfig.traceId as TraceIdConfig;\n } else if (LogixiaLoggerModule.loggerConfig.traceId === true) {\n resolvedTraceConfig = {\n enabled: true,\n contextKey: 'traceId',\n generator: () => TraceContext.instance.generate(),\n };\n }\n\n const middleware = new TraceMiddleware(resolvedTraceConfig);\n const middlewareConfig = (req: Request, res: Response, next: NextFunction) =>\n middleware.use(req, res, next);\n\n if (exclude) {\n consumer\n .apply(middlewareConfig)\n .exclude(...exclude)\n .forRoutes(...forRoutes);\n } else {\n consumer.apply(middlewareConfig).forRoutes(...forRoutes);\n }\n }\n\n /**\n * Configure the module with synchronous options\n */\n static forRoot(config?: Partial<LoggerConfig>) {\n // Store config for middleware access\n LogixiaLoggerModule.loggerConfig = config || {};\n\n const traceConfig =\n config?.traceId && typeof config.traceId === 'object'\n ? config.traceId\n : { enabled: !!config?.traceId };\n\n return {\n module: LogixiaLoggerModule,\n providers: [\n {\n provide: LOGIXIA_LOGGER_CONFIG,\n useValue: config || {},\n },\n {\n provide: LOGIXIA_TRACE_CONFIG,\n useValue: traceConfig,\n },\n {\n provide: LogixiaLoggerService,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n const defaultConfig: LoggerConfig = {\n level: 'info',\n service: 'NestJSApp',\n environment: 'development',\n fields: {},\n formatters: ['text'],\n outputs: ['console'],\n levelOptions: {\n level: 'info', // INFO level\n levels: {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n info: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n ...loggerConfig,\n };\n const service = new LogixiaLoggerService(defaultConfig);\n LogixiaLoggerModule._setGlobalLogger(service);\n return service;\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: KafkaTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new KafkaTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n {\n provide: WebSocketTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new WebSocketTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n ],\n exports: [\n LogixiaLoggerService,\n LOGIXIA_LOGGER_CONFIG,\n KafkaTraceInterceptor,\n WebSocketTraceInterceptor,\n ],\n global: true,\n };\n }\n\n /**\n * Configure the module with asynchronous options\n */\n static forRootAsync(options: LogixiaAsyncOptions) {\n return {\n module: LogixiaLoggerModule,\n imports: options.imports || [],\n providers: [\n ...this.createAsyncProviders(options),\n {\n provide: LOGIXIA_TRACE_CONFIG,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n return typeof loggerConfig?.traceId === 'object'\n ? loggerConfig.traceId\n : { enabled: !!loggerConfig?.traceId };\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: LogixiaLoggerService,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n const defaultConfig: LoggerConfig = {\n level: 'info',\n service: 'NestJSApp',\n environment: 'development',\n fields: {},\n formatters: ['text'],\n outputs: ['console'],\n levelOptions: {\n level: 'info', // INFO level\n levels: {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n info: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n ...loggerConfig,\n };\n // Store config for middleware access\n LogixiaLoggerModule.loggerConfig = defaultConfig;\n const service = new LogixiaLoggerService(defaultConfig);\n LogixiaLoggerModule._setGlobalLogger(service);\n return service;\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: KafkaTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new KafkaTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n {\n provide: WebSocketTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new WebSocketTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n ],\n exports: [\n LogixiaLoggerService,\n LOGIXIA_LOGGER_CONFIG,\n KafkaTraceInterceptor,\n WebSocketTraceInterceptor,\n ],\n global: true,\n };\n }\n\n /**\n * Create feature-specific logger instances\n */\n static forFeature(context: string) {\n const providerToken = `${LOGIXIA_LOGGER_PREFIX}${context.toUpperCase()}`;\n return {\n module: LogixiaLoggerModule,\n providers: [\n {\n provide: providerToken,\n useFactory: (baseLogger: LogixiaLoggerService) => {\n return baseLogger.child(context);\n },\n inject: [LogixiaLoggerService],\n },\n ],\n exports: [providerToken],\n };\n }\n\n private static createAsyncProviders(options: LogixiaAsyncOptions) {\n if (options.useExisting || options.useFactory) {\n return [this.createAsyncOptionsProvider(options)];\n }\n return [\n this.createAsyncOptionsProvider(options),\n {\n provide: options.useClass!,\n useClass: options.useClass!,\n },\n ];\n }\n\n private static createAsyncOptionsProvider(options: LogixiaAsyncOptions) {\n if (options.useFactory) {\n return {\n provide: LOGIXIA_LOGGER_CONFIG,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n }\n return {\n provide: LOGIXIA_LOGGER_CONFIG,\n useFactory: async (optionsFactory: LogixiaOptionsFactory) =>\n await optionsFactory.createLogixiaOptions(),\n inject: [options.useExisting || options.useClass!],\n };\n }\n}\n","/**\n * logixia — NestJS extras: @InjectLogger, @LogMethod, LogixiaExceptionFilter\n *\n * Completes the NestJS deep integration story:\n * - @InjectLogger() — inject the logger via NestJS DI without typing LOGIXIA_TOKEN manually\n * - @LogMethod() — auto-log method entry / exit with args and return value\n * - LogixiaExceptionFilter — catch-all exception filter that logs unhandled errors\n * with full request context before re-throwing\n *\n * @example Full setup\n * ```ts\n * // app.module.ts\n * import { LogixiaModule } from 'logixia';\n * @Module({ imports: [LogixiaModule.forRoot({ appName: 'api' })] })\n * export class AppModule {}\n *\n * // order.service.ts\n * import { Injectable } from '@nestjs/common';\n * import { InjectLogger, LogMethod, LogixiaLoggerService } from 'logixia';\n *\n * @Injectable()\n * export class OrderService {\n * constructor(@InjectLogger() private readonly logger: LogixiaLoggerService) {}\n *\n * @LogMethod()\n * async createOrder(dto: CreateOrderDto) { … }\n * }\n *\n * // main.ts\n * import { LogixiaExceptionFilter } from 'logixia';\n * app.useGlobalFilters(new LogixiaExceptionFilter(logger));\n * ```\n */\n\nimport type { ArgumentsHost, ExceptionFilter } from '@nestjs/common';\nimport { Catch, Inject, Optional } from '@nestjs/common';\n\nimport { ErrorResponseBuilder } from '../exceptions/builder';\nimport { isLogixiaException } from '../exceptions/exception';\nimport type { LoggerConfig, LogLevelString, TraceIdConfig } from '../types';\nimport { internalError, internalWarn } from '../utils/internal-log';\nimport { sanitizeIncomingId, TraceContext } from '../utils/trace.utils';\nimport {\n LOGIXIA_LOGGER_CONFIG,\n LOGIXIA_LOGGER_PREFIX,\n LogixiaLoggerModule,\n} from './logitron-logger.module';\nimport type { LogixiaLoggerService } from './logitron-nestjs.service';\nimport { resolveResponseHeader } from './trace.middleware';\n\n// ── @InjectLogger() ──────────────────────────────────────────────────────────\n\n/**\n * Inject the Logixia logger registered in the current NestJS DI container.\n *\n * Equivalent to `@Inject(LOGIXIA_LOGGER_TOKEN)` but without needing to import\n * the internal token constant yourself.\n *\n * @example\n * ```ts\n * constructor(@InjectLogger() private readonly logger: LogixiaLoggerService) {}\n * ```\n */\nexport const InjectLogger = (): ParameterDecorator => Inject(`${LOGIXIA_LOGGER_PREFIX}SERVICE`);\n\n// ── @LogMethod() ─────────────────────────────────────────────────────────────\n\nexport interface LogMethodOptions {\n /**\n * Log level to use for entry / exit messages.\n * @default 'debug'\n */\n level?: LogLevelString;\n /**\n * Whether to log the arguments passed to the method.\n * Disable for high-throughput hot paths.\n * @default true\n */\n logArgs?: boolean;\n /**\n * Whether to log the return value of the method.\n * @default false\n */\n logResult?: boolean;\n /**\n * Whether to log error stack traces for thrown errors.\n * @default true\n */\n logErrors?: boolean;\n /**\n * Custom label used in log messages instead of the auto-detected class.method name.\n */\n label?: string;\n}\n\n/**\n * Method decorator that auto-logs entry, exit, duration, and errors.\n *\n * Preserves the original method's sync/async contract: a synchronous method\n * stays synchronous (returns its value directly, with logs emitted\n * fire-and-forget), and an async method is awaited so exit/error logs reflect\n * the resolved result. Attaches to the logger found on the class instance via a\n * `logger` property (the conventional NestJS name).\n *\n * @example\n * ```ts\n * @LogMethod({ level: 'info', logArgs: true })\n * async processPayment(orderId: string): Promise<void> { … }\n * ```\n */\nexport function LogMethod(options: LogMethodOptions = {}): MethodDecorator {\n const { level = 'debug', logArgs = true, logResult = false, logErrors = true } = options;\n\n // Use PropertyDescriptor (not generic TypedPropertyDescriptor<T>) to avoid\n // strict generic inference issues with exactOptionalPropertyTypes.\n return function (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor\n ): PropertyDescriptor {\n const originalMethod = descriptor.value as ((...args: unknown[]) => unknown) | undefined;\n if (typeof originalMethod !== 'function') return descriptor;\n\n const methodName = String(propertyKey);\n const className =\n (target as { constructor?: { name?: string } }).constructor?.name ?? 'Unknown';\n const label = options.label ?? `${className}.${methodName}`;\n\n let _warnedNoLogger = false;\n\n // Surface logger failures on stderr instead of silently swallowing them.\n const reportLogFailure = (phase: string, err: unknown): void => {\n internalError(`@LogMethod(${label}) ${phase} log failed: ${String(err)}`);\n };\n\n // Emit a log line fire-and-forget, routing transport failures to stderr.\n const emit = (\n logger: LogixiaLoggerService,\n phase: string,\n message: string,\n data: Record<string, unknown>\n ): void => {\n const logFnRaw = (\n logger as unknown as Record<\n string,\n (msg: string, data?: Record<string, unknown>) => Promise<void>\n >\n )[level];\n const logFn = (typeof logFnRaw === 'function' ? logFnRaw : logger.debug).bind(logger);\n const p = logFn(message, data);\n if (p && typeof (p as Promise<void>).catch === 'function') {\n (p as Promise<void>).catch((e: unknown) => reportLogFailure(phase, e));\n }\n };\n\n const emitError = (logger: LogixiaLoggerService, error: unknown, start: number): void => {\n const err = error instanceof Error ? error : new Error(String(error));\n const errLog: unknown = logger.error(err, { method: label, durationMs: Date.now() - start });\n if (errLog && typeof (errLog as Promise<void>).catch === 'function') {\n (errLog as Promise<void>).catch((e: unknown) => reportLogFailure('error', e));\n }\n };\n\n descriptor.value = function (this: { logger?: LogixiaLoggerService }, ...args: unknown[]) {\n // Prefer the instance's own logger; fall back to the global module logger.\n const logger: LogixiaLoggerService | undefined =\n this.logger ?? LogixiaLoggerModule._globalLogger ?? undefined;\n\n if (!logger && !_warnedNoLogger) {\n _warnedNoLogger = true;\n internalWarn(\n `@LogMethod on ${label}: no logger available. ` +\n `Either inject LogixiaLoggerService as this.logger or ensure LogixiaLoggerModule is initialised.`\n );\n }\n\n const start = Date.now();\n const entry: Record<string, unknown> = { method: label };\n if (logArgs && args.length > 0) entry['args'] = args;\n // Entry log is fire-and-forget so a SYNC method is not forced to become\n // async just to await it.\n if (logger) emit(logger, 'entry', `→ ${label}`, entry);\n\n const buildExit = (result: unknown): Record<string, unknown> => {\n const exit: Record<string, unknown> = { method: label, durationMs: Date.now() - start };\n if (logResult) exit['result'] = result;\n return exit;\n };\n\n let result: unknown;\n try {\n result = originalMethod.apply(this, args);\n } catch (error) {\n // Synchronous throw.\n if (logger && logErrors) emitError(logger, error, start);\n throw error;\n }\n\n // Async method → await via the returned thenable so exit/error reflect the\n // resolved outcome, and preserve the Promise return type.\n if (result && typeof (result as PromiseLike<unknown>).then === 'function') {\n return (result as Promise<unknown>).then(\n (resolved) => {\n if (logger) emit(logger, 'exit', `← ${label}`, buildExit(resolved));\n return resolved;\n },\n (error: unknown) => {\n if (logger && logErrors) emitError(logger, error, start);\n throw error;\n }\n );\n }\n\n // Synchronous method → log exit fire-and-forget and return the value as-is,\n // preserving the original synchronous contract.\n if (logger) emit(logger, 'exit', `← ${label}`, buildExit(result));\n return result;\n };\n\n return descriptor;\n };\n}\n\n// ── LogixiaExceptionFilter ───────────────────────────────────────────────────\n\n/**\n * Global NestJS exception filter that converts any exception into the standard\n * `LogixiaErrorResponse` wire format and logs it with full request context.\n *\n * Handles three exception types in priority order:\n * 1. `LogixiaException` — typed fields used directly\n * 2. NestJS `HttpException` — status + message extracted\n * 3. Unknown / plain Error — falls back to 500 `server_error`\n *\n * **Debug block (off by default):**\n * Responses never include the `debug` block (stack trace, service, duration)\n * unless `exposeDebug: true` is passed in the filter options. The underlying\n * `cause` is only added when `exposeCause: true` is also set. Enable explicitly\n * for local development only, e.g.\n * `new LogixiaExceptionFilter(logger, undefined, { exposeDebug: process.env.NODE_ENV === 'development' })`.\n *\n * **Trace ID headers:**\n * `X-Trace-ID` and `X-Request-ID` are echoed back on every error response so\n * clients can correlate with server logs.\n *\n * **Retry-After header:**\n * Automatically added for `429` responses (`Retry-After: 60`).\n *\n * Register in `main.ts`:\n * ```ts\n * const logger = app.get(LogixiaLoggerService);\n * app.useGlobalFilters(new LogixiaExceptionFilter(logger));\n * ```\n */\nexport interface LogixiaExceptionFilterOptions {\n /**\n * Include the `debug` block (stack trace, service, duration) in error responses.\n * @default false\n */\n exposeDebug?: boolean;\n /**\n * Include `debug.cause` as well. Requires `exposeDebug`.\n * @default false\n */\n exposeCause?: boolean;\n}\n\n/** Injection token for {@link LogixiaExceptionFilterOptions}. */\nexport const LOGIXIA_EXCEPTION_FILTER_OPTIONS = 'LOGIXIA_EXCEPTION_FILTER_OPTIONS';\n\n@Catch()\nexport class LogixiaExceptionFilter implements ExceptionFilter {\n private readonly _logger: LogixiaLoggerService | undefined;\n private readonly _traceConfig: TraceIdConfig | undefined;\n private readonly _options: LogixiaExceptionFilterOptions;\n\n constructor(\n @Optional()\n @Inject(`${LOGIXIA_LOGGER_PREFIX}SERVICE`)\n logger?: LogixiaLoggerService,\n @Optional()\n @Inject(LOGIXIA_LOGGER_CONFIG)\n loggerConfig?: Partial<LoggerConfig>,\n @Optional()\n @Inject(LOGIXIA_EXCEPTION_FILTER_OPTIONS)\n options?: LogixiaExceptionFilterOptions\n ) {\n this._options = options ?? {};\n // Prefer the injected logger; fall back to the global module logger so\n // `new LogixiaExceptionFilter()` (registered in main.ts before DI resolves)\n // still logs without needing an explicit logger argument.\n this._logger = logger ?? LogixiaLoggerModule._globalLogger ?? undefined;\n // Pick up the user-configured trace settings (response header name, etc.)\n // so the filter echoes the same header the middleware writes.\n this._traceConfig =\n typeof loggerConfig?.traceId === 'object' ? loggerConfig.traceId : undefined;\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n\n const request = ctx.getRequest<{\n method?: string;\n url?: string;\n id?: string;\n startTime?: number;\n headers?: Record<string, string | string[] | undefined>;\n }>();\n\n interface MinimalResponse {\n status(code: number): MinimalResponse;\n json(body: unknown): void;\n setHeader(name: string, value: string): void;\n }\n const response = ctx.getResponse<MinimalResponse>();\n\n // ALS is the single source of truth (set by TraceMiddleware).\n // Fall back to header/request.id only if ALS has nothing (e.g. traceId disabled).\n const traceId =\n TraceContext.instance.getCurrentTraceId() ??\n sanitizeIncomingId(request.headers?.['x-trace-id']) ??\n sanitizeIncomingId(request.id) ??\n undefined;\n\n const { response: errorResponse, httpStatus } = ErrorResponseBuilder.build({\n exception,\n traceId,\n path: request.url ?? '/',\n startTime: request.startTime,\n exposeDebug: this._options.exposeDebug === true,\n exposeCause: this._options.exposeCause === true,\n });\n\n // ── Logging ──────────────────────────────────────────────────────────────\n if (this._logger) {\n const requestMeta: Record<string, unknown> = {\n method: request.method ?? '',\n url: request.url ?? '',\n status: httpStatus,\n // Only include trace_id when it exists — keeps log records honest when\n // tracing is disabled (instead of writing `trace_id: undefined`).\n ...(errorResponse.meta.trace_id !== undefined\n ? { trace_id: errorResponse.meta.trace_id }\n : {}),\n };\n\n // `error()` / `warn()` return Promise<void> for the structured overload.\n // We cannot await inside a synchronous ExceptionFilter.catch(), so attach\n // a `.catch()` to prevent unhandledRejection if a transport fails — and\n // fall back to stderr so the error is never silently swallowed.\n const onLogFailure = (err: unknown): void => {\n internalError(`ExceptionFilter failed to write log entry: ${String(err)}`);\n };\n\n let logPromise: Promise<void> | void;\n if (httpStatus >= 500) {\n const err = exception instanceof Error ? exception : new Error(String(exception));\n logPromise = this._logger.error(err, requestMeta);\n } else if (isLogixiaException(exception)) {\n logPromise = this._logger.warn(\n `[${errorResponse.error.code}] ${errorResponse.error.message}`,\n requestMeta\n );\n } else {\n logPromise = this._logger.warn(\n `[${httpStatus}] ${errorResponse.error.message}`,\n requestMeta\n );\n }\n\n if (logPromise && typeof (logPromise as Promise<void>).catch === 'function') {\n (logPromise as Promise<void>).catch(onLogFailure);\n }\n }\n\n // ── Response headers ──────────────────────────────────────────────────\n if (errorResponse.meta.trace_id) {\n const traceHeader = resolveResponseHeader(this._traceConfig);\n if (traceHeader) {\n try {\n response.setHeader(traceHeader, errorResponse.meta.trace_id);\n } catch {\n /* headers already sent or invalid — the body still carries the trace id */\n }\n }\n }\n if (httpStatus === 429) {\n try {\n response.setHeader('Retry-After', '60');\n } catch {\n /* headers already sent */\n }\n }\n\n response.status(httpStatus).json(errorResponse);\n }\n}\n","/**\n * logixia/nest — NestJS integration\n *\n * @example\n * import { LogixiaLoggerModule, LogixiaLoggerService } from 'logixia/nest';\n *\n * @Module({\n * imports: [LogixiaLoggerModule.forRoot({ level: 'info' })],\n * })\n * export class AppModule {}\n */\n\nimport { DEFAULT_CONFIG } from './core/default-config';\nimport { LogixiaLoggerService } from './core/logitron-nestjs.service';\nimport type { LoggerConfig } from './types';\n\n// Everything NestJS-specific. These were exported from the root `logixia`\n// entry before 2.0.0; keep this list a superset of what the root used to export.\nexport * from './core/logitron-logger.module';\nexport * from './core/logitron-nestjs.service';\nexport type { LogixiaExceptionFilterOptions, LogMethodOptions } from './core/nestjs-extras';\nexport {\n InjectLogger,\n LOGIXIA_EXCEPTION_FILTER_OPTIONS,\n LogixiaExceptionFilter,\n LogMethod,\n} from './core/nestjs-extras';\nexport { TraceMiddleware } from './core/trace.middleware';\n\n/**\n * Create a new Logixia logger service for NestJS\n * @param config - Logger configuration\n * @returns LogixiaLoggerService instance\n */\nexport function createLoggerService(config?: Partial<LoggerConfig>): LogixiaLoggerService {\n return new LogixiaLoggerService({ ...DEFAULT_CONFIG, ...config });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nest.mjs","names":[],"sources":["../src/core/logitron-nestjs.service.ts","../src/core/kafka-trace.interceptor.ts","../src/core/trace.middleware.ts","../src/core/websocket-trace.interceptor.ts","../src/core/logitron-logger.module.ts","../src/core/nestjs-extras.ts","../src/nest.ts"],"sourcesContent":["/**\n * NestJS Service integration for Logixia Logger\n *\n * Implements NestJS's `LoggerService` interface for framework compat, while\n * simultaneously exposing native async overloads that accept structured data:\n *\n * // NestJS compat — void, string context\n * logger.warn('message', 'AuthService');\n *\n * // Native async — Promise<void>, structured metadata\n * await logger.warn('message', { userId: 'u_abc', action: 'login' });\n *\n * TypeScript resolves the correct overload automatically based on the type of\n * the second argument:\n * - second arg is `Record<string, unknown>` → native path (returns Promise<void>)\n * - second arg is `string | undefined` → NestJS compat (returns void)\n *\n * No wrapper, no casting required on the calling side.\n */\n\nimport type { LoggerService } from '@nestjs/common';\nimport { Injectable, Scope } from '@nestjs/common';\n\nimport type { LoggerConfig, LogLevelString } from '../types';\nimport { LogLevel } from '../types';\n\n// ── Custom-level IntelliSense helpers ─────────────────────────────────────────\n\n/**\n * Level names that already have proper typed implementations on LogixiaLoggerService.\n * These are excluded from the auto-generated method type so we don't produce\n * duplicate / conflicting signatures.\n */\ntype _ServiceBuiltinLevels =\n 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'trace' | 'log' | 'logLevel';\n\n/**\n * Mapped type that adds one method per *custom* level (i.e. every key in TLevels\n * that is not already a built-in method on LogixiaLoggerService).\n *\n * @example\n * ServiceCustomLevelMethods<{ kafka: 3; mysql: 4; payment: 5 }>\n * // → { kafka(msg, data?): Promise<void>; mysql(...): …; payment(...): … }\n */\ntype ServiceCustomLevelMethods<TLevels extends Record<string, number>> = {\n readonly [K in keyof TLevels as K extends _ServiceBuiltinLevels ? never : K & string]: (\n message: string,\n data?: Record<string, unknown>\n ) => Promise<void>;\n};\n\n/**\n * The return type of `LogixiaLoggerService.create<T>(config)`.\n *\n * When `T` carries `levelOptions.levels`, this type intersects\n * `LogixiaLoggerService` with a method for every *custom* level so the IDE\n * suggests `service.kafka(...)`, `service.payment(...)`, etc.\n */\nexport type LogixiaServiceWithLevels<T extends LoggerConfig<Record<string, number>>> =\n T['levelOptions'] extends { levels: infer L }\n ? L extends Record<string, number>\n ? LogixiaLoggerService & ServiceCustomLevelMethods<L>\n : LogixiaLoggerService\n : LogixiaLoggerService;\n\n/**\n * Helper — extracts custom level names from a config object's `levelOptions.levels`.\n */\ntype _ExtractCustomLevelNames<T> = T extends { levelOptions?: { levels?: infer L } }\n ? L extends Record<string, number>\n ? Exclude<keyof L & string, _ServiceBuiltinLevels>\n : never\n : never;\n\n/**\n * Typed `LogixiaLoggerService` with autocomplete for custom levels.\n *\n * Accepts either:\n * - **string union** of custom level names: `LogixiaServiceWith<'kafka' | 'payment'>`\n * - **config object type** (via `typeof`): `LogixiaServiceWith<typeof logixiaConfig>`\n *\n * Define your config with `as const` once, derive the type everywhere:\n *\n * @example\n * ```ts\n * // logger.config.ts — define once\n * export const logixiaConfig = {\n * levelOptions: {\n * levels: { error: 0, warn: 1, info: 2, debug: 3, verbose: 4, kafka: 5, payment: 6 },\n * },\n * } as const;\n * export type AppLogger = LogixiaServiceWith<typeof logixiaConfig>;\n *\n * // any.controller.ts — use everywhere, no casting\n * constructor(private readonly logger: AppLogger) {}\n * // this.logger.kafka('msg') ← fully typed\n * // this.logger.payment('msg') ← fully typed\n * ```\n *\n * @example\n * ```ts\n * // Or use string union directly:\n * type AppLogger = LogixiaServiceWith<'kafka' | 'payment'>;\n * ```\n */\nexport type LogixiaServiceWith<T extends string | Record<string, unknown>> =\n LogixiaLoggerService & {\n readonly [\n K in T extends string ? Exclude<T, _ServiceBuiltinLevels> : _ExtractCustomLevelNames<T>\n ]: (message: string, data?: Record<string, unknown>) => Promise<void>;\n };\nimport { protectSecrets } from '../transports/secret-config';\nimport { safeToString } from '../utils/coerce.utils';\nimport { internalError } from '../utils/internal-log';\nimport { getTraceContextKey, TraceContext } from '../utils/trace.utils';\nimport { LogixiaLogger } from './logitron-logger';\n\n@Injectable({ scope: Scope.TRANSIENT })\nexport class LogixiaLoggerService implements LoggerService {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- index signature required for dynamic custom-level methods\n [K: string]: any;\n\n private logger: LogixiaLogger;\n private context?: string;\n private _mergedConfig: LoggerConfig;\n\n constructor(config?: LoggerConfig) {\n const defaultConfig: LoggerConfig = {\n appName: 'NestJS-App',\n environment: 'development',\n traceId: true,\n format: {\n timestamp: true,\n colorize: true,\n json: false,\n },\n silent: false,\n levelOptions: {\n level: LogLevel.INFO,\n levels: {\n error: 0,\n warn: 1,\n log: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n log: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n fields: {\n timestamp: '[yyyy-mm-dd HH:MM:ss.MS]',\n level: '[log_level]',\n appName: '[app_name]',\n traceId: '[trace_id]',\n message: '[message]',\n payload: '[payload]',\n timeTaken: '[time_taken_MS]',\n },\n };\n\n protectSecrets(this, ['_mergedConfig']);\n this._mergedConfig = { ...defaultConfig, ...config };\n this.logger = new LogixiaLogger(this._mergedConfig);\n this._createCustomLevelMethods();\n }\n\n // Dynamically adds a proxy method for every custom level defined in levelOptions.levels\n // so that `service.payment('msg')` works the same as `service.logLevel('payment', 'msg')`.\n private _createCustomLevelMethods(): void {\n const levels = this._mergedConfig.levelOptions?.levels;\n if (!levels) return;\n for (const levelName of Object.keys(levels)) {\n const lower = levelName.toLowerCase();\n // Skip levels that already have a built-in implementation on this class\n if (typeof (this as Record<string, unknown>)[lower] !== 'undefined') continue;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this as any)[lower] = async (\n message: string,\n data?: Record<string, unknown>\n ): Promise<void> => {\n return this.logger.logLevel(lower, message, data);\n };\n }\n }\n\n // ── log / info ──────────────────────────────────────────────────────────────\n\n /**\n * NestJS `LoggerService.log` — void, string context.\n * Maps internally to `info`.\n *\n * @example `logger.log('User signed up', 'AuthService')`\n */\n log(message: unknown, context?: string): void {\n this.setContextIfProvided(context);\n this.logger\n .info(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.log failed', err));\n }\n\n /**\n * Native async `info` — structured data, returns `Promise<void>`.\n *\n * @example `await logger.info('User signed up', { userId: 'u_abc' })`\n */\n async info(message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.info(message, data);\n }\n\n // ── error ──────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.error(new Error('DB timeout'), { requestId: 'req_abc' })`\n * @example `await logger.error('Login failed', { userId: 'u_abc' })`\n */\n error(message: string | Error, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — string trace + optional context, returns `void`.\n *\n * @example `logger.error('Something failed', err.stack, 'AuthService')`\n */\n error(message: unknown, trace?: string, context?: string): void;\n\n error(\n message: unknown,\n dataOrTrace?: Record<string, unknown> | string,\n context?: string\n ): void | Promise<void> {\n // ── Native path: second arg is a structured-data object ──────────────────\n if (typeof dataOrTrace === 'object' && dataOrTrace !== null) {\n return message instanceof Error\n ? this.logger.error(message, dataOrTrace)\n : this.logger.error(this.formatMessage(message), dataOrTrace);\n }\n\n // ── NestJS compat path: second arg is trace string or undefined ──────────\n this.setContextIfProvided(context);\n const errorData: Record<string, string> = {};\n if (typeof dataOrTrace === 'string' && dataOrTrace) {\n errorData.stack = dataOrTrace;\n }\n\n const logPromise =\n message instanceof Error\n ? this.logger.error(message, errorData)\n : this.logger.error(this.formatMessage(message), errorData);\n\n logPromise.catch((err: unknown) => internalError('LogixiaLoggerService.error failed', err));\n }\n\n // ── warn ───────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.warn('Rate limit approaching', { userId: 'u_abc', count: 90 })`\n */\n warn(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.warn('Deprecated API used', 'PaymentService')`\n */\n warn(message: unknown, context?: string): void;\n\n warn(message: unknown, dataOrContext?: Record<string, unknown> | string): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.warn(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .warn(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.warn failed', err));\n }\n\n // ── debug ──────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.debug('Cache miss', { key: 'user:abc', ttl: 300 })`\n */\n debug(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.debug('Processing request', 'OrderService')`\n */\n debug(message: unknown, context?: string): void;\n\n debug(message: unknown, dataOrContext?: Record<string, unknown> | string): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.debug(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .debug(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.debug failed', err));\n }\n\n // ── verbose ────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n * Maps to `trace` level internally.\n *\n * @example `await logger.verbose('Socket message received', { event: 'ping', size: 42 })`\n */\n verbose(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.verbose('Connection established', 'WebSocketGateway')`\n */\n verbose(message: unknown, context?: string): void;\n\n verbose(\n message: unknown,\n dataOrContext?: Record<string, unknown> | string\n ): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.trace(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .trace(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.verbose failed', err));\n }\n\n // ── trace / logLevel ───────────────────────────────────────────────────────\n\n /**\n * Native async `trace` — lowest verbosity level, structured data.\n */\n async trace(message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.trace(message, data);\n }\n\n /**\n * Log at any named level with structured data.\n */\n logLevel(level: string, message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.logLevel(level, message, data);\n }\n\n // ── Timing ─────────────────────────────────────────────────────────────────\n\n time(label: string): void {\n this.logger.time(label);\n }\n\n async timeEnd(label: string): Promise<number | undefined> {\n return this.logger.timeEnd(label);\n }\n\n async timeAsync<T>(label: string, fn: () => Promise<T>): Promise<T> {\n return this.logger.timeAsync(label, fn);\n }\n\n // ── Context / level management ─────────────────────────────────────────────\n\n setContext(context: string): void {\n const coerced = typeof context === 'string' ? context : safeToString(context);\n this.context = coerced;\n this.logger.setContext(coerced);\n }\n\n getContext(): string | undefined {\n return this.context;\n }\n\n setLevel(level: LogLevelString): void {\n this.logger.setLevel(level);\n }\n\n getLevel(): LogLevelString {\n return this.logger.getLevel();\n }\n\n // ── Child logger ───────────────────────────────────────────────────────────\n\n child(context: string, data?: Record<string, unknown>): LogixiaLoggerService {\n const childService = new LogixiaLoggerService(this._mergedConfig);\n childService.logger = this.logger.child(context, data) as LogixiaLogger;\n childService.context = context;\n return childService;\n }\n\n // ── Misc ───────────────────────────────────────────────────────────────────\n\n getCurrentTraceId(): string | undefined {\n return TraceContext.instance.getCurrentTraceId();\n }\n\n /** Returns the AsyncLocalStorage key currently used to store the trace ID. */\n get traceContextKey(): string {\n return getTraceContextKey();\n }\n\n async close(): Promise<void> {\n return this.logger.close();\n }\n\n static create<T extends LoggerConfig<Record<string, number>>>(\n config?: T\n ): LogixiaServiceWithLevels<T> {\n return new LogixiaLoggerService(config) as unknown as LogixiaServiceWithLevels<T>;\n }\n\n getLogger(): LogixiaLogger {\n return this.logger;\n }\n\n // ── Private helpers ────────────────────────────────────────────────────────\n\n private setContextIfProvided(context?: unknown): void {\n // NestJS framework occasionally passes non-string values (ExecutionContext,\n // arguments host, etc.) in the context slot. Silently ignore those — we\n // only want an explicit string label to override `this.context`.\n if (typeof context !== 'string' || context.length === 0) return;\n if (context !== this.context) {\n this.setContext(context);\n }\n }\n\n private formatMessage(message: unknown): string {\n if (typeof message === 'string') return message;\n // Use safeToString rather than raw JSON.stringify: NestJS passes arbitrary\n // values here, and JSON.stringify both THROWS on circular structures (which\n // would crash the log call) and RETURNS undefined for some inputs (e.g. a\n // toJSON returning undefined). safeToString handles both safely.\n return safeToString(message);\n }\n}\n","/** @format */\n\nimport type { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';\nimport { Injectable } from '@nestjs/common';\nimport { EMPTY, Observable } from 'rxjs';\n\nimport type { TraceIdConfig } from '../types';\nimport { extractTraceId, TraceContext } from '../utils/trace.utils';\nimport { LogixiaLoggerModule } from './logitron-logger.module';\n\n/**\n * Observable counters exposed for monitoring Kafka consumer trace hygiene.\n *\n * Usage:\n * import { KafkaTraceInterceptor } from 'logixia/nest';\n * setInterval(() => {\n * myMetrics.gauge('kafka.trace.dropped', KafkaTraceInterceptor.metrics.dropped);\n * }, 10_000);\n */\nexport interface KafkaTraceMetrics {\n /** Messages processed where a traceId was successfully resolved (body/header/ALS). */\n accepted: number;\n /** Messages handled without any traceId — `requireTraceId: false`. */\n acceptedWithoutTrace: number;\n /** Messages dropped because `requireTraceId: true` and no traceId was found. */\n dropped: number;\n}\n\n@Injectable()\nexport class KafkaTraceInterceptor implements NestInterceptor {\n /**\n * Process-wide counters. Readable from anywhere — scrape into your metrics\n * system (Prometheus, Datadog, CloudWatch) on an interval.\n */\n static readonly metrics: KafkaTraceMetrics = {\n accepted: 0,\n acceptedWithoutTrace: 0,\n dropped: 0,\n };\n\n /** Reset counters (tests). */\n static resetMetrics(): void {\n KafkaTraceInterceptor.metrics.accepted = 0;\n KafkaTraceInterceptor.metrics.acceptedWithoutTrace = 0;\n KafkaTraceInterceptor.metrics.dropped = 0;\n }\n\n private readonly ctx = TraceContext.instance;\n private readonly config: TraceIdConfig;\n\n /**\n * @param config - TraceIdConfig options (extractor keys, contextKey, etc.)\n * @param requireTraceId - When true, messages with no traceId are silently skipped\n * (EMPTY Observable — message is ack'd, consumer stays alive).\n * A WARN is logged AND `KafkaTraceInterceptor.metrics.dropped`\n * increments so the missing traceId is observable end-to-end.\n * Default: false (handler runs without trace context).\n */\n constructor(\n config?: TraceIdConfig,\n private readonly requireTraceId: boolean = false\n ) {\n this.config = {\n enabled: true,\n contextKey: 'traceId',\n extractor: {\n body: ['traceId', 'trace_id', 'x-trace-id'],\n header: ['x-trace-id', 'trace-id'],\n },\n ...config,\n };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- NestJS interceptor interface requires Observable<any>\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n if (!this.config.enabled) {\n return next.handle();\n }\n\n const rpcContext = context.switchToRpc();\n const data = rpcContext.getData();\n const rpcData = rpcContext.getContext();\n\n let traceId: string | undefined;\n\n if (this.config.extractor) {\n traceId = extractTraceId(\n { body: data, headers: rpcData?.headers ?? {}, query: {}, params: {} },\n this.config.extractor\n );\n }\n\n if (!traceId) {\n traceId = this.ctx.getCurrentTraceId();\n }\n\n if (!traceId) {\n if (this.requireTraceId) {\n // Warn via global logger (set when LogixiaLoggerModule boots) and ack\n // the message by returning EMPTY — consumer stays alive, no retry loop.\n KafkaTraceInterceptor.metrics.dropped++;\n LogixiaLoggerModule.getGlobalLogger()?.warn(\n `[KafkaTraceInterceptor] Missing traceId on topic \"${rpcData?.topic}\" — message skipped.`\n );\n return EMPTY;\n }\n KafkaTraceInterceptor.metrics.acceptedWithoutTrace++;\n return next.handle();\n }\n\n KafkaTraceInterceptor.metrics.accepted++;\n\n const kafkaContext = {\n messageType: 'kafka',\n topic: rpcData?.topic,\n partition: rpcData?.partition,\n offset: rpcData?.offset,\n key: rpcData?.key,\n timestamp: rpcData?.timestamp,\n };\n\n return new Observable((subscriber) => {\n // Capture the inner subscription so it is torn down when the outer\n // subscriber unsubscribes (consumer shutdown, upstream takeUntil/timeout).\n // Without returning it, the handler subscription leaked and kept running\n // after cancellation.\n let inner: { unsubscribe(): void } | undefined;\n this.ctx.run(\n traceId!,\n () => {\n inner = next.handle().subscribe({\n next: (value) => subscriber.next(value),\n error: (err) => subscriber.error(err),\n complete: () => subscriber.complete(),\n });\n },\n kafkaContext\n );\n return () => inner?.unsubscribe();\n });\n }\n}\n","/**\n * Trace ID middleware for NestJS integration\n */\n\nimport type { NestMiddleware } from '@nestjs/common';\nimport { Injectable, Optional } from '@nestjs/common';\nimport type { NextFunction, Request, Response } from 'express';\n\nimport type { TraceIdConfig } from '../types';\nimport { internalWarn } from '../utils/internal-log';\nimport { DEFAULT_TRACE_HEADERS, extractTraceId, TraceContext } from '../utils/trace.utils';\n\n/** Default response header used to echo the resolved traceId back to the caller. */\nexport const DEFAULT_TRACE_RESPONSE_HEADER = 'X-Trace-Id';\n\n/**\n * Resolve the response header name from config.\n * - `undefined` → default `'X-Trace-Id'`\n * - `string` → user's custom header\n * - `false` → `null` (suppress entirely)\n */\nexport function resolveResponseHeader(config?: TraceIdConfig): string | null {\n if (config?.responseHeader === false) return null;\n return config?.responseHeader ?? DEFAULT_TRACE_RESPONSE_HEADER;\n}\n\n/**\n * Echo the trace ID on the response, tolerating non-Express responses and\n * already-sent headers. NestJS can run on Fastify (reply.header() instead of\n * res.setHeader()), and on a closed/sent response setHeader throws — neither\n * should crash the request. The trace ID is still propagated via async context.\n */\nfunction writeTraceHeader(res: unknown, header: string, traceId: string): void {\n const r = res as {\n setHeader?: (k: string, v: string) => void;\n header?: (k: string, v: string) => void;\n headersSent?: boolean;\n };\n if (r.headersSent) return;\n try {\n if (typeof r.setHeader === 'function') r.setHeader(header, traceId);\n else if (typeof r.header === 'function') r.header(header, traceId);\n } catch {\n /* response not in a header-settable state — context propagation still works */\n }\n}\n\n// Extend Express Request interface — requires namespace to augment Express typings\n/* eslint-disable @typescript-eslint/no-namespace */\ndeclare global {\n namespace Express {\n interface Request {\n traceId?: string;\n }\n }\n}\n/* eslint-enable @typescript-eslint/no-namespace */\n\n@Injectable()\nexport class TraceMiddleware implements NestMiddleware {\n private readonly ctx = TraceContext.instance;\n\n constructor(@Optional() private readonly config?: TraceIdConfig) {\n const defaultExtractor = {\n header: DEFAULT_TRACE_HEADERS,\n query: ['traceId', 'trace_id'],\n };\n this.config = {\n enabled: true,\n generator: () => this.ctx.generate(),\n contextKey: 'traceId',\n ...config,\n extractor: config?.extractor\n ? { ...defaultExtractor, ...config.extractor }\n : defaultExtractor,\n };\n // Only mutate the process-wide context key when tracing is actually enabled —\n // otherwise a disabled middleware would still change global state.\n if (this.config.enabled) {\n this.ctx.setContextKey(this.config.contextKey ?? 'traceId');\n }\n }\n\n use(req: Request, res: Response, next: NextFunction): void {\n if (!this.config?.enabled) {\n return next();\n }\n\n let traceId: string | undefined;\n\n if (this.config.extractor) {\n traceId = extractTraceId(req, this.config.extractor);\n }\n\n if (!traceId && this.config.generator) {\n const candidate = this.config.generator();\n // Guard against a user-supplied generator that returns a bad value —\n // fall back to the built-in UUID generator so the request always has\n // a valid, non-empty traceId downstream.\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n traceId = candidate;\n } else {\n internalWarn(\n 'TraceIdConfig.generator returned a non-string/empty value — using built-in generator.'\n );\n }\n }\n if (!traceId) {\n traceId = this.ctx.generate();\n }\n\n req.traceId = traceId;\n\n const header = resolveResponseHeader(this.config);\n if (header) writeTraceHeader(res, header, traceId);\n\n this.ctx.run(traceId, () => next(), {\n method: req.method,\n url: req.url,\n userAgent: req.get('User-Agent'),\n ip: req.ip || req.socket?.remoteAddress || req.connection?.remoteAddress,\n });\n }\n}\n\n/**\n * Factory function to create trace middleware with configuration\n */\nexport function createTraceMiddleware(config?: TraceIdConfig): TraceMiddleware {\n return new TraceMiddleware(config);\n}\n\n/**\n * Functional middleware for Express-style usage\n */\nexport function traceMiddleware(config?: TraceIdConfig) {\n const ctx = TraceContext.instance;\n const defaultExtractor = {\n header: DEFAULT_TRACE_HEADERS,\n query: ['traceId', 'trace_id'],\n };\n const traceConfig = {\n enabled: true,\n generator: () => ctx.generate(),\n contextKey: 'traceId',\n ...config,\n extractor: config?.extractor ? { ...defaultExtractor, ...config.extractor } : defaultExtractor,\n };\n\n // Only mutate the process-wide context key when the middleware is actually\n // enabled — otherwise a disabled instance would still change global state.\n if (traceConfig.enabled) {\n ctx.setContextKey(traceConfig.contextKey ?? 'traceId');\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (!traceConfig.enabled) {\n return next();\n }\n\n let traceId: string | undefined;\n\n if (traceConfig.extractor) {\n traceId = extractTraceId(req, traceConfig.extractor);\n }\n\n if (!traceId && traceConfig.generator) {\n const candidate = traceConfig.generator();\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n traceId = candidate;\n } else {\n internalWarn(\n 'TraceIdConfig.generator returned a non-string/empty value — using built-in generator.'\n );\n }\n }\n if (!traceId) {\n traceId = ctx.generate();\n }\n\n req.traceId = traceId;\n\n const header = resolveResponseHeader(traceConfig);\n if (header) writeTraceHeader(res, header, traceId);\n\n ctx.run(traceId, () => next(), {\n method: req.method,\n url: req.url,\n userAgent: req.get('User-Agent'),\n ip: req.ip || req.socket?.remoteAddress || req.connection?.remoteAddress,\n });\n };\n}\n","/** @format */\n\nimport type { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';\nimport { Injectable } from '@nestjs/common';\nimport { Observable } from 'rxjs';\n\nimport type { TraceIdConfig } from '../types';\nimport { extractTraceId, TraceContext } from '../utils/trace.utils';\n\n@Injectable()\nexport class WebSocketTraceInterceptor implements NestInterceptor {\n private readonly ctx = TraceContext.instance;\n private readonly config: TraceIdConfig;\n\n constructor(config?: TraceIdConfig) {\n this.config = {\n enabled: true,\n contextKey: 'traceId',\n extractor: {\n body: ['traceId', 'trace_id', 'x-trace-id'],\n header: ['x-trace-id', 'trace-id'],\n query: ['traceId', 'trace_id'],\n },\n ...config,\n };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- NestJS interceptor interface requires Observable<any>\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n // Check if trace ID is enabled\n if (!this.config.enabled) {\n return next.handle();\n }\n\n const wsContext = context.switchToWs();\n const data = wsContext.getData();\n const client = wsContext.getClient();\n\n let traceId: string | undefined;\n\n // Try to extract existing trace ID using extractor\n if (this.config.extractor) {\n // Create a request-like object for extractTraceId\n const requestLike = {\n body: data,\n headers: client?.handshake?.headers || {},\n query: client?.handshake?.query || {},\n params: {},\n };\n traceId = extractTraceId(requestLike, this.config.extractor);\n }\n\n // Only use current trace ID if no extraction happened and we have one\n if (!traceId) {\n traceId = this.ctx.getCurrentTraceId();\n }\n\n // If still no trace ID and enabled, skip (don't generate)\n if (!traceId) {\n return next.handle();\n }\n\n // Set up WebSocket-specific context data\n const wsContextData = {\n messageType: 'websocket',\n event: data?.event,\n socketId: client?.id,\n rooms: client?.rooms ? Array.from(client.rooms) : [],\n clientAddress: client?.handshake?.address,\n };\n\n // Run the handler with trace ID context\n return new Observable((observer) => {\n // Capture the inner subscription so it is torn down when the outer observer\n // unsubscribes — otherwise the handler subscription leaks after the socket\n // disconnects or an upstream operator cancels.\n let inner: { unsubscribe(): void } | undefined;\n this.ctx.run(\n traceId!,\n () => {\n inner = next.handle().subscribe({\n next: (value) => observer.next(value),\n error: (err) => observer.error(err),\n complete: () => observer.complete(),\n });\n },\n wsContextData\n );\n return () => inner?.unsubscribe();\n });\n }\n}\n","import type {\n InjectionToken,\n MiddlewareConsumer,\n ModuleMetadata,\n NestModule,\n OptionalFactoryDependency,\n Type,\n} from '@nestjs/common';\nimport { Module, RequestMethod } from '@nestjs/common';\nimport type { RouteInfo } from '@nestjs/common/interfaces/middleware/middleware-configuration.interface';\nimport type { NextFunction, Request, Response } from 'express';\n\nimport type { LoggerConfig, TraceIdConfig } from '../types';\nimport { internalWarn } from '../utils/internal-log';\nimport { TraceContext } from '../utils/trace.utils';\nimport { KafkaTraceInterceptor } from './kafka-trace.interceptor';\nimport { LogixiaLoggerService } from './logitron-nestjs.service';\nimport { TraceMiddleware } from './trace.middleware';\nimport { WebSocketTraceInterceptor } from './websocket-trace.interceptor';\n\nconst DEFAULT_ROUTES: RouteInfo[] = [{ path: '*', method: RequestMethod.ALL }];\n\n// Constants for provider tokens\nexport const LOGIXIA_LOGGER_CONFIG = 'LOGIXIA_LOGGER_CONFIG';\nexport const LOGIXIA_TRACE_CONFIG = 'TRACE_CONFIG';\nexport const LOGIXIA_LOGGER_PREFIX = 'LOGIXIA_LOGGER_';\n\n// Export the service and interceptors for external use\nexport { KafkaTraceInterceptor } from './kafka-trace.interceptor';\nexport { LogixiaLoggerService } from './logitron-nestjs.service';\nexport { WebSocketTraceInterceptor } from './websocket-trace.interceptor';\n\n// Interface for module configuration\ninterface LogixiaModuleConfig {\n forRoutes?: RouteInfo[];\n exclude?: RouteInfo[];\n}\n\n// Interface for async configuration\nexport interface LogixiaAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n useExisting?: Type<LogixiaOptionsFactory>;\n useClass?: Type<LogixiaOptionsFactory>;\n useFactory?: (...args: unknown[]) => Promise<Partial<LoggerConfig>> | Partial<LoggerConfig>;\n inject?: Array<InjectionToken | OptionalFactoryDependency>;\n}\n\n// Interface for options factory\nexport interface LogixiaOptionsFactory {\n createLogixiaOptions(): Promise<Partial<LoggerConfig>> | Partial<LoggerConfig>;\n}\n\n/**\n * Logixia Logger Module for NestJS dependency injection\n */\n@Module({})\nexport class LogixiaLoggerModule implements NestModule {\n private config: LogixiaModuleConfig = {};\n private static loggerConfig: Partial<LoggerConfig> = {};\n\n /**\n * @internal Backing field for the global logger. Do not read or write\n * directly — use {@link getGlobalLogger} / {@link _setGlobalLogger} which\n * enforce single-init semantics.\n */\n // Retained for backwards compatibility with internal callers that read the\n // field directly (e.g. nestjs-extras). Treat as read-only — writes must go\n // through _setGlobalLogger / _resetGlobalLogger.\n // eslint-disable-next-line sonarjs/public-static-readonly -- intentional: we need to swap this in tests via _resetGlobalLogger, so `readonly` is too strict\n static _globalLogger: LogixiaLoggerService | null = null;\n\n /**\n * @internal Set the global logger exactly once.\n *\n * Called from the module's forRoot / forRootAsync factory. If the module is\n * initialised more than once in the same process (nested DI context, test\n * harness creating multiple apps, hot reload, etc.) a warning is written to\n * stderr and the first logger wins — silently overwriting would allow the\n * newer instance's transport config to replace the live one while the old\n * one is still being used by registered shutdown hooks, decorators, etc.\n *\n * Use {@link _resetGlobalLogger} in tests to reset between runs.\n */\n static _setGlobalLogger(service: LogixiaLoggerService): void {\n if (LogixiaLoggerModule._globalLogger !== null) {\n internalWarn(\n 'LogixiaLoggerModule.forRoot() was called more than once — ignoring the second init. ' +\n 'If this is intentional (e.g. in tests), call LogixiaLoggerModule._resetGlobalLogger() first.'\n );\n return;\n }\n LogixiaLoggerModule._globalLogger = service;\n }\n\n /** @internal Clear the global logger. Tests only. */\n static _resetGlobalLogger(): void {\n LogixiaLoggerModule._globalLogger = null;\n }\n\n /**\n * Returns the global LogixiaLoggerService instance that was created when the\n * module booted. Useful for logging outside of NestJS DI — utility functions,\n * plain scripts, decorators — without injecting the service everywhere.\n *\n * Returns `null` if called before `LogixiaLoggerModule.forRoot[Async]()` has\n * been initialised (i.e. before the NestJS app has started).\n *\n * @example\n * ```ts\n * // some-util.ts\n * import { LogixiaLoggerModule } from 'logixia/nest';\n *\n * export function doSomething() {\n * LogixiaLoggerModule.getGlobalLogger()?.info('doing something');\n * }\n * ```\n */\n static getGlobalLogger(): LogixiaLoggerService | null {\n return LogixiaLoggerModule._globalLogger;\n }\n\n configure(consumer: MiddlewareConsumer) {\n const { forRoutes = DEFAULT_ROUTES, exclude } = this.config;\n\n // Resolve the trace config ONCE at configure() time — it does not change\n // per request, so constructing a fresh TraceMiddleware on every invocation\n // (the old behaviour) was just allocation churn.\n let resolvedTraceConfig: TraceIdConfig | undefined;\n if (typeof LogixiaLoggerModule.loggerConfig.traceId === 'object') {\n resolvedTraceConfig = LogixiaLoggerModule.loggerConfig.traceId as TraceIdConfig;\n } else if (LogixiaLoggerModule.loggerConfig.traceId === true) {\n resolvedTraceConfig = {\n enabled: true,\n contextKey: 'traceId',\n generator: () => TraceContext.instance.generate(),\n };\n }\n\n const middleware = new TraceMiddleware(resolvedTraceConfig);\n const middlewareConfig = (req: Request, res: Response, next: NextFunction) =>\n middleware.use(req, res, next);\n\n if (exclude) {\n consumer\n .apply(middlewareConfig)\n .exclude(...exclude)\n .forRoutes(...forRoutes);\n } else {\n consumer.apply(middlewareConfig).forRoutes(...forRoutes);\n }\n }\n\n /**\n * Configure the module with synchronous options\n */\n static forRoot(config?: Partial<LoggerConfig>) {\n // Store config for middleware access\n LogixiaLoggerModule.loggerConfig = config || {};\n\n const traceConfig =\n config?.traceId && typeof config.traceId === 'object'\n ? config.traceId\n : { enabled: !!config?.traceId };\n\n return {\n module: LogixiaLoggerModule,\n providers: [\n {\n provide: LOGIXIA_LOGGER_CONFIG,\n useValue: config || {},\n },\n {\n provide: LOGIXIA_TRACE_CONFIG,\n useValue: traceConfig,\n },\n {\n provide: LogixiaLoggerService,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n const defaultConfig: LoggerConfig = {\n level: 'info',\n service: 'NestJSApp',\n environment: 'development',\n fields: {},\n formatters: ['text'],\n outputs: ['console'],\n levelOptions: {\n level: 'info', // INFO level\n levels: {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n info: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n ...loggerConfig,\n };\n const service = new LogixiaLoggerService(defaultConfig);\n LogixiaLoggerModule._setGlobalLogger(service);\n return service;\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: KafkaTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new KafkaTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n {\n provide: WebSocketTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new WebSocketTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n ],\n exports: [\n LogixiaLoggerService,\n LOGIXIA_LOGGER_CONFIG,\n KafkaTraceInterceptor,\n WebSocketTraceInterceptor,\n ],\n global: true,\n };\n }\n\n /**\n * Configure the module with asynchronous options\n */\n static forRootAsync(options: LogixiaAsyncOptions) {\n return {\n module: LogixiaLoggerModule,\n imports: options.imports || [],\n providers: [\n ...this.createAsyncProviders(options),\n {\n provide: LOGIXIA_TRACE_CONFIG,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n return typeof loggerConfig?.traceId === 'object'\n ? loggerConfig.traceId\n : { enabled: !!loggerConfig?.traceId };\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: LogixiaLoggerService,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n const defaultConfig: LoggerConfig = {\n level: 'info',\n service: 'NestJSApp',\n environment: 'development',\n fields: {},\n formatters: ['text'],\n outputs: ['console'],\n levelOptions: {\n level: 'info', // INFO level\n levels: {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n info: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n ...loggerConfig,\n };\n // Store config for middleware access\n LogixiaLoggerModule.loggerConfig = defaultConfig;\n const service = new LogixiaLoggerService(defaultConfig);\n LogixiaLoggerModule._setGlobalLogger(service);\n return service;\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: KafkaTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new KafkaTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n {\n provide: WebSocketTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new WebSocketTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n ],\n exports: [\n LogixiaLoggerService,\n LOGIXIA_LOGGER_CONFIG,\n KafkaTraceInterceptor,\n WebSocketTraceInterceptor,\n ],\n global: true,\n };\n }\n\n /**\n * Create feature-specific logger instances\n */\n static forFeature(context: string) {\n const providerToken = `${LOGIXIA_LOGGER_PREFIX}${context.toUpperCase()}`;\n return {\n module: LogixiaLoggerModule,\n providers: [\n {\n provide: providerToken,\n useFactory: (baseLogger: LogixiaLoggerService) => {\n return baseLogger.child(context);\n },\n inject: [LogixiaLoggerService],\n },\n ],\n exports: [providerToken],\n };\n }\n\n private static createAsyncProviders(options: LogixiaAsyncOptions) {\n if (options.useExisting || options.useFactory) {\n return [this.createAsyncOptionsProvider(options)];\n }\n return [\n this.createAsyncOptionsProvider(options),\n {\n provide: options.useClass!,\n useClass: options.useClass!,\n },\n ];\n }\n\n private static createAsyncOptionsProvider(options: LogixiaAsyncOptions) {\n if (options.useFactory) {\n return {\n provide: LOGIXIA_LOGGER_CONFIG,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n }\n return {\n provide: LOGIXIA_LOGGER_CONFIG,\n useFactory: async (optionsFactory: LogixiaOptionsFactory) =>\n await optionsFactory.createLogixiaOptions(),\n inject: [options.useExisting || options.useClass!],\n };\n }\n}\n","/**\n * logixia — NestJS extras: @InjectLogger, @LogMethod, LogixiaExceptionFilter\n *\n * Completes the NestJS deep integration story:\n * - @InjectLogger() — inject the logger via NestJS DI without typing LOGIXIA_TOKEN manually\n * - @LogMethod() — auto-log method entry / exit with args and return value\n * - LogixiaExceptionFilter — catch-all exception filter that logs unhandled errors\n * with full request context before re-throwing\n *\n * @example Full setup\n * ```ts\n * // app.module.ts\n * import { LogixiaModule } from 'logixia';\n * @Module({ imports: [LogixiaModule.forRoot({ appName: 'api' })] })\n * export class AppModule {}\n *\n * // order.service.ts\n * import { Injectable } from '@nestjs/common';\n * import { InjectLogger, LogMethod, LogixiaLoggerService } from 'logixia';\n *\n * @Injectable()\n * export class OrderService {\n * constructor(@InjectLogger() private readonly logger: LogixiaLoggerService) {}\n *\n * @LogMethod()\n * async createOrder(dto: CreateOrderDto) { … }\n * }\n *\n * // main.ts\n * import { LogixiaExceptionFilter } from 'logixia';\n * app.useGlobalFilters(new LogixiaExceptionFilter(logger));\n * ```\n */\n\nimport type { ArgumentsHost, ExceptionFilter } from '@nestjs/common';\nimport { Catch, Inject, Optional } from '@nestjs/common';\n\nimport { ErrorResponseBuilder } from '../exceptions/builder';\nimport { isLogixiaException } from '../exceptions/exception';\nimport type { LoggerConfig, LogLevelString, TraceIdConfig } from '../types';\nimport { internalError, internalWarn } from '../utils/internal-log';\nimport { sanitizeIncomingId, TraceContext } from '../utils/trace.utils';\nimport {\n LOGIXIA_LOGGER_CONFIG,\n LOGIXIA_LOGGER_PREFIX,\n LogixiaLoggerModule,\n} from './logitron-logger.module';\nimport type { LogixiaLoggerService } from './logitron-nestjs.service';\nimport { resolveResponseHeader } from './trace.middleware';\n\n// ── @InjectLogger() ──────────────────────────────────────────────────────────\n\n/**\n * Inject the Logixia logger registered in the current NestJS DI container.\n *\n * Equivalent to `@Inject(LOGIXIA_LOGGER_TOKEN)` but without needing to import\n * the internal token constant yourself.\n *\n * @example\n * ```ts\n * constructor(@InjectLogger() private readonly logger: LogixiaLoggerService) {}\n * ```\n */\nexport const InjectLogger = (): ParameterDecorator => Inject(`${LOGIXIA_LOGGER_PREFIX}SERVICE`);\n\n// ── @LogMethod() ─────────────────────────────────────────────────────────────\n\nexport interface LogMethodOptions {\n /**\n * Log level to use for entry / exit messages.\n * @default 'debug'\n */\n level?: LogLevelString;\n /**\n * Whether to log the arguments passed to the method.\n * Disable for high-throughput hot paths.\n * @default true\n */\n logArgs?: boolean;\n /**\n * Whether to log the return value of the method.\n * @default false\n */\n logResult?: boolean;\n /**\n * Whether to log error stack traces for thrown errors.\n * @default true\n */\n logErrors?: boolean;\n /**\n * Custom label used in log messages instead of the auto-detected class.method name.\n */\n label?: string;\n}\n\n/**\n * Method decorator that auto-logs entry, exit, duration, and errors.\n *\n * Preserves the original method's sync/async contract: a synchronous method\n * stays synchronous (returns its value directly, with logs emitted\n * fire-and-forget), and an async method is awaited so exit/error logs reflect\n * the resolved result. Attaches to the logger found on the class instance via a\n * `logger` property (the conventional NestJS name).\n *\n * @example\n * ```ts\n * @LogMethod({ level: 'info', logArgs: true })\n * async processPayment(orderId: string): Promise<void> { … }\n * ```\n */\nexport function LogMethod(options: LogMethodOptions = {}): MethodDecorator {\n const { level = 'debug', logArgs = true, logResult = false, logErrors = true } = options;\n\n // Use PropertyDescriptor (not generic TypedPropertyDescriptor<T>) to avoid\n // strict generic inference issues with exactOptionalPropertyTypes.\n return function (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor\n ): PropertyDescriptor {\n const originalMethod = descriptor.value as ((...args: unknown[]) => unknown) | undefined;\n if (typeof originalMethod !== 'function') return descriptor;\n\n const methodName = String(propertyKey);\n const className =\n (target as { constructor?: { name?: string } }).constructor?.name ?? 'Unknown';\n const label = options.label ?? `${className}.${methodName}`;\n\n let _warnedNoLogger = false;\n\n // Surface logger failures on stderr instead of silently swallowing them.\n const reportLogFailure = (phase: string, err: unknown): void => {\n internalError(`@LogMethod(${label}) ${phase} log failed: ${String(err)}`);\n };\n\n // Emit a log line fire-and-forget, routing transport failures to stderr.\n const emit = (\n logger: LogixiaLoggerService,\n phase: string,\n message: string,\n data: Record<string, unknown>\n ): void => {\n const logFnRaw = (\n logger as unknown as Record<\n string,\n (msg: string, data?: Record<string, unknown>) => Promise<void>\n >\n )[level];\n const logFn = (typeof logFnRaw === 'function' ? logFnRaw : logger.debug).bind(logger);\n const p = logFn(message, data);\n if (p && typeof (p as Promise<void>).catch === 'function') {\n (p as Promise<void>).catch((e: unknown) => reportLogFailure(phase, e));\n }\n };\n\n const emitError = (logger: LogixiaLoggerService, error: unknown, start: number): void => {\n const err = error instanceof Error ? error : new Error(String(error));\n const errLog: unknown = logger.error(err, { method: label, durationMs: Date.now() - start });\n if (errLog && typeof (errLog as Promise<void>).catch === 'function') {\n (errLog as Promise<void>).catch((e: unknown) => reportLogFailure('error', e));\n }\n };\n\n descriptor.value = function (this: { logger?: LogixiaLoggerService }, ...args: unknown[]) {\n // Prefer the instance's own logger; fall back to the global module logger.\n const logger: LogixiaLoggerService | undefined =\n this.logger ?? LogixiaLoggerModule._globalLogger ?? undefined;\n\n if (!logger && !_warnedNoLogger) {\n _warnedNoLogger = true;\n internalWarn(\n `@LogMethod on ${label}: no logger available. ` +\n `Either inject LogixiaLoggerService as this.logger or ensure LogixiaLoggerModule is initialised.`\n );\n }\n\n const start = Date.now();\n const entry: Record<string, unknown> = { method: label };\n if (logArgs && args.length > 0) entry['args'] = args;\n // Entry log is fire-and-forget so a SYNC method is not forced to become\n // async just to await it.\n if (logger) emit(logger, 'entry', `→ ${label}`, entry);\n\n const buildExit = (result: unknown): Record<string, unknown> => {\n const exit: Record<string, unknown> = { method: label, durationMs: Date.now() - start };\n if (logResult) exit['result'] = result;\n return exit;\n };\n\n let result: unknown;\n try {\n result = originalMethod.apply(this, args);\n } catch (error) {\n // Synchronous throw.\n if (logger && logErrors) emitError(logger, error, start);\n throw error;\n }\n\n // Async method → await via the returned thenable so exit/error reflect the\n // resolved outcome, and preserve the Promise return type.\n if (result && typeof (result as PromiseLike<unknown>).then === 'function') {\n return (result as Promise<unknown>).then(\n (resolved) => {\n if (logger) emit(logger, 'exit', `← ${label}`, buildExit(resolved));\n return resolved;\n },\n (error: unknown) => {\n if (logger && logErrors) emitError(logger, error, start);\n throw error;\n }\n );\n }\n\n // Synchronous method → log exit fire-and-forget and return the value as-is,\n // preserving the original synchronous contract.\n if (logger) emit(logger, 'exit', `← ${label}`, buildExit(result));\n return result;\n };\n\n return descriptor;\n };\n}\n\n// ── LogixiaExceptionFilter ───────────────────────────────────────────────────\n\n/**\n * Global NestJS exception filter that converts any exception into the standard\n * `LogixiaErrorResponse` wire format and logs it with full request context.\n *\n * Handles three exception types in priority order:\n * 1. `LogixiaException` — typed fields used directly\n * 2. NestJS `HttpException` — status + message extracted\n * 3. Unknown / plain Error — falls back to 500 `server_error`\n *\n * **Debug block (off by default):**\n * Responses never include the `debug` block (stack trace, service, duration)\n * unless `exposeDebug: true` is passed in the filter options. The underlying\n * `cause` is only added when `exposeCause: true` is also set. Enable explicitly\n * for local development only, e.g.\n * `new LogixiaExceptionFilter(logger, undefined, { exposeDebug: process.env.NODE_ENV === 'development' })`.\n *\n * **Trace ID headers:**\n * `X-Trace-ID` and `X-Request-ID` are echoed back on every error response so\n * clients can correlate with server logs.\n *\n * **Retry-After header:**\n * Automatically added for `429` responses (`Retry-After: 60`).\n *\n * Register in `main.ts`:\n * ```ts\n * const logger = app.get(LogixiaLoggerService);\n * app.useGlobalFilters(new LogixiaExceptionFilter(logger));\n * ```\n */\nexport interface LogixiaExceptionFilterOptions {\n /**\n * Include the `debug` block (stack trace, service, duration) in error responses.\n * @default false\n */\n exposeDebug?: boolean;\n /**\n * Include `debug.cause` as well. Requires `exposeDebug`.\n * @default false\n */\n exposeCause?: boolean;\n}\n\n/** Injection token for {@link LogixiaExceptionFilterOptions}. */\nexport const LOGIXIA_EXCEPTION_FILTER_OPTIONS = 'LOGIXIA_EXCEPTION_FILTER_OPTIONS';\n\n@Catch()\nexport class LogixiaExceptionFilter implements ExceptionFilter {\n private readonly _logger: LogixiaLoggerService | undefined;\n private readonly _traceConfig: TraceIdConfig | undefined;\n private readonly _options: LogixiaExceptionFilterOptions;\n\n constructor(\n @Optional()\n @Inject(`${LOGIXIA_LOGGER_PREFIX}SERVICE`)\n logger?: LogixiaLoggerService,\n @Optional()\n @Inject(LOGIXIA_LOGGER_CONFIG)\n loggerConfig?: Partial<LoggerConfig>,\n @Optional()\n @Inject(LOGIXIA_EXCEPTION_FILTER_OPTIONS)\n options?: LogixiaExceptionFilterOptions\n ) {\n this._options = options ?? {};\n // Prefer the injected logger; fall back to the global module logger so\n // `new LogixiaExceptionFilter()` (registered in main.ts before DI resolves)\n // still logs without needing an explicit logger argument.\n this._logger = logger ?? LogixiaLoggerModule._globalLogger ?? undefined;\n // Pick up the user-configured trace settings (response header name, etc.)\n // so the filter echoes the same header the middleware writes.\n this._traceConfig =\n typeof loggerConfig?.traceId === 'object' ? loggerConfig.traceId : undefined;\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n\n const request = ctx.getRequest<{\n method?: string;\n url?: string;\n id?: string;\n startTime?: number;\n headers?: Record<string, string | string[] | undefined>;\n }>();\n\n interface MinimalResponse {\n status(code: number): MinimalResponse;\n json(body: unknown): void;\n setHeader(name: string, value: string): void;\n }\n const response = ctx.getResponse<MinimalResponse>();\n\n // ALS is the single source of truth (set by TraceMiddleware).\n // Fall back to header/request.id only if ALS has nothing (e.g. traceId disabled).\n const traceId =\n TraceContext.instance.getCurrentTraceId() ??\n sanitizeIncomingId(request.headers?.['x-trace-id']) ??\n sanitizeIncomingId(request.id) ??\n undefined;\n\n const { response: errorResponse, httpStatus } = ErrorResponseBuilder.build({\n exception,\n traceId,\n path: request.url ?? '/',\n startTime: request.startTime,\n exposeDebug: this._options.exposeDebug === true,\n exposeCause: this._options.exposeCause === true,\n });\n\n // ── Logging ──────────────────────────────────────────────────────────────\n if (this._logger) {\n const requestMeta: Record<string, unknown> = {\n method: request.method ?? '',\n url: request.url ?? '',\n status: httpStatus,\n // Only include trace_id when it exists — keeps log records honest when\n // tracing is disabled (instead of writing `trace_id: undefined`).\n ...(errorResponse.meta.trace_id !== undefined\n ? { trace_id: errorResponse.meta.trace_id }\n : {}),\n };\n\n // `error()` / `warn()` return Promise<void> for the structured overload.\n // We cannot await inside a synchronous ExceptionFilter.catch(), so attach\n // a `.catch()` to prevent unhandledRejection if a transport fails — and\n // fall back to stderr so the error is never silently swallowed.\n const onLogFailure = (err: unknown): void => {\n internalError(`ExceptionFilter failed to write log entry: ${String(err)}`);\n };\n\n let logPromise: Promise<void> | void;\n if (httpStatus >= 500) {\n const err = exception instanceof Error ? exception : new Error(String(exception));\n logPromise = this._logger.error(err, requestMeta);\n } else if (isLogixiaException(exception)) {\n logPromise = this._logger.warn(\n `[${errorResponse.error.code}] ${errorResponse.error.message}`,\n requestMeta\n );\n } else {\n logPromise = this._logger.warn(\n `[${httpStatus}] ${errorResponse.error.message}`,\n requestMeta\n );\n }\n\n if (logPromise && typeof (logPromise as Promise<void>).catch === 'function') {\n (logPromise as Promise<void>).catch(onLogFailure);\n }\n }\n\n // ── Response headers ──────────────────────────────────────────────────\n if (errorResponse.meta.trace_id) {\n const traceHeader = resolveResponseHeader(this._traceConfig);\n if (traceHeader) {\n try {\n response.setHeader(traceHeader, errorResponse.meta.trace_id);\n } catch {\n /* headers already sent or invalid — the body still carries the trace id */\n }\n }\n }\n if (httpStatus === 429) {\n try {\n response.setHeader('Retry-After', '60');\n } catch {\n /* headers already sent */\n }\n }\n\n response.status(httpStatus).json(errorResponse);\n }\n}\n","/**\n * logixia/nest — NestJS integration\n *\n * @example\n * import { LogixiaLoggerModule, LogixiaLoggerService } from 'logixia/nest';\n *\n * @Module({\n * imports: [LogixiaLoggerModule.forRoot({ level: 'info' })],\n * })\n * export class AppModule {}\n */\n\nimport { DEFAULT_CONFIG } from './core/default-config';\nimport { LogixiaLoggerService } from './core/logitron-nestjs.service';\nimport type { LoggerConfig } from './types';\n\n// Everything NestJS-specific. These were exported from the root `logixia`\n// entry before 2.0.0; keep this list a superset of what the root used to export.\nexport * from './core/logitron-logger.module';\nexport * from './core/logitron-nestjs.service';\nexport type { LogixiaExceptionFilterOptions, LogMethodOptions } from './core/nestjs-extras';\nexport {\n InjectLogger,\n LOGIXIA_EXCEPTION_FILTER_OPTIONS,\n LogixiaExceptionFilter,\n LogMethod,\n} from './core/nestjs-extras';\nexport { TraceMiddleware } from './core/trace.middleware';\n\n/**\n * Create a new Logixia logger service for NestJS\n * @param config - Logger configuration\n * @returns LogixiaLoggerService instance\n */\nexport function createLoggerService(config?: Partial<LoggerConfig>): LogixiaLoggerService {\n return new LogixiaLoggerService({ ...DEFAULT_CONFIG, ...config });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsHO,IAAM,uBAAA,wBAAN,MAAM,qBAA8C;CAQzD,YAAY,QAAuB;EACjC,MAAM,gBAA8B;GAClC,SAAS;GACT,aAAa;GACb,SAAS;GACT,QAAQ;IACN,WAAW;IACX,UAAU;IACV,MAAM;GACR;GACA,QAAQ;GACR,cAAc;IACZ,OAAO,SAAS;IAChB,QAAQ;KACN,OAAO;KACP,MAAM;KACN,KAAK;KACL,OAAO;KACP,SAAS;IACX;IACA,QAAQ;KACN,OAAO;KACP,MAAM;KACN,KAAK;KACL,OAAO;KACP,SAAS;IACX;GACF;GACA,QAAQ;IACN,WAAW;IACX,OAAO;IACP,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,WAAW;GACb;EACF;EAEA,eAAe,MAAM,CAAC,eAAe,CAAC;EACtC,KAAK,gBAAgB;GAAE,GAAG;GAAe,GAAG;EAAO;EACnD,KAAK,SAAS,IAAI,cAAc,KAAK,aAAa;EAClD,KAAK,0BAA0B;CACjC;CAIA,4BAA0C;;EACxC,MAAM,UAAA,wBAAS,KAAK,cAAc,kBAAA,QAAA,0BAAA,KAAA,IAAA,KAAA,IAAA,sBAAc;EAChD,IAAI,CAAC,QAAQ;EACb,KAAK,MAAM,aAAa,OAAO,KAAK,MAAM,GAAG;GAC3C,MAAM,QAAQ,UAAU,YAAY;GAEpC,IAAI,OAAQ,KAAiC,WAAW,aAAa;GAErE,KAAc,SAAS,OACrB,SACA,SACkB;IAClB,OAAO,KAAK,OAAO,SAAS,OAAO,SAAS,IAAI;GAClD;EACF;CACF;;;;;;;CAUA,IAAI,SAAkB,SAAwB;EAC5C,KAAK,qBAAqB,OAAO;EACjC,KAAK,OACF,KAAK,KAAK,cAAc,OAAO,CAAC,CAAC,CACjC,OAAO,QAAiB,cAAc,mCAAmC,GAAG,CAAC;CAClF;;;;;;CAOA,MAAM,KAAK,SAAiB,MAA+C;EACzE,OAAO,KAAK,OAAO,KAAK,SAAS,IAAI;CACvC;CAmBA,MACE,SACA,aACA,SACsB;EAEtB,IAAI,OAAO,gBAAgB,YAAY,gBAAgB,MACrD,OAAO,mBAAmB,QACtB,KAAK,OAAO,MAAM,SAAS,WAAW,IACtC,KAAK,OAAO,MAAM,KAAK,cAAc,OAAO,GAAG,WAAW;EAIhE,KAAK,qBAAqB,OAAO;EACjC,MAAM,YAAoC,CAAC;EAC3C,IAAI,OAAO,gBAAgB,YAAY,aACrC,UAAU,QAAQ;EAQpB,CAJE,mBAAmB,QACf,KAAK,OAAO,MAAM,SAAS,SAAS,IACpC,KAAK,OAAO,MAAM,KAAK,cAAc,OAAO,GAAG,SAAS,EAAA,CAEnD,OAAO,QAAiB,cAAc,qCAAqC,GAAG,CAAC;CAC5F;CAkBA,KAAK,SAAkB,eAAwE;EAC7F,IAAI,OAAO,kBAAkB,YAAY,kBAAkB,MACzD,OAAO,KAAK,OAAO,KAAK,KAAK,cAAc,OAAO,GAAG,aAAa;EAEpE,KAAK,qBAAqB,OAAO,kBAAkB,WAAW,gBAAgB,KAAA,CAAS;EACvF,KAAK,OACF,KAAK,KAAK,cAAc,OAAO,CAAC,CAAC,CACjC,OAAO,QAAiB,cAAc,oCAAoC,GAAG,CAAC;CACnF;CAkBA,MAAM,SAAkB,eAAwE;EAC9F,IAAI,OAAO,kBAAkB,YAAY,kBAAkB,MACzD,OAAO,KAAK,OAAO,MAAM,KAAK,cAAc,OAAO,GAAG,aAAa;EAErE,KAAK,qBAAqB,OAAO,kBAAkB,WAAW,gBAAgB,KAAA,CAAS;EACvF,KAAK,OACF,MAAM,KAAK,cAAc,OAAO,CAAC,CAAC,CAClC,OAAO,QAAiB,cAAc,qCAAqC,GAAG,CAAC;CACpF;CAmBA,QACE,SACA,eACsB;EACtB,IAAI,OAAO,kBAAkB,YAAY,kBAAkB,MACzD,OAAO,KAAK,OAAO,MAAM,KAAK,cAAc,OAAO,GAAG,aAAa;EAErE,KAAK,qBAAqB,OAAO,kBAAkB,WAAW,gBAAgB,KAAA,CAAS;EACvF,KAAK,OACF,MAAM,KAAK,cAAc,OAAO,CAAC,CAAC,CAClC,OAAO,QAAiB,cAAc,uCAAuC,GAAG,CAAC;CACtF;;;;CAOA,MAAM,MAAM,SAAiB,MAA+C;EAC1E,OAAO,KAAK,OAAO,MAAM,SAAS,IAAI;CACxC;;;;CAKA,SAAS,OAAe,SAAiB,MAA+C;EACtF,OAAO,KAAK,OAAO,SAAS,OAAO,SAAS,IAAI;CAClD;CAIA,KAAK,OAAqB;EACxB,KAAK,OAAO,KAAK,KAAK;CACxB;CAEA,MAAM,QAAQ,OAA4C;EACxD,OAAO,KAAK,OAAO,QAAQ,KAAK;CAClC;CAEA,MAAM,UAAa,OAAe,IAAkC;EAClE,OAAO,KAAK,OAAO,UAAU,OAAO,EAAE;CACxC;CAIA,WAAW,SAAuB;EAChC,MAAM,UAAU,OAAO,YAAY,WAAW,UAAU,aAAa,OAAO;EAC5E,KAAK,UAAU;EACf,KAAK,OAAO,WAAW,OAAO;CAChC;CAEA,aAAiC;EAC/B,OAAO,KAAK;CACd;CAEA,SAAS,OAA6B;EACpC,KAAK,OAAO,SAAS,KAAK;CAC5B;CAEA,WAA2B;EACzB,OAAO,KAAK,OAAO,SAAS;CAC9B;CAIA,MAAM,SAAiB,MAAsD;EAC3E,MAAM,eAAe,IAAA,sBAAyB,KAAK,aAAa;EAChE,aAAa,SAAS,KAAK,OAAO,MAAM,SAAS,IAAI;EACrD,aAAa,UAAU;EACvB,OAAO;CACT;CAIA,oBAAwC;EACtC,OAAO,aAAa,SAAS,kBAAkB;CACjD;;CAGA,IAAI,kBAA0B;EAC5B,OAAO,mBAAmB;CAC5B;CAEA,MAAM,QAAuB;EAC3B,OAAO,KAAK,OAAO,MAAM;CAC3B;CAEA,OAAO,OACL,QAC6B;EAC7B,OAAO,IAAA,sBAAyB,MAAM;CACxC;CAEA,YAA2B;EACzB,OAAO,KAAK;CACd;CAIA,qBAA6B,SAAyB;EAIpD,IAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG;EACzD,IAAI,YAAY,KAAK,SACnB,KAAK,WAAW,OAAO;CAE3B;CAEA,cAAsB,SAA0B;EAC9C,IAAI,OAAO,YAAY,UAAU,OAAO;EAKxC,OAAO,aAAa,OAAO;CAC7B;AACF;AAvUC,uBAAA,wBAAA,WAAA,CAAA,WAAW,EAAE,OAAO,MAAM,UAAU,CAAC,GAAA,mBAAA,qBAAA,CAAA,MAAA,CAAA,CAAA,GAAA,oBAAA;;;ACxF/B,IAAM,wBAAN,MAAM,sBAAiD;;;;;CAY5D,OAAO,eAAqB;EAC1B,uBAAsB,QAAQ,WAAW;EACzC,uBAAsB,QAAQ,uBAAuB;EACrD,uBAAsB,QAAQ,UAAU;CAC1C;;;;;;;;;CAaA,YACE,QACA,iBAA2C,OAC3C;EADiB,KAAA,iBAAA;EAbI,KAAA,MAAA,aAAa;EAelC,KAAK,SAAS;GACZ,SAAS;GACT,YAAY;GACZ,WAAW;IACT,MAAM;KAAC;KAAW;KAAY;IAAY;IAC1C,QAAQ,CAAC,cAAc,UAAU;GACnC;GACA,GAAG;EACL;CACF;CAGA,UAAU,SAA2B,MAAoC;EACvE,IAAI,CAAC,KAAK,OAAO,SACf,OAAO,KAAK,OAAO;EAGrB,MAAM,aAAa,QAAQ,YAAY;EACvC,MAAM,OAAO,WAAW,QAAQ;EAChC,MAAM,UAAU,WAAW,WAAW;EAEtC,IAAI;EAEJ,IAAI,KAAK,OAAO,WACd,UAAU,eACR;GAAE,MAAM;GAAM,UAAA,YAAA,QAAA,YAAA,KAAA,IAAA,KAAA,IAAS,QAAS,YAAW,CAAC;GAAG,OAAO,CAAC;GAAG,QAAQ,CAAC;EAAE,GACrE,KAAK,OAAO,SACd;EAGF,IAAI,CAAC,SACH,UAAU,KAAK,IAAI,kBAAkB;EAGvC,IAAI,CAAC,SAAS;GACZ,IAAI,KAAK,gBAAgB;;IAGvB,uBAAsB,QAAQ;IAC9B,CAAA,wBAAA,oBAAoB,gBAAgB,OAAA,QAAA,0BAAA,KAAA,KAAA,sBAAG,KACrC,qDAAA,YAAA,QAAA,YAAA,KAAA,IAAA,KAAA,IAAqD,QAAS,MAAM,qBACtE;IACA,OAAO;GACT;GACA,uBAAsB,QAAQ;GAC9B,OAAO,KAAK,OAAO;EACrB;EAEA,uBAAsB,QAAQ;EAE9B,MAAM,eAAe;GACnB,aAAa;GACb,OAAA,YAAA,QAAA,YAAA,KAAA,IAAA,KAAA,IAAO,QAAS;GAChB,WAAA,YAAA,QAAA,YAAA,KAAA,IAAA,KAAA,IAAW,QAAS;GACpB,QAAA,YAAA,QAAA,YAAA,KAAA,IAAA,KAAA,IAAQ,QAAS;GACjB,KAAA,YAAA,QAAA,YAAA,KAAA,IAAA,KAAA,IAAK,QAAS;GACd,WAAA,YAAA,QAAA,YAAA,KAAA,IAAA,KAAA,IAAW,QAAS;EACtB;EAEA,OAAO,IAAI,YAAY,eAAe;GAKpC,IAAI;GACJ,KAAK,IAAI,IACP,eACM;IACJ,QAAQ,KAAK,OAAO,CAAC,CAAC,UAAU;KAC9B,OAAO,UAAU,WAAW,KAAK,KAAK;KACtC,QAAQ,QAAQ,WAAW,MAAM,GAAG;KACpC,gBAAgB,WAAW,SAAS;IACtC,CAAC;GACH,GACA,YACF;GACA,aAAA,UAAA,QAAA,UAAA,KAAA,IAAA,KAAA,IAAa,MAAO,YAAY;EAClC,CAAC;CACH;CA1G6C,OAAA,WAAA,KAAA,UAAA;EAC3C,UAAU;EACV,sBAAsB;EACtB,SAAS;CACX;AAuGF;AAjHC,wBAAA,yBAAA,WAAA,CAAA,WAAW,GAAA,mBAAA,qBAAA,CAAA,QAAA,OAAA,CAAA,CAAA,GAAA,qBAAA;;;;;;;;;;;;;ACPZ,SAAgB,sBAAsB,QAAuC;CAC3E,KAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IAAI,OAAQ,oBAAmB,OAAO,OAAO;CAC7C,QAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IAAO,OAAQ,mBAAA;AACjB;;;;;;;AAQA,SAAS,iBAAiB,KAAc,QAAgB,SAAuB;CAC7E,MAAM,IAAI;CAKV,IAAI,EAAE,aAAa;CACnB,IAAI;EACF,IAAI,OAAO,EAAE,cAAc,YAAY,EAAE,UAAU,QAAQ,OAAO;OAC7D,IAAI,OAAO,EAAE,WAAW,YAAY,EAAE,OAAO,QAAQ,OAAO;CACnE,QAAQ,CAER;AACF;AAcO,IAAM,kBAAN,MAAM,gBAA0C;CAGrD,YAAY,QAAqD;EAAxB,KAAA,SAAA;EAFlB,KAAA,MAAA,aAAa;EAGlC,MAAM,mBAAmB;GACvB,QAAQ;GACR,OAAO,CAAC,WAAW,UAAU;EAC/B;EACA,KAAK,SAAS;GACZ,SAAS;GACT,iBAAiB,KAAK,IAAI,SAAS;GACnC,YAAY;GACZ,GAAG;GACH,YAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IAAW,OAAQ,aACf;IAAE,GAAG;IAAkB,GAAG,OAAO;GAAU,IAC3C;EACN;EAGA,IAAI,KAAK,OAAO,SACd,KAAK,IAAI,cAAc,KAAK,OAAO,cAAc,SAAS;CAE9D;CAEA,IAAI,KAAc,KAAe,MAA0B;;EACzD,IAAI,GAAA,eAAC,KAAK,YAAA,QAAA,iBAAA,KAAA,IAAA,KAAA,IAAA,aAAQ,UAChB,OAAO,KAAK;EAGd,IAAI;EAEJ,IAAI,KAAK,OAAO,WACd,UAAU,eAAe,KAAK,KAAK,OAAO,SAAS;EAGrD,IAAI,CAAC,WAAW,KAAK,OAAO,WAAW;GACrC,MAAM,YAAY,KAAK,OAAO,UAAU;GAIxC,IAAI,OAAO,cAAc,YAAY,UAAU,KAAK,CAAC,CAAC,SAAS,GAC7D,UAAU;QAEV,aACE,uFACF;EAEJ;EACA,IAAI,CAAC,SACH,UAAU,KAAK,IAAI,SAAS;EAG9B,IAAI,UAAU;EAEd,MAAM,SAAS,sBAAsB,KAAK,MAAM;EAChD,IAAI,QAAQ,iBAAiB,KAAK,QAAQ,OAAO;EAEjD,KAAK,IAAI,IAAI,eAAe,KAAK,GAAG;GAClC,QAAQ,IAAI;GACZ,KAAK,IAAI;GACT,WAAW,IAAI,IAAI,YAAY;GAC/B,IAAI,IAAI,QAAA,cAAM,IAAI,YAAA,QAAA,gBAAA,KAAA,IAAA,KAAA,IAAA,YAAQ,oBAAA,kBAAiB,IAAI,gBAAA,QAAA,oBAAA,KAAA,IAAA,KAAA,IAAA,gBAAY;EAC7D,CAAC;CACH;AACF;;CAjEC,WAAW;CAIG,gBAAA,GAAA,SAAS,CAAA;;;;ACpDjB,IAAM,4BAAN,MAAM,0BAAqD;CAIhE,YAAY,QAAwB;EAHb,KAAA,MAAA,aAAa;EAIlC,KAAK,SAAS;GACZ,SAAS;GACT,YAAY;GACZ,WAAW;IACT,MAAM;KAAC;KAAW;KAAY;IAAY;IAC1C,QAAQ,CAAC,cAAc,UAAU;IACjC,OAAO,CAAC,WAAW,UAAU;GAC/B;GACA,GAAG;EACL;CACF;CAGA,UAAU,SAA2B,MAAoC;;EAEvE,IAAI,CAAC,KAAK,OAAO,SACf,OAAO,KAAK,OAAO;EAGrB,MAAM,YAAY,QAAQ,WAAW;EACrC,MAAM,OAAO,UAAU,QAAQ;EAC/B,MAAM,SAAS,UAAU,UAAU;EAEnC,IAAI;EAGJ,IAAI,KAAK,OAAO,WAAW;;GAEzB,MAAM,cAAc;IAClB,MAAM;IACN,UAAA,WAAA,QAAA,WAAA,KAAA,MAAA,oBAAS,OAAQ,eAAA,QAAA,sBAAA,KAAA,IAAA,KAAA,IAAA,kBAAW,YAAW,CAAC;IACxC,QAAA,WAAA,QAAA,WAAA,KAAA,MAAA,qBAAO,OAAQ,eAAA,QAAA,uBAAA,KAAA,IAAA,KAAA,IAAA,mBAAW,UAAS,CAAC;IACpC,QAAQ,CAAC;GACX;GACA,UAAU,eAAe,aAAa,KAAK,OAAO,SAAS;EAC7D;EAGA,IAAI,CAAC,SACH,UAAU,KAAK,IAAI,kBAAkB;EAIvC,IAAI,CAAC,SACH,OAAO,KAAK,OAAO;EAIrB,MAAM,gBAAgB;GACpB,aAAa;GACb,OAAA,SAAA,QAAA,SAAA,KAAA,IAAA,KAAA,IAAO,KAAM;GACb,UAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IAAU,OAAQ;GAClB,QAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IAAO,OAAQ,SAAQ,MAAM,KAAK,OAAO,KAAK,IAAI,CAAC;GACnD,eAAA,WAAA,QAAA,WAAA,KAAA,MAAA,qBAAe,OAAQ,eAAA,QAAA,uBAAA,KAAA,IAAA,KAAA,IAAA,mBAAW;EACpC;EAGA,OAAO,IAAI,YAAY,aAAa;GAIlC,IAAI;GACJ,KAAK,IAAI,IACP,eACM;IACJ,QAAQ,KAAK,OAAO,CAAC,CAAC,UAAU;KAC9B,OAAO,UAAU,SAAS,KAAK,KAAK;KACpC,QAAQ,QAAQ,SAAS,MAAM,GAAG;KAClC,gBAAgB,SAAS,SAAS;IACpC,CAAC;GACH,GACA,aACF;GACA,aAAA,UAAA,QAAA,UAAA,KAAA,IAAA,KAAA,IAAa,MAAO,YAAY;EAClC,CAAC;CACH;AACF;AAlFC,4BAAA,WAAA,CAAA,WAAW,GAAA,mBAAA,qBAAA,CAAA,MAAA,CAAA,CAAA,GAAA,yBAAA;;;ACWZ,MAAM,iBAA8B,CAAC;CAAE,MAAM;CAAK,QAAQ,cAAc;AAAI,CAAC;AAG7E,MAAa,wBAAwB;AACrC,MAAa,uBAAuB;AACpC,MAAa,wBAAwB;AA8B9B,IAAM,sBAAN,MAAM,oBAA0C;;;;;EACf,KAAA,SAAA,CAAC;;;;;;;;;;;;;;CA0BvC,OAAO,iBAAiB,SAAqC;EAC3D,IAAA,qBAAwB,kBAAkB,MAAM;GAC9C,aACE,kLAEF;GACA;EACF;EACA,qBAAoB,gBAAgB;CACtC;;CAGA,OAAO,qBAA2B;EAChC,qBAAoB,gBAAgB;CACtC;;;;;;;;;;;;;;;;;;;CAoBA,OAAO,kBAA+C;EACpD,OAAA,qBAA2B;CAC7B;CAEA,UAAU,UAA8B;EACtC,MAAM,EAAE,YAAY,gBAAgB,YAAY,KAAK;EAKrD,IAAI;EACJ,IAAI,OAAA,qBAA2B,aAAa,YAAY,UACtD,sBAAA,qBAA0C,aAAa;OAClD,IAAA,qBAAwB,aAAa,YAAY,MACtD,sBAAsB;GACpB,SAAS;GACT,YAAY;GACZ,iBAAiB,aAAa,SAAS,SAAS;EAClD;EAGF,MAAM,aAAa,IAAI,gBAAgB,mBAAmB;EAC1D,MAAM,oBAAoB,KAAc,KAAe,SACrD,WAAW,IAAI,KAAK,KAAK,IAAI;EAE/B,IAAI,SACF,SACG,MAAM,gBAAgB,CAAC,CACvB,QAAQ,GAAG,OAAO,CAAC,CACnB,UAAU,GAAG,SAAS;OAEzB,SAAS,MAAM,gBAAgB,CAAC,CAAC,UAAU,GAAG,SAAS;CAE3D;;;;CAKA,OAAO,QAAQ,QAAgC;EAE7C,qBAAoB,eAAe,UAAU,CAAC;EAE9C,MAAM,eAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IACJ,OAAQ,YAAW,OAAO,OAAO,YAAY,WACzC,OAAO,UACP,EAAE,SAAS,CAAC,EAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IAAC,OAAQ,SAAQ;EAEnC,OAAO;GACL,QAAA;GACA,WAAW;IACT;KACE,SAAS;KACT,UAAU,UAAU,CAAC;IACvB;IACA;KACE,SAAS;KACT,UAAU;IACZ;IACA;KACE,SAAS;KACT,aAAa,iBAAwC;MACnD,MAAM,gBAA8B;OAClC,OAAO;OACP,SAAS;OACT,aAAa;OACb,QAAQ,CAAC;OACT,YAAY,CAAC,MAAM;OACnB,SAAS,CAAC,SAAS;OACnB,cAAc;QACZ,OAAO;QACP,QAAQ;SACN,OAAO;SACP,MAAM;SACN,MAAM;SACN,OAAO;SACP,SAAS;QACX;QACA,QAAQ;SACN,OAAO;SACP,MAAM;SACN,MAAM;SACN,OAAO;SACP,SAAS;QACX;OACF;OACA,GAAG;MACL;MACA,MAAM,UAAU,IAAI,qBAAqB,aAAa;MACtD,qBAAoB,iBAAiB,OAAO;MAC5C,OAAO;KACT;KACA,QAAQ,CAAC,qBAAqB;IAChC;IACA;KACE,SAAS;KACT,aAAa,gBACX,IAAI,sBAAsB,WAAW;KACvC,QAAQ,CAAC,oBAAoB;IAC/B;IACA;KACE,SAAS;KACT,aAAa,gBACX,IAAI,0BAA0B,WAAW;KAC3C,QAAQ,CAAC,oBAAoB;IAC/B;GACF;GACA,SAAS;IACP;IACA;IACA;IACA;GACF;GACA,QAAQ;EACV;CACF;;;;CAKA,OAAO,aAAa,SAA8B;EAChD,OAAO;GACL,QAAA;GACA,SAAS,QAAQ,WAAW,CAAC;GAC7B,WAAW;IACT,GAAG,KAAK,qBAAqB,OAAO;IACpC;KACE,SAAS;KACT,aAAa,iBAAwC;MACnD,OAAO,QAAA,iBAAA,QAAA,iBAAA,KAAA,IAAA,KAAA,IAAO,aAAc,aAAY,WACpC,aAAa,UACb,EAAE,SAAS,CAAC,EAAA,iBAAA,QAAA,iBAAA,KAAA,IAAA,KAAA,IAAC,aAAc,SAAQ;KACzC;KACA,QAAQ,CAAC,qBAAqB;IAChC;IACA;KACE,SAAS;KACT,aAAa,iBAAwC;MACnD,MAAM,gBAA8B;OAClC,OAAO;OACP,SAAS;OACT,aAAa;OACb,QAAQ,CAAC;OACT,YAAY,CAAC,MAAM;OACnB,SAAS,CAAC,SAAS;OACnB,cAAc;QACZ,OAAO;QACP,QAAQ;SACN,OAAO;SACP,MAAM;SACN,MAAM;SACN,OAAO;SACP,SAAS;QACX;QACA,QAAQ;SACN,OAAO;SACP,MAAM;SACN,MAAM;SACN,OAAO;SACP,SAAS;QACX;OACF;OACA,GAAG;MACL;MAEA,qBAAoB,eAAe;MACnC,MAAM,UAAU,IAAI,qBAAqB,aAAa;MACtD,qBAAoB,iBAAiB,OAAO;MAC5C,OAAO;KACT;KACA,QAAQ,CAAC,qBAAqB;IAChC;IACA;KACE,SAAS;KACT,aAAa,gBACX,IAAI,sBAAsB,WAAW;KACvC,QAAQ,CAAC,oBAAoB;IAC/B;IACA;KACE,SAAS;KACT,aAAa,gBACX,IAAI,0BAA0B,WAAW;KAC3C,QAAQ,CAAC,oBAAoB;IAC/B;GACF;GACA,SAAS;IACP;IACA;IACA;IACA;GACF;GACA,QAAQ;EACV;CACF;;;;CAKA,OAAO,WAAW,SAAiB;EACjC,MAAM,gBAAgB,GAAG,wBAAwB,QAAQ,YAAY;EACrE,OAAO;GACL,QAAA;GACA,WAAW,CACT;IACE,SAAS;IACT,aAAa,eAAqC;KAChD,OAAO,WAAW,MAAM,OAAO;IACjC;IACA,QAAQ,CAAC,oBAAoB;GAC/B,CACF;GACA,SAAS,CAAC,aAAa;EACzB;CACF;CAEA,OAAe,qBAAqB,SAA8B;EAChE,IAAI,QAAQ,eAAe,QAAQ,YACjC,OAAO,CAAC,KAAK,2BAA2B,OAAO,CAAC;EAElD,OAAO,CACL,KAAK,2BAA2B,OAAO,GACvC;GACE,SAAS,QAAQ;GACjB,UAAU,QAAQ;EACpB,CACF;CACF;CAEA,OAAe,2BAA2B,SAA8B;EACtE,IAAI,QAAQ,YACV,OAAO;GACL,SAAS;GACT,YAAY,QAAQ;GACpB,QAAQ,QAAQ,UAAU,CAAC;EAC7B;EAEF,OAAO;GACL,SAAS;GACT,YAAY,OAAO,mBACjB,MAAM,eAAe,qBAAqB;GAC5C,QAAQ,CAAC,QAAQ,eAAe,QAAQ,QAAS;EACnD;CACF;CA5SqD,OAAA,YAAA,KAAA,eAAA,CAAC,GAAA,KAAA,gBAWF;AAkStD;AAhTC,sBAAA,uBAAA,WAAA,CAAA,OAAO,CAAC,CAAC,CAAA,GAAA,mBAAA;;;;;;;;;;;;;ACSV,MAAa,qBAAyC,OAAO,GAAG,sBAAsB,QAAQ;;;;;;;;;;;;;;;;AA+C9F,SAAgB,UAAU,UAA4B,CAAC,GAAoB;CACzE,MAAM,EAAE,QAAQ,SAAS,UAAU,MAAM,YAAY,OAAO,YAAY,SAAS;CAIjF,OAAO,SACL,QACA,aACA,YACoB;;EACpB,MAAM,iBAAiB,WAAW;EAClC,IAAI,OAAO,mBAAmB,YAAY,OAAO;EAEjD,MAAM,aAAa,OAAO,WAAW;EACrC,MAAM,cAAA,eACH,OAA+C,iBAAA,QAAA,iBAAA,KAAA,IAAA,KAAA,IAAA,aAAa,SAAQ;EACvE,MAAM,QAAQ,QAAQ,SAAS,GAAG,UAAU,GAAG;EAE/C,IAAI,kBAAkB;EAGtB,MAAM,oBAAoB,OAAe,QAAuB;GAC9D,cAAc,cAAc,MAAM,IAAI,MAAM,eAAe,OAAO,GAAG,GAAG;EAC1E;EAGA,MAAM,QACJ,QACA,OACA,SACA,SACS;GACT,MAAM,WACJ,OAIA;GAEF,MAAM,KADS,OAAO,aAAa,aAAa,WAAW,OAAO,MAAA,CAAO,KAAK,MAChE,CAAC,CAAC,SAAS,IAAI;GAC7B,IAAI,KAAK,OAAQ,EAAoB,UAAU,YAC7C,EAAqB,OAAO,MAAe,iBAAiB,OAAO,CAAC,CAAC;EAEzE;EAEA,MAAM,aAAa,QAA8B,OAAgB,UAAwB;GACvF,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;GACpE,MAAM,SAAkB,OAAO,MAAM,KAAK;IAAE,QAAQ;IAAO,YAAY,KAAK,IAAI,IAAI;GAAM,CAAC;GAC3F,IAAI,UAAU,OAAQ,OAAyB,UAAU,YACvD,OAA0B,OAAO,MAAe,iBAAiB,SAAS,CAAC,CAAC;EAEhF;EAEA,WAAW,QAAQ,SAAmD,GAAG,MAAiB;GAExF,MAAM,SACJ,KAAK,UAAU,oBAAoB,iBAAiB,KAAA;GAEtD,IAAI,CAAC,UAAU,CAAC,iBAAiB;IAC/B,kBAAkB;IAClB,aACE,iBAAiB,MAAM,uHAEzB;GACF;GAEA,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,QAAiC,EAAE,QAAQ,MAAM;GACvD,IAAI,WAAW,KAAK,SAAS,GAAG,MAAM,UAAU;GAGhD,IAAI,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,KAAK;GAErD,MAAM,aAAa,WAA6C;IAC9D,MAAM,OAAgC;KAAE,QAAQ;KAAO,YAAY,KAAK,IAAI,IAAI;IAAM;IACtF,IAAI,WAAW,KAAK,YAAY;IAChC,OAAO;GACT;GAEA,IAAI;GACJ,IAAI;IACF,SAAS,eAAe,MAAM,MAAM,IAAI;GAC1C,SAAS,OAAO;IAEd,IAAI,UAAU,WAAW,UAAU,QAAQ,OAAO,KAAK;IACvD,MAAM;GACR;GAIA,IAAI,UAAU,OAAQ,OAAgC,SAAS,YAC7D,OAAQ,OAA4B,MACjC,aAAa;IACZ,IAAI,QAAQ,KAAK,QAAQ,QAAQ,KAAK,SAAS,UAAU,QAAQ,CAAC;IAClE,OAAO;GACT,IACC,UAAmB;IAClB,IAAI,UAAU,WAAW,UAAU,QAAQ,OAAO,KAAK;IACvD,MAAM;GACR,CACF;GAKF,IAAI,QAAQ,KAAK,QAAQ,QAAQ,KAAK,SAAS,UAAU,MAAM,CAAC;GAChE,OAAO;EACT;EAEA,OAAO;CACT;AACF;;AA+CA,MAAa,mCAAmC;AAGzC,IAAM,yBAAN,MAAM,uBAAkD;CAK7D,YACE,QAGA,cAGA,SAGA;EACA,KAAK,WAAW,WAAW,CAAC;EAI5B,KAAK,UAAU,UAAU,oBAAoB,iBAAiB,KAAA;EAG9D,KAAK,eACH,QAAA,iBAAA,QAAA,iBAAA,KAAA,IAAA,KAAA,IAAO,aAAc,aAAY,WAAW,aAAa,UAAU,KAAA;CACvE;CAEA,MAAM,WAAoB,MAA2B;;EACnD,MAAM,MAAM,KAAK,aAAa;EAE9B,MAAM,UAAU,IAAI,WAMjB;EAOH,MAAM,WAAW,IAAI,YAA6B;EAIlD,MAAM,UACJ,aAAa,SAAS,kBAAkB,KACxC,oBAAA,mBAAmB,QAAQ,aAAA,QAAA,qBAAA,KAAA,IAAA,KAAA,IAAA,iBAAU,aAAa,KAClD,mBAAmB,QAAQ,EAAE,KAC7B,KAAA;EAEF,MAAM,EAAE,UAAU,eAAe,eAAe,qBAAqB,MAAM;GACzE;GACA;GACA,MAAM,QAAQ,OAAO;GACrB,WAAW,QAAQ;GACnB,aAAa,KAAK,SAAS,gBAAgB;GAC3C,aAAa,KAAK,SAAS,gBAAgB;EAC7C,CAAC;EAGD,IAAI,KAAK,SAAS;GAChB,MAAM,cAAuC;IAC3C,QAAQ,QAAQ,UAAU;IAC1B,KAAK,QAAQ,OAAO;IACpB,QAAQ;IAGR,GAAI,cAAc,KAAK,aAAa,KAAA,IAChC,EAAE,UAAU,cAAc,KAAK,SAAS,IACxC,CAAC;GACP;GAMA,MAAM,gBAAgB,QAAuB;IAC3C,cAAc,8CAA8C,OAAO,GAAG,GAAG;GAC3E;GAEA,IAAI;GACJ,IAAI,cAAc,KAAK;IACrB,MAAM,MAAM,qBAAqB,QAAQ,YAAY,IAAI,MAAM,OAAO,SAAS,CAAC;IAChF,aAAa,KAAK,QAAQ,MAAM,KAAK,WAAW;GAClD,OAAO,IAAI,mBAAmB,SAAS,GACrC,aAAa,KAAK,QAAQ,KACxB,IAAI,cAAc,MAAM,KAAK,IAAI,cAAc,MAAM,WACrD,WACF;QAEA,aAAa,KAAK,QAAQ,KACxB,IAAI,WAAW,IAAI,cAAc,MAAM,WACvC,WACF;GAGF,IAAI,cAAc,OAAQ,WAA6B,UAAU,YAC/D,WAA8B,MAAM,YAAY;EAEpD;EAGA,IAAI,cAAc,KAAK,UAAU;GAC/B,MAAM,cAAc,sBAAsB,KAAK,YAAY;GAC3D,IAAI,aACF,IAAI;IACF,SAAS,UAAU,aAAa,cAAc,KAAK,QAAQ;GAC7D,QAAQ,CAER;EAEJ;EACA,IAAI,eAAe,KACjB,IAAI;GACF,SAAS,UAAU,eAAe,IAAI;EACxC,QAAQ,CAER;EAGF,SAAS,OAAO,UAAU,CAAC,CAAC,KAAK,aAAa;CAChD;AACF;;CA9HC,MAAM;CAOF,gBAAA,GAAA,SAAS,CAAA;CACT,gBAAA,GAAA,OAAO,GAAG,sBAAsB,QAAQ,CAAA;CAExC,gBAAA,GAAA,SAAS,CAAA;CACT,gBAAA,GAAA,OAAO,qBAAqB,CAAA;CAE5B,gBAAA,GAAA,SAAS,CAAA;CACT,gBAAA,GAAA,OAAO,gCAAgC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;AC1P5C,SAAgB,oBAAoB,QAAsD;CACxF,OAAO,IAAI,qBAAqB;EAAE,GAAG;EAAgB,GAAG;CAAO,CAAC;AAClE"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
// src/utils/trace.utils.ts
|
|
4
|
+
/**
|
|
5
|
+
* Trace ID utilities for Logitron
|
|
6
|
+
*/
|
|
5
7
|
/** Default key used to store the trace ID in AsyncLocalStorage. */
|
|
6
8
|
const TRACE_CONTEXT_KEY = "traceId";
|
|
7
9
|
/**
|
|
@@ -20,7 +22,6 @@ const TRACE_CONTEXT_KEY = "traceId";
|
|
|
20
22
|
* TraceContext.instance.getCurrentTraceId() // same as standalone fn
|
|
21
23
|
*/
|
|
22
24
|
var TraceContext = class TraceContext {
|
|
23
|
-
static #_ = this._instance = null;
|
|
24
25
|
constructor() {
|
|
25
26
|
this.storage = new AsyncLocalStorage();
|
|
26
27
|
this._contextKey = TRACE_CONTEXT_KEY;
|
|
@@ -83,6 +84,7 @@ var TraceContext = class TraceContext {
|
|
|
83
84
|
...data
|
|
84
85
|
}, fn);
|
|
85
86
|
}
|
|
87
|
+
static #_ = () => this._instance = null;
|
|
86
88
|
};
|
|
87
89
|
/**
|
|
88
90
|
* The shared AsyncLocalStorage instance.
|
|
@@ -180,7 +182,7 @@ const SAFE_INCOMING_ID = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
|
180
182
|
*/
|
|
181
183
|
function sanitizeIncomingId(value) {
|
|
182
184
|
const first = Array.isArray(value) ? value[0] : value;
|
|
183
|
-
if (typeof first !== "string" || first.length >
|
|
185
|
+
if (typeof first !== "string" || first.length > 256) return void 0;
|
|
184
186
|
const trimmed = first.trim();
|
|
185
187
|
return SAFE_INCOMING_ID.test(trimmed) ? trimmed : void 0;
|
|
186
188
|
}
|
|
@@ -258,7 +260,7 @@ function createTraceMiddleware(config) {
|
|
|
258
260
|
...config.extractor
|
|
259
261
|
} : defaultExtractor
|
|
260
262
|
};
|
|
261
|
-
_setActiveContextKey(resolvedConfig.contextKey ??
|
|
263
|
+
_setActiveContextKey(resolvedConfig.contextKey ?? "traceId");
|
|
262
264
|
return (req, res, next) => {
|
|
263
265
|
let traceId;
|
|
264
266
|
if (resolvedConfig.extractor) traceId = extractTraceId(req, resolvedConfig.extractor);
|
|
@@ -272,7 +274,40 @@ function createTraceMiddleware(config) {
|
|
|
272
274
|
runWithTraceId(traceId, () => next());
|
|
273
275
|
};
|
|
274
276
|
}
|
|
277
|
+
// src/utils/request-trace.ts
|
|
278
|
+
/**
|
|
279
|
+
* Per-request trace ID resolution shared by the HTTP logger middleware and the
|
|
280
|
+
* context helpers. Internal: not re-exported from the package entry points.
|
|
281
|
+
*/
|
|
282
|
+
/** Fastify's default `genReqId` output (`req-` + base36 counter), unique only per process. */
|
|
283
|
+
const FASTIFY_COUNTER_ID = /^req-[\da-z]+$/;
|
|
284
|
+
const FALLBACK_KEY = "_logixiaFallbackId";
|
|
285
|
+
/** Header names to read a trace ID from, defaulting to the library-wide list. */
|
|
286
|
+
function resolveTraceHeaders(option) {
|
|
287
|
+
if (option === void 0) return DEFAULT_TRACE_HEADERS;
|
|
288
|
+
return typeof option === "string" ? [option] : option;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Resolve the trace ID for a request: a sanitised incoming header (honouring
|
|
292
|
+
* `traceparent`), then a non-counter `request.id`, then a generated ID. Header
|
|
293
|
+
* and `request.id` are recomputed per call so each caller's own header list is
|
|
294
|
+
* honoured; only the generated fallback is stored on the request so every helper
|
|
295
|
+
* agrees when no ID was sent.
|
|
296
|
+
*/
|
|
297
|
+
function resolveRequestTraceId(req, headers) {
|
|
298
|
+
const fromHeader = extractTraceId(req, { header: [...headers] });
|
|
299
|
+
if (fromHeader !== void 0) return fromHeader;
|
|
300
|
+
const fromId = sanitizeIncomingId(req.id);
|
|
301
|
+
if (fromId !== void 0 && !FASTIFY_COUNTER_ID.test(fromId)) return fromId;
|
|
302
|
+
const holder = req;
|
|
303
|
+
const cached = holder[FALLBACK_KEY];
|
|
304
|
+
if (typeof cached === "string") return cached;
|
|
305
|
+
const generated = generateTraceId();
|
|
306
|
+
try {
|
|
307
|
+
holder[FALLBACK_KEY] = generated;
|
|
308
|
+
} catch {}
|
|
309
|
+
return generated;
|
|
310
|
+
}
|
|
311
|
+
export { TRACE_CONTEXT_KEY as a, createTraceMiddleware as c, getTraceContextKey as d, runWithTraceId as f, traceStorage as h, MAX_INCOMING_ID_LENGTH as i, extractTraceId as l, setTraceId as m, resolveTraceHeaders as n, TraceContext as o, sanitizeIncomingId as p, DEFAULT_TRACE_HEADERS as r, _setActiveContextKey as s, resolveRequestTraceId as t, getCurrentTraceId as u };
|
|
275
312
|
|
|
276
|
-
//#
|
|
277
|
-
export { _setActiveContextKey as a, getCurrentTraceId as c, sanitizeIncomingId as d, setTraceId as f, TraceContext as i, getTraceContextKey as l, MAX_INCOMING_ID_LENGTH as n, createTraceMiddleware as o, traceStorage as p, TRACE_CONTEXT_KEY as r, extractTraceId as s, DEFAULT_TRACE_HEADERS as t, runWithTraceId as u };
|
|
278
|
-
//# sourceMappingURL=trace.utils-CvXgaiQT.mjs.map
|
|
313
|
+
//# sourceMappingURL=request-trace-C_fvIDv4.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-trace-C_fvIDv4.mjs","names":[],"sources":["../src/utils/trace.utils.ts","../src/utils/request-trace.ts"],"sourcesContent":["/**\n * Trace ID utilities for Logitron\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\n\nimport type { TraceIdConfig, TraceIdExtractorConfig } from '../types';\n\n/** Default key used to store the trace ID in AsyncLocalStorage. */\nexport const TRACE_CONTEXT_KEY = 'traceId' as const;\n\n// ── TraceContext class ────────────────────────────────────────────────────────\n\n/**\n * Singleton that owns the AsyncLocalStorage and the active contextKey.\n *\n * Why a class instead of bare module-level variables?\n * - The contextKey is user-configurable; encapsulating it here means there is\n * exactly one place that reads and writes it.\n * - All helpers (getCurrentTraceId, runWithTraceId, etc.) delegate to this\n * instance, so the key is always in sync without hidden global state.\n * - Easier to test: you can reset the singleton between test cases.\n *\n * Usage (advanced):\n * import { TraceContext } from 'logixia';\n * TraceContext.instance.contextKey // → 'traceId' (or custom)\n * TraceContext.instance.getCurrentTraceId() // same as standalone fn\n */\nexport class TraceContext {\n private static _instance: TraceContext | null = null;\n\n readonly storage = new AsyncLocalStorage<Record<string, unknown>>();\n private _contextKey: string = TRACE_CONTEXT_KEY;\n\n private constructor() {}\n\n /** The process-wide singleton. */\n static get instance(): TraceContext {\n if (!TraceContext._instance) {\n TraceContext._instance = new TraceContext();\n }\n return TraceContext._instance;\n }\n\n /** @internal Reset the singleton (useful in tests). */\n static _reset(): void {\n TraceContext._instance = null;\n }\n\n // ── Key management ──────────────────────────────────────────────────────────\n\n /** The AsyncLocalStorage key that holds the trace ID value. */\n get contextKey(): string {\n return this._contextKey;\n }\n\n /** @internal Called by TraceMiddleware when it boots to register the user's key. */\n setContextKey(key: string): void {\n this._contextKey = key;\n }\n\n // ── Core operations ─────────────────────────────────────────────────────────\n\n /** UUID v4 generator (default). */\n generate(): string {\n return randomUUID();\n }\n\n /** Read the trace ID from the current async context. */\n getCurrentTraceId(): string | undefined {\n return this.storage.getStore()?.[this._contextKey] as string | undefined;\n }\n\n /**\n * Mutate the CURRENT async context in-place.\n *\n * ⚠️ DEPRECATED — unsafe for concurrent requests.\n *\n * Uses `AsyncLocalStorage.enterWith()`, which mutates the current async\n * execution context and every Promise chain spawned from it. In a server\n * processing overlapping requests this can cause a trace ID set for one\n * request to bleed into *other* in-flight requests that share the same\n * async parent (e.g. a module-level setup function or a cached handler).\n *\n * Use {@link run} instead — it scopes the context to a callback so there\n * is no risk of cross-request leakage.\n *\n * @deprecated Use `TraceContext.instance.run(traceId, fn)` — do not call\n * `setTraceId` from request-handling code.\n */\n setTraceId(traceId: string, data?: Record<string, unknown>): void {\n const current = this.storage.getStore() ?? {};\n this.storage.enterWith({ ...current, [this._contextKey]: traceId, ...data });\n }\n\n /** Run `fn` inside a new async context that carries `traceId`. */\n run<T>(traceId: string, fn: () => T, data?: Record<string, unknown>): T {\n return this.storage.run({ [this._contextKey]: traceId, ...data }, fn);\n }\n}\n\n// ── Module-level aliases (backwards-compatible public API) ────────────────────\n\n/**\n * The shared AsyncLocalStorage instance.\n * @deprecated Prefer `TraceContext.instance.storage` for new code.\n */\nexport const traceStorage = TraceContext.instance.storage;\n\n/** Returns the key currently used to store the trace ID in AsyncLocalStorage. */\nexport function getTraceContextKey(): string {\n return TraceContext.instance.contextKey;\n}\n\n/** @internal Called by TraceMiddleware / traceMiddleware() when they boot. */\nexport function _setActiveContextKey(key: string): void {\n TraceContext.instance.setContextKey(key);\n}\n\n/** Generate a UUID v4 trace ID. */\nexport function generateTraceId(): string {\n return TraceContext.instance.generate();\n}\n\n/**\n * Get the current trace ID from async context.\n * Returns `undefined` when called outside a traced request.\n */\nexport function getCurrentTraceId(): string | undefined {\n return TraceContext.instance.getCurrentTraceId();\n}\n\n/**\n * Set trace ID in the CURRENT async context without starting a new one.\n *\n * ⚠️ DEPRECATED — unsafe for concurrent requests.\n *\n * Uses `AsyncLocalStorage.enterWith()`, which mutates the current async\n * execution context and every Promise chain spawned from it. Under load this\n * can cause a trace ID from one request to bleed into others sharing the same\n * async parent.\n *\n * Use {@link runWithTraceId} instead. Migration patterns:\n *\n * **Express / Fastify middleware — before:**\n * ```ts\n * app.use((req, _res, next) => {\n * setTraceId(req.headers['x-trace-id'] ?? generateTraceId());\n * next();\n * });\n * ```\n * **after:**\n * ```ts\n * app.use((req, _res, next) => {\n * runWithTraceId(req.headers['x-trace-id'] ?? generateTraceId(), () => next());\n * });\n * ```\n *\n * **Kafka / queue consumer — before:**\n * ```ts\n * async function handle(msg) {\n * setTraceId(msg.headers['x-trace-id']);\n * await processMessage(msg);\n * }\n * ```\n * **after:**\n * ```ts\n * async function handle(msg) {\n * await runWithTraceId(msg.headers['x-trace-id'], () => processMessage(msg));\n * }\n * ```\n *\n * **Background job — before:**\n * ```ts\n * setTraceId(generateTraceId(), { jobId: job.id });\n * await job.run();\n * ```\n * **after:**\n * ```ts\n * await runWithTraceId(generateTraceId(), () => job.run(), { jobId: job.id });\n * ```\n *\n * @deprecated Use `runWithTraceId(traceId, fn)` — do not call `setTraceId`\n * from request-handling code.\n */\nexport function setTraceId(traceId: string, data?: Record<string, unknown>): void {\n TraceContext.instance.setTraceId(traceId, data);\n}\n\n/** Run `fn` inside a new async context carrying `traceId`. */\nexport function runWithTraceId<T>(traceId: string, fn: () => T, data?: Record<string, unknown>): T {\n return TraceContext.instance.run(traceId, fn, data);\n}\n\n// ── Request extraction ────────────────────────────────────────────────────────\n\ntype HeaderValue = string | string[] | undefined;\n\n/** Shape that extractTraceId accepts (Express-compatible) */\ninterface RequestLike {\n headers?: Record<string, HeaderValue>;\n query?: Record<string, HeaderValue>;\n body?: Record<string, string | undefined>;\n params?: Record<string, string | undefined>;\n}\n\n/** Maximum accepted length for an incoming trace / correlation / request ID. */\nexport const MAX_INCOMING_ID_LENGTH = 128;\n\nconst SAFE_INCOMING_ID = /^[A-Za-z0-9._:-]{1,128}$/;\n\n/**\n * Validate an externally supplied identifier (trace ID, correlation ID, origin\n * service name, message-queue ID). Accepts only 1-128 characters from\n * `[A-Za-z0-9._:-]`; surrounding whitespace is trimmed first. Arrays use their\n * first element. Returns the cleaned value, or `undefined` when it is unusable\n * so callers can generate a fresh ID instead of passing client text through.\n */\nexport function sanitizeIncomingId(value: unknown): string | undefined {\n const first = Array.isArray(value) ? value[0] : value;\n if (typeof first !== 'string' || first.length > MAX_INCOMING_ID_LENGTH * 2) return undefined;\n const trimmed = first.trim();\n return SAFE_INCOMING_ID.test(trimmed) ? trimmed : undefined;\n}\n\n/** W3C trace-context: `version-traceId(32hex)-spanId(16hex)-flags(2hex)`. */\nconst W3C_TRACEPARENT_RE = /^[\\da-f]{2}-([\\da-f]{32})-[\\da-f]{16}-[\\da-f]{2}$/i;\n\n/**\n * Extract the 32-hex trace-id segment from a W3C `traceparent` header value.\n * Returns the parsed trace ID, or the original value unchanged when it is not a\n * well-formed traceparent (so non-W3C propagation still works).\n */\nfunction parseTraceparent(value: string): string {\n const m = W3C_TRACEPARENT_RE.exec(value);\n return m ? m[1]! : value;\n}\n\n/** Extract trace ID from request using configuration (header → query → body → params). */\nexport function extractTraceId(\n request: unknown,\n config: TraceIdExtractorConfig\n): string | undefined {\n const req = request as RequestLike;\n\n if (config.header) {\n const headers = Array.isArray(config.header) ? config.header : [config.header];\n for (const header of headers) {\n const lower = header.toLowerCase();\n const value = sanitizeIncomingId(req.headers?.[lower]);\n if (value) return lower === 'traceparent' ? parseTraceparent(value) : value;\n }\n }\n\n if (config.query) {\n const queries = Array.isArray(config.query) ? config.query : [config.query];\n for (const query of queries) {\n const value = sanitizeIncomingId(req.query?.[query]);\n if (value) return value;\n }\n }\n\n if (config.body) {\n const bodyFields = Array.isArray(config.body) ? config.body : [config.body];\n for (const field of bodyFields) {\n const value = sanitizeIncomingId(req.body?.[field]);\n if (value) return value;\n }\n }\n\n if (config.params) {\n const paramFields = Array.isArray(config.params) ? config.params : [config.params];\n for (const param of paramFields) {\n const value = sanitizeIncomingId(req.params?.[param]);\n if (value) return value;\n }\n }\n\n return undefined;\n}\n\n/**\n * Default headers checked for incoming trace ID propagation, in priority order:\n * traceparent (W3C/OTel) → x-trace-id → x-request-id → x-correlation-id → trace-id\n */\nexport const DEFAULT_TRACE_HEADERS = [\n 'traceparent',\n 'x-trace-id',\n 'x-request-id',\n 'x-correlation-id',\n 'trace-id',\n];\n\n/**\n * Create trace ID middleware for Express/NestJS\n */\nexport function createTraceMiddleware(config: TraceIdConfig) {\n const defaultExtractor = {\n header: DEFAULT_TRACE_HEADERS,\n query: ['traceId', 'trace_id'],\n };\n const resolvedConfig: TraceIdConfig = {\n ...config,\n extractor: config?.extractor ? { ...defaultExtractor, ...config.extractor } : defaultExtractor,\n };\n\n _setActiveContextKey(resolvedConfig.contextKey ?? TRACE_CONTEXT_KEY);\n\n return (req: unknown, res: unknown, next: () => void) => {\n let traceId: string | undefined;\n\n if (resolvedConfig.extractor) {\n traceId = extractTraceId(req, resolvedConfig.extractor);\n }\n\n if (!traceId) {\n traceId = resolvedConfig.generator ? resolvedConfig.generator() : generateTraceId();\n }\n\n (req as Record<string, unknown>).traceId = traceId;\n // Echo the trace ID back on the response, tolerating different response APIs:\n // Express/Node use res.setHeader(), Fastify replies use reply.header(). Guard\n // both and never let a missing/!function method (or already-sent headers)\n // crash the request — the trace ID is still propagated via async context.\n const resObj = res as {\n setHeader?: (k: string, v: string) => void;\n header?: (k: string, v: string) => void;\n headersSent?: boolean;\n };\n if (!resObj.headersSent) {\n try {\n if (typeof resObj.setHeader === 'function') {\n resObj.setHeader('X-Trace-Id', traceId);\n } else if (typeof resObj.header === 'function') {\n resObj.header('X-Trace-Id', traceId);\n }\n } catch {\n /* response not in a header-settable state — context propagation still works */\n }\n }\n\n runWithTraceId(traceId, () => next());\n };\n}\n","/**\n * Per-request trace ID resolution shared by the HTTP logger middleware and the\n * context helpers. Internal: not re-exported from the package entry points.\n */\n\nimport {\n DEFAULT_TRACE_HEADERS,\n extractTraceId,\n generateTraceId,\n sanitizeIncomingId,\n} from './trace.utils';\n\nexport type TraceHeaderOption = string | readonly string[];\n\n/** Minimal structural request shape; Express and Fastify requests satisfy it. */\nexport interface ContextRequestLike {\n headers?: Record<string, string | string[] | undefined>;\n id?: unknown;\n}\n\n/** Fastify's default `genReqId` output (`req-` + base36 counter), unique only per process. */\nconst FASTIFY_COUNTER_ID = /^req-[\\da-z]+$/;\n\nconst FALLBACK_KEY = '_logixiaFallbackId';\n\n/** Header names to read a trace ID from, defaulting to the library-wide list. */\nexport function resolveTraceHeaders(option: TraceHeaderOption | undefined): readonly string[] {\n if (option === undefined) return DEFAULT_TRACE_HEADERS;\n return typeof option === 'string' ? [option] : option;\n}\n\n/**\n * Resolve the trace ID for a request: a sanitised incoming header (honouring\n * `traceparent`), then a non-counter `request.id`, then a generated ID. Header\n * and `request.id` are recomputed per call so each caller's own header list is\n * honoured; only the generated fallback is stored on the request so every helper\n * agrees when no ID was sent.\n */\nexport function resolveRequestTraceId(req: ContextRequestLike, headers: readonly string[]): string {\n const fromHeader = extractTraceId(req, { header: [...headers] });\n if (fromHeader !== undefined) return fromHeader;\n\n const fromId = sanitizeIncomingId(req.id);\n if (fromId !== undefined && !FASTIFY_COUNTER_ID.test(fromId)) return fromId;\n\n const holder = req as Record<string, unknown>;\n const cached = holder[FALLBACK_KEY];\n if (typeof cached === 'string') return cached;\n const generated = generateTraceId();\n try {\n holder[FALLBACK_KEY] = generated;\n } catch {\n // frozen request object: each caller generates its own\n }\n return generated;\n}\n"],"mappings":"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"}
|