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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"builder-D44QktIo.js","names":["current: LogEntry","next: LogEntry | null","serialized: Record<string, unknown>","out: Record<string, unknown>","_otelApi: OtelApi | null | undefined","_bridgeOptions: OtelBridgeOptions | null","PII_CONSERVATIVE_PATTERNS: readonly RegExp[]","PII_CONSERVATIVE_PATHS: readonly string[]","PII_AGGRESSIVE_PATTERNS: readonly RegExp[]","PII_AGGRESSIVE_PATHS: readonly string[]","mergedPaths: readonly string[]","mergedPatterns: readonly RegExp[]","result: unknown[] | undefined","result: Record<string, unknown> | undefined","serialized: Record<string, unknown>","json: unknown","safeToString","OPAQUE_BUILTINS: readonly (abstract new (...args: never[]) => object)[]","activeHandler: ((signal: NodeJS.Signals) => void | Promise<void>) | undefined","activeSignals: NodeJS.Signals[]","activeOptions: FlushOnExitOptions | undefined","beforeExitHandler: (() => void) | undefined","osConstants","conflicts: string[]","TraceContext","TransportManager","normalized: GracefulShutdownConfig","_AUTO_PALETTE: readonly string[]","safeToString","traceId","LogixiaContext","mergedData: typeof data","payload: Record<string, unknown> | undefined","safeMessage: string","entry: LogEntry","finalEntry: LogEntry | null","stringifyForLog","stripControlChars","result: void | Promise<void>","TraceContext","cause: string | undefined","debug","errorBlock: LogixiaErrorResponse<TCode, TType>['error']","message: string"],"sources":["../src/types/index.ts","../src/core/default-config.ts","../src/plugin.ts","../src/utils/error.utils.ts","../src/utils/otel.ts","../src/utils/redact.utils.ts","../src/utils/sampling.utils.ts","../src/utils/shutdown.utils.ts","../src/core/logitron-logger.ts","../src/exceptions/exception.ts","../src/exceptions/builder.ts"],"sourcesContent":["/**\n * Core type definitions for Logixia Logger\n */\n\nimport type { HttpRequest, HttpResponse } from './http.types';\nimport type { TransportConfig } from './transport.types';\n\n// Log levels const object for better flexibility\nexport const LogLevel = {\n ERROR: 'error',\n WARN: 'warn',\n INFO: 'info',\n DEBUG: 'debug',\n TRACE: 'trace',\n VERBOSE: 'verbose',\n} as const;\n\nexport type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];\nexport type LogLevelString = LogLevel | (string & {});\n\n// Predefined color types\nexport type LogColor =\n | 'black'\n | 'red'\n | 'green'\n | 'yellow'\n | 'blue'\n | 'magenta'\n | 'cyan'\n | 'white'\n | 'gray'\n | 'grey'\n | 'brightRed'\n | 'brightGreen'\n | 'brightYellow'\n | 'brightBlue'\n | 'brightMagenta'\n | 'brightCyan'\n | 'brightWhite';\n\n// Predefined field keys that can be enabled/disabled\nexport type LogFieldKey =\n | 'timestamp'\n | 'level'\n | 'appName'\n | 'service'\n | 'traceId'\n | 'message'\n | 'payload'\n | 'timeTaken'\n | 'context'\n | 'userId'\n | 'sessionId'\n | 'environment';\n\n// Environment types\nexport type Environment = 'development' | 'production';\n\n// Trace ID configuration\nexport interface TraceIdExtractorConfig {\n header?: string | string[];\n query?: string | string[];\n body?: string | string[];\n params?: string | string[];\n}\n\nexport interface TraceIdConfig {\n enabled: boolean;\n generator?: () => string;\n contextKey?: string;\n extractor?: TraceIdExtractorConfig;\n /**\n * Name of the response header the middleware writes the resolved traceId\n * into (and that the exception filter echoes back on error responses).\n *\n * Defaults to `'X-Trace-Id'`. Set to `false` to suppress the response\n * header entirely (useful when the caller already supplies one and you\n * don't want to echo it back).\n *\n * @default 'X-Trace-Id'\n */\n responseHeader?: string | false;\n}\n\n// ── Redaction ──────────────────────────────────────────────────────────────────\nexport interface RedactConfig {\n /**\n * Dot-notation field paths to redact. Supports `*` (one segment) and `**` (any depth).\n * @example `['req.headers.authorization', '*.password', 'user.creditCard']`\n */\n paths?: string[];\n /**\n * Dot-notation field paths exempt from `patterns` / `autoDetect` value-pattern\n * scanning. Use this for internal identifiers whose *value* happens to look\n * like PII to a pattern (e.g. a vendor reference id embedding an epoch\n * timestamp digit-run that the aggressive phone-number pattern matches).\n *\n * Checked before pattern-based redaction (step 3): a matched field's value\n * is passed through untouched, skipping the pattern scan entirely. This does\n * NOT override `paths` — if a field matches both `paths` and `excludePaths`,\n * `paths` wins (censored), since `paths` is checked first.\n *\n * @example `['**.vendorRefId', '**.traceId', '**.interactionId']`\n */\n excludePaths?: string[];\n /**\n * Regex patterns applied to string values — replaces matches with the censor string.\n * @example `[/Bearer\\s+\\S+/gi, /sk-[a-z0-9]{32,}/gi]`\n */\n patterns?: RegExp[];\n /** Replacement value for redacted content. Default: `\"[REDACTED]\"` */\n censor?: string;\n /**\n * Auto-detect and redact common PII and secret patterns without manual configuration.\n *\n * - `true` / `'conservative'` — JWT tokens, Bearer/API-key strings, common secret field names\n * (`password`, `token`, `secret`, `apiKey`, `authorization`, `credentials`)\n * - `'aggressive'` — everything above **plus** email addresses, credit-card numbers,\n * US SSNs, phone numbers, and IP addresses\n *\n * Auto-detected patterns are applied **in addition to** any explicit `paths` / `patterns`.\n *\n * @example\n * ```ts\n * const logger = createLogger({ redact: { autoDetect: 'aggressive' } });\n * await logger.info('user signed up', { email: 'alice@example.com', password: 'hunter2' });\n * // → email: '[REDACTED]', password: '[REDACTED]'\n * ```\n */\n autoDetect?: boolean | 'conservative' | 'aggressive';\n}\n\n// ── Log Sampling ───────────────────────────────────────────────────────────────\n/**\n * Built-in log sampling / rate limiting.\n *\n * @example\n * ```ts\n * sampling: {\n * rate: 0.1, // log 10% of all entries\n * perLevel: { debug: 0.01 }, // override: debug at 1%\n * maxLogsPerSecond: 500, // hard cap — extras dropped\n * traceConsistent: true, // if a traceId is sampled, keep all logs for that trace\n * }\n * ```\n */\nexport interface SamplingConfig {\n /**\n * Global sample rate for all log levels: 0.0 (drop all) → 1.0 (keep all).\n * Default: 1.0 (no sampling).\n */\n rate?: number;\n /**\n * Per-level rate overrides. Unmentioned levels fall back to `rate`.\n * ERROR and WARN default to 1.0 even when a lower global rate is set,\n * unless you explicitly override them here.\n * @example `{ debug: 0.05, info: 0.5 }`\n */\n perLevel?: Partial<Record<string, number>>;\n /**\n * Hard cap on logs emitted per second across all levels, applied after the\n * rate / trace decision (so it also holds with `traceConsistent`). ERROR, WARN\n * and FATAL are exempt. Excess entries are dropped and counted in the stats.\n * Default: unlimited.\n */\n maxLogsPerSecond?: number;\n /**\n * When true, all log entries sharing a traceId are either all kept or all\n * dropped — preventing a sampled trace from having missing log entries.\n * Decisions are kept in a bounded LRU (100k traces, 5 min idle TTL) and\n * survive stats resets. Logs with no active trace are sampled individually.\n * Default: false.\n */\n traceConsistent?: boolean;\n /**\n * Emit a periodic sampling stats entry at this interval (ms).\n * Stats include: sampled, dropped, and rate per level over the window.\n * Set to 0 to disable. Default: 60_000 (60 s).\n */\n statsIntervalMs?: number;\n /**\n * Adaptive (anomaly-driven) sampling. When the error rate over a sliding\n * window crosses a threshold, the effective sample rate is boosted toward 1.0\n * so an incident is captured in full; in steady state it relaxes back to the\n * base `rate`. This balances high-volume cost control with not-missing-logs\n * exactly when they matter most.\n *\n * @example `{ adaptive: { errorRateThreshold: 0.05, boostRate: 1.0 } }`\n */\n adaptive?: AdaptiveSamplingConfig;\n}\n\nexport interface AdaptiveSamplingConfig {\n /**\n * Fraction of evaluated entries that must be errors within the window to\n * trigger a boost. e.g. 0.05 = boost once ≥5% of recent logs are errors.\n * Default: 0.05.\n */\n errorRateThreshold?: number;\n /**\n * Sample rate to use while boosted (overrides base `rate`/`perLevel`).\n * Default: 1.0 (keep everything during an incident).\n */\n boostRate?: number;\n /** Sliding window size in ms over which the error rate is measured. Default: 10_000. */\n windowMs?: number;\n /**\n * Minimum events in the window before the error rate is trusted (avoids\n * boosting on a single error in a quiet system). Default: 20.\n */\n minSamples?: number;\n}\n\n// ── Namespace Levels ───────────────────────────────────────────────────────────\n/**\n * Per-namespace log level overrides.\n * Keys are namespace patterns (dot-separated, `*` wildcard); values are log levels.\n *\n * @example\n * ```ts\n * namespaceLevels: {\n * 'db.*': 'debug', // all db.* namespaces → DEBUG\n * 'http.*': 'warn', // all http.* → WARN only\n * 'payment': 'trace', // payment namespace → TRACE\n * }\n * ```\n * ENV overrides: `LOGIXIA_LEVEL_DB=debug` maps to namespace `db`.\n */\nexport type NamespaceLevels = Record<string, LogLevelString>;\n\n// ── Graceful Shutdown ──────────────────────────────────────────────────────────\nexport interface GracefulShutdownConfig {\n /** Auto-register SIGTERM/SIGINT handlers to flush this logger on exit. Default: false */\n enabled: boolean;\n /** Max ms to wait for transports to flush. Default: 5000 */\n timeout?: number;\n /** Signals to listen on. Default: ['SIGTERM', 'SIGINT'] */\n signals?: NodeJS.Signals[];\n /**\n * Whether logixia ends the process after flushing. Default: 'auto' — exit only\n * when logixia is the sole listener for the signal; if the app has its own\n * handler it flushes and leaves the exit to the app. Exits with 128 + signal number.\n */\n exit?: 'auto' | 'always' | 'never';\n}\n\nexport interface LoggerConfig<TLevels extends Record<string, number> = Record<string, number>> {\n appName?: string;\n environment?: Environment;\n traceId?: boolean | TraceIdConfig;\n format?: {\n timestamp?: boolean;\n colorize?: boolean;\n json?: boolean;\n };\n silent?: boolean;\n levelOptions?:\n | {\n level?: keyof TLevels | LogLevelString;\n levels?: TLevels;\n colors?: Partial<Record<keyof TLevels | LogLevel, LogColor>>;\n }\n | undefined;\n fields?: Partial<Record<LogFieldKey, string | boolean>>;\n /**\n * Built-in log redaction — masks sensitive fields before they reach any transport.\n * @see RedactConfig\n */\n redact?: RedactConfig;\n /**\n * Per-namespace log level overrides.\n * A child logger's context is used as its namespace for matching.\n * ENV vars `LOGIXIA_LEVEL_<NS>=<level>` also apply.\n */\n namespaceLevels?: NamespaceLevels;\n /**\n * Automatically register SIGTERM/SIGINT handlers that flush all transports\n * before the process exits — prevents losing the last N seconds of logs on\n * deployments / restarts.\n */\n gracefulShutdown?: boolean | GracefulShutdownConfig;\n /**\n * Built-in log sampling & rate limiting.\n * Completely missing from all existing loggers — eliminates the need to\n * implement sampling logic in application code.\n */\n sampling?: SamplingConfig;\n /** Transport configuration — console, file, database, analytics, etc. */\n transports?: TransportConfig;\n [key: string]: unknown;\n}\n\n// Base logger interface with standard methods\nexport interface IBaseLogger {\n error(message: string, data?: Record<string, unknown>): Promise<void>;\n error(error: Error, data?: Record<string, unknown>): Promise<void>;\n warn(message: string, data?: Record<string, unknown>): Promise<void>;\n info(message: string, data?: Record<string, unknown>): Promise<void>;\n debug(message: string, data?: Record<string, unknown>): Promise<void>;\n trace(message: string, data?: Record<string, unknown>): Promise<void>;\n verbose(message: string, data?: Record<string, unknown>): Promise<void>;\n logLevel(level: string, message: string, data?: Record<string, unknown>): Promise<void>;\n\n time(label: string): void;\n timeEnd(label: string): Promise<number | undefined>;\n timeAsync<T>(label: string, fn: () => Promise<T>): Promise<T>;\n\n setLevel(level: LogLevel | string): void;\n getLevel(): string;\n setContext(context: string): void;\n getContext(): string | undefined;\n\n // Field Management Methods\n enableField(fieldName: string): void;\n disableField(fieldName: string): void;\n isFieldEnabled(fieldName: string): boolean;\n getFieldState(): Record<string, boolean>;\n resetFieldState(): void;\n\n // Transport Level Management Methods\n /** @deprecated No-op. Library code never prompts on stdin; use setTransportLevels(). */\n enableTransportLevelPrompting(): void;\n /** @deprecated No-op. */\n disableTransportLevelPrompting(): void;\n setTransportLevels(transportId: string, levels: string[]): void;\n getTransportLevels(transportId: string): string[] | undefined;\n clearTransportLevelPreferences(): void;\n getAvailableTransports(): string[];\n\n child(context: string, data?: Record<string, unknown>): ILogger;\n close(): Promise<void>;\n\n // Plugin API (Feature 20)\n // Typed as unknown to avoid a circular import between types/index.ts and plugin.ts.\n // The concrete LogixiaLogger class constrains this to LogixiaPlugin.\n use(plugin: { name: string }): this;\n unuse(pluginName: string): this;\n}\n\n// Type for custom level methods based on config\nexport type CustomLevelMethods<T extends Record<string, number>> = {\n [K in keyof T]: (message: string, data?: Record<string, unknown>) => Promise<void>;\n};\n\n// Generic logger type that combines base logger with custom level methods\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- empty default is intentional for optional generic\nexport type ILogger<TLevels extends Record<string, number> = {}> = IBaseLogger &\n CustomLevelMethods<TLevels>;\n\n// Default logger interface for backward compatibility\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- marker interface for backward compat\nexport interface ILoggerDefault extends IBaseLogger {}\n\n// Helper type to create logger with specific custom levels\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- generic type needs any to accept all LoggerConfig shapes\nexport type LoggerWithLevels<T extends LoggerConfig<any>> = T['levelOptions'] extends {\n levels: infer L;\n}\n ? L extends Record<string, number>\n ? ILogger<L>\n : ILoggerDefault\n : ILoggerDefault;\n\n// Helper type to extract levels from config for IntelliSense\nexport type ExtractLevels<T> = T extends LoggerConfig<infer L> ? L : Record<string, number>;\n\n// Log entry interface\nexport interface LogEntry {\n timestamp: string;\n level: string;\n appName: string;\n environment?: string;\n traceId?: string;\n message: string;\n payload?: Record<string, unknown>;\n context?: string;\n error?: Error;\n}\n\n// Error serialization options\nexport interface ErrorSerializationOptions {\n includeStack?: boolean;\n maxDepth?: number;\n excludeFields?: string[];\n}\n\n// Timing entry interface\nexport interface TimingEntry {\n label: string;\n startTime: number;\n endTime?: number;\n duration?: number;\n}\n\n// Context data interface\nexport interface ContextData {\n [key: string]: unknown;\n}\n\n// Log formatter interface\nexport interface ILogFormatter {\n format(entry: LogEntry): string;\n}\n\n// Request context interface for tracking request lifecycle\nexport interface RequestContext {\n traceId: string;\n startTime: number;\n endTime?: number;\n duration?: number;\n request: HttpRequest;\n response?: HttpResponse;\n error?: Error;\n userId?: string;\n sessionId?: string;\n userAgent?: string;\n ip?: string;\n}\n\n// Default log levels with colors\nexport const DEFAULT_LOG_LEVELS = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n verbose: 5,\n};\n\nexport const DEFAULT_LOG_COLORS = {\n error: 'red',\n warn: 'yellow',\n info: 'green',\n debug: 'blue',\n trace: 'magenta',\n verbose: 'cyan',\n};\n\n// Additional exports for compatibility\nexport type { LoggerConfig as LoggerConfigInterface };\n\n// Export all HTTP types\nexport * from './http.types';\n","import type { Environment, LogColor } from '../types';\nimport { LogLevel } from '../types';\n\n/**\n * Default configuration for Logixia logger\n */\nexport const DEFAULT_CONFIG = {\n appName: 'App',\n environment: 'development' as Environment,\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 [LogLevel.ERROR]: 0,\n [LogLevel.WARN]: 1,\n [LogLevel.INFO]: 2,\n [LogLevel.DEBUG]: 3,\n [LogLevel.TRACE]: 4,\n [LogLevel.VERBOSE]: 5,\n },\n colors: {\n [LogLevel.ERROR]: 'red',\n [LogLevel.WARN]: 'yellow',\n [LogLevel.INFO]: 'blue',\n [LogLevel.DEBUG]: 'green',\n [LogLevel.TRACE]: 'gray',\n [LogLevel.VERBOSE]: 'cyan',\n } as Record<string, LogColor>,\n },\n fields: {\n timestamp: true,\n level: true,\n appName: true,\n traceId: true,\n message: true,\n payload: true,\n timeTaken: true,\n },\n outputs: ['console'],\n};\n","/**\n * logixia — Plugin / Extension API\n *\n * Provides a formal plugin interface so community code and internal extensions\n * can add transports, transformers, and middleware without forking the core.\n *\n * Lifecycle hooks (in call order):\n * 1. `onInit` — called once immediately after `logger.use(plugin)`\n * 2. `onLog` — called for every log entry, post-redaction, pre-transport\n * 3. `onError` — called when a transport write fails\n * 4. `onShutdown` — called when the logger is closed\n *\n * @example Custom plugin\n * ```ts\n * import { LogixiaPlugin, usePlugin } from 'logixia';\n *\n * const sentryPlugin: LogixiaPlugin = {\n * name: 'sentry',\n * onError(err) { Sentry.captureException(err); },\n * onLog(entry) {\n * // enrich every entry with a build tag\n * return { ...entry, payload: { ...entry.payload, buildId: process.env.BUILD_ID } };\n * },\n * };\n *\n * logger.use(sentryPlugin); // per-instance\n * usePlugin(sentryPlugin); // global — applied to all future logger instances\n * ```\n */\n\nimport type { LogEntry } from './types/index';\n\n// ── Plugin interface ──────────────────────────────────────────────────────────\n\nexport interface LogixiaPlugin {\n /**\n * Unique plugin name.\n * logixia uses this to prevent duplicate registration of the same plugin\n * on the same logger instance.\n */\n name: string;\n\n /**\n * Called once immediately after `logger.use(plugin)` is called.\n * Use for one-time setup (open connections, allocate buffers, etc.).\n * Async `onInit` errors are silently swallowed to avoid blocking the logger.\n */\n onInit?(): void | Promise<void>;\n\n /**\n * Called for every log entry **after** PII redaction and **before** transport\n * dispatch. Plugins run in registration order; each receives the (possibly\n * modified) output of the previous plugin.\n *\n * - Return the entry (modified or unchanged) to continue processing.\n * - Return `null` to **drop** the entry — no transport will receive it.\n *\n * Errors thrown inside `onLog` are swallowed so a buggy plugin cannot crash\n * logging; the chain continues with the previous (un-transformed) entry.\n */\n onLog?(entry: LogEntry): LogEntry | null | Promise<LogEntry | null>;\n\n /**\n * Called when a transport write fails (after any configured retries).\n * Useful for routing transport errors to an alerting or metrics system.\n * Errors thrown inside `onError` are silently swallowed.\n */\n onError?(error: Error, entry?: LogEntry): void | Promise<void>;\n\n /**\n * Called when the logger is closed via `logger.close()` or the process\n * receives a shutdown signal (when `gracefulShutdown` is enabled).\n * Errors thrown inside `onShutdown` are silently swallowed.\n */\n onShutdown?(): void | Promise<void>;\n}\n\n// ── PluginRegistry ────────────────────────────────────────────────────────────\n\n/**\n * Holds an ordered list of `LogixiaPlugin` instances and dispatches lifecycle\n * events to them. One registry is created per logger instance; a global\n * singleton is also exported for process-wide registration.\n */\nexport class PluginRegistry {\n private readonly _plugins: LogixiaPlugin[] = [];\n\n /**\n * Register a plugin. Silently skips if a plugin with the same `name` is\n * already registered on this registry.\n */\n register(plugin: LogixiaPlugin): void {\n if (this._plugins.some((p) => p.name === plugin.name)) return;\n this._plugins.push(plugin);\n if (plugin.onInit) {\n // Isolate onInit: a synchronous throw must not propagate to the caller of\n // register()/use() (the docs promise onInit errors are swallowed). The\n // async branch is guarded with .catch for the same reason.\n try {\n const result = plugin.onInit();\n if (result instanceof Promise) result.catch(() => {});\n } catch {\n /* swallow — a buggy onInit must not break registration */\n }\n }\n }\n\n /** Remove a previously registered plugin by name. No-op if not found. */\n unregister(name: string): void {\n const idx = this._plugins.findIndex((p) => p.name === name);\n if (idx !== -1) this._plugins.splice(idx, 1);\n }\n\n /** Returns `true` if a plugin with the given name is registered. */\n has(name: string): boolean {\n return this._plugins.some((p) => p.name === name);\n }\n\n /** Number of currently registered plugins. */\n get size(): number {\n return this._plugins.length;\n }\n\n /**\n * Run all `onLog` hooks in order.\n * Returns `null` if any plugin cancels the entry; otherwise returns the\n * (possibly transformed) entry.\n */\n async runOnLog(entry: LogEntry): Promise<LogEntry | null> {\n let current: LogEntry = entry;\n for (const plugin of this._plugins) {\n if (!plugin.onLog) continue;\n let next: LogEntry | null;\n try {\n next = await plugin.onLog(current);\n } catch {\n // Isolate buggy plugins: a throwing onLog must not crash logging.\n // Skip this plugin and continue the chain with the un-transformed entry.\n continue;\n }\n if (next === null) return null;\n current = next;\n }\n return current;\n }\n\n /**\n * Notify all `onError` hooks.\n * Errors thrown inside hooks are swallowed to prevent error cascades.\n */\n async runOnError(error: Error, entry?: LogEntry): Promise<void> {\n for (const plugin of this._plugins) {\n if (plugin.onError) {\n // Guard the SYNCHRONOUS call too — a sync throw here would otherwise\n // propagate out of runOnError and turn a recoverable transport failure\n // (the very thing onError exists to report) into a crash.\n try {\n const r = plugin.onError(error, entry);\n if (r instanceof Promise) await r.catch(() => {});\n } catch {\n /* swallow — onError hooks must never crash error handling */\n }\n }\n }\n }\n\n /** Run all `onShutdown` hooks concurrently. Hook errors are swallowed. */\n async runOnShutdown(): Promise<void> {\n await Promise.all(\n this._plugins\n .filter((p) => Boolean(p.onShutdown))\n .map((p) => {\n // Guard the synchronous call: a sync throw in onShutdown would reject\n // this map and, via Promise.all, break graceful shutdown → log loss.\n try {\n const r = p.onShutdown!();\n return r instanceof Promise ? r.catch(() => {}) : Promise.resolve();\n } catch {\n return Promise.resolve();\n }\n })\n );\n }\n}\n\n// ── Global registry ───────────────────────────────────────────────────────────\n\n/**\n * Module-level singleton registry.\n *\n * Plugins registered here are automatically copied into every **new** logger\n * instance created after the registration. Already-created loggers are not\n * retroactively affected — use `logger.use(plugin)` for per-instance control.\n */\nexport const globalPluginRegistry = new PluginRegistry();\n\n/**\n * Register a plugin in the global registry so it applies to every future\n * logger instance.\n *\n * @example\n * ```ts\n * import { usePlugin } from 'logixia';\n *\n * usePlugin({\n * name: 'audit-sink',\n * onLog(entry) {\n * if (entry.level === 'error') auditQueue.push(entry);\n * return entry;\n * },\n * });\n * ```\n */\nexport function usePlugin(plugin: LogixiaPlugin): void {\n globalPluginRegistry.register(plugin);\n}\n","/**\n * Error serialization utilities for Logixia\n *\n * v1.1 improvements:\n * - Full ES2022 `cause` chain serialization (recursive)\n * - AggregateError.errors array serialization\n * - Standard extra fields: code, statusCode, status, errno, syscall, path\n * - Circular-reference safe via a WeakSet seen guard\n */\n\nimport type { ErrorSerializationOptions } from '../types';\n\n// Well-known extra fields to always capture when present on an error\nconst EXTRA_FIELDS = [\n 'code',\n 'statusCode',\n 'status',\n 'errno',\n 'syscall',\n 'path',\n 'address',\n 'port',\n 'type',\n] as const;\n\n/**\n * Serialize an Error into a plain JSON-safe object, including:\n * - `name`, `message`, `stack`\n * - `cause` (recursively serialized, full ES2022 chain)\n * - `errors` (for AggregateError)\n * - standard Node.js error fields (`code`, `statusCode`, `errno`, …)\n * - any other enumerable own properties\n */\nexport function serializeError(\n error: Error,\n options: ErrorSerializationOptions = {}\n): Record<string, unknown> {\n const { includeStack = true, maxDepth = 5, excludeFields = [] } = options;\n const seen = new WeakSet<object>();\n return _serializeError(error, includeStack, maxDepth, excludeFields, 0, seen);\n}\n\nfunction _serializeError(\n error: Error,\n includeStack: boolean,\n maxDepth: number,\n excludeFields: string[],\n depth: number,\n seen: WeakSet<object>\n): Record<string, unknown> {\n if (depth >= maxDepth) {\n return { name: error.name, message: error.message, _truncated: true };\n }\n\n if (seen.has(error)) {\n return { name: error.name, message: error.message, _circular: true };\n }\n seen.add(error);\n\n const serialized: Record<string, unknown> = {\n name: error.name,\n message: error.message,\n };\n\n if (includeStack && error.stack) {\n serialized.stack = error.stack;\n }\n\n // ── ES2022 cause chain ──────────────────────────────────────────────────────\n const errorWithCause = error as Error & { cause?: unknown };\n if (errorWithCause.cause !== undefined) {\n if (errorWithCause.cause instanceof Error) {\n serialized.cause = _serializeError(\n errorWithCause.cause,\n includeStack,\n maxDepth,\n excludeFields,\n depth + 1,\n seen\n );\n } else {\n serialized.cause = serializeValue(errorWithCause.cause, maxDepth - depth - 1, seen);\n }\n }\n\n // ── AggregateError.errors ───────────────────────────────────────────────────\n const aggregateError = error as Error & { errors?: unknown[] };\n if (Array.isArray(aggregateError.errors)) {\n serialized.errors = aggregateError.errors.map((e) =>\n e instanceof Error\n ? _serializeError(e, includeStack, maxDepth, excludeFields, depth + 1, seen)\n : serializeValue(e, maxDepth - depth - 1, seen)\n );\n }\n\n // ── Standard Node.js / HTTP error fields ───────────────────────────────────\n const errorRecord = error as unknown as Record<string, unknown>;\n for (const field of EXTRA_FIELDS) {\n if (!excludeFields.includes(field) && field in error && errorRecord[field] !== undefined) {\n serialized[field] = errorRecord[field];\n }\n }\n\n // ── All other own enumerable properties ────────────────────────────────────\n const skip = new Set<string>([\n 'name',\n 'message',\n 'stack',\n 'cause',\n 'errors',\n ...EXTRA_FIELDS,\n ...excludeFields,\n ]);\n\n for (const key of Object.getOwnPropertyNames(error)) {\n if (skip.has(key)) continue;\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;\n try {\n serialized[key] = serializeValue(errorRecord[key], maxDepth - depth - 1, seen);\n } catch {\n serialized[key] = '[Unserializable]';\n }\n }\n\n return serialized;\n}\n\n/**\n * Recursively serialize an arbitrary value to a JSON-safe representation.\n *\n * The `seen` guard is threaded through (not recreated) so cross-referencing\n * errors nested inside plain objects/arrays are caught by the same circular\n * check that protects the top-level error tree, rather than only relying on the\n * depth limit.\n */\nfunction serializeValue(value: unknown, remainingDepth: number, seen: WeakSet<object>): unknown {\n if (remainingDepth <= 0) return '[Max Depth]';\n if (value === null || value === undefined) return value;\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value;\n }\n\n if (value instanceof Date) return value.toISOString();\n\n if (value instanceof Error) {\n if (seen.has(value)) {\n return { name: value.name, message: value.message, _circular: true };\n }\n return _serializeError(value, true, remainingDepth, [], 0, seen);\n }\n\n if (Array.isArray(value)) {\n if (seen.has(value)) return '[Circular]';\n seen.add(value);\n return value.map((item) => serializeValue(item, remainingDepth - 1, seen));\n }\n\n if (typeof value === 'object') {\n if (seen.has(value)) return '[Circular]';\n seen.add(value);\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (k === '__proto__' || k === 'constructor' || k === 'prototype') continue;\n try {\n out[k] = serializeValue(v, remainingDepth - 1, seen);\n } catch {\n out[k] = '[Unserializable]';\n }\n }\n return out;\n }\n\n return String(value);\n}\n\n/**\n * Type guard: returns true if the value looks like an Error object.\n */\nexport function isError(value: unknown): value is Error {\n return (\n value instanceof Error ||\n (Boolean(value) &&\n typeof value === 'object' &&\n 'name' in (value as object) &&\n 'message' in (value as object))\n );\n}\n\n/**\n * Coerce any thrown value into a proper Error instance.\n */\nexport function normalizeError(error: unknown): Error {\n if (isError(error)) return error;\n\n if (typeof error === 'string') return new Error(error);\n\n if (typeof error === 'object' && error !== null) {\n const e = error as Record<string, unknown>;\n const err = new Error(typeof e['message'] === 'string' ? e['message'] : 'Unknown error');\n Object.assign(err, error);\n return err;\n }\n\n return new Error(String(error));\n}\n","/**\n * logixia — OpenTelemetry auto trace-log correlation\n *\n * Zero-config: if `@opentelemetry/api` is installed, logixia automatically\n * reads the active span context and injects `traceId`, `spanId`, and\n * `traceFlags` into every log entry. No manual wiring needed.\n *\n * The integration is completely optional — if `@opentelemetry/api` is absent\n * (or the OTel SDK is not initialised), all helpers return `undefined` silently.\n *\n * Additionally exposes a `createOtelLogExporter()` factory that routes every\n * logixia log entry through the active OTel LoggerProvider (OTLP export).\n *\n * @example Auto bridge (zero config)\n * ```ts\n * import { createLogger } from 'logixia';\n * import { initOtelBridge } from 'logixia';\n *\n * // Call once at app startup, after your OTel SDK is initialised\n * initOtelBridge();\n *\n * const logger = createLogger({ appName: 'api' });\n * // Every logger.info / warn / error call now auto-injects traceId + spanId\n * // from the currently active OTel span — no per-call code needed.\n * ```\n *\n * @example Manual span context injection\n * ```ts\n * import { getActiveOtelContext } from 'logixia';\n *\n * const ctx = getActiveOtelContext();\n * await logger.info('Payment processed', { ...ctx, orderId: 'ord_123' });\n * // → { traceId: 'abc...', spanId: 'def...', traceFlags: 1, orderId: 'ord_123' }\n * ```\n */\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface OtelSpanContext {\n /** W3C 32-hex-char trace ID */\n traceId: string;\n /** W3C 16-hex-char span ID */\n spanId: string;\n /** W3C trace-flags integer (1 = sampled) */\n traceFlags: number;\n /** Whether this context is from a valid, sampled span */\n isSampled: boolean;\n}\n\nexport interface OtelBridgeOptions {\n /**\n * Field name written to log entries for the trace ID.\n * @default 'traceId'\n */\n traceIdField?: string;\n /**\n * Field name written to log entries for the span ID.\n * @default 'spanId'\n */\n spanIdField?: string;\n /**\n * Field name written to log entries for trace flags.\n * @default 'traceFlags'\n */\n traceFlagsField?: string;\n /**\n * Only inject context when the span is sampled (traceFlags bit 1 set).\n * @default false\n */\n sampledOnly?: boolean;\n}\n\n// ── OTel API dynamic import ───────────────────────────────────────────────────\n\ntype OtelApi = {\n context: { active(): unknown };\n trace: {\n getSpanContext(\n ctx: unknown\n ): { traceId: string; spanId: string; traceFlags: number } | undefined;\n isSpanContextValid(sc: { traceId: string; spanId: string; traceFlags: number }): boolean;\n TraceFlags: { SAMPLED: number };\n };\n};\n\nlet _otelApi: OtelApi | null | undefined; // undefined = not yet resolved; null = not available\n\nfunction tryLoadOtelApi(): OtelApi | null {\n if (_otelApi !== undefined) return _otelApi;\n try {\n // Dynamic require so the package stays optional — no hard peer dep\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n _otelApi = require('@opentelemetry/api') as OtelApi;\n return _otelApi;\n } catch {\n _otelApi = null;\n return null;\n }\n}\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Read the currently active OTel span context (if any) and return its fields\n * in a plain object suitable for spreading into a log entry.\n *\n * Returns `undefined` when:\n * - `@opentelemetry/api` is not installed\n * - No active span exists (root context)\n * - The span context is invalid (all-zeros)\n */\nexport function getActiveOtelContext(opts: OtelBridgeOptions = {}): OtelSpanContext | undefined {\n const api = tryLoadOtelApi();\n if (!api) return undefined;\n\n // Wrap the whole OTel interaction: this runs on EVERY log call via the bridge,\n // and a broken/mismatched OTel SDK whose context/trace methods throw would\n // otherwise crash logging itself. The integration is meant to be silent — on\n // any failure we just skip injection.\n try {\n const ctx = api.context.active();\n const sc = api.trace.getSpanContext(ctx);\n if (!sc || !api.trace.isSpanContextValid(sc)) return undefined;\n\n const isSampled =\n (sc.traceFlags & api.trace.TraceFlags.SAMPLED) === api.trace.TraceFlags.SAMPLED;\n\n if (opts.sampledOnly && !isSampled) return undefined;\n\n return {\n traceId: sc.traceId,\n spanId: sc.spanId,\n traceFlags: sc.traceFlags,\n isSampled,\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Returns a metadata object with OTel context fields ready to merge into a log call,\n * using the configured field names.\n *\n * Returns `{}` when no active span exists (safe to spread unconditionally).\n *\n * @example\n * ```ts\n * await logger.info('Payment processed', {\n * ...getOtelMetaFields(),\n * orderId: 'ord_123',\n * });\n * ```\n */\nexport function getOtelMetaFields(opts: OtelBridgeOptions = {}): Record<string, unknown> {\n const { traceIdField = 'traceId', spanIdField = 'spanId', traceFlagsField = 'traceFlags' } = opts;\n\n const ctx = getActiveOtelContext(opts);\n if (!ctx) return {};\n\n return {\n [traceIdField]: ctx.traceId,\n [spanIdField]: ctx.spanId,\n [traceFlagsField]: ctx.traceFlags,\n };\n}\n\n// ── Module-level bridge state ─────────────────────────────────────────────────\n\nlet _bridgeOptions: OtelBridgeOptions | null = null;\n\n/**\n * Initialise the global OTel bridge.\n *\n * Once called, logixia's internal log pipeline checks for an active OTel span\n * on **every** log call and automatically merges the span context into the\n * entry's metadata — no per-call wiring needed.\n *\n * Call once at app startup, **after** the OTel SDK has been initialised:\n * ```ts\n * import { initOtelBridge } from 'logixia';\n * initOtelBridge();\n * ```\n */\nexport function initOtelBridge(opts: OtelBridgeOptions = {}): void {\n _bridgeOptions = opts;\n}\n\n/**\n * @internal\n * True when initOtelBridge() has been called. Lets the logger hot path skip the\n * `_getOtelPayloadIfEnabled()` call (and its `{}` allocation + Object.keys) on\n * every log when the bridge is off — the overwhelmingly common case.\n */\nexport function _isOtelBridgeEnabled(): boolean {\n return _bridgeOptions !== null;\n}\n\n/**\n * @internal\n * Used by the core logger to inject OTel context when the bridge is active.\n * Returns `{}` when the bridge is not initialised or no active span exists.\n */\nexport function _getOtelPayloadIfEnabled(): Record<string, unknown> {\n if (!_bridgeOptions) return {};\n return getOtelMetaFields(_bridgeOptions);\n}\n\n/**\n * Disable the OTel bridge (useful for tests).\n */\nexport function disableOtelBridge(): void {\n _bridgeOptions = null;\n}\n","/**\n * Log redaction utilities for Logixia\n *\n * Solves the #1 logging security problem: sensitive data (PII, secrets, tokens)\n * being logged to transports that shouldn't have them.\n *\n * Addresses Winston issue #1079 \"redacting secrets\" which has been open for years\n * with no built-in solution.\n *\n * @example\n * ```ts\n * const logger = createLogger({\n * redact: {\n * paths: ['req.headers.authorization', '*.password', 'user.creditCard', 'token'],\n * patterns: [/Bearer\\s+\\S+/gi, /sk-[a-z0-9]{32,}/gi],\n * censor: '[REDACTED]',\n * }\n * });\n * ```\n */\n\nimport type { RedactConfig } from '../types';\nimport { safeToString } from './coerce.utils';\nimport { serializeError } from './error.utils';\n\nexport type { RedactConfig };\n\nconst DEFAULT_CENSOR = '[REDACTED]';\n\n/** Maximum nesting depth walked; deeper values are replaced with a marker. */\nconst MAX_DEPTH = 32;\n/** Maximum number of objects/arrays visited per redaction pass. */\nconst MAX_NODES = 10_000;\n/**\n * Strings longer than this are truncated before pattern scanning. The tail is\n * dropped rather than emitted unscanned, so oversized input can never carry an\n * unredacted secret past the patterns.\n */\nconst MAX_SCAN_LENGTH = 16_384;\nconst MAX_DEPTH_MARKER = '[MaxDepth]';\nconst MAX_NODES_MARKER = '[MaxNodes]';\nexport const REDACTION_FAILED = '[RedactionFailed]';\n\n// ── Built-in PII / secret patterns ──────────────────────────────────────────\n\n/**\n * Conservative patterns: tokens and secrets that should NEVER appear in logs.\n * Applied when `autoDetect: true` or `autoDetect: 'conservative'`.\n */\nconst PII_CONSERVATIVE_PATTERNS: readonly RegExp[] = [\n // JWT tokens (three base64url segments separated by dots); segment lengths are\n // bounded so scanning stays linear on adversarial input\n /eyJ[A-Za-z0-9_-]{1,1024}\\.[A-Za-z0-9_-]{1,16384}\\.[A-Za-z0-9_-]{0,1024}/g,\n // Bearer / Token auth header values\n // eslint-disable-next-line sonarjs/duplicates-in-character-class\n /Bearer\\s+[A-Za-z0-9._~+/-]+=*/gi,\n // Generic API key patterns (sk-, pk-, api-, etc.)\n // eslint-disable-next-line sonarjs/duplicates-in-character-class\n /\\b(?:sk|pk|api|key|secret|token)-[A-Za-z0-9_-]{16,}/gi,\n // AWS-style access key IDs\n /\\bAKIA[0-9A-Z]{16}\\b/g,\n // AWS secret access keys, recognised by the adjacent key name\n // eslint-disable-next-line sonarjs/duplicates-in-character-class\n /secret[_-]?(?:access[_-]?)?key[\"'\\s:=]{1,6}[A-Za-z0-9/+]{40}(?![A-Za-z0-9/+])/gi,\n];\n\n/**\n * Conservative field-name paths auto-redacted by name regardless of value.\n */\nconst PII_CONSERVATIVE_PATHS: readonly string[] = [\n '**.password',\n '**.passwd',\n '**.secret',\n '**.token',\n '**.apiKey',\n '**.api_key',\n '**.accessToken',\n '**.access_token',\n '**.refreshToken',\n '**.refresh_token',\n '**.authorization',\n '**.credentials',\n '**.privateKey',\n '**.private_key',\n '**.clientSecret',\n '**.client_secret',\n '**.cookie',\n '**.set-cookie',\n '**.x-api-key',\n '**.session',\n '**.proxy-authorization',\n '**.x-auth-token',\n '**.x-access-token',\n '**.aws_secret_access_key',\n '**.awsSecretAccessKey',\n '**.secretAccessKey',\n];\n\n/**\n * Aggressive patterns: also catch personal data that could identify a person.\n * Applied when `autoDetect: 'aggressive'`.\n */\nconst PII_AGGRESSIVE_PATTERNS: readonly RegExp[] = [\n // Email addresses\n /\\b[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\\.[A-Za-z]{2,24}\\b/g,\n // US Social Security Numbers (XXX-XX-XXXX or XXXXXXXXX)\n /\\b\\d{3}-?\\d{2}-?\\d{4}\\b/g,\n // Credit / debit card numbers (13-19 digits, optional spaces/dashes)\n /\\b(?:\\d[ -]?){13,19}\\b/g,\n // US phone numbers\n /\\b(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\\b/g,\n // IPv4 addresses\n /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g,\n];\n\nconst PII_AGGRESSIVE_PATHS: readonly string[] = [\n ...PII_CONSERVATIVE_PATHS,\n '**.email',\n '**.emailAddress',\n '**.email_address',\n '**.phone',\n '**.phoneNumber',\n '**.phone_number',\n '**.mobile',\n '**.ssn',\n '**.sin',\n '**.dob',\n '**.dateOfBirth',\n '**.date_of_birth',\n '**.creditCard',\n '**.credit_card',\n '**.cardNumber',\n '**.card_number',\n '**.cvv',\n '**.cvc',\n '**.ipAddress',\n '**.ip_address',\n];\n\n/**\n * Build an effective config that merges `autoDetect` PII rules into the\n * explicit `paths` and `patterns` the caller provided.\n */\nfunction resolveConfig(config: RedactConfig): RedactConfig {\n const { autoDetect } = config;\n const { paths = [], patterns = [] } = config;\n\n let mergedPaths: readonly string[] = paths;\n let mergedPatterns: readonly RegExp[] = patterns;\n\n if (autoDetect) {\n const aggressive = autoDetect === 'aggressive';\n const extraPaths = aggressive ? PII_AGGRESSIVE_PATHS : PII_CONSERVATIVE_PATHS;\n const extraPatterns = aggressive\n ? [...PII_CONSERVATIVE_PATTERNS, ...PII_AGGRESSIVE_PATTERNS]\n : PII_CONSERVATIVE_PATTERNS;\n mergedPaths = [...paths, ...extraPaths];\n mergedPatterns = [...patterns, ...extraPatterns];\n }\n\n // Filter out non-strings / non-RegExps: callers occasionally pass through\n // env-derived arrays that contain `undefined` entries (e.g.\n // `LOGIXIA_REDACT=,foo,`), and a non-string would crash `pathToRegExp`'s\n // split/replace pipeline.\n return {\n ...config,\n paths: mergedPaths.filter((p): p is string => typeof p === 'string'),\n patterns: mergedPatterns.filter((p): p is RegExp => p instanceof RegExp),\n };\n}\n\n/**\n * Convert a dot-notation path pattern to a RegExp.\n * Supports `*` (exactly one segment) and `**` (zero or more segments).\n *\n * Because `**` may match *zero* segments, it also absorbs the dot separator\n * that joins it to its neighbour — so `**.password` matches both a bare\n * top-level `password` (zero leading segments) and any nested `*.password`.\n *\n * Examples:\n * \"password\" → /^password$/\n * \"user.password\" → /^user\\.password$/\n * \"*.token\" → /^[^.]+\\.token$/\n * \"req.headers.*\" → /^req\\.headers\\.[^.]+$/\n * \"**\" → /^.*$/\n * \"**.password\" → /^(?:.*\\.)?password$/ (matches `password` and `a.b.password`)\n * \"req.**\" → /^req(?:\\..*)?$/ (matches `req` and `req.a.b`)\n *\n * Consecutive `**` segments are collapsed (`a.**.**.b` ≡ `a.**.b`).\n */\nfunction pathToRegExp(pattern: string): RegExp {\n // Collapse runs of consecutive `**` — they are semantically redundant\n // (`a.**.**.b` ≡ `a.**.b`) and would otherwise emit two optional groups that\n // fight over the shared separator and fail to match zero-segment paths.\n const segments = pattern\n .split('.')\n .filter((seg, i, arr) => !(seg === '**' && arr[i - 1] === '**'));\n const lastIndex = segments.length - 1;\n\n let regexStr = '';\n for (const [i, segment] of segments.entries()) {\n // A `**` token emits an optional group that already contains the dot on\n // one side, so the matching boundary separator must NOT be emitted here:\n // - a non-final `**` (leading/middle) → group `(?:.*\\.)?` owns its RIGHT dot\n // - a trailing `**` → group `(?:\\..*)?` owns its LEFT dot\n // Every other boundary (including a middle `**`'s structural LEFT dot) is a\n // literal `\\.`.\n const prevOwnsRightDot = i > 0 && segments[i - 1] === '**' && i - 1 < lastIndex;\n const ownsLeftDot = segment === '**' && i === lastIndex && i > 0;\n if (i > 0 && !prevOwnsRightDot && !ownsLeftDot) {\n regexStr += String.raw`\\.`;\n }\n\n if (segment === '**') {\n // `**` = zero or more path segments.\n if (lastIndex === 0) {\n regexStr += '.*'; // standalone `**`\n } else if (i === lastIndex) {\n regexStr += String.raw`(?:\\..*)?`; // trailing `X.**` — optional \".segs\"\n } else {\n regexStr += String.raw`(?:.*\\.)?`; // leading/middle — optional \"segs.\"\n }\n continue;\n }\n\n regexStr += segment === '*' ? '[^.]+' : segment.replace(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&');\n }\n\n return new RegExp(`^${regexStr}$`, 'i');\n}\n\n/** Pre-compiled path matchers keyed by pattern string for perf */\nconst patternCache = new Map<string, RegExp>();\n\nfunction matchesPath(fullPath: string, pattern: string): boolean {\n let re = patternCache.get(pattern);\n if (!re) {\n re = pathToRegExp(pattern);\n patternCache.set(pattern, re);\n }\n return re.test(fullPath);\n}\n\nfunction isTokenChar(code: number): boolean {\n return (\n (code >= 48 && code <= 57) || // 0-9\n (code >= 65 && code <= 90) || // A-Z\n (code >= 97 && code <= 122) || // a-z\n code === 46 || // .\n code === 95 || // _\n code === 126 || // ~\n code === 43 || // +\n code === 47 || // /\n code === 61 || // =\n code === 45 // -\n );\n}\n\nfunction applyPatterns(value: string, patterns: readonly RegExp[], censor: string): string {\n let redacted = value;\n let suffix = '';\n if (redacted.length > MAX_SCAN_LENGTH) {\n // Drop the trailing run of token characters so a secret straddling the cut\n // is removed whole rather than emitted as an unredactable prefix.\n let end = MAX_SCAN_LENGTH;\n while (end > 0 && isTokenChar(redacted.charCodeAt(end - 1))) end--;\n suffix = `…[truncated ${value.length - end} unscanned chars]`;\n redacted = redacted.slice(0, end);\n }\n for (const pattern of patterns) {\n redacted = redacted.replace(pattern, censor);\n }\n return redacted + suffix;\n}\n\nconst CIRCULAR = '[Circular]';\n\ninterface WalkState {\n config: RedactConfig;\n ancestors: Set<object>;\n nodes: number;\n}\n\nfunction joinPath(parent: string, key: string): string {\n return parent ? `${parent}.${key}` : key;\n}\n\nfunction walkValue(\n value: unknown,\n state: WalkState,\n fullPath: string,\n bare: string,\n depth: number\n): unknown {\n const { paths = [], excludePaths = [], patterns = [], censor = DEFAULT_CENSOR } = state.config;\n\n if (paths.some((p) => matchesPath(fullPath, p) || matchesPath(bare, p))) {\n return censor;\n }\n\n if (typeof value === 'object' && value !== null) {\n if (depth >= MAX_DEPTH) return MAX_DEPTH_MARKER;\n if (++state.nodes > MAX_NODES) return MAX_NODES_MARKER;\n }\n\n if (typeof value === 'string') {\n if (patterns.length === 0) return value;\n if (excludePaths.some((p) => matchesPath(fullPath, p) || matchesPath(bare, p))) return value;\n return applyPatterns(value, patterns, censor);\n }\n\n if (Array.isArray(value)) {\n return walkContainer(value, state, fullPath, bare, depth, walkArray);\n }\n\n if (value instanceof Error) {\n return walkContainer(value, state, fullPath, bare, depth, walkError);\n }\n\n if (value instanceof URL) {\n const url = new URL(value.href);\n url.username = '';\n url.password = '';\n const redacted = walkValue(url.href, state, fullPath, bare, depth);\n return redacted === value.href ? value : redacted;\n }\n\n if (isPlainObject(value)) {\n const walk =\n typeof (value as { toJSON?: unknown }).toJSON === 'function' ? walkToJSON : walkRecord;\n return walkContainer(value as object, state, fullPath, bare, depth, walk);\n }\n\n return value;\n}\n\nfunction walkContainer(\n value: object,\n state: WalkState,\n fullPath: string,\n bare: string,\n depth: number,\n walk: (value: never, state: WalkState, fullPath: string, bare: string, depth: number) => unknown\n): unknown {\n if (state.ancestors.has(value)) return CIRCULAR;\n state.ancestors.add(value);\n try {\n return walk(value as never, state, fullPath, bare, depth + 1);\n } finally {\n state.ancestors.delete(value);\n }\n}\n\n/**\n * Array elements are matched by their indexed path (`users.0.password`) and by\n * the index-free path (`users.password`) that earlier versions used.\n */\nfunction walkArray(\n arr: unknown[],\n state: WalkState,\n fullPath: string,\n bare: string,\n depth: number\n): unknown[] {\n let result: unknown[] | undefined;\n for (const [i, item] of arr.entries()) {\n const next = walkValue(item, state, joinPath(fullPath, String(i)), bare, depth);\n if (next !== item && !result) result = arr.slice(0, i);\n if (result) result.push(next);\n }\n return result ?? arr;\n}\n\nfunction walkRecord(\n obj: Record<string, unknown>,\n state: WalkState,\n fullPath: string,\n bare: string,\n depth: number\n): Record<string, unknown> {\n let result: Record<string, unknown> | undefined;\n const entries = Object.entries(obj);\n for (const [index, [key, value]] of entries.entries()) {\n // Prototype pollution guard: skip forbidden keys that could mutate\n // Object.prototype when assigned via bracket notation on a literal object.\n const forbidden = key === '__proto__' || key === 'constructor' || key === 'prototype';\n const next = forbidden\n ? undefined\n : walkValue(value, state, joinPath(fullPath, key), joinPath(bare, key), depth);\n if ((forbidden || next !== value) && !result) {\n result = Object.fromEntries(entries.slice(0, index));\n }\n if (result && !forbidden) result[key] = next;\n }\n return result ?? obj;\n}\n\n/** Errors are serialized (own props + cause chain) and the result is walked. */\nfunction walkError(\n err: Error,\n state: WalkState,\n fullPath: string,\n bare: string,\n depth: number\n): Record<string, unknown> {\n let serialized: Record<string, unknown>;\n try {\n serialized = serializeError(err);\n } catch {\n return { name: err.name, message: REDACTION_FAILED };\n }\n const result = walkRecord(serialized, state, fullPath, bare, depth);\n return result === serialized ? { ...serialized } : result;\n}\n\n/** Objects with `toJSON()` are redacted via the value they would serialize to. */\nfunction walkToJSON(\n obj: { toJSON: () => unknown },\n state: WalkState,\n fullPath: string,\n bare: string,\n depth: number\n): unknown {\n let json: unknown;\n try {\n json = obj.toJSON();\n } catch {\n return REDACTION_FAILED;\n }\n if (json === obj) return walkRecord(obj as Record<string, unknown>, state, fullPath, bare, depth);\n return walkValue(json, state, fullPath, bare, depth);\n}\n\n/**\n * Redact an object according to the given RedactConfig and return a new\n * top-level object. Subtrees with nothing to redact are shared with the input,\n * never mutated. Circular references become `[Circular]`.\n */\nexport function redactObject(\n obj: Record<string, unknown>,\n config: RedactConfig,\n _currentPath = ''\n): Record<string, unknown> {\n const state: WalkState = { config, ancestors: new Set([obj]), nodes: 0 };\n const result = walkRecord(obj, state, _currentPath, _currentPath, 0);\n return result === obj ? { ...obj } : result;\n}\n\n/**\n * Apply pattern-based redaction to a single string (e.g. the log message).\n *\n * Path-based rules don't apply to a bare string — only the `patterns` are run.\n * Returns the input unchanged when no patterns are configured, so the hot path\n * stays allocation-free for the common no-redact case.\n */\nexport function applyRedactionToString(value: unknown, config: RedactConfig | undefined): string {\n const text = typeof value === 'string' ? value : safeToString(value);\n if (!config) return text;\n const resolved = resolveConfig(config);\n if (!resolved.patterns || resolved.patterns.length === 0) return text;\n return applyPatterns(text, resolved.patterns, resolved.censor ?? DEFAULT_CENSOR);\n}\n\n/**\n * Apply redaction to a log payload (top-level call convenience wrapper).\n * Returns a new object — never mutates the input.\n */\nexport function applyRedaction(\n payload: Record<string, unknown> | undefined,\n config: RedactConfig | undefined\n): Record<string, unknown> | undefined {\n if (!payload || !config) return payload;\n const resolved = resolveConfig(config);\n if (\n (!resolved.paths || resolved.paths.length === 0) &&\n (!resolved.patterns || resolved.patterns.length === 0)\n ) {\n return payload;\n }\n return redactObject(payload, resolved);\n}\n\nconst OPAQUE_BUILTINS: readonly (abstract new (...args: never[]) => object)[] = [\n Date,\n Error,\n RegExp,\n URL,\n URLSearchParams,\n ArrayBuffer,\n DataView,\n Map,\n Set,\n WeakMap,\n WeakSet,\n Promise,\n];\n\n/** Plain objects and class instances are walked; built-ins are left alone. */\nfunction isPlainObject(value: unknown): boolean {\n if (value === null || typeof value !== 'object') return false;\n if (ArrayBuffer.isView(value)) return false;\n return !OPAQUE_BUILTINS.some((ctor) => value instanceof ctor);\n}\n","/**\n * Log sampling & rate-limiting engine.\n *\n * Completely stateless between log calls — all state lives in the Sampler instance\n * so multiple loggers can have independent sampling budgets.\n */\n\nimport type { SamplingConfig } from '../types';\n\n// Safety-critical levels that are NEVER sampled below 100 % by default.\n// Per SamplingConfig docs, ERROR and WARN are always emitted unless explicitly\n// overridden via `perLevel`; `fatal` (a common custom highest-severity level)\n// is included for the same reason.\nconst ALWAYS_EMIT_LEVELS = new Set(['error', 'warn', 'fatal']);\n\nconst MAX_CACHED_TRACE_ID_LENGTH = 256;\n\nfunction isCacheableTraceId(id: string): boolean {\n if (typeof id !== 'string' || id.length === 0 || id.length > MAX_CACHED_TRACE_ID_LENGTH) {\n return false;\n }\n for (let i = 0; i < id.length; i++) {\n const c = id.charCodeAt(i);\n if (c < 0x20 || (c >= 0x7f && c <= 0x9f)) return false;\n }\n return true;\n}\n\n// ── Sampler ───────────────────────────────────────────────────────────────────\n\nexport interface SamplingStats {\n /** Total calls evaluated since last reset. */\n evaluated: number;\n /** Total calls emitted (passed through). */\n emitted: number;\n /** Total calls dropped. */\n dropped: number;\n /** Per-level breakdown. */\n byLevel: Record<string, { evaluated: number; emitted: number }>;\n /** Window start (ms since epoch). */\n windowStart: number;\n}\n\nexport class Sampler {\n private readonly config: SamplingConfig;\n /**\n * Per-trace decisions in LRU order (Map preserves insertion order; a hit\n * re-inserts the key). Survives resetStats() so a long trace is not re-decided\n * mid-flight. Bounded by size, by an idle TTL (refreshed on hit) and by a hard\n * lifetime measured from the first decision.\n */\n private readonly traceDecisions = new Map<\n string,\n { emit: boolean; firstAt: number; seenAt: number }\n >();\n private readonly maxTrackedTraces = 100_000;\n private readonly traceTtlMs = 5 * 60_000;\n private readonly traceMaxLifetimeMs = 60 * 60_000;\n\n // Rate-limiting state\n private _tokenBucket = 0;\n private _lastRefillMs = Date.now();\n\n // Adaptive (anomaly-driven) sampling state — a sliding window of recent\n // (timestamp, isError) samples. `_adaptiveHead` marks the oldest live entry so\n // eviction is O(1); the array is compacted once the dead prefix dominates.\n private _adaptiveWindow: Array<{ t: number; err: boolean }> = [];\n private _adaptiveHead = 0;\n private _adaptiveErrors = 0;\n\n // Stats\n private _stats: SamplingStats = {\n evaluated: 0,\n emitted: 0,\n dropped: 0,\n byLevel: {},\n windowStart: Date.now(),\n };\n private _statsTimer?: ReturnType<typeof setInterval>;\n\n constructor(config: SamplingConfig, onStats?: (stats: SamplingStats) => void) {\n this.config = config;\n\n // Initialise token bucket to the max cap\n if (config.maxLogsPerSecond && config.maxLogsPerSecond > 0) {\n this._tokenBucket = config.maxLogsPerSecond;\n }\n\n // Periodic stats reporter\n const interval = config.statsIntervalMs ?? 60_000;\n if (interval > 0 && onStats) {\n this._statsTimer = setInterval(() => {\n const snapshot = this.getStats();\n onStats(snapshot);\n this.resetStats();\n }, interval);\n // Don't prevent process exit\n if (this._statsTimer.unref) this._statsTimer.unref();\n }\n }\n\n /**\n * Decide whether a given log entry should be emitted.\n *\n * @param level Log level string (lowercase)\n * @param traceId Active trace ID, if any\n * @returns true → emit, false → drop\n */\n shouldEmit(level: string, traceId?: string): boolean {\n const lvl = level.toLowerCase();\n this._trackEvaluated(lvl);\n if (this.config.adaptive) this._recordAdaptiveSample(lvl);\n\n // ── 1. Safety: error/fatal always pass (unless explicitly overridden) ─────\n if (ALWAYS_EMIT_LEVELS.has(lvl) && this.config.perLevel?.[lvl] === undefined) {\n this._trackEmitted(lvl);\n return true;\n }\n\n // ── 2. Rate-based decision (cached per trace when traceConsistent) ────────\n const emit =\n this.config.traceConsistent && traceId\n ? this._decideForTrace(traceId, lvl)\n : this._sampleByRate(lvl);\n if (!emit) {\n this._trackDropped(lvl);\n return false;\n }\n\n // ── 3. Hard cap (token bucket) — applies to every kept entry ──────────────\n if (this.config.maxLogsPerSecond && this.config.maxLogsPerSecond > 0) {\n if (!this._consumeToken()) {\n this._trackDropped(lvl);\n return false;\n }\n }\n\n this._trackEmitted(lvl);\n return true;\n }\n\n getStats(): SamplingStats {\n return { ...this._stats, byLevel: { ...this._stats.byLevel } };\n }\n\n resetStats(): void {\n this._stats = {\n evaluated: 0,\n emitted: 0,\n dropped: 0,\n byLevel: {},\n windowStart: Date.now(),\n };\n }\n\n destroy(): void {\n if (this._statsTimer) clearInterval(this._statsTimer);\n }\n\n // ── Private helpers ─────────────────────────────────────────────────────────\n\n private _sampleByRate(level: string): boolean {\n const baseRate =\n this.config.perLevel?.[level] ?? this.config.perLevel?.['*'] ?? this.config.rate ?? 1.0;\n\n // Adaptive boost: during an error anomaly, lift the rate so the incident is\n // captured in full, then relax back to the base rate in steady state.\n const rate = Math.max(baseRate, this._adaptiveBoostRate());\n\n if (rate >= 1.0) return true;\n if (rate <= 0.0) return false;\n // eslint-disable-next-line sonarjs/pseudo-random -- probabilistic sampling, not security-sensitive\n return Math.random() < rate;\n }\n\n /** Record one evaluated sample and evict entries older than the window. O(1) amortized. */\n private _recordAdaptiveSample(level: string): void {\n const now = Date.now();\n const windowMs = this.config.adaptive?.windowMs ?? 10_000;\n const err = level === 'error' || level === 'fatal';\n this._adaptiveWindow.push({ t: now, err });\n if (err) this._adaptiveErrors += 1;\n\n const cutoff = now - windowMs;\n const win = this._adaptiveWindow;\n while (this._adaptiveHead < win.length && win[this._adaptiveHead]!.t < cutoff) {\n if (win[this._adaptiveHead]!.err) this._adaptiveErrors -= 1;\n this._adaptiveHead += 1;\n }\n if (this._adaptiveHead >= 1024 && this._adaptiveHead * 2 >= win.length) {\n this._adaptiveWindow = win.slice(this._adaptiveHead);\n this._adaptiveHead = 0;\n }\n }\n\n /**\n * Effective boost rate (0 = no boost). Returns the configured boostRate when\n * the windowed error rate is at/above the threshold AND there are enough\n * samples to trust it; otherwise 0.\n */\n private _adaptiveBoostRate(): number {\n const cfg = this.config.adaptive;\n if (!cfg) return 0;\n const minSamples = cfg.minSamples ?? 20;\n const total = this._adaptiveWindow.length - this._adaptiveHead;\n if (total < minSamples) return 0;\n\n const errorRate = this._adaptiveErrors / total;\n const threshold = cfg.errorRateThreshold ?? 0.05;\n return errorRate >= threshold ? (cfg.boostRate ?? 1.0) : 0;\n }\n\n /** @internal Expose the current adaptive boost decision (tests / observability). */\n isBoosting(): boolean {\n return this._adaptiveBoostRate() > 0;\n }\n\n /**\n * Return the cached decision for a trace, or make and cache a new one. Entries\n * idle past the TTL, or older than the hard lifetime, are re-decided; the least\n * recently used entry is evicted once the cap is reached. IDs that are empty,\n * too long or contain control characters are sampled independently and never cached.\n */\n private _decideForTrace(traceId: string, level: string): boolean {\n if (!isCacheableTraceId(traceId)) return this._sampleByRate(level);\n\n const now = Date.now();\n const known = this.traceDecisions.get(traceId);\n if (\n known &&\n now - known.seenAt <= this.traceTtlMs &&\n now - known.firstAt <= this.traceMaxLifetimeMs\n ) {\n this.traceDecisions.delete(traceId);\n known.seenAt = now;\n this.traceDecisions.set(traceId, known);\n return known.emit;\n }\n\n const emit = this._sampleByRate(level);\n this.traceDecisions.delete(traceId);\n this.traceDecisions.set(traceId, { emit, firstAt: now, seenAt: now });\n if (this.traceDecisions.size > this.maxTrackedTraces) {\n const oldest = this.traceDecisions.keys().next().value;\n if (oldest !== undefined) this.traceDecisions.delete(oldest);\n }\n return emit;\n }\n\n private _consumeToken(): boolean {\n const now = Date.now();\n const elapsed = (now - this._lastRefillMs) / 1000;\n const max = this.config.maxLogsPerSecond!;\n\n // Refill tokens proportional to elapsed time\n this._tokenBucket = Math.min(max, this._tokenBucket + elapsed * max);\n this._lastRefillMs = now;\n\n if (this._tokenBucket >= 1) {\n this._tokenBucket -= 1;\n return true;\n }\n return false;\n }\n\n private _ensure(level: string): void {\n if (!this._stats.byLevel[level]) {\n this._stats.byLevel[level] = { evaluated: 0, emitted: 0 };\n }\n }\n\n private _trackEvaluated(level: string): void {\n this._stats.evaluated++;\n this._ensure(level);\n this._stats.byLevel[level]!.evaluated++;\n }\n\n private _trackEmitted(level: string): void {\n this._stats.emitted++;\n this._ensure(level);\n this._stats.byLevel[level]!.emitted++;\n }\n\n private _trackDropped(_level: string): void {\n this._stats.dropped++;\n }\n}\n","/**\n * Graceful shutdown utilities for Logixia\n *\n * Ensures all in-flight logs are flushed to every transport before the process\n * exits on SIGTERM / SIGINT — solving the \"last N seconds of logs are lost on\n * deployment\" problem reported in Pino issue #2002 and LogDNA issue #15.\n */\n\nimport { constants as osConstants } from 'node:os';\n\nexport type ExitMode = 'auto' | 'always' | 'never';\n\nexport interface FlushOnExitOptions {\n /** How long (ms) to wait for transports to flush before force-exiting. Default: 5000 */\n timeout?: number;\n /** OS signals that trigger a graceful flush. Default: ['SIGTERM', 'SIGINT'] */\n signals?: NodeJS.Signals[];\n /** Called just before flushing starts — useful for stopping traffic intake */\n beforeFlush?: () => void | Promise<void>;\n /** Called after all loggers have flushed successfully */\n afterFlush?: () => void | Promise<void>;\n /**\n * Whether logixia ends the process after flushing.\n * - `'auto'` (default): exit only when logixia's handler is the only listener for the\n * signal. If the app registered its own handler (server.close(), NestJS shutdown\n * hooks), logixia just flushes and leaves the exit to the app.\n * - `'always'`: always exit after the flush.\n * - `'never'`: never exit; only flush.\n * When logixia exits it uses 128 + the signal number.\n */\n exit?: ExitMode;\n}\n\ntype Closeable = { close(): Promise<void>; flush?(): Promise<void> };\n\nconst MAX_BEFORE_EXIT_FLUSHES = 5;\n\n/** Module-level registry of all logger instances that have opted into graceful shutdown */\nconst registry = new Set<Closeable>();\nlet shutdownHandlerRegistered = false;\n/** Guards the handler against re-entrancy: a second signal (e.g. SIGINT after\n * SIGTERM, or an impatient double Ctrl+C) must not start a second concurrent\n * flush+exit, which could exit the process and truncate the first flush mid-write. */\nlet shutdownInProgress = false;\n/** Our own handler + the signals we attached it to, so reset() can detach exactly it. */\nlet activeHandler: ((signal: NodeJS.Signals) => void | Promise<void>) | undefined;\nlet activeSignals: NodeJS.Signals[] = [];\nlet activeOptions: FlushOnExitOptions | undefined;\nlet beforeExitHandler: (() => void) | undefined;\n\n/**\n * Register a logger instance so it is included in the graceful shutdown flush.\n * Called automatically when `gracefulShutdown: true` is set in logger config.\n */\n/** Test helper: number of loggers currently registered for graceful shutdown. */\nexport function _shutdownRegistrySize(): number {\n return registry.size;\n}\n\nexport function registerForShutdown(logger: Closeable): void {\n registry.add(logger);\n}\n\n/**\n * Deregister a logger (e.g. after `logger.close()` is called manually).\n */\nexport function deregisterFromShutdown(logger: Closeable): void {\n registry.delete(logger);\n}\n\n/**\n * Register SIGTERM / SIGINT handlers that flush all registered loggers before\n * the process exits. Idempotent — the first call wins and later calls with\n * conflicting options print a warning. The process is ended with 128 + signal\n * number only when logixia's handler is the sole listener for that signal (see\n * `exit`); otherwise it just flushes and leaves shutdown to the application.\n * Loggers are also flushed (not closed) on `beforeExit`.\n *\n * @example\n * ```ts\n * import { flushOnExit } from 'logixia';\n * flushOnExit({ timeout: 5000 });\n * ```\n */\nexport function flushOnExit(options: FlushOnExitOptions = {}): void {\n if (shutdownHandlerRegistered) {\n warnOnConflict(activeOptions, options);\n return;\n }\n shutdownHandlerRegistered = true;\n activeOptions = options;\n\n const {\n timeout = 5000,\n signals = ['SIGTERM', 'SIGINT'],\n beforeFlush,\n afterFlush,\n exit = 'auto',\n } = options;\n\n const shouldExit = (signal: NodeJS.Signals): boolean =>\n exit === 'always' || (exit === 'auto' && process.listenerCount(signal) <= 1);\n\n const handler = async (signal: NodeJS.Signals) => {\n // Re-entrancy guard: a flush is already running from an earlier signal.\n // Starting a second one would race two close()/exit() sequences and could\n // truncate the in-flight flush — exactly the log loss we are preventing.\n if (shutdownInProgress) return;\n shutdownInProgress = true;\n\n // Force-exit safety net — if flushing hangs, don't block the process forever.\n // Only armed when logixia owns the exit; otherwise the app decides.\n const forceExitTimer = shouldExit(signal)\n ? setTimeout(() => {\n // Keep the force-exit message visible even when internal logs are silenced.\n process.stderr.write(\n `[logixia] Graceful shutdown timed out after ${timeout}ms on ${signal}. Force-exiting.\\n`\n );\n process.exit(1);\n }, timeout).unref()\n : undefined;\n\n try {\n if (beforeFlush) await beforeFlush();\n\n // Flush all registered loggers concurrently, ignoring individual failures\n await Promise.allSettled([...registry].map((logger) => logger.close()));\n\n if (afterFlush) await afterFlush();\n } catch (err) {\n process.stderr.write(`[logixia] Shutdown hook failed: ${String(err)}\\n`);\n } finally {\n clearTimeout(forceExitTimer);\n if (shouldExit(signal)) {\n process.exit(128 + (osConstants.signals[signal] ?? 0));\n }\n shutdownInProgress = false;\n }\n };\n\n // Register our own handler unconditionally. Signals support multiple\n // listeners, so other frameworks' handlers (NestJS/Express) don't block ours —\n // the previous `listenerCount === 0` guard meant the documented flush silently\n // never ran whenever any other listener existed. The `shutdownHandlerRegistered`\n // flag above keeps THIS function idempotent (one logixia handler, not N).\n activeHandler = handler;\n activeSignals = signals;\n for (const signal of signals) {\n process.on(signal, activeHandler);\n }\n\n // Normal exit (event loop drained): flush, never close, since beforeExit can fire\n // again and the app may keep logging. Not re-entrant, and capped so a transport\n // that schedules work on every flush cannot keep the process alive forever.\n let beforeExitFlushes = 0;\n let beforeExitFlushing = false;\n beforeExitHandler = () => {\n if (beforeExitFlushing || shutdownInProgress || beforeExitFlushes >= MAX_BEFORE_EXIT_FLUSHES) {\n return;\n }\n beforeExitFlushing = true;\n beforeExitFlushes += 1;\n void Promise.allSettled([...registry].map((logger) => logger.flush?.())).finally(() => {\n beforeExitFlushing = false;\n });\n };\n process.on('beforeExit', beforeExitHandler);\n}\n\nfunction warnOnConflict(active: FlushOnExitOptions | undefined, next: FlushOnExitOptions): void {\n if (!active) return;\n const conflicts: string[] = [];\n if (next.timeout !== undefined && next.timeout !== (active.timeout ?? 5000)) {\n conflicts.push('timeout');\n }\n if (next.exit !== undefined && next.exit !== (active.exit ?? 'auto')) conflicts.push('exit');\n if (next.signals !== undefined) {\n const current = new Set(active.signals ?? ['SIGTERM', 'SIGINT']);\n if (next.signals.length !== current.size || next.signals.some((sig) => !current.has(sig))) {\n conflicts.push('signals');\n }\n }\n if (next.beforeFlush && next.beforeFlush !== active.beforeFlush) conflicts.push('beforeFlush');\n if (next.afterFlush && next.afterFlush !== active.afterFlush) conflicts.push('afterFlush');\n if (conflicts.length === 0) return;\n process.stderr.write(\n `[logixia] flushOnExit was already configured; ignoring conflicting options: ${conflicts.join(', ')}.\\n`\n );\n}\n\n/**\n * Remove all graceful shutdown handlers and clear the registry.\n * Primarily useful in tests.\n */\nexport function resetShutdownHandlers(): void {\n registry.clear();\n if (activeHandler) {\n for (const signal of activeSignals) {\n process.removeListener(signal, activeHandler);\n }\n }\n if (beforeExitHandler) process.removeListener('beforeExit', beforeExitHandler);\n beforeExitHandler = undefined;\n activeHandler = undefined;\n activeSignals = [];\n activeOptions = undefined;\n shutdownHandlerRegistered = false;\n shutdownInProgress = false;\n}\n","/**\n * Core Logixia Logger implementation\n *\n * v1.1 additions:\n * - Feature 1: Graceful shutdown / flushOnExit (auto-registered via config)\n * - Feature 2: Built-in log redaction (path-based + regex)\n * - Feature 3: Per-namespace log levels + LOGIXIA_LEVEL* ENV overrides\n * - Feature 4: Cause-chain error serialization (handled in error.utils)\n * - Feature 5: Adaptive log level based on NODE_ENV / CI detection\n */\n\nimport buildFastStringify from 'fast-json-stringify';\n\n// ── Module-level JSON serializer (built once, reused for all loggers) ─────────\n// Covers the fixed LogEntry shape; unknown payload fields handled by additionalProperties\nconst _fastStringifyEntry = buildFastStringify({\n type: 'object',\n properties: {\n timestamp: { type: 'string' },\n level: { type: 'string' },\n appName: { type: 'string' },\n environment: { type: 'string' },\n message: { type: 'string' },\n context: { type: 'string' },\n traceId: { type: 'string' },\n payload: { type: 'object', additionalProperties: true },\n },\n additionalProperties: true,\n});\n\nimport { LogixiaContext } from '../context/async-context';\nimport type { LogixiaPlugin } from '../plugin';\nimport { globalPluginRegistry, PluginRegistry } from '../plugin';\nimport { TransportManager } from '../transports/transport.manager';\nimport type {\n ContextData,\n GracefulShutdownConfig,\n ILogger,\n ILoggerDefault,\n LogEntry,\n LoggerConfig,\n LoggerWithLevels,\n LogLevelString,\n NamespaceLevels,\n TimingEntry,\n} from '../types';\nimport { LogLevel } from '../types';\nimport { safeToString } from '../utils/coerce.utils';\nimport { isError, serializeError } from '../utils/error.utils';\nimport { internalError, internalLog, internalWarn } from '../utils/internal-log';\nimport { _getOtelPayloadIfEnabled, _isOtelBridgeEnabled } from '../utils/otel';\nimport { applyRedaction, applyRedactionToString, REDACTION_FAILED } from '../utils/redact.utils';\nimport { stringifyForLog } from '../utils/safe-stringify';\nimport { Sampler } from '../utils/sampling.utils';\nimport { stripControlChars } from '../utils/sanitize.utils';\nimport { deregisterFromShutdown, flushOnExit, registerForShutdown } from '../utils/shutdown.utils';\nimport { TraceContext } from '../utils/trace.utils';\n\n// ── Hot-path timestamp cache ─────────────────────────────────────────────────\n// `new Date().toISOString()` is one of the most expensive things on the log hot\n// path (~2.2M ops/sec vs ~18M for Date.now()). Within a single millisecond every\n// log shares the same ISO string, so cache it keyed on the integer epoch ms and\n// only re-format when the clock ticks over. Worst case at very high throughput:\n// thousands of logs reuse one allocation instead of each paying for toISOString.\nlet _tsCacheMs = 0;\nlet _tsCacheStr = '';\nfunction nowIso(): string {\n const ms = Date.now();\n if (ms !== _tsCacheMs) {\n _tsCacheMs = ms;\n _tsCacheStr = new Date(ms).toISOString();\n }\n return _tsCacheStr;\n}\n\n// ── Namespace level helpers ──────────────────────────────────────────────────\n\nfunction namespacePatternToRegex(pattern: string): RegExp {\n const escaped = pattern\n .split('.')\n .map((s) => (s === '*' ? '[^.]+' : s.replace(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&')))\n .join('\\\\.');\n return new RegExp(`^${escaped}$`);\n}\n\n/** Max compiled patterns to keep in memory. Oldest entry is evicted when full. */\nconst _NS_CACHE_MAX = 1000;\nconst _nsPatternCache = new Map<string, RegExp>();\n/**\n * One-shot warning so operators notice runaway pattern growth.\n * If the cache is being thrashed (>N evictions) the namespace level config is\n * almost certainly wrong — likely dynamic/unique patterns being registered.\n */\nlet _nsCacheEvictionWarned = false;\nlet _nsCacheEvictionCount = 0;\n\nfunction matchesNamespacePattern(ns: string, pattern: string): boolean {\n let re = _nsPatternCache.get(pattern);\n if (!re) {\n re = namespacePatternToRegex(pattern);\n // Evict the oldest entry when the cache hits its limit\n if (_nsPatternCache.size >= _NS_CACHE_MAX) {\n const firstKey = _nsPatternCache.keys().next().value;\n if (firstKey !== undefined) _nsPatternCache.delete(firstKey);\n _nsCacheEvictionCount++;\n if (!_nsCacheEvictionWarned) {\n _nsCacheEvictionWarned = true;\n internalWarn(\n `namespace pattern cache hit ${_NS_CACHE_MAX} entries — evicting. ` +\n `This usually means dynamic/unique patterns are being registered at runtime; ` +\n `review your levelOptions.namespaces configuration.`\n );\n }\n }\n _nsPatternCache.set(pattern, re);\n }\n return re.test(ns);\n}\n\n/** @internal Test helper to inspect/reset namespace pattern cache state. */\nexport const _nsCacheInternal = {\n size: (): number => _nsPatternCache.size,\n evictionCount: (): number => _nsCacheEvictionCount,\n reset: (): void => {\n _nsPatternCache.clear();\n _nsCacheEvictionCount = 0;\n _nsCacheEvictionWarned = false;\n },\n};\n\n// ── Feature 5: Adaptive level resolution ────────────────────────────────────\n\n/**\n * Map a level name onto a known level key: exact match first (so custom levels\n * keep their declared casing), then lower case (so `DEBUG` → `debug`).\n */\nfunction canonicalLevel(level: unknown, known: { has(key: string): boolean }): string | undefined {\n if (typeof level !== 'string') return undefined;\n if (known.has(level)) return level;\n const lower = level.toLowerCase();\n return known.has(lower) ? lower : undefined;\n}\n\nfunction resolveInitialLevel(config: LoggerConfig): LogLevelString {\n // 1. Hard env override — an unknown value is skipped here so the configured level\n // still applies; resolveEffectiveLevel() reports it.\n const envLevel = process.env['LOGIXIA_LEVEL'];\n const knownLevels = new Set<string>([\n ...Object.values(LogLevel),\n ...Object.keys(config.levelOptions?.levels ?? {}),\n ]);\n if (envLevel && canonicalLevel(envLevel, knownLevels)) return envLevel as LogLevelString;\n\n // 2. Explicit config value\n if (config.levelOptions?.level) return config.levelOptions.level as LogLevelString;\n\n // 3. NODE_ENV smart defaults\n const nodeEnv = process.env['NODE_ENV'];\n if (nodeEnv === 'development') return LogLevel.DEBUG;\n if (nodeEnv === 'test') return LogLevel.WARN;\n if (nodeEnv === 'production') return LogLevel.INFO;\n\n // 4. CI detection\n if (process.env['CI']) return LogLevel.INFO;\n\n return LogLevel.INFO;\n}\n\n// ── Logger class ─────────────────────────────────────────────────────────────\n\nexport class LogixiaLogger<\n TConfig extends LoggerConfig<Record<string, number>> = LoggerConfig,\n> implements ILoggerDefault {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- index signature for dynamic custom level methods\n [K: string]: any;\n\n private config: TConfig;\n private context?: string;\n private timers: Map<string, TimingEntry> = new Map();\n private contextData: ContextData = {};\n private transportManager: TransportManager | undefined;\n private fieldState: Map<string, boolean> = new Map();\n\n /** Stable fallback trace ID generated ONCE per logger instance. */\n private readonly fallbackTraceId: string = TraceContext.instance.generate();\n\n // ── Performance: hot-path caches (rebuilt when config changes) ───────────────\n /** Numeric value for each known log level — built once, read on every log call. */\n private _levelValues: Map<string, number> = new Map();\n /** Numeric threshold for the currently active log level. */\n private _minLevelValue = 2;\n /** `source=value` pairs already reported as unknown levels — warn once per logger. */\n private readonly _warnedInvalidLevels = new Set<string>();\n /** Pre-built ANSI color codes to avoid recreating the object in colorize(). */\n private _colorMap: Map<string, string> = new Map();\n /** Pre-computed field-enabled booleans so isFieldEnabled() isn't called per log. */\n private _fieldCache: Map<string, boolean> = new Map();\n /** True when contextData is non-empty — avoids Object.keys() check on hot path. */\n private _hasContextData = false;\n /**\n * Pre-computed `[INFO] `, `[WARN] ` etc. strings — avoids a colorize() call per log.\n * Key: lowercase level name. Value: formatted bracket string ready to concatenate.\n */\n private _formattedLevels: Map<string, string> = new Map();\n /** Pre-computed `[appName] ` string — avoids template literal allocation per log. */\n private _formattedAppName = '';\n /** True when a redact config is present — short-circuits applyRedaction when false. */\n private _hasRedact = false;\n /** Sampling engine — only created when sampling config is present. */\n private _sampler: Sampler | undefined;\n /** Per-instance plugin registry — also inherits from the global registry at creation time. */\n private readonly _pluginRegistry: PluginRegistry;\n /** Set on loggers created by child(); they borrow the root's transports, sampler and plugins. */\n private readonly _parent: LogixiaLogger<TConfig> | undefined;\n\n constructor(config: TConfig, context?: string, parent?: LogixiaLogger<TConfig>) {\n this._parent = parent;\n this._pluginRegistry = parent ? parent._pluginRegistry : new PluginRegistry();\n\n const defaultConfig: LoggerConfig = {\n appName: 'App',\n environment: 'development',\n traceId: true,\n format: { timestamp: true, colorize: true, json: false },\n silent: false,\n levelOptions: {\n level: LogLevel.INFO,\n levels: {\n [LogLevel.ERROR]: 0,\n [LogLevel.WARN]: 1,\n [LogLevel.INFO]: 2,\n [LogLevel.DEBUG]: 3,\n [LogLevel.TRACE]: 4,\n [LogLevel.VERBOSE]: 5,\n },\n colors: {\n [LogLevel.ERROR]: 'red',\n [LogLevel.WARN]: 'yellow',\n [LogLevel.INFO]: 'blue',\n [LogLevel.DEBUG]: 'green',\n [LogLevel.TRACE]: 'gray',\n [LogLevel.VERBOSE]: 'cyan',\n },\n },\n };\n\n this.config = { ...defaultConfig, ...config };\n\n // ── Feature 5: Adaptive log level ───────────────────────────────────────\n const resolvedLevel = resolveInitialLevel(this.config);\n this.config.levelOptions = { ...this.config.levelOptions, level: resolvedLevel };\n\n this.config.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 this.context = context ?? '';\n\n if (parent) {\n this.transportManager = parent.transportManager;\n this._sampler = parent._sampler;\n } else if (this.config.transports) {\n // Inject levelOptions.colors into the console transport config so\n // ConsoleTransport can colorize custom levels (e.g. kafka, mongo)\n // using the same colors the user configured on the logger.\n const transportsWithColors = { ...this.config.transports };\n const userColors = this.config.levelOptions?.colors as Record<string, string> | undefined;\n if (userColors && transportsWithColors.console) {\n const consoleBase =\n typeof transportsWithColors.console === 'object' ? transportsWithColors.console : {};\n transportsWithColors.console = { ...consoleBase, levelColors: userColors };\n }\n this.transportManager = new TransportManager(transportsWithColors);\n }\n\n // ── Feature 8: Log sampling ───────────────────────────────────────────────\n if (!parent && this.config.sampling) {\n this._sampler = new Sampler(this.config.sampling, (stats) => {\n // Emit sampling stats as an INFO log via direct stdout to avoid recursion\n process.stdout.write(\n JSON.stringify({\n level: 'info',\n message: '[logixia/sampling] stats',\n ...stats,\n }) + '\\n'\n );\n });\n }\n\n // ── Feature 1: Graceful shutdown ─────────────────────────────────────────\n if (!parent) this.setupGracefulShutdown();\n\n this.createCustomLevelMethods();\n\n // ── Feature 20: Seed with any plugins already in the global registry ─────\n // Plugins registered via usePlugin() before this logger was created are\n // automatically included in this instance's registry.\n if (!parent) {\n for (const p of (globalPluginRegistry as unknown as { _plugins: LogixiaPlugin[] })._plugins) {\n this._pluginRegistry.register(p);\n }\n }\n\n // ── Build hot-path caches after all config is finalised ──────────────────\n this._buildPerfCaches();\n }\n\n // ── Feature 1 ────────────────────────────────────────────────────────────────\n\n private setupGracefulShutdown(): void {\n const shutdownCfg = this.config.gracefulShutdown;\n if (!shutdownCfg) return;\n\n const normalized: GracefulShutdownConfig =\n shutdownCfg === true ? { enabled: true } : shutdownCfg;\n\n if (!normalized.enabled) return;\n\n registerForShutdown(this);\n flushOnExit({\n timeout: normalized.timeout ?? 5000,\n signals: normalized.signals ?? ['SIGTERM', 'SIGINT'],\n ...(normalized.exit ? { exit: normalized.exit } : {}),\n });\n }\n\n private createCustomLevelMethods(): void {\n if (this.config.levelOptions?.levels) {\n for (const levelName of Object.keys(this.config.levelOptions.levels)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (!(this as any)[levelName.toLowerCase()]) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this as any)[levelName.toLowerCase()] = async (\n message: string,\n data?: Record<string, unknown>\n ) => {\n await this.logLevel(levelName.toLowerCase(), message, data);\n };\n }\n }\n }\n }\n\n /**\n * Rebuild all hot-path caches after any config mutation or level change.\n * Keeps the actual log() call free of allocations in the common case.\n */\n private _buildPerfCaches(): void {\n // 1. Level value map — pre-merge built-ins + custom levels once\n const customLevelEntries = Object.entries(this.config.levelOptions?.levels ?? {});\n this._levelValues = new Map<string, number>([\n [LogLevel.ERROR, 0],\n [LogLevel.WARN, 1],\n [LogLevel.INFO, 2],\n [LogLevel.DEBUG, 3],\n [LogLevel.TRACE, 4],\n [LogLevel.VERBOSE, 5],\n ...customLevelEntries,\n ]);\n // Validate the configured level against the real map (built-ins + custom levels)\n // and store it in canonical form so getLevel() reports what is actually in effect.\n this.config.levelOptions = this.config.levelOptions ?? {};\n this.config.levelOptions.level =\n this._validLevel(this.config.levelOptions.level, 'levelOptions.level') ?? LogLevel.INFO;\n const effectiveLevel = this.resolveEffectiveLevel();\n this._minLevelValue = this._levelValues.get(effectiveLevel) ?? 2;\n\n // 2. ANSI color map — static, built once\n this._colorMap = new Map([\n ['black', '\\x1b[30m'],\n ['red', '\\x1b[31m'],\n ['green', '\\x1b[32m'],\n ['yellow', '\\x1b[33m'],\n ['blue', '\\x1b[34m'],\n ['magenta', '\\x1b[35m'],\n ['cyan', '\\x1b[36m'],\n ['white', '\\x1b[37m'],\n ['gray', '\\x1b[90m'],\n ['grey', '\\x1b[90m'],\n ['brightred', '\\x1b[91m'],\n ['brightgreen', '\\x1b[92m'],\n ['brightyellow', '\\x1b[93m'],\n ['brightblue', '\\x1b[94m'],\n ['brightmagenta', '\\x1b[95m'],\n ['brightcyan', '\\x1b[96m'],\n ['brightwhite', '\\x1b[97m'],\n ['reset', '\\x1b[0m'],\n ]);\n\n // 3. Field enabled cache — replaces per-call isFieldEnabled() calls\n const fieldNames = [\n 'timestamp',\n 'level',\n 'appName',\n 'traceId',\n 'context',\n 'message',\n 'payload',\n ];\n for (const f of fieldNames) {\n if (this.fieldState.has(f)) {\n this._fieldCache.set(f, this.fieldState.get(f)!);\n } else if (this.config.fields?.[f as keyof typeof this.config.fields] === undefined) {\n this._fieldCache.set(f, true);\n } else {\n this._fieldCache.set(f, this.config.fields[f as keyof typeof this.config.fields] !== false);\n }\n }\n\n // 4. Pre-computed formatted level strings (e.g. \"[INFO] \" with ANSI codes baked in)\n // Eliminates a colorize() call + template literal allocation on every log call.\n const colorize = this.config.format?.colorize ?? true;\n this._formattedLevels = new Map();\n\n // Palette cycled for custom levels that have no explicit color configured.\n // Skips 'white' because it looks identical to the terminal default (appears \"uncolored\").\n const _AUTO_PALETTE: readonly string[] = ['magenta', 'cyan', 'yellow', 'green', 'blue'];\n const _BUILTIN_LEVELS = new Set(['error', 'warn', 'info', 'debug', 'trace', 'verbose']);\n let _paletteIdx = 0;\n\n for (const [lvl] of this._levelValues) {\n const upper = lvl.toUpperCase();\n if (colorize && this._fieldCache.get('level') !== false) {\n let colorName = this.config.levelOptions?.colors?.[lvl] as string | undefined;\n if (!colorName) {\n if (_BUILTIN_LEVELS.has(lvl)) {\n colorName = 'white'; // built-in fallback (shouldn't happen with default config)\n } else {\n // Custom level — auto-assign a distinctive color from the palette\n colorName = _AUTO_PALETTE[_paletteIdx % _AUTO_PALETTE.length]!;\n _paletteIdx++;\n }\n }\n const code = this._colorMap.get(colorName.toLowerCase()) ?? this._colorMap.get('white')!;\n const reset = this._colorMap.get('reset')!;\n this._formattedLevels.set(lvl, `[${code}${upper}${reset}] `);\n } else {\n this._formattedLevels.set(lvl, `[${upper}] `);\n }\n }\n\n // 5. Pre-computed \"[appName] \" string (gray when colorize is on)\n const appNameRaw = `[${this.config.appName ?? 'App'}]`;\n if (this._fieldCache.get('appName') === false) {\n this._formattedAppName = '';\n } else {\n this._formattedAppName = colorize\n ? `${this._colorMap.get('gray')!}${appNameRaw}${this._colorMap.get('reset')!} `\n : `${appNameRaw} `;\n }\n\n // 6. Redact flag — if no redact config, skip applyRedaction entirely.\n // autoDetect injects built-in PII paths/patterns at redaction time, so\n // it must flip the flag on even with no explicit paths/patterns set —\n // otherwise autoDetect-only configs silently leak PII.\n this._hasRedact = !!(\n this.config.redact &&\n ((this.config.redact.paths?.length ?? 0) > 0 ||\n (this.config.redact.patterns?.length ?? 0) > 0 ||\n !!this.config.redact.autoDetect)\n );\n }\n\n // ── Public logging API ───────────────────────────────────────────────────────\n\n async error(messageOrError: string | Error, data?: Record<string, unknown>): Promise<void> {\n if (isError(messageOrError)) {\n await this.log('error', messageOrError.message, {\n ...data,\n error: serializeError(messageOrError),\n });\n } else {\n await this.log('error', messageOrError, data);\n }\n }\n\n async warn(message: string, data?: Record<string, unknown>): Promise<void> {\n await this.log('warn', message, data);\n }\n\n async info(message: string, data?: Record<string, unknown>): Promise<void> {\n await this.log('info', message, data);\n }\n\n async debug(message: string, data?: Record<string, unknown>): Promise<void> {\n await this.log('debug', message, data);\n }\n\n async trace(message: string, data?: Record<string, unknown>): Promise<void> {\n await this.log('trace', message, data);\n }\n\n async verbose(message: string, data?: Record<string, unknown>): Promise<void> {\n await this.log('verbose', message, data);\n }\n\n async logLevel(level: string, message: string, data?: Record<string, unknown>): Promise<void> {\n await this.log(level, message, data);\n }\n\n // ── Timer API ────────────────────────────────────────────────────────────────\n\n time(label: string): void {\n this.timers.set(label, { label, startTime: Date.now() });\n }\n\n async timeEnd(label: string): Promise<number | undefined> {\n const timer = this.timers.get(label);\n if (!timer) {\n await this.warn(`Timer '${label}' does not exist`);\n return undefined;\n }\n const endTime = Date.now();\n const duration = endTime - timer.startTime;\n timer.endTime = endTime;\n timer.duration = duration;\n await this.info(`Timer '${label}' finished`, {\n duration: `${duration}ms`,\n startTime: new Date(timer.startTime).toISOString(),\n endTime: new Date(endTime).toISOString(),\n });\n this.timers.delete(label);\n return duration;\n }\n\n async timeAsync<T>(label: string, fn: () => Promise<T>): Promise<T> {\n this.time(label);\n try {\n const result = await fn();\n await this.timeEnd(label);\n return result;\n } catch (error) {\n await this.timeEnd(label);\n throw error;\n }\n }\n\n // ── Level & context management ───────────────────────────────────────────────\n\n setLevel(level: LogLevelString): void {\n const canonical = canonicalLevel(level, this._levelValues);\n if (canonical === undefined) {\n // Refuse unknown levels so getLevel() and the active threshold stay unchanged\n internalWarn(\n `setLevel: unknown log level '${String(level)}' ignored; valid levels: ${this._validLevelList()}. ` +\n `Keeping '${this.getLevel()}'.`\n );\n return;\n }\n this.config.levelOptions = this.config.levelOptions ?? {};\n this.config.levelOptions.level = canonical;\n // Refresh the cached numeric threshold so shouldLog() stays accurate\n this._minLevelValue = this._levelValues.get(canonical) ?? this._minLevelValue;\n // Rebuild level string cache in case colours are keyed per-level\n this._buildPerfCaches();\n }\n\n getLevel(): LogLevelString {\n return (this.config.levelOptions?.level as LogLevelString) ?? LogLevel.INFO;\n }\n\n private _validLevelList(): string {\n return [...this._levelValues.keys()].join(', ');\n }\n\n /**\n * Canonicalise a level from config/ENV. Unknown values return undefined so the\n * caller falls through to the next source, and warn once per logger per source.\n */\n private _validLevel(level: unknown, source: string): string | undefined {\n if (level === undefined || level === '') return undefined;\n const canonical = canonicalLevel(level, this._levelValues);\n if (canonical === undefined) {\n const key = `${source}=${String(level)}`;\n if (!this._warnedInvalidLevels.has(key)) {\n this._warnedInvalidLevels.add(key);\n internalWarn(\n `Unknown log level '${String(level)}' from ${source}; valid levels: ${this._validLevelList()}. ` +\n `Falling back to the next level source (default '${LogLevel.INFO}').`\n );\n }\n }\n return canonical;\n }\n\n /**\n * Replace the per-namespace level map at runtime — no restart needed.\n *\n * This is the runtime counterpart to the `namespaceLevels` config option and\n * the most-requested logging feature across the Winston/Pino issue trackers\n * (flip a module's verbosity live to chase a bug without raising global\n * volume). The new map fully replaces the previous one.\n *\n * @example\n * ```ts\n * // Turn on debug for the DB layer only, live:\n * logger.setNamespaceLevels({ 'db.*': 'debug', '*': 'info' });\n * ```\n */\n setNamespaceLevels(levels: NamespaceLevels): void {\n this.config.namespaceLevels = { ...levels };\n // Re-resolve the effective level (which consults namespaceLevels) and rebuild\n // the hot-path caches so the change takes effect on the very next log call.\n this._buildPerfCaches();\n }\n\n /** Merge entries into the existing per-namespace level map at runtime. */\n patchNamespaceLevels(levels: NamespaceLevels): void {\n this.config.namespaceLevels = { ...this.config.namespaceLevels, ...levels };\n this._buildPerfCaches();\n }\n\n /** Return a copy of the current per-namespace level map. */\n getNamespaceLevels(): NamespaceLevels {\n return { ...this.config.namespaceLevels };\n }\n\n setContext(context: string): void {\n this.context = typeof context === 'string' ? context : safeToString(context);\n }\n\n getContext(): string | undefined {\n return this.context;\n }\n\n // ── Field management ─────────────────────────────────────────────────────────\n\n enableField(fieldName: string): void {\n this.fieldState.set(fieldName, true);\n this._fieldCache.set(fieldName, true);\n // Rebuild derivative caches that depend on field visibility\n if (fieldName === 'level' || fieldName === 'appName') this._buildPerfCaches();\n internalLog(`Field '${fieldName}' enabled`);\n }\n\n disableField(fieldName: string): void {\n this.fieldState.set(fieldName, false);\n this._fieldCache.set(fieldName, false);\n // Rebuild derivative caches that depend on field visibility\n if (fieldName === 'level' || fieldName === 'appName') this._buildPerfCaches();\n internalLog(`Field '${fieldName}' disabled`);\n }\n\n isFieldEnabled(fieldName: string): boolean {\n if (this.fieldState.has(fieldName)) return this.fieldState.get(fieldName)!;\n if (this.config.fields?.[fieldName as keyof typeof this.config.fields] !== undefined) {\n return this.config.fields[fieldName as keyof typeof this.config.fields] !== false;\n }\n return true;\n }\n\n getFieldState(): Record<string, boolean> {\n const allFields = [\n 'timestamp',\n 'level',\n 'appName',\n 'service',\n 'traceId',\n 'message',\n 'payload',\n 'timeTaken',\n 'context',\n 'userId',\n 'sessionId',\n 'environment',\n ];\n return Object.fromEntries(allFields.map((f) => [f, this.isFieldEnabled(f)]));\n }\n\n resetFieldState(): void {\n this.fieldState.clear();\n internalLog('Field state reset to configuration defaults');\n }\n\n // ── Transport level management ───────────────────────────────────────────────\n\n /** @deprecated No-op. Library code never prompts on stdin; use setTransportLevels(). */\n enableTransportLevelPrompting(): void {\n if (this.transportManager) this.transportManager.enableLevelPrompting();\n else internalWarn('Transport manager not initialized');\n }\n\n /** @deprecated No-op. */\n disableTransportLevelPrompting(): void {\n if (this.transportManager) this.transportManager.disableLevelPrompting();\n else internalWarn('Transport manager not initialized');\n }\n\n setTransportLevels(transportId: string, levels: string[]): void {\n if (this.transportManager) this.transportManager.setTransportLevels(transportId, levels);\n else internalWarn('Transport manager not initialized');\n }\n\n getTransportLevels(transportId: string): string[] | undefined {\n if (this.transportManager) return this.transportManager.getTransportLevels(transportId);\n internalWarn('Transport manager not initialized');\n return undefined;\n }\n\n clearTransportLevelPreferences(): void {\n if (this.transportManager) this.transportManager.clearTransportLevelPreferences();\n else internalWarn('Transport manager not initialized');\n }\n\n getAvailableTransports(): string[] {\n return this.transportManager?.getTransports() ?? [];\n }\n\n // ── Child logger ─────────────────────────────────────────────────────────────\n\n child(context: string, data?: Record<string, unknown>): ILogger {\n const childLogger = new LogixiaLogger(this.config, context, this);\n // Inherit the parent's bound fields plus any child-specific data. The\n // hot-path merge in log() is gated on _hasContextData, so it must be set\n // here or the merged fields are silently dropped from every log.\n const mergedContextData = { ...this.contextData, ...data };\n if (Object.keys(mergedContextData).length > 0) {\n childLogger.contextData = mergedContextData;\n childLogger._hasContextData = true;\n }\n return childLogger;\n }\n\n // ── Feature 20: Plugin API ────────────────────────────────────────────────────\n\n /**\n * Register a plugin on this logger instance.\n *\n * @example\n * ```ts\n * logger.use({\n * name: 'audit',\n * onLog(entry) { auditQueue.push(entry); return entry; },\n * });\n * ```\n */\n use(plugin: LogixiaPlugin): this {\n this._pluginRegistry.register(plugin);\n return this;\n }\n\n /**\n * Remove a previously registered plugin by name.\n * No-op if the plugin is not registered on this instance.\n */\n unuse(pluginName: string): this {\n this._pluginRegistry.unregister(pluginName);\n return this;\n }\n\n // ── Flush / health / close ───────────────────────────────────────────────────\n\n async flush(): Promise<void> {\n if (this.transportManager) await this.transportManager.flush();\n }\n\n async healthCheck(): Promise<{ healthy: boolean; details: Record<string, unknown> }> {\n if (!this.transportManager) {\n return { healthy: false, details: { error: 'TransportManager not initialized' } };\n }\n return this.transportManager.healthCheck();\n }\n\n async close(): Promise<void> {\n for (const [label, timer] of this.timers) {\n await this.warn(`Timer '${label}' was not ended properly`, {\n startTime: new Date(timer.startTime).toISOString(),\n duration: `${Date.now() - timer.startTime}ms (incomplete)`,\n });\n }\n this.timers.clear();\n\n if (this._parent) return;\n\n if (this.transportManager) {\n await this.transportManager.close();\n }\n\n this._sampler?.destroy();\n await this._pluginRegistry.runOnShutdown();\n deregisterFromShutdown(this);\n }\n\n // ── Core log method ──────────────────────────────────────────────────────────\n\n private async log(level: string, message: string, data?: Record<string, unknown>): Promise<void> {\n if (this.config.silent) return;\n if (!this.shouldLog(level)) return;\n\n // ── Feature 8: Sampling ───────────────────────────────────────────────────\n if (this._sampler) {\n const traceId = this.config.traceId ? TraceContext.instance.getCurrentTraceId() : undefined;\n if (!this._sampler.shouldEmit(level, traceId)) return;\n }\n\n // ── Feature 6: AsyncLocalStorage context auto-merge ───────────────────────\n // Merge ALS-stored fields (requestId, userId, …) into the payload so every\n // log call inside a LogixiaContext.run() scope automatically carries them.\n const alsContext = LogixiaContext.get();\n const hasAls = alsContext !== undefined && Object.keys(alsContext).length > 0;\n // ── Feature 14: OTel auto trace-log correlation ────────────────────────────\n // Only touch the OTel bridge when it has actually been initialised — skipping\n // the `{}` allocation + Object.keys on every log in the common (bridge-off) case.\n const otelFields = _isOtelBridgeEnabled() ? _getOtelPayloadIfEnabled() : undefined;\n const hasOtel = otelFields !== undefined && Object.keys(otelFields).length > 0;\n let mergedData: typeof data;\n if (hasAls) {\n mergedData = { ...alsContext, ...(hasOtel ? otelFields : {}), ...data };\n } else if (hasOtel) {\n mergedData = { ...otelFields, ...data };\n } else {\n mergedData = data;\n }\n\n // ── Feature 2: Redaction ─────────────────────────────────────────────────\n // Avoid spread allocation when contextData is empty (the common case)\n const rawPayload = this._hasContextData ? { ...this.contextData, ...mergedData } : mergedData;\n // _hasRedact is pre-computed in _buildPerfCaches() — skips the entire redaction\n // code path when no redact config is present (fast path for the common case).\n let payload: Record<string, unknown> | undefined;\n if (rawPayload !== undefined && rawPayload !== null) {\n if (this._hasRedact) {\n // Fail closed: if redaction cannot complete, never emit the raw payload.\n try {\n payload = applyRedaction(rawPayload, this.config.redact) ?? rawPayload;\n } catch (error) {\n internalError('Redaction failed', error);\n payload = { redaction: REDACTION_FAILED };\n }\n } else {\n payload = rawPayload;\n }\n }\n\n // Use a monomorphic LogEntry shape — always the same fields, some may be undefined.\n // Consistent shape lets V8 inline-cache property accesses across calls.\n const traceId = this.config.traceId\n ? (TraceContext.instance.getCurrentTraceId() ?? this.fallbackTraceId)\n : undefined;\n // Pattern-based redaction also applies to the message string — a secret\n // interpolated into the message (e.g. `Auth: Bearer ${token}`) would\n // otherwise bypass redaction entirely and leak in plaintext. Path rules\n // don't apply to a bare string, so only `patterns` run here.\n let safeMessage: string = message;\n if (this._hasRedact) {\n try {\n safeMessage = applyRedactionToString(message, this.config.redact);\n } catch (error) {\n internalError('Redaction failed', error);\n safeMessage = REDACTION_FAILED;\n }\n }\n const entry: LogEntry = {\n timestamp: nowIso(),\n level,\n appName: this.config.appName ?? 'App',\n environment: this.config.environment ?? 'development',\n message: safeMessage,\n };\n if (this.context) entry.context = this.context;\n if (payload !== undefined) entry.payload = payload;\n if (traceId !== undefined) entry.traceId = traceId;\n\n // ── Feature 20: Plugin onLog hooks ────────────────────────────────────────\n // Plugins run post-redaction, pre-transport. Any plugin may mutate or cancel\n // the entry by returning null. We only run the pipeline when plugins are registered.\n let finalEntry: LogEntry | null = entry;\n if (this._pluginRegistry.size > 0) {\n finalEntry = await this._pluginRegistry.runOnLog(entry);\n if (finalEntry === null) return; // entry cancelled by a plugin\n }\n\n // NOTE: do NOT pre-format here. When a transport manager is present (the\n // normal case) each transport formats the entry itself, so eagerly calling\n // formatLog() would be wasted work thrown away. output() formats lazily only\n // for the no-transport fallback path.\n const out = this.output(finalEntry, level);\n if (out !== undefined) await out;\n }\n\n // ── Feature 3: Namespace-aware shouldLog ─────────────────────────────────────\n\n /**\n * Hot-path level check: a single Map lookup + integer compare.\n * The level map and threshold are pre-built in _buildPerfCaches().\n */\n private shouldLog(level: string): boolean {\n const v = this._levelValues.get(level);\n return v !== undefined && v <= this._minLevelValue;\n }\n\n /**\n * Feature 3: Resolve the effective log level for this logger instance.\n *\n * Priority:\n * 1. ENV `LOGIXIA_LEVEL_<NS_UPPER>` (e.g. LOGIXIA_LEVEL_DB for ns \"db\" or \"db.queries\")\n * 2. Matching `namespaceLevels` config entry (longer pattern = more specific, wins)\n * 3. Global `LOGIXIA_LEVEL` ENV override\n * 4. `levelOptions.level` (resolved via Feature 5 in constructor)\n */\n private resolveEffectiveLevel(): LogLevelString {\n const ns = this.context;\n\n if (ns) {\n // 1. ENV namespace override: LOGIXIA_LEVEL_DB → context \"db\" or \"db.queries\"\n const nsKey = ns.split('.')[0]!.toUpperCase();\n const envNsLevel = this._validLevel(\n process.env[`LOGIXIA_LEVEL_${nsKey}`],\n `LOGIXIA_LEVEL_${nsKey}`\n );\n if (envNsLevel) return envNsLevel;\n\n // 2. namespaceLevels config\n const namespaceLevels = this.config.namespaceLevels;\n if (namespaceLevels) {\n const sortedPatterns = Object.keys(namespaceLevels).sort((a, b) => b.length - a.length);\n for (const pattern of sortedPatterns) {\n if (matchesNamespacePattern(ns, pattern)) {\n const nsLevel = this._validLevel(\n namespaceLevels[pattern],\n `namespaceLevels['${pattern}']`\n );\n if (nsLevel) return nsLevel;\n }\n }\n }\n }\n\n // 3. Global ENV override\n const globalEnv = this._validLevel(process.env['LOGIXIA_LEVEL'], 'LOGIXIA_LEVEL');\n if (globalEnv) return globalEnv;\n\n // 4. Config-resolved level\n return this.getLevel();\n }\n\n // ── Formatters ───────────────────────────────────────────────────────────────\n\n private formatLog(entry: LogEntry): string {\n // JSON mode: use fast-json-stringify (pre-compiled serializer, ~59% faster than JSON.stringify)\n if (this.config.format?.json) {\n try {\n return _fastStringifyEntry(entry);\n } catch {\n // A BigInt or a cycle in the payload — rare, so pay for the safe walk only then.\n return stringifyForLog(entry);\n }\n }\n\n let formatted = '';\n\n const doColorize = this.config.format?.colorize ?? true;\n const gray = doColorize ? this._colorMap.get('gray')! : '';\n const cyan = doColorize ? this._colorMap.get('cyan')! : '';\n const yellow = doColorize ? this._colorMap.get('yellow')! : '';\n const reset = doColorize ? this._colorMap.get('reset')! : '';\n\n // Use _fieldCache instead of calling isFieldEnabled() per field\n if (this.config.format?.timestamp !== false && this._fieldCache.get('timestamp') !== false) {\n // entry.timestamp is already an ISO string — no need to re-parse it\n formatted += `${gray}[${entry.timestamp}]${reset} `;\n }\n\n // Use pre-computed level string (avoids colorize() call + template literal allocation)\n if (this._fieldCache.get('level') !== false) {\n formatted += this._formattedLevels.get(entry.level) ?? `[${entry.level.toUpperCase()}] `;\n }\n\n // Use pre-computed \"[appName] \" string (built once in _buildPerfCaches)\n formatted += this._formattedAppName;\n\n if (entry.traceId && this._fieldCache.get('traceId') !== false)\n formatted += `${cyan}[${stripControlChars(String(entry.traceId))}]${reset} `;\n if (entry.context && this._fieldCache.get('context') !== false)\n formatted += `${yellow}[${stripControlChars(String(entry.context))}]${reset} `;\n if (this._fieldCache.get('message') !== false) {\n formatted += stripControlChars(safeToString(entry.message));\n }\n\n if (entry.payload !== undefined && this._fieldCache.get('payload') !== false) {\n formatted += ` ${stringifyForLog(entry.payload)}`;\n }\n\n return formatted;\n }\n\n private colorize(text: string, color: string): string {\n if (!this.config.format?.colorize) return text;\n // Use pre-built _colorMap instead of recreating the colors object every call\n const code = this._colorMap.get(color.toLowerCase()) ?? this._colorMap.get('white')!;\n return `${code}${text}${this._colorMap.get('reset')!}`;\n }\n\n /**\n * Dispatch the entry to transports (each formats itself). Returns `void` when\n * the write completes synchronously (console-only hot path) and a Promise only\n * when a transport is genuinely async — so the caller awaits only when needed.\n * Formatting for the no-transport fallback is done lazily, never on the\n * transport path.\n */\n private output(entry: LogEntry, level: string): void | Promise<void> {\n if (this.transportManager) {\n let result: void | Promise<void>;\n try {\n result = this.transportManager.write(entry);\n } catch (error) {\n return this._handleOutputError(error, entry, level);\n }\n if (result && typeof (result as Promise<void>).then === 'function') {\n return (result as Promise<void>).then(undefined, (error: unknown) =>\n this._handleOutputError(error, entry, level)\n );\n }\n return; // synchronous transport write completed\n }\n\n // Fallback: no transport manager → format lazily and write to stdout/stderr.\n const sink = level === LogLevel.ERROR ? process.stderr : process.stdout;\n sink.write(this.formatLog(entry) + '\\n');\n }\n\n /** Shared transport-failure handler: log internally, notify plugins, then fall\n * back to a direct stdout/stderr write so the entry is never lost. */\n private async _handleOutputError(error: unknown, entry: LogEntry, level: string): Promise<void> {\n internalError('Transport write failed', error);\n if (this._pluginRegistry.size > 0) {\n await this._pluginRegistry.runOnError(\n error instanceof Error ? error : new Error(String(error)),\n entry\n );\n }\n const sink = level === LogLevel.ERROR ? process.stderr : process.stdout;\n sink.write(this.formatLog(entry) + '\\n');\n }\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function createLogger<T extends LoggerConfig<Record<string, number>>>(\n config: T,\n context?: string\n): LoggerWithLevels<T> {\n const logger = new LogixiaLogger<T>(config, context);\n const mutableLogger = logger as unknown as Record<string, unknown>;\n\n if (config.levelOptions?.levels) {\n for (const levelName of Object.keys(config.levelOptions.levels)) {\n if (!mutableLogger[levelName]) {\n mutableLogger[levelName] = async (message: string, data?: Record<string, unknown>) => {\n await logger.logLevel(levelName, message, data);\n };\n }\n }\n }\n\n return logger as unknown as LoggerWithLevels<T>;\n}\n","/**\n * LogixiaException — a strictly typed, framework-agnostic exception class.\n *\n * You bring your own error codes and types; logixia enforces the shape.\n * The `ErrorResponseBuilder` knows how to turn a `LogixiaException` into the\n * standard `LogixiaErrorResponse` wire format.\n *\n * @template TCode - Your error code union. e.g. `'PE-AUTH-001' | 'PE-USR-001'`\n * @template TType - Your error type union. e.g. `'authentication_error' | 'validation_error'`\n *\n * @example Basic throw\n * ```ts\n * throw new LogixiaException({\n * code: 'PE-AUTH-001',\n * type: 'authentication_error',\n * httpStatus: 401,\n * message: 'Invalid email or password.',\n * });\n * ```\n *\n * @example Fully typed with your own code/type unions\n * ```ts\n * type AppCode = 'PE-AUTH-001' | 'PE-VAL-001';\n * type AppType = 'authentication_error' | 'validation_error';\n *\n * throw new LogixiaException<AppCode, AppType>({\n * code: 'PE-VAL-001',\n * type: 'validation_error',\n * httpStatus: 400,\n * message: 'Validation failed.',\n * details: [\n * { field: 'email', message: 'must be a valid email', code: 'invalid_format' },\n * ],\n * });\n * ```\n *\n * @example With field pointer (Stripe param pattern)\n * ```ts\n * throw new LogixiaException({\n * code: 'PE-USR-002',\n * type: 'conflict_error',\n * httpStatus: 409,\n * message: 'This email is already in use.',\n * param: 'email',\n * });\n * ```\n *\n * @example With cause chain (ES 2022)\n * ```ts\n * try {\n * await db.save(user);\n * } catch (err) {\n * throw new LogixiaException({\n * code: 'PE-DB-001',\n * type: 'server_error',\n * httpStatus: 409,\n * message: 'Duplicate record.',\n * cause: err instanceof Error ? err : undefined,\n * });\n * }\n * ```\n */\n\nimport type { ErrorDetail } from './types.js';\n\n// ── Options ───────────────────────────────────────────────────────────────────\n\n/**\n * Constructor options for `LogixiaException`.\n *\n * All user-supplied fields — logixia only owns the wire format.\n */\nexport interface LogixiaExceptionOptions<\n TCode extends string = string,\n TType extends string = string,\n> {\n /**\n * Machine-readable, stable error code.\n * e.g. `'PE-AUTH-001'`\n */\n code: TCode;\n\n /**\n * Broad error type category.\n * e.g. `'authentication_error'` | `'validation_error'` | `'rate_limit_error'`\n */\n type: TType;\n\n /**\n * HTTP status code to send on the wire.\n * e.g. `401` | `400` | `429` | `500`\n */\n httpStatus: number;\n\n /**\n * Human-readable message for the end-user.\n * This IS sent in the response body — keep it safe (no internal paths, etc.).\n */\n message: string;\n\n /**\n * The specific request field that caused this error (Stripe pattern).\n * e.g. `'email'` | `'metadata.name'`\n */\n param?: string;\n\n /**\n * Array of per-field validation errors (GitHub pattern).\n * Typically used for `400` / `422` validation failures.\n */\n details?: ErrorDetail[];\n\n /**\n * Documentation URL for this error (Twilio pattern).\n * e.g. `'https://docs.example.com/errors/PE-AUTH-001'`\n */\n docUrl?: string;\n\n /**\n * Original error for ES 2022 cause chaining.\n * Serialised into `debug.cause` by the `ErrorResponseBuilder`.\n * Never sent to the client in production.\n */\n cause?: Error;\n\n /**\n * Arbitrary metadata for logging purposes only.\n * This is **never** included in the HTTP response — it is passed to your\n * logger / monitoring integrations through the exception object.\n *\n * @example\n * ```ts\n * metadata: { userId: 'u_abc', attemptCount: 3 }\n * ```\n */\n metadata?: Record<string, unknown>;\n}\n\n// ── Exception class ───────────────────────────────────────────────────────────\n\nexport class LogixiaException<\n TCode extends string = string,\n TType extends string = string,\n> extends Error {\n /** @readonly The machine-readable error code supplied by the caller. */\n public readonly errorCode: TCode;\n /** @readonly The error type category supplied by the caller. */\n public readonly errorType: TType;\n /** @readonly HTTP status code to respond with. */\n public readonly httpStatus: number;\n /** @readonly Field pointer that caused this error (Stripe pattern). */\n public readonly param: string | undefined;\n /** @readonly Field-level validation errors (GitHub pattern). */\n public readonly details: ErrorDetail[] | undefined;\n /** @readonly Documentation URL for this error (Twilio pattern). */\n public readonly docUrl: string | undefined;\n /**\n * @readonly Extra context for your logger — never serialised into the HTTP response.\n */\n public readonly metadata: Record<string, unknown> | undefined;\n\n constructor(options: LogixiaExceptionOptions<TCode, TType>) {\n // Pass `cause` through the standard ES 2022 Error options so native\n // tooling (Node.js, Sentry, etc.) can walk the full error chain.\n super(options.message, { cause: options.cause });\n\n this.name = 'LogixiaException';\n this.errorCode = options.code;\n this.errorType = options.type;\n this.httpStatus = options.httpStatus;\n this.param = options.param;\n this.details = options.details;\n this.docUrl = options.docUrl;\n this.metadata = options.metadata;\n\n // Restore the correct prototype chain when compiling to ES5.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ── Type guard ────────────────────────────────────────────────────────────────\n\n/**\n * Returns `true` when `value` is a `LogixiaException` instance.\n *\n * Useful in exception filters or middleware that need to distinguish a\n * `LogixiaException` from a plain `Error` or a framework `HttpException`.\n *\n * @example\n * ```ts\n * if (isLogixiaException(err)) {\n * console.log(err.errorCode, err.httpStatus);\n * }\n * ```\n */\nexport function isLogixiaException<TCode extends string = string, TType extends string = string>(\n value?: unknown\n): value is LogixiaException<TCode, TType> {\n return value instanceof LogixiaException;\n}\n","/**\n * ErrorResponseBuilder — turns any exception into a `LogixiaErrorResponse`.\n *\n * Priority order:\n * 1. `LogixiaException` — typed fields used directly\n * 2. NestJS `HttpException` — duck-typed; status + message extracted\n * 3. Plain `Error` / unknown — falls back to 500 `server_error`\n *\n * The builder **always** populates `debug` when possible.\n * Your exception filter is responsible for stripping it in production:\n * ```ts\n * if (process.env.NODE_ENV === 'production') delete response.debug;\n * ```\n */\n\nimport { TraceContext } from '../utils/trace.utils.js';\nimport { isLogixiaException } from './exception.js';\nimport type { LogixiaErrorResponse } from './types.js';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\n/** Input parameters for `ErrorResponseBuilder.build`. */\nexport interface BuildParams {\n /** The caught exception — any type. */\n exception: unknown;\n /**\n * Trace ID to embed in `meta.trace_id`.\n * If omitted a UUID-based ID is auto-generated.\n */\n traceId?: string | undefined;\n /** Request path. e.g. `'/api/v1/auth/login'` */\n path: string;\n /**\n * Originating service name for `debug.service`.\n * e.g. `process.env.SERVICE_NAME` → `'gatekeeper'`\n */\n service?: string | undefined;\n /**\n * `Date.now()` captured at the start of the request.\n * When present, `debug.duration_ms` is computed automatically.\n */\n startTime?: number | undefined;\n /**\n * Include the `debug` block (stack trace, service, duration) in the response.\n * Disabled by default so internal details are never returned to clients unless\n * the caller opts in.\n * @default false\n */\n exposeDebug?: boolean | undefined;\n /**\n * Also include `debug.cause` (the underlying error message). Only applies when\n * `exposeDebug` is enabled, because causes often carry connection strings or\n * other internal detail.\n * @default false\n */\n exposeCause?: boolean | undefined;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\n/**\n * Generates a trace ID via the shared {@link TraceContext} generator.\n *\n * Delegates to `TraceContext.instance.generate()` so any custom generator\n * configured on `TraceIdConfig.generator` is respected — avoids the silent\n * \"builder has its own UUID source\" divergence this module had previously.\n *\n * @example `'550e8400-e29b-41d4-a716-446655440000'`\n */\nexport function generateTraceId(): string {\n return TraceContext.instance.generate();\n}\n\n/** @deprecated Use `generateTraceId` instead. */\nexport const generateRequestId = generateTraceId;\n\n/**\n * Maps an HTTP status code to a human-friendly error type string.\n * Used as a fallback when the exception is a generic `HttpException`.\n */\nfunction httpStatusToType(status: number): string {\n if (status === 400) return 'api_error';\n if (status === 401) return 'authentication_error';\n if (status === 402) return 'payment_error';\n if (status === 403) return 'authorization_error';\n if (status === 404) return 'not_found_error';\n if (status === 408) return 'timeout_error';\n if (status === 409) return 'conflict_error';\n if (status === 422) return 'validation_error';\n if (status === 429) return 'rate_limit_error';\n if (status >= 500) return 'server_error';\n if (status >= 400) return 'api_error';\n return 'server_error';\n}\n\n/**\n * Duck-type check for NestJS `HttpException`.\n * Avoids a hard import on `@nestjs/common` so the builder is usable outside NestJS.\n */\nfunction isHttpException(\n value: unknown\n): value is { getStatus(): number; getResponse(): unknown; message: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Record<string, unknown>)['getStatus'] === 'function' &&\n typeof (value as Record<string, unknown>)['getResponse'] === 'function'\n );\n}\n\n/**\n * Builds the optional `debug` block from an error.\n * Returns `undefined` when there is nothing useful to include.\n */\nfunction buildDebug(\n error: unknown,\n service: string | undefined,\n durationMs: number | undefined,\n expose: { debug?: boolean | undefined; cause?: boolean | undefined }\n): LogixiaErrorResponse['debug'] {\n if (expose.debug !== true) return undefined;\n const stack = error instanceof Error ? error.stack : undefined;\n\n const causeRaw =\n error instanceof Error ? (error as Error & { cause?: unknown }).cause : undefined;\n let cause: string | undefined;\n if (expose.cause !== true) {\n cause = undefined;\n } else if (causeRaw instanceof Error) {\n cause = causeRaw.message;\n } else if (causeRaw !== undefined && causeRaw !== null) {\n cause = String(causeRaw);\n }\n\n if (!stack && !cause && !service && durationMs === undefined) return undefined;\n\n return {\n ...(stack !== undefined ? { stack } : {}),\n ...(cause !== undefined ? { cause } : {}),\n ...(service !== undefined ? { service } : {}),\n ...(durationMs !== undefined ? { duration_ms: durationMs } : {}),\n };\n}\n\n// ── Builder ───────────────────────────────────────────────────────────────────\n\nexport class ErrorResponseBuilder {\n /**\n * Build a `LogixiaErrorResponse` from any thrown value.\n *\n * @param params - See `BuildParams`.\n * @returns The unified error response and the HTTP status code to send.\n *\n * @remarks\n * `traceId` does not need to be supplied by the caller in most cases — the\n * builder reads `TraceContext.instance.getCurrentTraceId()` internally and\n * falls back to the explicit `traceId` argument only when AsyncLocalStorage\n * is empty. If neither source yields a value, `meta.trace_id` is omitted.\n *\n * @example In a NestJS exception filter\n * ```ts\n * const { response, httpStatus } = ErrorResponseBuilder.build<AppCode, AppType>({\n * exception,\n * // Omit traceId — it will be picked up from ALS automatically.\n * path: request.url,\n * service: process.env.SERVICE_NAME,\n * startTime: request.startTime,\n * });\n *\n * if (process.env.NODE_ENV === 'production') delete response.debug;\n * // Echo the resolved traceId back on whatever header your TraceIdConfig says —\n * // do NOT hardcode 'X-Trace-Id', use `resolveResponseHeader(config)` instead.\n * if (response.meta.trace_id) {\n * response.setHeader(resolveResponseHeader(config) ?? 'X-Trace-Id', response.meta.trace_id);\n * }\n * response.status(httpStatus).json(response);\n * ```\n */\n static build<TCode extends string = string, TType extends string = string>(\n params: BuildParams\n ): { response: LogixiaErrorResponse<TCode, TType>; httpStatus: number } {\n const {\n exception,\n path,\n service,\n startTime,\n traceId: rawTraceId,\n exposeDebug,\n exposeCause,\n } = params;\n const expose = { debug: exposeDebug, cause: exposeCause };\n // ALS is authoritative → caller-supplied → undefined (field omitted from response).\n const traceId = TraceContext.instance.getCurrentTraceId() ?? rawTraceId;\n const timestamp = new Date().toISOString();\n const durationMs = startTime !== undefined ? Date.now() - startTime : undefined;\n\n // ── 1. LogixiaException ────────────────────────────────────────────────\n if (isLogixiaException<TCode, TType>(exception)) {\n const debug = buildDebug(exception, service, durationMs, expose);\n\n const errorBlock: LogixiaErrorResponse<TCode, TType>['error'] = {\n type: exception.errorType,\n code: exception.errorCode,\n message: exception.message,\n };\n if (exception.param !== undefined) errorBlock.param = exception.param;\n if (exception.details !== undefined && exception.details.length > 0) {\n errorBlock.details = exception.details;\n }\n if (exception.docUrl !== undefined) errorBlock.doc_url = exception.docUrl;\n\n const response: LogixiaErrorResponse<TCode, TType> = {\n success: false,\n error: errorBlock,\n meta: {\n ...(traceId !== undefined ? { trace_id: traceId } : {}),\n timestamp,\n path,\n status: exception.httpStatus,\n },\n ...(debug !== undefined ? { debug } : {}),\n };\n\n return { response, httpStatus: exception.httpStatus };\n }\n\n // ── 2. NestJS HttpException (duck-typed) ──────────────────────────────\n if (isHttpException(exception)) {\n const status = exception.getStatus();\n const exResponse = exception.getResponse();\n\n // NestJS nests the message: { statusCode, message, error } or a plain string\n let message: string;\n if (typeof exResponse === 'string') {\n message = exResponse;\n } else if (typeof exResponse === 'object' && exResponse !== null && 'message' in exResponse) {\n const raw = (exResponse as { message: unknown }).message;\n message = Array.isArray(raw) ? raw.join(', ') : String(raw);\n } else {\n message = exception.message;\n }\n\n const type = httpStatusToType(status) as TType;\n const code = `HTTP_${status}` as TCode;\n const debug = buildDebug(exception, service, durationMs, expose);\n\n const response: LogixiaErrorResponse<TCode, TType> = {\n success: false,\n error: { type, code, message },\n meta: { ...(traceId !== undefined ? { trace_id: traceId } : {}), timestamp, path, status },\n ...(debug !== undefined ? { debug } : {}),\n };\n\n return { response, httpStatus: status };\n }\n\n // ── 3. Unknown / plain Error ──────────────────────────────────────────\n const err = exception instanceof Error ? exception : new Error(String(exception));\n const debug = buildDebug(err, service, durationMs, expose);\n\n const response: LogixiaErrorResponse<TCode, TType> = {\n success: false,\n error: {\n type: 'server_error' as TType,\n code: 'INTERNAL_SERVER_ERROR' as TCode,\n message: 'An unexpected error occurred.',\n },\n meta: {\n ...(traceId !== undefined ? { trace_id: traceId } : {}),\n timestamp,\n path,\n status: 500,\n },\n ...(debug !== undefined ? { debug } : {}),\n };\n\n return { response, httpStatus: 500 };\n }\n}\n"],"mappings":"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"}
|
package/dist/chunk-DLSkYcPk.mjs
DELETED
package/dist/chunk-nOFOJqeH.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
//#region rolldown:runtime
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
-
key = keys[i];
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
-
get: ((k) => from[k]).bind(null, key),
|
|
13
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
-
value: mod,
|
|
20
|
-
enumerable: true
|
|
21
|
-
}) : target, mod));
|
|
22
|
-
|
|
23
|
-
//#endregion
|
|
24
|
-
|
|
25
|
-
Object.defineProperty(exports, '__toESM', {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
get: function () {
|
|
28
|
-
return __toESM;
|
|
29
|
-
}
|
|
30
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloudwatch.transport-BO1ahxw-.js","names":["out: Record<string, Record<string, string>>","section: Record<string, string> | undefined","path","os","text: string","fs","headers: Record<string, string>","httpRequest","crypto","headers: Record<string, string>","HttpError","DEFAULT_REQUEST_TIMEOUT_MS","BatchBuffer","DEFAULT_MAX_BUFFER_SIZE","isPermanentHttpError","stringifyForLog","mergeCoreFields","metricNames: string[]","httpRequest"],"sources":["../src/transports/aws-credentials.ts","../src/transports/aws-sigv4.ts","../src/transports/cloudwatch.transport.ts"],"sourcesContent":["/**\n * AWS credential resolution without the SDK.\n *\n * Order: explicit config, environment variables, shared credentials file,\n * ECS/container credentials, EC2 instance metadata (IMDSv2).\n * Not supported: SSO, assume-role profiles, credential_process, web identity.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\nimport { internalWarn } from '../utils/internal-log';\nimport { type AwsCredentials } from './aws-sigv4';\nimport { httpRequest } from './batch-buffer';\n\nconst REFRESH_MARGIN_MS = 5 * 60 * 1000;\nconst FAILURE_BACKOFF_MS = 30 * 1000;\nconst METADATA_TIMEOUT_MS = 2000;\n\nexport interface AwsCredentialConfig {\n accessKeyId?: string | undefined;\n secretAccessKey?: string | undefined;\n sessionToken?: string | undefined;\n}\n\n/** Parse the sections of an AWS ini file into `{ section: { key: value } }`. */\nexport function parseIni(text: string): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n let section: Record<string, string> | undefined;\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (!line || line.startsWith('#') || line.startsWith(';')) continue;\n const header = /^\\[(.+)\\]$/.exec(line);\n if (header) {\n section = out[header[1]!.trim()] = out[header[1]!.trim()] ?? {};\n continue;\n }\n const eq = line.indexOf('=');\n if (eq > 0 && section) section[line.slice(0, eq).trim()] = line.slice(eq + 1).trim();\n }\n return out;\n}\n\nfunction fromEnv(): AwsCredentials | undefined {\n const accessKeyId = process.env['AWS_ACCESS_KEY_ID'];\n const secretAccessKey = process.env['AWS_SECRET_ACCESS_KEY'];\n if (!accessKeyId || !secretAccessKey) return undefined;\n return { accessKeyId, secretAccessKey, sessionToken: process.env['AWS_SESSION_TOKEN'] };\n}\n\nfunction fromSharedFile(): AwsCredentials | undefined {\n const file =\n process.env['AWS_SHARED_CREDENTIALS_FILE'] ?? path.join(os.homedir(), '.aws', 'credentials');\n const profile = process.env['AWS_PROFILE'] ?? 'default';\n let text: string;\n try {\n text = fs.readFileSync(file, 'utf8');\n } catch {\n return undefined;\n }\n const section = parseIni(text)[profile];\n const accessKeyId = section?.['aws_access_key_id'];\n const secretAccessKey = section?.['aws_secret_access_key'];\n if (!accessKeyId || !secretAccessKey) return undefined;\n return { accessKeyId, secretAccessKey, sessionToken: section?.['aws_session_token'] };\n}\n\ninterface CredentialDocument {\n AccessKeyId?: string;\n SecretAccessKey?: string;\n Token?: string;\n Expiration?: string;\n}\n\nfunction fromDocument(raw: string): AwsCredentials | undefined {\n const doc = JSON.parse(raw) as CredentialDocument;\n if (!doc.AccessKeyId || !doc.SecretAccessKey) return undefined;\n const expiresAt = doc.Expiration ? Date.parse(doc.Expiration) : Number.NaN;\n return {\n accessKeyId: doc.AccessKeyId,\n secretAccessKey: doc.SecretAccessKey,\n sessionToken: doc.Token,\n expiresAt: Number.isNaN(expiresAt) ? undefined : expiresAt,\n };\n}\n\nconst CONTAINER_HOSTS = new Set([\n // eslint-disable-next-line sonarjs/no-hardcoded-ip -- fixed ECS credentials endpoint\n '169.254.170.2',\n // eslint-disable-next-line sonarjs/no-hardcoded-ip -- fixed EKS pod identity endpoint\n '169.254.170.23',\n '[fd00:ec2::23]',\n 'localhost',\n '[::1]',\n]);\n\n/** Same rule as the AWS SDKs: never send the container token to an arbitrary http host. */\nfunction isAllowedContainerHost(url: URL): boolean {\n if (url.protocol === 'https:') return true;\n if (url.protocol !== 'http:') return false;\n return CONTAINER_HOSTS.has(url.hostname) || /^127(?:\\.\\d{1,3}){3}$/.test(url.hostname);\n}\n\nasync function fromContainer(): Promise<AwsCredentials | undefined> {\n const relative = process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'];\n const full = process.env['AWS_CONTAINER_CREDENTIALS_FULL_URI'];\n if (!relative && !full) return undefined;\n const url = new URL(relative ? `http://169.254.170.2${relative}` : (full as string));\n if (!relative && !isAllowedContainerHost(url)) {\n internalWarn(\n `ignoring AWS_CONTAINER_CREDENTIALS_FULL_URI: ${url.host} is not https or a loopback / ECS / EKS address`\n );\n return undefined;\n }\n const headers: Record<string, string> = {};\n const tokenFile = process.env['AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE'];\n const token = tokenFile\n ? fs.readFileSync(tokenFile, 'utf8').trim()\n : process.env['AWS_CONTAINER_AUTHORIZATION_TOKEN'];\n if (token) headers['Authorization'] = token;\n const res = await httpRequest({\n url,\n method: 'GET',\n headers,\n timeoutMs: METADATA_TIMEOUT_MS,\n label: 'AWS container credentials',\n });\n return fromDocument(res.body);\n}\n\nasync function fromInstanceMetadata(): Promise<AwsCredentials | undefined> {\n if (process.env['AWS_EC2_METADATA_DISABLED'] === 'true') return undefined;\n const base = process.env['AWS_EC2_METADATA_SERVICE_ENDPOINT'] ?? 'http://169.254.169.254';\n const get = (p: string, method: string, headers: Record<string, string>) =>\n httpRequest({\n url: new URL(p, base),\n method,\n headers,\n timeoutMs: METADATA_TIMEOUT_MS,\n label: 'EC2 instance metadata',\n });\n const session = await get('/latest/api/token', 'PUT', {\n 'X-aws-ec2-metadata-token-ttl-seconds': '21600',\n });\n const auth = { 'X-aws-ec2-metadata-token': session.body.trim() };\n const roles = await get('/latest/meta-data/iam/security-credentials/', 'GET', auth);\n const role = roles.body.split('\\n')[0]?.trim();\n if (!role) return undefined;\n const creds = await get(\n `/latest/meta-data/iam/security-credentials/${encodeURIComponent(role)}`,\n 'GET',\n auth\n );\n return fromDocument(creds.body);\n}\n\nexport class AwsCredentialProvider {\n private cached: AwsCredentials | undefined;\n private failedAt = 0;\n private readonly explicit: AwsCredentials | undefined;\n\n constructor(config: AwsCredentialConfig) {\n if (config.accessKeyId && config.secretAccessKey) {\n this.explicit = {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n sessionToken: config.sessionToken,\n };\n }\n }\n\n /** Throws when no source yields credentials, so the caller keeps its buffer. */\n async get(): Promise<AwsCredentials> {\n if (this.explicit) return this.explicit;\n const env = fromEnv();\n if (env) return env;\n if (this.cached && !this.isExpiring(this.cached)) return this.cached;\n if (Date.now() - this.failedAt < FAILURE_BACKOFF_MS) {\n throw new Error('no AWS credentials found (retrying shortly)');\n }\n\n let found = fromSharedFile();\n for (const source of [fromContainer, fromInstanceMetadata]) {\n if (found) break;\n try {\n found = await source();\n } catch {\n /* source not available here; try the next */\n }\n }\n if (!found) {\n this.failedAt = Date.now();\n throw new Error(\n 'no AWS credentials found: set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, a shared credentials file, container credentials, or run on EC2 with an instance role'\n );\n }\n this.cached = found;\n return found;\n }\n\n invalidate(): void {\n this.cached = undefined;\n this.failedAt = 0;\n }\n\n private isExpiring(c: AwsCredentials): boolean {\n return c.expiresAt !== undefined && c.expiresAt - Date.now() < REFRESH_MARGIN_MS;\n }\n}\n","/**\n * AWS Signature Version 4 request signing, dependency-free.\n */\n\nimport * as crypto from 'node:crypto';\n\nexport interface AwsCredentials {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string | undefined;\n /** Epoch ms after which the credentials are no longer valid. */\n expiresAt?: number | undefined;\n}\n\nexport interface SignV4Options {\n method: string;\n path: string;\n query?: string;\n /** Must include `host`. Names are lowercased before signing. */\n headers: Record<string, string>;\n body: string;\n region: string;\n service: string;\n credentials: AwsCredentials;\n date?: Date;\n}\n\nconst sha256Hex = (data: string): string => crypto.createHash('sha256').update(data).digest('hex');\n\nconst hmac = (key: Buffer | string, msg: string): Buffer =>\n crypto.createHmac('sha256', key).update(msg).digest();\n\n/** Returns the request headers (lowercase names) with `x-amz-date` and `authorization` added. */\nexport function signV4(opts: SignV4Options): Record<string, string> {\n const {\n method,\n path,\n query = '',\n body,\n region,\n service,\n credentials,\n headers: input,\n date,\n } = opts;\n const amzDate = (date ?? new Date()).toISOString().replace(/[:-]|\\.\\d{3}/g, '');\n const dateStamp = amzDate.slice(0, 8);\n\n const headers: Record<string, string> = {};\n for (const [k, v] of Object.entries(input)) headers[k.toLowerCase()] = v;\n headers['x-amz-date'] = amzDate;\n if (credentials.sessionToken) headers['x-amz-security-token'] = credentials.sessionToken;\n\n const names = Object.keys(headers).sort();\n const canonicalHeaders = names\n .map((n) => `${n}:${headers[n]!.trim().replace(/\\s+/g, ' ')}\\n`)\n .join('');\n const signedHeaders = names.join(';');\n\n const canonicalRequest = [\n method,\n path,\n query,\n canonicalHeaders,\n signedHeaders,\n sha256Hex(body),\n ].join('\\n');\n const scope = `${dateStamp}/${region}/${service}/aws4_request`;\n const stringToSign = ['AWS4-HMAC-SHA256', amzDate, scope, sha256Hex(canonicalRequest)].join('\\n');\n\n const signingKey = hmac(\n hmac(hmac(hmac(`AWS4${credentials.secretAccessKey}`, dateStamp), region), service),\n 'aws4_request'\n );\n const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex');\n\n headers['authorization'] =\n `AWS4-HMAC-SHA256 Credential=${credentials.accessKeyId}/${scope}, ` +\n `SignedHeaders=${signedHeaders}, Signature=${signature}`;\n return headers;\n}\n","/**\n * logixia — AWS CloudWatch Logs transport\n *\n * Sends log entries to AWS CloudWatch Logs via the PutLogEvents API.\n * Supports EMF (Embedded Metric Format) for automatic metric extraction.\n *\n * Auth, in order: explicit config, environment variables, the shared\n * credentials file (AWS_PROFILE, AWS_SHARED_CREDENTIALS_FILE), ECS container\n * credentials, then EC2 instance metadata (IMDSv2). SSO, assume-role profiles\n * and credential_process are not supported. No SDK dependency — raw HTTPS with\n * AWS Signature Version 4.\n *\n * The log group and stream are created on first use if they do not exist.\n *\n * @example\n * ```ts\n * import { CloudWatchTransport } from 'logixia';\n *\n * const logger = createLogger({\n * transports: {\n * cloudwatch: new CloudWatchTransport({\n * region: 'us-east-1',\n * logGroupName: '/myapp/production',\n * logStreamName: `api-${process.env.HOSTNAME}`,\n * batchSize: 100,\n * flushIntervalMs: 5000,\n * }),\n * },\n * });\n * ```\n */\n\nimport type { IAsyncTransport, TransportLogEntry } from '../types/transport.types';\nimport { internalWarn } from '../utils/internal-log';\nimport { stringifyForLog } from '../utils/safe-stringify';\nimport { AwsCredentialProvider } from './aws-credentials';\nimport { signV4 } from './aws-sigv4';\nimport {\n BatchBuffer,\n DEFAULT_MAX_BUFFER_SIZE,\n DEFAULT_REQUEST_TIMEOUT_MS,\n HttpError,\n httpRequest,\n isPermanentHttpError,\n} from './batch-buffer';\nimport { mergeCoreFields } from './entry-fields';\n\nexport interface CloudWatchTransportConfig {\n /** AWS region, e.g. `'us-east-1'`. Falls back to `AWS_REGION` env var. */\n region?: string;\n /** CloudWatch Logs group name. Created automatically if it does not exist. */\n logGroupName: string;\n /** CloudWatch Logs stream name. Defaults to hostname + process PID. */\n logStreamName?: string;\n /** Override the Logs endpoint, e.g. for LocalStack. Default: `https://logs.<region>.amazonaws.com`. */\n endpoint?: string;\n /** AWS access key ID. Falls back to the credential chain described above. */\n accessKeyId?: string;\n /** AWS secret access key. Used together with `accessKeyId`. */\n secretAccessKey?: string;\n /** AWS session token for temporary credentials. Used together with `accessKeyId`. */\n sessionToken?: string;\n /**\n * Number of log events to batch before flushing.\n * CloudWatch allows max 10,000 events per PutLogEvents call; larger values are capped.\n * @default 100\n */\n batchSize?: number;\n /**\n * Max ms between flushes even if batchSize is not reached.\n * @default 5000\n */\n flushIntervalMs?: number;\n /**\n * Enable EMF (Embedded Metric Format) — wraps log entries as CloudWatch\n * metric namespaces so numeric fields become CloudWatch Metrics automatically.\n * @default false\n */\n emf?: boolean;\n /** CloudWatch Metrics namespace used by EMF. @default 'Logixia' */\n emfNamespace?: string;\n /**\n * Payload fields published as EMF metrics. When set, only these numeric\n * fields become metrics; when unset every numeric payload field does (up to\n * the EMF limit of 100 per entry).\n */\n emfMetrics?: string[];\n /** Abort a request that has not finished after this many ms. @default 10000 */\n requestTimeoutMs?: number;\n /** Max buffered events; the oldest are dropped past this. @default 10000 */\n maxBufferSize?: number;\n /** Minimum log level to forward. */\n level?: string;\n}\n\nconst MAX_EVENTS_PER_PUT = 10_000;\nconst EMF_MAX_METRICS = 100;\n\n/** Error types worth retrying even though CloudWatch reports them as HTTP 400. */\nconst RETRYABLE_TYPES = new Set([\n 'ThrottlingException',\n 'ThrottledException',\n 'LimitExceededException',\n 'ServiceUnavailableException',\n 'ExpiredTokenException',\n 'ResourceNotFoundException',\n]);\n\nfunction awsErrorType(err: unknown): string | undefined {\n if (!(err instanceof HttpError)) return undefined;\n try {\n const type = (JSON.parse(err.body) as { __type?: string }).__type;\n return type?.split('#').pop();\n } catch {\n return undefined;\n }\n}\n\ninterface CwLogEvent {\n timestamp: number;\n message: string;\n}\n\n/**\n * AWS CloudWatch Logs transport with EMF support and batched PutLogEvents calls.\n */\nexport class CloudWatchTransport implements IAsyncTransport {\n public readonly name = 'cloudwatch';\n public readonly batchSize: number;\n public readonly flushInterval: number;\n public readonly level: string | undefined;\n\n private readonly buffer: BatchBuffer<CwLogEvent>;\n private readonly requestTimeoutMs: number;\n private flushTimer: NodeJS.Timeout | null = null;\n private readonly credentials: AwsCredentialProvider;\n private readonly endpoint: URL;\n private streamReady = false;\n\n private readonly region: string;\n private readonly logGroupName: string;\n private readonly logStreamName: string;\n private readonly emf: boolean;\n private readonly emfNamespace: string;\n private readonly emfMetrics: ReadonlySet<string> | undefined;\n\n constructor(config: CloudWatchTransportConfig) {\n this.region =\n config.region ??\n process.env['AWS_REGION'] ??\n process.env['AWS_DEFAULT_REGION'] ??\n 'us-east-1';\n this.logGroupName = config.logGroupName;\n this.logStreamName =\n config.logStreamName ?? `${process.env['HOSTNAME'] ?? 'node'}-${process.pid}`;\n this.credentials = new AwsCredentialProvider(config);\n this.endpoint = new URL(config.endpoint ?? `https://logs.${this.region}.amazonaws.com`);\n this.batchSize = Math.min(config.batchSize ?? 100, MAX_EVENTS_PER_PUT);\n this.emfNamespace = config.emfNamespace ?? 'Logixia';\n this.flushInterval = config.flushIntervalMs ?? 5000;\n this.emf = config.emf ?? false;\n this.emfMetrics = config.emfMetrics ? new Set(config.emfMetrics) : undefined;\n this.level = config.level;\n this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n this.buffer = new BatchBuffer<CwLogEvent>({\n name: 'CloudWatchTransport',\n batchSize: this.batchSize,\n maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,\n send: (events) => this.putLogEvents(events),\n shouldRetry: (err) =>\n !isPermanentHttpError(err) || RETRYABLE_TYPES.has(awsErrorType(err) ?? ''),\n });\n\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.flushInterval);\n if (this.flushTimer.unref) this.flushTimer.unref();\n }\n\n write(entry: TransportLogEntry): void {\n const timestamp = entry.timestamp ? new Date(entry.timestamp).getTime() : Date.now();\n const message = this.emf ? this.toEmf(entry) : stringifyForLog(entry);\n this.buffer.push({ timestamp, message });\n this.buffer.flushIfFull();\n }\n\n flush(): Promise<void> {\n return this.buffer.flush();\n }\n\n /**\n * Flush remaining events and stop the interval timer on shutdown. Without this\n * the manager's close() skips the transport (close was undefined) and any\n * buffered events were lost on deploy. Waits for any in-flight send first.\n */\n async close(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.buffer.close();\n }\n\n private toEmf(entry: TransportLogEntry): string {\n const { level, message, data: payload, timestamp } = entry;\n const fields = mergeCoreFields({ _aws: undefined, level, message }, payload);\n const metricNames: string[] = [];\n for (const [k, v] of Object.entries(fields)) {\n if (k === '_aws' || k === 'level' || k === 'message' || typeof v !== 'number') continue;\n if (this.emfMetrics && !this.emfMetrics.has(k)) continue;\n if (metricNames.length < EMF_MAX_METRICS) metricNames.push(k);\n }\n fields['_aws'] = {\n Timestamp: timestamp ? new Date(timestamp).getTime() : Date.now(),\n CloudWatchMetrics:\n metricNames.length > 0\n ? [\n {\n Namespace: this.emfNamespace,\n Dimensions: [['level']],\n Metrics: metricNames.map((n) => ({ Name: n, Unit: 'None' })),\n },\n ]\n : [],\n };\n return stringifyForLog(fields);\n }\n\n private async putLogEvents(events: CwLogEvent[]): Promise<void> {\n await this.ensureStream();\n const logEvents = [...events].sort((a, b) => a.timestamp - b.timestamp);\n try {\n await this.call('PutLogEvents', {\n logGroupName: this.logGroupName,\n logStreamName: this.logStreamName,\n logEvents,\n });\n } catch (err) {\n const type = awsErrorType(err);\n if (type === 'DataAlreadyAcceptedException') return;\n if (type === 'ResourceNotFoundException') this.streamReady = false;\n if (type === 'ExpiredTokenException') this.credentials.invalidate();\n throw err;\n }\n }\n\n private async ensureStream(): Promise<void> {\n if (this.streamReady) return;\n try {\n await this.call('CreateLogGroup', { logGroupName: this.logGroupName });\n } catch (err) {\n if (awsErrorType(err) === 'ExpiredTokenException') this.credentials.invalidate();\n if (!(err instanceof HttpError)) throw err;\n if (awsErrorType(err) !== 'ResourceAlreadyExistsException') {\n internalWarn(`CloudWatchTransport: CreateLogGroup failed, continuing (${err.message})`);\n }\n }\n try {\n await this.call('CreateLogStream', {\n logGroupName: this.logGroupName,\n logStreamName: this.logStreamName,\n });\n } catch (err) {\n if (awsErrorType(err) !== 'ResourceAlreadyExistsException') throw err;\n }\n this.streamReady = true;\n }\n\n private async call(action: string, payload: Record<string, unknown>): Promise<void> {\n const credentials = await this.credentials.get();\n const body = stringifyForLog(payload);\n const { host } = this.endpoint;\n const headers = signV4({\n method: 'POST',\n path: '/',\n headers: {\n host,\n 'content-type': 'application/x-amz-json-1.1',\n 'x-amz-target': `Logs_20140328.${action}`,\n },\n body,\n region: this.region,\n service: 'logs',\n credentials,\n });\n await httpRequest({\n url: this.endpoint,\n headers,\n body,\n timeoutMs: this.requestTimeoutMs,\n label: `CloudWatch ${action}`,\n });\n }\n}\n"],"mappings":"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"}
|