logixia 1.13.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +81 -16
  2. package/dist/{async-context-CwBNMm2E.mjs → async-context-BzJrbfQs.mjs} +8 -4
  3. package/dist/async-context-BzJrbfQs.mjs.map +1 -0
  4. package/dist/{async-context-CSHWoHMB.js → async-context-DyQQYq3I.js} +8 -4
  5. package/dist/async-context-DyQQYq3I.js.map +1 -0
  6. package/dist/{azure-monitor.transport-CG7ClkYj.d.ts → azure-monitor.transport-Cn_3Usvu.d.ts} +2 -2
  7. package/dist/{azure-monitor.transport-CG7ClkYj.d.ts.map → azure-monitor.transport-Cn_3Usvu.d.ts.map} +1 -1
  8. package/dist/{azure-monitor.transport-Cm74kXZS.d.mts → azure-monitor.transport-D7Da4RAb.d.mts} +2 -2
  9. package/dist/{azure-monitor.transport-Cm74kXZS.d.mts.map → azure-monitor.transport-D7Da4RAb.d.mts.map} +1 -1
  10. package/dist/azure.d.mts +2 -2
  11. package/dist/azure.d.ts +2 -2
  12. package/dist/browser.d.mts +9 -0
  13. package/dist/browser.d.mts.map +1 -1
  14. package/dist/browser.d.ts +9 -0
  15. package/dist/browser.d.ts.map +1 -1
  16. package/dist/browser.js +43 -12
  17. package/dist/browser.js.map +1 -1
  18. package/dist/browser.mjs +43 -12
  19. package/dist/browser.mjs.map +1 -1
  20. package/dist/{logitron-logger.module-Bs3XYZgF.mjs → builder-0gEzRopq.mjs} +383 -1021
  21. package/dist/builder-0gEzRopq.mjs.map +1 -0
  22. package/dist/{logitron-logger.module-BsDZR5BH.js → builder-D44QktIo.js} +411 -1155
  23. package/dist/builder-D44QktIo.js.map +1 -0
  24. package/dist/cli/index.js +130 -65
  25. package/dist/cloudwatch.d.mts +2 -2
  26. package/dist/cloudwatch.d.ts +2 -2
  27. package/dist/cloudwatch.js +2 -1
  28. package/dist/cloudwatch.mjs +2 -1
  29. package/dist/{cloudwatch.transport-pNBNWJLt.js → cloudwatch.transport-BO1ahxw-.js} +26 -19
  30. package/dist/cloudwatch.transport-BO1ahxw-.js.map +1 -0
  31. package/dist/{cloudwatch.transport-yBwm4OeO.mjs → cloudwatch.transport-DZ6ies7g.mjs} +26 -19
  32. package/dist/cloudwatch.transport-DZ6ies7g.mjs.map +1 -0
  33. package/dist/{cloudwatch.transport-CGHY4buE.d.mts → cloudwatch.transport-DsEq633o.d.ts} +9 -2
  34. package/dist/cloudwatch.transport-DsEq633o.d.ts.map +1 -0
  35. package/dist/{cloudwatch.transport-DK_8cKd3.d.ts → cloudwatch.transport-UlyZFWMn.d.mts} +9 -2
  36. package/dist/cloudwatch.transport-UlyZFWMn.d.mts.map +1 -0
  37. package/dist/{coerce.utils-BN980Y9V.js → coerce.utils-B-LilukN.js} +1 -1
  38. package/dist/{coerce.utils-BN980Y9V.js.map → coerce.utils-B-LilukN.js.map} +1 -1
  39. package/dist/{coerce.utils-Dxv4_ikC.mjs → coerce.utils-Cu6IUTgX.mjs} +1 -1
  40. package/dist/{coerce.utils-Dxv4_ikC.mjs.map → coerce.utils-Cu6IUTgX.mjs.map} +1 -1
  41. package/dist/correlation.d.mts +24 -6
  42. package/dist/correlation.d.mts.map +1 -1
  43. package/dist/correlation.d.ts +24 -6
  44. package/dist/correlation.d.ts.map +1 -1
  45. package/dist/correlation.js +41 -16
  46. package/dist/correlation.js.map +1 -1
  47. package/dist/correlation.mjs +41 -16
  48. package/dist/correlation.mjs.map +1 -1
  49. package/dist/entry-fields-BJkuPnIg.mjs +30 -0
  50. package/dist/entry-fields-BJkuPnIg.mjs.map +1 -0
  51. package/dist/entry-fields-BvOLFlJ4.js +36 -0
  52. package/dist/entry-fields-BvOLFlJ4.js.map +1 -0
  53. package/dist/gcp.d.mts +2 -2
  54. package/dist/gcp.d.ts +2 -2
  55. package/dist/gcp.js +2 -1
  56. package/dist/gcp.mjs +2 -1
  57. package/dist/{gcp.transport-BOhkVKlI.d.ts → gcp.transport-B7oc97sG.d.ts} +2 -2
  58. package/dist/gcp.transport-B7oc97sG.d.ts.map +1 -0
  59. package/dist/{gcp.transport-SHdtc1n0.js → gcp.transport-CHV8MGgz.js} +5 -5
  60. package/dist/gcp.transport-CHV8MGgz.js.map +1 -0
  61. package/dist/{gcp.transport-BJuNRFe_.mjs → gcp.transport-DBX5TPIy.mjs} +5 -5
  62. package/dist/gcp.transport-DBX5TPIy.mjs.map +1 -0
  63. package/dist/{gcp.transport-Bi6CUqZR.d.mts → gcp.transport-GrJurKo8.d.mts} +2 -2
  64. package/dist/gcp.transport-GrJurKo8.d.mts.map +1 -0
  65. package/dist/{index-BPKwwERo.d.mts → index-3mw5gaCw.d.mts} +2 -2
  66. package/dist/{index-BPKwwERo.d.mts.map → index-3mw5gaCw.d.mts.map} +1 -1
  67. package/dist/{index-C1X-TE5I.d.ts → index-DhIoploR.d.ts} +2 -2
  68. package/dist/{index-C1X-TE5I.d.ts.map → index-DhIoploR.d.ts.map} +1 -1
  69. package/dist/index.d.mts +99 -137
  70. package/dist/index.d.mts.map +1 -1
  71. package/dist/index.d.ts +99 -137
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +146 -510
  74. package/dist/index.js.map +1 -1
  75. package/dist/index.mjs +99 -431
  76. package/dist/index.mjs.map +1 -1
  77. package/dist/logitron-logger-BFDSO8Io.d.mts +257 -0
  78. package/dist/logitron-logger-BFDSO8Io.d.mts.map +1 -0
  79. package/dist/logitron-logger-UVeN-mQm.d.ts +257 -0
  80. package/dist/logitron-logger-UVeN-mQm.d.ts.map +1 -0
  81. package/dist/middleware.d.mts +11 -4
  82. package/dist/middleware.d.mts.map +1 -1
  83. package/dist/middleware.d.ts +11 -4
  84. package/dist/middleware.d.ts.map +1 -1
  85. package/dist/middleware.js +148 -24
  86. package/dist/middleware.js.map +1 -1
  87. package/dist/middleware.mjs +148 -24
  88. package/dist/middleware.mjs.map +1 -1
  89. package/dist/nest.d.mts +481 -6
  90. package/dist/nest.d.mts.map +1 -1
  91. package/dist/nest.d.ts +481 -6
  92. package/dist/nest.d.ts.map +1 -1
  93. package/dist/nest.js +884 -13
  94. package/dist/nest.js.map +1 -0
  95. package/dist/nest.mjs +863 -6
  96. package/dist/nest.mjs.map +1 -0
  97. package/dist/{search-CFQRISUv.mjs → search-BFbu_oVn.mjs} +35 -12
  98. package/dist/search-BFbu_oVn.mjs.map +1 -0
  99. package/dist/{search-njTI2hdo.js → search-C4V0OMEn.js} +35 -12
  100. package/dist/search-C4V0OMEn.js.map +1 -0
  101. package/dist/{search-DujhR94O.d.ts → search-CNh9uVwR.d.ts} +2 -3
  102. package/dist/search-CNh9uVwR.d.ts.map +1 -0
  103. package/dist/{search-CQOo-Iq6.d.mts → search-DXANsQ2n.d.mts} +2 -3
  104. package/dist/search-DXANsQ2n.d.mts.map +1 -0
  105. package/dist/search.d.mts +3 -3
  106. package/dist/search.d.ts +3 -3
  107. package/dist/search.js +2 -2
  108. package/dist/search.mjs +2 -2
  109. package/dist/slack.transport-BZzoXDPn.d.mts +112 -0
  110. package/dist/slack.transport-BZzoXDPn.d.mts.map +1 -0
  111. package/dist/slack.transport-BfJRouB2.js +654 -0
  112. package/dist/slack.transport-BfJRouB2.js.map +1 -0
  113. package/dist/slack.transport-Bzw7sucI.mjs +643 -0
  114. package/dist/slack.transport-Bzw7sucI.mjs.map +1 -0
  115. package/dist/slack.transport-CXjQYOes.d.ts +112 -0
  116. package/dist/slack.transport-CXjQYOes.d.ts.map +1 -0
  117. package/dist/testing.d.mts +2 -2
  118. package/dist/testing.d.ts +2 -2
  119. package/dist/trace.utils-CvXgaiQT.mjs +278 -0
  120. package/dist/trace.utils-CvXgaiQT.mjs.map +1 -0
  121. package/dist/trace.utils-DpBOLDtq.js +358 -0
  122. package/dist/trace.utils-DpBOLDtq.js.map +1 -0
  123. package/dist/{transport.manager-D6KL3t9V.mjs → transport.manager-BiuCAJd2.mjs} +526 -160
  124. package/dist/transport.manager-BiuCAJd2.mjs.map +1 -0
  125. package/dist/{transport.manager-BivyUTtU.js → transport.manager-CXbKKdVE.js} +537 -159
  126. package/dist/transport.manager-CXbKKdVE.js.map +1 -0
  127. package/dist/{transport.types-B5vcyv2k.d.mts → transport.types-BMnurPcc.d.mts} +23 -3
  128. package/dist/transport.types-BMnurPcc.d.mts.map +1 -0
  129. package/dist/{transport.types-BuY84TwO.d.ts → transport.types-CGoHpWQR.d.ts} +23 -3
  130. package/dist/transport.types-CGoHpWQR.d.ts.map +1 -0
  131. package/dist/transports.d.mts +50 -20
  132. package/dist/transports.d.mts.map +1 -1
  133. package/dist/transports.d.ts +50 -20
  134. package/dist/transports.d.ts.map +1 -1
  135. package/dist/transports.js +9 -5
  136. package/dist/transports.mjs +8 -6
  137. package/dist/worker-entry.js +307 -55
  138. package/dist/worker.d.mts +2 -2
  139. package/dist/worker.d.ts +2 -2
  140. package/dist/worker.js +1 -1
  141. package/dist/worker.mjs +1 -1
  142. package/dist/{worker.transport-CfH6z37Z.js → worker.transport-BdPxu3PN.js} +1 -1
  143. package/dist/{worker.transport-CfH6z37Z.js.map → worker.transport-BdPxu3PN.js.map} +1 -1
  144. package/dist/{worker.transport-mKXgNK0L.d.ts → worker.transport-CdzSZJmw.d.ts} +2 -2
  145. package/dist/{worker.transport-mKXgNK0L.d.ts.map → worker.transport-CdzSZJmw.d.ts.map} +1 -1
  146. package/dist/{worker.transport-BP8Q28Z2.d.mts → worker.transport-JvGPog3C.d.mts} +2 -2
  147. package/dist/{worker.transport-BP8Q28Z2.d.mts.map → worker.transport-JvGPog3C.d.mts.map} +1 -1
  148. package/dist/{worker.transport-BhMyvqQ2.mjs → worker.transport-lPxO2MVL.mjs} +1 -1
  149. package/dist/{worker.transport-BhMyvqQ2.mjs.map → worker.transport-lPxO2MVL.mjs.map} +1 -1
  150. package/package.json +27 -14
  151. package/dist/.tsbuildinfo +0 -1
  152. package/dist/async-context-CSHWoHMB.js.map +0 -1
  153. package/dist/async-context-CwBNMm2E.mjs.map +0 -1
  154. package/dist/cloudwatch.transport-CGHY4buE.d.mts.map +0 -1
  155. package/dist/cloudwatch.transport-DK_8cKd3.d.ts.map +0 -1
  156. package/dist/cloudwatch.transport-pNBNWJLt.js.map +0 -1
  157. package/dist/cloudwatch.transport-yBwm4OeO.mjs.map +0 -1
  158. package/dist/gcp.transport-BJuNRFe_.mjs.map +0 -1
  159. package/dist/gcp.transport-BOhkVKlI.d.ts.map +0 -1
  160. package/dist/gcp.transport-Bi6CUqZR.d.mts.map +0 -1
  161. package/dist/gcp.transport-SHdtc1n0.js.map +0 -1
  162. package/dist/logitron-logger.module-BdG1Jnpk.d.mts +0 -618
  163. package/dist/logitron-logger.module-BdG1Jnpk.d.mts.map +0 -1
  164. package/dist/logitron-logger.module-Bs3XYZgF.mjs.map +0 -1
  165. package/dist/logitron-logger.module-BsDZR5BH.js.map +0 -1
  166. package/dist/logitron-logger.module-CbXy2gfW.d.ts +0 -618
  167. package/dist/logitron-logger.module-CbXy2gfW.d.ts.map +0 -1
  168. package/dist/search-CFQRISUv.mjs.map +0 -1
  169. package/dist/search-CQOo-Iq6.d.mts.map +0 -1
  170. package/dist/search-DujhR94O.d.ts.map +0 -1
  171. package/dist/search-njTI2hdo.js.map +0 -1
  172. package/dist/transport.manager-BivyUTtU.js.map +0 -1
  173. package/dist/transport.manager-D6KL3t9V.mjs.map +0 -1
  174. package/dist/transport.types-B5vcyv2k.d.mts.map +0 -1
  175. package/dist/transport.types-BuY84TwO.d.ts.map +0 -1
  176. package/scripts/postinstall.js +0 -61
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nest.mjs","names":["LogixiaLoggerService","errorData: Record<string, string>","KafkaTraceInterceptor","config?: TraceIdConfig","requireTraceId: boolean","traceId: string | undefined","inner: { unsubscribe(): void } | undefined","TraceMiddleware","config?: TraceIdConfig","traceId: string | undefined","WebSocketTraceInterceptor","config?: TraceIdConfig","traceId: string | undefined","inner: { unsubscribe(): void } | undefined","DEFAULT_ROUTES: RouteInfo[]","LogixiaLoggerModule","resolvedTraceConfig: TraceIdConfig | undefined","traceConfig","defaultConfig: LoggerConfig","errLog: unknown","logger: LogixiaLoggerService | undefined","entry: Record<string, unknown>","exit: Record<string, unknown>","result","result: unknown","LogixiaExceptionFilter","logger?: LogixiaLoggerService","loggerConfig?: Partial<LoggerConfig>","options?: LogixiaExceptionFilterOptions","requestMeta: Record<string, unknown>","logPromise: Promise<void> | void"],"sources":["../src/core/logitron-nestjs.service.ts","../src/core/kafka-trace.interceptor.ts","../src/core/trace.middleware.ts","../src/core/websocket-trace.interceptor.ts","../src/core/logitron-logger.module.ts","../src/core/nestjs-extras.ts","../src/nest.ts"],"sourcesContent":["/**\n * NestJS Service integration for Logixia Logger\n *\n * Implements NestJS's `LoggerService` interface for framework compat, while\n * simultaneously exposing native async overloads that accept structured data:\n *\n * // NestJS compat — void, string context\n * logger.warn('message', 'AuthService');\n *\n * // Native async — Promise<void>, structured metadata\n * await logger.warn('message', { userId: 'u_abc', action: 'login' });\n *\n * TypeScript resolves the correct overload automatically based on the type of\n * the second argument:\n * - second arg is `Record<string, unknown>` → native path (returns Promise<void>)\n * - second arg is `string | undefined` → NestJS compat (returns void)\n *\n * No wrapper, no casting required on the calling side.\n */\n\nimport type { LoggerService } from '@nestjs/common';\nimport { Injectable, Scope } from '@nestjs/common';\n\nimport type { LoggerConfig, LogLevelString } from '../types';\nimport { LogLevel } from '../types';\n\n// ── Custom-level IntelliSense helpers ─────────────────────────────────────────\n\n/**\n * Level names that already have proper typed implementations on LogixiaLoggerService.\n * These are excluded from the auto-generated method type so we don't produce\n * duplicate / conflicting signatures.\n */\ntype _ServiceBuiltinLevels =\n 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'trace' | 'log' | 'logLevel';\n\n/**\n * Mapped type that adds one method per *custom* level (i.e. every key in TLevels\n * that is not already a built-in method on LogixiaLoggerService).\n *\n * @example\n * ServiceCustomLevelMethods<{ kafka: 3; mysql: 4; payment: 5 }>\n * // → { kafka(msg, data?): Promise<void>; mysql(...): …; payment(...): … }\n */\ntype ServiceCustomLevelMethods<TLevels extends Record<string, number>> = {\n readonly [K in keyof TLevels as K extends _ServiceBuiltinLevels ? never : K & string]: (\n message: string,\n data?: Record<string, unknown>\n ) => Promise<void>;\n};\n\n/**\n * The return type of `LogixiaLoggerService.create<T>(config)`.\n *\n * When `T` carries `levelOptions.levels`, this type intersects\n * `LogixiaLoggerService` with a method for every *custom* level so the IDE\n * suggests `service.kafka(...)`, `service.payment(...)`, etc.\n */\nexport type LogixiaServiceWithLevels<T extends LoggerConfig<Record<string, number>>> =\n T['levelOptions'] extends { levels: infer L }\n ? L extends Record<string, number>\n ? LogixiaLoggerService & ServiceCustomLevelMethods<L>\n : LogixiaLoggerService\n : LogixiaLoggerService;\n\n/**\n * Helper — extracts custom level names from a config object's `levelOptions.levels`.\n */\ntype _ExtractCustomLevelNames<T> = T extends { levelOptions?: { levels?: infer L } }\n ? L extends Record<string, number>\n ? Exclude<keyof L & string, _ServiceBuiltinLevels>\n : never\n : never;\n\n/**\n * Typed `LogixiaLoggerService` with autocomplete for custom levels.\n *\n * Accepts either:\n * - **string union** of custom level names: `LogixiaServiceWith<'kafka' | 'payment'>`\n * - **config object type** (via `typeof`): `LogixiaServiceWith<typeof logixiaConfig>`\n *\n * Define your config with `as const` once, derive the type everywhere:\n *\n * @example\n * ```ts\n * // logger.config.ts — define once\n * export const logixiaConfig = {\n * levelOptions: {\n * levels: { error: 0, warn: 1, info: 2, debug: 3, verbose: 4, kafka: 5, payment: 6 },\n * },\n * } as const;\n * export type AppLogger = LogixiaServiceWith<typeof logixiaConfig>;\n *\n * // any.controller.ts — use everywhere, no casting\n * constructor(private readonly logger: AppLogger) {}\n * // this.logger.kafka('msg') ← fully typed\n * // this.logger.payment('msg') ← fully typed\n * ```\n *\n * @example\n * ```ts\n * // Or use string union directly:\n * type AppLogger = LogixiaServiceWith<'kafka' | 'payment'>;\n * ```\n */\nexport type LogixiaServiceWith<T extends string | Record<string, unknown>> =\n LogixiaLoggerService & {\n readonly [\n K in T extends string ? Exclude<T, _ServiceBuiltinLevels> : _ExtractCustomLevelNames<T>\n ]: (message: string, data?: Record<string, unknown>) => Promise<void>;\n };\nimport { safeToString } from '../utils/coerce.utils';\nimport { internalError } from '../utils/internal-log';\nimport { getTraceContextKey, TraceContext } from '../utils/trace.utils';\nimport { LogixiaLogger } from './logitron-logger';\n\n@Injectable({ scope: Scope.TRANSIENT })\nexport class LogixiaLoggerService implements LoggerService {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- index signature required for dynamic custom-level methods\n [K: string]: any;\n\n private logger: LogixiaLogger;\n private context?: string;\n private _mergedConfig: LoggerConfig;\n\n constructor(config?: LoggerConfig) {\n const defaultConfig: LoggerConfig = {\n appName: 'NestJS-App',\n environment: 'development',\n traceId: true,\n format: {\n timestamp: true,\n colorize: true,\n json: false,\n },\n silent: false,\n levelOptions: {\n level: LogLevel.INFO,\n levels: {\n error: 0,\n warn: 1,\n log: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n log: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n fields: {\n timestamp: '[yyyy-mm-dd HH:MM:ss.MS]',\n level: '[log_level]',\n appName: '[app_name]',\n traceId: '[trace_id]',\n message: '[message]',\n payload: '[payload]',\n timeTaken: '[time_taken_MS]',\n },\n };\n\n this._mergedConfig = { ...defaultConfig, ...config };\n this.logger = new LogixiaLogger(this._mergedConfig);\n this._createCustomLevelMethods();\n }\n\n // Dynamically adds a proxy method for every custom level defined in levelOptions.levels\n // so that `service.payment('msg')` works the same as `service.logLevel('payment', 'msg')`.\n private _createCustomLevelMethods(): void {\n const levels = this._mergedConfig.levelOptions?.levels;\n if (!levels) return;\n for (const levelName of Object.keys(levels)) {\n const lower = levelName.toLowerCase();\n // Skip levels that already have a built-in implementation on this class\n if (typeof (this as Record<string, unknown>)[lower] !== 'undefined') continue;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this as any)[lower] = async (\n message: string,\n data?: Record<string, unknown>\n ): Promise<void> => {\n return this.logger.logLevel(lower, message, data);\n };\n }\n }\n\n // ── log / info ──────────────────────────────────────────────────────────────\n\n /**\n * NestJS `LoggerService.log` — void, string context.\n * Maps internally to `info`.\n *\n * @example `logger.log('User signed up', 'AuthService')`\n */\n log(message: unknown, context?: string): void {\n this.setContextIfProvided(context);\n this.logger\n .info(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.log failed', err));\n }\n\n /**\n * Native async `info` — structured data, returns `Promise<void>`.\n *\n * @example `await logger.info('User signed up', { userId: 'u_abc' })`\n */\n async info(message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.info(message, data);\n }\n\n // ── error ──────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.error(new Error('DB timeout'), { requestId: 'req_abc' })`\n * @example `await logger.error('Login failed', { userId: 'u_abc' })`\n */\n error(message: string | Error, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — string trace + optional context, returns `void`.\n *\n * @example `logger.error('Something failed', err.stack, 'AuthService')`\n */\n error(message: unknown, trace?: string, context?: string): void;\n\n error(\n message: unknown,\n dataOrTrace?: Record<string, unknown> | string,\n context?: string\n ): void | Promise<void> {\n // ── Native path: second arg is a structured-data object ──────────────────\n if (typeof dataOrTrace === 'object' && dataOrTrace !== null) {\n return message instanceof Error\n ? this.logger.error(message, dataOrTrace)\n : this.logger.error(this.formatMessage(message), dataOrTrace);\n }\n\n // ── NestJS compat path: second arg is trace string or undefined ──────────\n this.setContextIfProvided(context);\n const errorData: Record<string, string> = {};\n if (typeof dataOrTrace === 'string' && dataOrTrace) {\n errorData.stack = dataOrTrace;\n }\n\n const logPromise =\n message instanceof Error\n ? this.logger.error(message, errorData)\n : this.logger.error(this.formatMessage(message), errorData);\n\n logPromise.catch((err: unknown) => internalError('LogixiaLoggerService.error failed', err));\n }\n\n // ── warn ───────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.warn('Rate limit approaching', { userId: 'u_abc', count: 90 })`\n */\n warn(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.warn('Deprecated API used', 'PaymentService')`\n */\n warn(message: unknown, context?: string): void;\n\n warn(message: unknown, dataOrContext?: Record<string, unknown> | string): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.warn(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .warn(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.warn failed', err));\n }\n\n // ── debug ──────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n *\n * @example `await logger.debug('Cache miss', { key: 'user:abc', ttl: 300 })`\n */\n debug(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.debug('Processing request', 'OrderService')`\n */\n debug(message: unknown, context?: string): void;\n\n debug(message: unknown, dataOrContext?: Record<string, unknown> | string): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.debug(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .debug(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.debug failed', err));\n }\n\n // ── verbose ────────────────────────────────────────────────────────────────\n\n /**\n * Native async overload — structured metadata, returns `Promise<void>`.\n * Maps to `trace` level internally.\n *\n * @example `await logger.verbose('Socket message received', { event: 'ping', size: 42 })`\n */\n verbose(message: string, data: Record<string, unknown>): Promise<void>;\n\n /**\n * NestJS compat overload — optional context string, returns `void`.\n *\n * @example `logger.verbose('Connection established', 'WebSocketGateway')`\n */\n verbose(message: unknown, context?: string): void;\n\n verbose(\n message: unknown,\n dataOrContext?: Record<string, unknown> | string\n ): void | Promise<void> {\n if (typeof dataOrContext === 'object' && dataOrContext !== null) {\n return this.logger.trace(this.formatMessage(message), dataOrContext);\n }\n this.setContextIfProvided(typeof dataOrContext === 'string' ? dataOrContext : undefined);\n this.logger\n .trace(this.formatMessage(message))\n .catch((err: unknown) => internalError('LogixiaLoggerService.verbose failed', err));\n }\n\n // ── trace / logLevel ───────────────────────────────────────────────────────\n\n /**\n * Native async `trace` — lowest verbosity level, structured data.\n */\n async trace(message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.trace(message, data);\n }\n\n /**\n * Log at any named level with structured data.\n */\n logLevel(level: string, message: string, data?: Record<string, unknown>): Promise<void> {\n return this.logger.logLevel(level, message, data);\n }\n\n // ── Timing ─────────────────────────────────────────────────────────────────\n\n time(label: string): void {\n this.logger.time(label);\n }\n\n async timeEnd(label: string): Promise<number | undefined> {\n return this.logger.timeEnd(label);\n }\n\n async timeAsync<T>(label: string, fn: () => Promise<T>): Promise<T> {\n return this.logger.timeAsync(label, fn);\n }\n\n // ── Context / level management ─────────────────────────────────────────────\n\n setContext(context: string): void {\n const coerced = typeof context === 'string' ? context : safeToString(context);\n this.context = coerced;\n this.logger.setContext(coerced);\n }\n\n getContext(): string | undefined {\n return this.context;\n }\n\n setLevel(level: LogLevelString): void {\n this.logger.setLevel(level);\n }\n\n getLevel(): LogLevelString {\n return this.logger.getLevel();\n }\n\n // ── Child logger ───────────────────────────────────────────────────────────\n\n child(context: string, data?: Record<string, unknown>): LogixiaLoggerService {\n const childService = new LogixiaLoggerService(this._mergedConfig);\n childService.logger = this.logger.child(context, data) as LogixiaLogger;\n childService.context = context;\n return childService;\n }\n\n // ── Misc ───────────────────────────────────────────────────────────────────\n\n getCurrentTraceId(): string | undefined {\n return TraceContext.instance.getCurrentTraceId();\n }\n\n /** Returns the AsyncLocalStorage key currently used to store the trace ID. */\n get traceContextKey(): string {\n return getTraceContextKey();\n }\n\n async close(): Promise<void> {\n return this.logger.close();\n }\n\n static create<T extends LoggerConfig<Record<string, number>>>(\n config?: T\n ): LogixiaServiceWithLevels<T> {\n return new LogixiaLoggerService(config) as unknown as LogixiaServiceWithLevels<T>;\n }\n\n getLogger(): LogixiaLogger {\n return this.logger;\n }\n\n // ── Private helpers ────────────────────────────────────────────────────────\n\n private setContextIfProvided(context?: unknown): void {\n // NestJS framework occasionally passes non-string values (ExecutionContext,\n // arguments host, etc.) in the context slot. Silently ignore those — we\n // only want an explicit string label to override `this.context`.\n if (typeof context !== 'string' || context.length === 0) return;\n if (context !== this.context) {\n this.setContext(context);\n }\n }\n\n private formatMessage(message: unknown): string {\n if (typeof message === 'string') return message;\n // Use safeToString rather than raw JSON.stringify: NestJS passes arbitrary\n // values here, and JSON.stringify both THROWS on circular structures (which\n // would crash the log call) and RETURNS undefined for some inputs (e.g. a\n // toJSON returning undefined). safeToString handles both safely.\n return safeToString(message);\n }\n}\n","/** @format */\n\nimport type { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';\nimport { Injectable } from '@nestjs/common';\nimport { EMPTY, Observable } from 'rxjs';\n\nimport type { TraceIdConfig } from '../types';\nimport { extractTraceId, TraceContext } from '../utils/trace.utils';\nimport { LogixiaLoggerModule } from './logitron-logger.module';\n\n/**\n * Observable counters exposed for monitoring Kafka consumer trace hygiene.\n *\n * Usage:\n * import { KafkaTraceInterceptor } from 'logixia/nest';\n * setInterval(() => {\n * myMetrics.gauge('kafka.trace.dropped', KafkaTraceInterceptor.metrics.dropped);\n * }, 10_000);\n */\nexport interface KafkaTraceMetrics {\n /** Messages processed where a traceId was successfully resolved (body/header/ALS). */\n accepted: number;\n /** Messages handled without any traceId — `requireTraceId: false`. */\n acceptedWithoutTrace: number;\n /** Messages dropped because `requireTraceId: true` and no traceId was found. */\n dropped: number;\n}\n\n@Injectable()\nexport class KafkaTraceInterceptor implements NestInterceptor {\n /**\n * Process-wide counters. Readable from anywhere — scrape into your metrics\n * system (Prometheus, Datadog, CloudWatch) on an interval.\n */\n static readonly metrics: KafkaTraceMetrics = {\n accepted: 0,\n acceptedWithoutTrace: 0,\n dropped: 0,\n };\n\n /** Reset counters (tests). */\n static resetMetrics(): void {\n KafkaTraceInterceptor.metrics.accepted = 0;\n KafkaTraceInterceptor.metrics.acceptedWithoutTrace = 0;\n KafkaTraceInterceptor.metrics.dropped = 0;\n }\n\n private readonly ctx = TraceContext.instance;\n\n /**\n * @param config - TraceIdConfig options (extractor keys, contextKey, etc.)\n * @param requireTraceId - When true, messages with no traceId are silently skipped\n * (EMPTY Observable — message is ack'd, consumer stays alive).\n * A WARN is logged AND `KafkaTraceInterceptor.metrics.dropped`\n * increments so the missing traceId is observable end-to-end.\n * Default: false (handler runs without trace context).\n */\n constructor(\n private readonly config?: TraceIdConfig,\n private readonly requireTraceId: boolean = false\n ) {\n this.config = {\n enabled: true,\n contextKey: 'traceId',\n extractor: {\n body: ['traceId', 'trace_id', 'x-trace-id'],\n header: ['x-trace-id', 'trace-id'],\n },\n ...config,\n };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- NestJS interceptor interface requires Observable<any>\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n if (!this.config?.enabled) {\n return next.handle();\n }\n\n const rpcContext = context.switchToRpc();\n const data = rpcContext.getData();\n const rpcData = rpcContext.getContext();\n\n let traceId: string | undefined;\n\n if (this.config.extractor) {\n traceId = extractTraceId(\n { body: data, headers: rpcData?.headers ?? {}, query: {}, params: {} },\n this.config.extractor\n );\n }\n\n if (!traceId) {\n traceId = this.ctx.getCurrentTraceId();\n }\n\n if (!traceId) {\n if (this.requireTraceId) {\n // Warn via global logger (set when LogixiaLoggerModule boots) and ack\n // the message by returning EMPTY — consumer stays alive, no retry loop.\n KafkaTraceInterceptor.metrics.dropped++;\n LogixiaLoggerModule.getGlobalLogger()?.warn(\n `[KafkaTraceInterceptor] Missing traceId on topic \"${rpcData?.topic}\" — message skipped.`\n );\n return EMPTY;\n }\n KafkaTraceInterceptor.metrics.acceptedWithoutTrace++;\n return next.handle();\n }\n\n KafkaTraceInterceptor.metrics.accepted++;\n\n const kafkaContext = {\n messageType: 'kafka',\n topic: rpcData?.topic,\n partition: rpcData?.partition,\n offset: rpcData?.offset,\n key: rpcData?.key,\n timestamp: rpcData?.timestamp,\n };\n\n return new Observable((subscriber) => {\n // Capture the inner subscription so it is torn down when the outer\n // subscriber unsubscribes (consumer shutdown, upstream takeUntil/timeout).\n // Without returning it, the handler subscription leaked and kept running\n // after cancellation.\n let inner: { unsubscribe(): void } | undefined;\n this.ctx.run(\n traceId!,\n () => {\n inner = next.handle().subscribe({\n next: (value) => subscriber.next(value),\n error: (err) => subscriber.error(err),\n complete: () => subscriber.complete(),\n });\n },\n kafkaContext\n );\n return () => inner?.unsubscribe();\n });\n }\n}\n","/**\n * Trace ID middleware for NestJS integration\n */\n\nimport type { NestMiddleware } from '@nestjs/common';\nimport { Injectable, Optional } from '@nestjs/common';\nimport type { NextFunction, Request, Response } from 'express';\n\nimport type { TraceIdConfig } from '../types';\nimport { internalWarn } from '../utils/internal-log';\nimport { DEFAULT_TRACE_HEADERS, extractTraceId, TraceContext } from '../utils/trace.utils';\n\n/** Default response header used to echo the resolved traceId back to the caller. */\nexport const DEFAULT_TRACE_RESPONSE_HEADER = 'X-Trace-Id';\n\n/**\n * Resolve the response header name from config.\n * - `undefined` → default `'X-Trace-Id'`\n * - `string` → user's custom header\n * - `false` → `null` (suppress entirely)\n */\nexport function resolveResponseHeader(config?: TraceIdConfig): string | null {\n if (config?.responseHeader === false) return null;\n return config?.responseHeader ?? DEFAULT_TRACE_RESPONSE_HEADER;\n}\n\n/**\n * Echo the trace ID on the response, tolerating non-Express responses and\n * already-sent headers. NestJS can run on Fastify (reply.header() instead of\n * res.setHeader()), and on a closed/sent response setHeader throws — neither\n * should crash the request. The trace ID is still propagated via async context.\n */\nfunction writeTraceHeader(res: unknown, header: string, traceId: string): void {\n const r = res as {\n setHeader?: (k: string, v: string) => void;\n header?: (k: string, v: string) => void;\n headersSent?: boolean;\n };\n if (r.headersSent) return;\n try {\n if (typeof r.setHeader === 'function') r.setHeader(header, traceId);\n else if (typeof r.header === 'function') r.header(header, traceId);\n } catch {\n /* response not in a header-settable state — context propagation still works */\n }\n}\n\n// Extend Express Request interface — requires namespace to augment Express typings\n/* eslint-disable @typescript-eslint/no-namespace */\ndeclare global {\n namespace Express {\n interface Request {\n traceId?: string;\n }\n }\n}\n/* eslint-enable @typescript-eslint/no-namespace */\n\n@Injectable()\nexport class TraceMiddleware implements NestMiddleware {\n private readonly ctx = TraceContext.instance;\n\n constructor(@Optional() private readonly config?: TraceIdConfig) {\n const defaultExtractor = {\n header: DEFAULT_TRACE_HEADERS,\n query: ['traceId', 'trace_id'],\n };\n this.config = {\n enabled: true,\n generator: () => this.ctx.generate(),\n contextKey: 'traceId',\n ...config,\n extractor: config?.extractor\n ? { ...defaultExtractor, ...config.extractor }\n : defaultExtractor,\n };\n // Only mutate the process-wide context key when tracing is actually enabled —\n // otherwise a disabled middleware would still change global state.\n if (this.config.enabled) {\n this.ctx.setContextKey(this.config.contextKey ?? 'traceId');\n }\n }\n\n use(req: Request, res: Response, next: NextFunction): void {\n if (!this.config?.enabled) {\n return next();\n }\n\n let traceId: string | undefined;\n\n if (this.config.extractor) {\n traceId = extractTraceId(req, this.config.extractor);\n }\n\n if (!traceId && this.config.generator) {\n const candidate = this.config.generator();\n // Guard against a user-supplied generator that returns a bad value —\n // fall back to the built-in UUID generator so the request always has\n // a valid, non-empty traceId downstream.\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n traceId = candidate;\n } else {\n internalWarn(\n 'TraceIdConfig.generator returned a non-string/empty value — using built-in generator.'\n );\n }\n }\n if (!traceId) {\n traceId = this.ctx.generate();\n }\n\n req.traceId = traceId;\n\n const header = resolveResponseHeader(this.config);\n if (header) writeTraceHeader(res, header, traceId);\n\n this.ctx.run(traceId, () => next(), {\n method: req.method,\n url: req.url,\n userAgent: req.get('User-Agent'),\n ip: req.ip || req.socket?.remoteAddress || req.connection?.remoteAddress,\n });\n }\n}\n\n/**\n * Factory function to create trace middleware with configuration\n */\nexport function createTraceMiddleware(config?: TraceIdConfig): TraceMiddleware {\n return new TraceMiddleware(config);\n}\n\n/**\n * Functional middleware for Express-style usage\n */\nexport function traceMiddleware(config?: TraceIdConfig) {\n const ctx = TraceContext.instance;\n const defaultExtractor = {\n header: DEFAULT_TRACE_HEADERS,\n query: ['traceId', 'trace_id'],\n };\n const traceConfig = {\n enabled: true,\n generator: () => ctx.generate(),\n contextKey: 'traceId',\n ...config,\n extractor: config?.extractor ? { ...defaultExtractor, ...config.extractor } : defaultExtractor,\n };\n\n // Only mutate the process-wide context key when the middleware is actually\n // enabled — otherwise a disabled instance would still change global state.\n if (traceConfig.enabled) {\n ctx.setContextKey(traceConfig.contextKey ?? 'traceId');\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (!traceConfig.enabled) {\n return next();\n }\n\n let traceId: string | undefined;\n\n if (traceConfig.extractor) {\n traceId = extractTraceId(req, traceConfig.extractor);\n }\n\n if (!traceId && traceConfig.generator) {\n const candidate = traceConfig.generator();\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n traceId = candidate;\n } else {\n internalWarn(\n 'TraceIdConfig.generator returned a non-string/empty value — using built-in generator.'\n );\n }\n }\n if (!traceId) {\n traceId = ctx.generate();\n }\n\n req.traceId = traceId;\n\n const header = resolveResponseHeader(traceConfig);\n if (header) writeTraceHeader(res, header, traceId);\n\n ctx.run(traceId, () => next(), {\n method: req.method,\n url: req.url,\n userAgent: req.get('User-Agent'),\n ip: req.ip || req.socket?.remoteAddress || req.connection?.remoteAddress,\n });\n };\n}\n","/** @format */\n\nimport type { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';\nimport { Injectable } from '@nestjs/common';\nimport { Observable } from 'rxjs';\n\nimport type { TraceIdConfig } from '../types';\nimport { extractTraceId, TraceContext } from '../utils/trace.utils';\n\n@Injectable()\nexport class WebSocketTraceInterceptor implements NestInterceptor {\n private readonly ctx = TraceContext.instance;\n\n constructor(private readonly config?: TraceIdConfig) {\n this.config = {\n enabled: true,\n contextKey: 'traceId',\n extractor: {\n body: ['traceId', 'trace_id', 'x-trace-id'],\n header: ['x-trace-id', 'trace-id'],\n query: ['traceId', 'trace_id'],\n },\n ...config,\n };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- NestJS interceptor interface requires Observable<any>\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n // Check if trace ID is enabled\n if (!this.config?.enabled) {\n return next.handle();\n }\n\n const wsContext = context.switchToWs();\n const data = wsContext.getData();\n const client = wsContext.getClient();\n\n let traceId: string | undefined;\n\n // Try to extract existing trace ID using extractor\n if (this.config.extractor) {\n // Create a request-like object for extractTraceId\n const requestLike = {\n body: data,\n headers: client?.handshake?.headers || {},\n query: client?.handshake?.query || {},\n params: {},\n };\n traceId = extractTraceId(requestLike, this.config.extractor);\n }\n\n // Only use current trace ID if no extraction happened and we have one\n if (!traceId) {\n traceId = this.ctx.getCurrentTraceId();\n }\n\n // If still no trace ID and enabled, skip (don't generate)\n if (!traceId) {\n return next.handle();\n }\n\n // Set up WebSocket-specific context data\n const wsContextData = {\n messageType: 'websocket',\n event: data?.event,\n socketId: client?.id,\n rooms: client?.rooms ? Array.from(client.rooms) : [],\n clientAddress: client?.handshake?.address,\n };\n\n // Run the handler with trace ID context\n return new Observable((observer) => {\n // Capture the inner subscription so it is torn down when the outer observer\n // unsubscribes — otherwise the handler subscription leaks after the socket\n // disconnects or an upstream operator cancels.\n let inner: { unsubscribe(): void } | undefined;\n this.ctx.run(\n traceId!,\n () => {\n inner = next.handle().subscribe({\n next: (value) => observer.next(value),\n error: (err) => observer.error(err),\n complete: () => observer.complete(),\n });\n },\n wsContextData\n );\n return () => inner?.unsubscribe();\n });\n }\n}\n","import type {\n InjectionToken,\n MiddlewareConsumer,\n ModuleMetadata,\n NestModule,\n OptionalFactoryDependency,\n Type,\n} from '@nestjs/common';\nimport { Module, RequestMethod } from '@nestjs/common';\nimport type { RouteInfo } from '@nestjs/common/interfaces/middleware/middleware-configuration.interface';\nimport type { NextFunction, Request, Response } from 'express';\n\nimport type { LoggerConfig, TraceIdConfig } from '../types';\nimport { internalWarn } from '../utils/internal-log';\nimport { TraceContext } from '../utils/trace.utils';\nimport { KafkaTraceInterceptor } from './kafka-trace.interceptor';\nimport { LogixiaLoggerService } from './logitron-nestjs.service';\nimport { TraceMiddleware } from './trace.middleware';\nimport { WebSocketTraceInterceptor } from './websocket-trace.interceptor';\n\nconst DEFAULT_ROUTES: RouteInfo[] = [{ path: '*', method: RequestMethod.ALL }];\n\n// Constants for provider tokens\nexport const LOGIXIA_LOGGER_CONFIG = 'LOGIXIA_LOGGER_CONFIG';\nexport const LOGIXIA_TRACE_CONFIG = 'TRACE_CONFIG';\nexport const LOGIXIA_LOGGER_PREFIX = 'LOGIXIA_LOGGER_';\n\n// Export the service and interceptors for external use\nexport { KafkaTraceInterceptor } from './kafka-trace.interceptor';\nexport { LogixiaLoggerService } from './logitron-nestjs.service';\nexport { WebSocketTraceInterceptor } from './websocket-trace.interceptor';\n\n// Interface for module configuration\ninterface LogixiaModuleConfig {\n forRoutes?: RouteInfo[];\n exclude?: RouteInfo[];\n}\n\n// Interface for async configuration\nexport interface LogixiaAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n useExisting?: Type<LogixiaOptionsFactory>;\n useClass?: Type<LogixiaOptionsFactory>;\n useFactory?: (...args: unknown[]) => Promise<Partial<LoggerConfig>> | Partial<LoggerConfig>;\n inject?: Array<InjectionToken | OptionalFactoryDependency>;\n}\n\n// Interface for options factory\nexport interface LogixiaOptionsFactory {\n createLogixiaOptions(): Promise<Partial<LoggerConfig>> | Partial<LoggerConfig>;\n}\n\n/**\n * Logixia Logger Module for NestJS dependency injection\n */\n@Module({})\nexport class LogixiaLoggerModule implements NestModule {\n private config: LogixiaModuleConfig = {};\n private static loggerConfig: Partial<LoggerConfig> = {};\n\n /**\n * @internal Backing field for the global logger. Do not read or write\n * directly — use {@link getGlobalLogger} / {@link _setGlobalLogger} which\n * enforce single-init semantics.\n */\n // Retained for backwards compatibility with internal callers that read the\n // field directly (e.g. nestjs-extras). Treat as read-only — writes must go\n // through _setGlobalLogger / _resetGlobalLogger.\n // eslint-disable-next-line sonarjs/public-static-readonly -- intentional: we need to swap this in tests via _resetGlobalLogger, so `readonly` is too strict\n static _globalLogger: LogixiaLoggerService | null = null;\n\n /**\n * @internal Set the global logger exactly once.\n *\n * Called from the module's forRoot / forRootAsync factory. If the module is\n * initialised more than once in the same process (nested DI context, test\n * harness creating multiple apps, hot reload, etc.) a warning is written to\n * stderr and the first logger wins — silently overwriting would allow the\n * newer instance's transport config to replace the live one while the old\n * one is still being used by registered shutdown hooks, decorators, etc.\n *\n * Use {@link _resetGlobalLogger} in tests to reset between runs.\n */\n static _setGlobalLogger(service: LogixiaLoggerService): void {\n if (LogixiaLoggerModule._globalLogger !== null) {\n internalWarn(\n 'LogixiaLoggerModule.forRoot() was called more than once — ignoring the second init. ' +\n 'If this is intentional (e.g. in tests), call LogixiaLoggerModule._resetGlobalLogger() first.'\n );\n return;\n }\n LogixiaLoggerModule._globalLogger = service;\n }\n\n /** @internal Clear the global logger. Tests only. */\n static _resetGlobalLogger(): void {\n LogixiaLoggerModule._globalLogger = null;\n }\n\n /**\n * Returns the global LogixiaLoggerService instance that was created when the\n * module booted. Useful for logging outside of NestJS DI — utility functions,\n * plain scripts, decorators — without injecting the service everywhere.\n *\n * Returns `null` if called before `LogixiaLoggerModule.forRoot[Async]()` has\n * been initialised (i.e. before the NestJS app has started).\n *\n * @example\n * ```ts\n * // some-util.ts\n * import { LogixiaLoggerModule } from 'logixia/nest';\n *\n * export function doSomething() {\n * LogixiaLoggerModule.getGlobalLogger()?.info('doing something');\n * }\n * ```\n */\n static getGlobalLogger(): LogixiaLoggerService | null {\n return LogixiaLoggerModule._globalLogger;\n }\n\n configure(consumer: MiddlewareConsumer) {\n const { forRoutes = DEFAULT_ROUTES, exclude } = this.config;\n\n // Resolve the trace config ONCE at configure() time — it does not change\n // per request, so constructing a fresh TraceMiddleware on every invocation\n // (the old behaviour) was just allocation churn.\n let resolvedTraceConfig: TraceIdConfig | undefined;\n if (typeof LogixiaLoggerModule.loggerConfig.traceId === 'object') {\n resolvedTraceConfig = LogixiaLoggerModule.loggerConfig.traceId as TraceIdConfig;\n } else if (LogixiaLoggerModule.loggerConfig.traceId === true) {\n resolvedTraceConfig = {\n enabled: true,\n contextKey: 'traceId',\n generator: () => TraceContext.instance.generate(),\n };\n }\n\n const middleware = new TraceMiddleware(resolvedTraceConfig);\n const middlewareConfig = (req: Request, res: Response, next: NextFunction) =>\n middleware.use(req, res, next);\n\n if (exclude) {\n consumer\n .apply(middlewareConfig)\n .exclude(...exclude)\n .forRoutes(...forRoutes);\n } else {\n consumer.apply(middlewareConfig).forRoutes(...forRoutes);\n }\n }\n\n /**\n * Configure the module with synchronous options\n */\n static forRoot(config?: Partial<LoggerConfig>) {\n // Store config for middleware access\n LogixiaLoggerModule.loggerConfig = config || {};\n\n const traceConfig =\n config?.traceId && typeof config.traceId === 'object'\n ? config.traceId\n : { enabled: !!config?.traceId };\n\n return {\n module: LogixiaLoggerModule,\n providers: [\n {\n provide: LOGIXIA_LOGGER_CONFIG,\n useValue: config || {},\n },\n {\n provide: LOGIXIA_TRACE_CONFIG,\n useValue: traceConfig,\n },\n {\n provide: LogixiaLoggerService,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n const defaultConfig: LoggerConfig = {\n level: 'info',\n service: 'NestJSApp',\n environment: 'development',\n fields: {},\n formatters: ['text'],\n outputs: ['console'],\n levelOptions: {\n level: 'info', // INFO level\n levels: {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n info: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n ...loggerConfig,\n };\n const service = new LogixiaLoggerService(defaultConfig);\n LogixiaLoggerModule._setGlobalLogger(service);\n return service;\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: KafkaTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new KafkaTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n {\n provide: WebSocketTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new WebSocketTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n ],\n exports: [\n LogixiaLoggerService,\n LOGIXIA_LOGGER_CONFIG,\n KafkaTraceInterceptor,\n WebSocketTraceInterceptor,\n ],\n global: true,\n };\n }\n\n /**\n * Configure the module with asynchronous options\n */\n static forRootAsync(options: LogixiaAsyncOptions) {\n return {\n module: LogixiaLoggerModule,\n imports: options.imports || [],\n providers: [\n ...this.createAsyncProviders(options),\n {\n provide: LOGIXIA_TRACE_CONFIG,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n return typeof loggerConfig?.traceId === 'object'\n ? loggerConfig.traceId\n : { enabled: !!loggerConfig?.traceId };\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: LogixiaLoggerService,\n useFactory: (loggerConfig: Partial<LoggerConfig>) => {\n const defaultConfig: LoggerConfig = {\n level: 'info',\n service: 'NestJSApp',\n environment: 'development',\n fields: {},\n formatters: ['text'],\n outputs: ['console'],\n levelOptions: {\n level: 'info', // INFO level\n levels: {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n verbose: 4,\n },\n colors: {\n error: 'red',\n warn: 'yellow',\n info: 'green',\n debug: 'blue',\n verbose: 'cyan',\n },\n },\n ...loggerConfig,\n };\n // Store config for middleware access\n LogixiaLoggerModule.loggerConfig = defaultConfig;\n const service = new LogixiaLoggerService(defaultConfig);\n LogixiaLoggerModule._setGlobalLogger(service);\n return service;\n },\n inject: [LOGIXIA_LOGGER_CONFIG],\n },\n {\n provide: KafkaTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new KafkaTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n {\n provide: WebSocketTraceInterceptor,\n useFactory: (traceConfig: TraceIdConfig | undefined) =>\n new WebSocketTraceInterceptor(traceConfig),\n inject: [LOGIXIA_TRACE_CONFIG],\n },\n ],\n exports: [\n LogixiaLoggerService,\n LOGIXIA_LOGGER_CONFIG,\n KafkaTraceInterceptor,\n WebSocketTraceInterceptor,\n ],\n global: true,\n };\n }\n\n /**\n * Create feature-specific logger instances\n */\n static forFeature(context: string) {\n const providerToken = `${LOGIXIA_LOGGER_PREFIX}${context.toUpperCase()}`;\n return {\n module: LogixiaLoggerModule,\n providers: [\n {\n provide: providerToken,\n useFactory: (baseLogger: LogixiaLoggerService) => {\n return baseLogger.child(context);\n },\n inject: [LogixiaLoggerService],\n },\n ],\n exports: [providerToken],\n };\n }\n\n private static createAsyncProviders(options: LogixiaAsyncOptions) {\n if (options.useExisting || options.useFactory) {\n return [this.createAsyncOptionsProvider(options)];\n }\n return [\n this.createAsyncOptionsProvider(options),\n {\n provide: options.useClass!,\n useClass: options.useClass!,\n },\n ];\n }\n\n private static createAsyncOptionsProvider(options: LogixiaAsyncOptions) {\n if (options.useFactory) {\n return {\n provide: LOGIXIA_LOGGER_CONFIG,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n }\n return {\n provide: LOGIXIA_LOGGER_CONFIG,\n useFactory: async (optionsFactory: LogixiaOptionsFactory) =>\n await optionsFactory.createLogixiaOptions(),\n inject: [options.useExisting || options.useClass!],\n };\n }\n}\n","/**\n * logixia — NestJS extras: @InjectLogger, @LogMethod, LogixiaExceptionFilter\n *\n * Completes the NestJS deep integration story:\n * - @InjectLogger() — inject the logger via NestJS DI without typing LOGIXIA_TOKEN manually\n * - @LogMethod() — auto-log method entry / exit with args and return value\n * - LogixiaExceptionFilter — catch-all exception filter that logs unhandled errors\n * with full request context before re-throwing\n *\n * @example Full setup\n * ```ts\n * // app.module.ts\n * import { LogixiaModule } from 'logixia';\n * @Module({ imports: [LogixiaModule.forRoot({ appName: 'api' })] })\n * export class AppModule {}\n *\n * // order.service.ts\n * import { Injectable } from '@nestjs/common';\n * import { InjectLogger, LogMethod, LogixiaLoggerService } from 'logixia';\n *\n * @Injectable()\n * export class OrderService {\n * constructor(@InjectLogger() private readonly logger: LogixiaLoggerService) {}\n *\n * @LogMethod()\n * async createOrder(dto: CreateOrderDto) { … }\n * }\n *\n * // main.ts\n * import { LogixiaExceptionFilter } from 'logixia';\n * app.useGlobalFilters(new LogixiaExceptionFilter(logger));\n * ```\n */\n\nimport type { ArgumentsHost, ExceptionFilter } from '@nestjs/common';\nimport { Catch, Inject, Optional } from '@nestjs/common';\n\nimport { ErrorResponseBuilder } from '../exceptions/builder';\nimport { isLogixiaException } from '../exceptions/exception';\nimport type { LoggerConfig, LogLevelString, TraceIdConfig } from '../types';\nimport { internalError, internalWarn } from '../utils/internal-log';\nimport { sanitizeIncomingId, TraceContext } from '../utils/trace.utils';\nimport {\n LOGIXIA_LOGGER_CONFIG,\n LOGIXIA_LOGGER_PREFIX,\n LogixiaLoggerModule,\n} from './logitron-logger.module';\nimport type { LogixiaLoggerService } from './logitron-nestjs.service';\nimport { resolveResponseHeader } from './trace.middleware';\n\n// ── @InjectLogger() ──────────────────────────────────────────────────────────\n\n/**\n * Inject the Logixia logger registered in the current NestJS DI container.\n *\n * Equivalent to `@Inject(LOGIXIA_LOGGER_TOKEN)` but without needing to import\n * the internal token constant yourself.\n *\n * @example\n * ```ts\n * constructor(@InjectLogger() private readonly logger: LogixiaLoggerService) {}\n * ```\n */\nexport const InjectLogger = (): ParameterDecorator => Inject(`${LOGIXIA_LOGGER_PREFIX}SERVICE`);\n\n// ── @LogMethod() ─────────────────────────────────────────────────────────────\n\nexport interface LogMethodOptions {\n /**\n * Log level to use for entry / exit messages.\n * @default 'debug'\n */\n level?: LogLevelString;\n /**\n * Whether to log the arguments passed to the method.\n * Disable for high-throughput hot paths.\n * @default true\n */\n logArgs?: boolean;\n /**\n * Whether to log the return value of the method.\n * @default false\n */\n logResult?: boolean;\n /**\n * Whether to log error stack traces for thrown errors.\n * @default true\n */\n logErrors?: boolean;\n /**\n * Custom label used in log messages instead of the auto-detected class.method name.\n */\n label?: string;\n}\n\n/**\n * Method decorator that auto-logs entry, exit, duration, and errors.\n *\n * Preserves the original method's sync/async contract: a synchronous method\n * stays synchronous (returns its value directly, with logs emitted\n * fire-and-forget), and an async method is awaited so exit/error logs reflect\n * the resolved result. Attaches to the logger found on the class instance via a\n * `logger` property (the conventional NestJS name).\n *\n * @example\n * ```ts\n * @LogMethod({ level: 'info', logArgs: true })\n * async processPayment(orderId: string): Promise<void> { … }\n * ```\n */\nexport function LogMethod(options: LogMethodOptions = {}): MethodDecorator {\n const { level = 'debug', logArgs = true, logResult = false, logErrors = true } = options;\n\n // Use PropertyDescriptor (not generic TypedPropertyDescriptor<T>) to avoid\n // strict generic inference issues with exactOptionalPropertyTypes.\n return function (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor\n ): PropertyDescriptor {\n const originalMethod = descriptor.value as ((...args: unknown[]) => unknown) | undefined;\n if (typeof originalMethod !== 'function') return descriptor;\n\n const methodName = String(propertyKey);\n const className =\n (target as { constructor?: { name?: string } }).constructor?.name ?? 'Unknown';\n const label = options.label ?? `${className}.${methodName}`;\n\n let _warnedNoLogger = false;\n\n // Surface logger failures on stderr instead of silently swallowing them.\n const reportLogFailure = (phase: string, err: unknown): void => {\n internalError(`@LogMethod(${label}) ${phase} log failed: ${String(err)}`);\n };\n\n // Emit a log line fire-and-forget, routing transport failures to stderr.\n const emit = (\n logger: LogixiaLoggerService,\n phase: string,\n message: string,\n data: Record<string, unknown>\n ): void => {\n const logFnRaw = (\n logger as unknown as Record<\n string,\n (msg: string, data?: Record<string, unknown>) => Promise<void>\n >\n )[level];\n const logFn = (typeof logFnRaw === 'function' ? logFnRaw : logger.debug).bind(logger);\n const p = logFn(message, data);\n if (p && typeof (p as Promise<void>).catch === 'function') {\n (p as Promise<void>).catch((e: unknown) => reportLogFailure(phase, e));\n }\n };\n\n const emitError = (logger: LogixiaLoggerService, error: unknown, start: number): void => {\n const err = error instanceof Error ? error : new Error(String(error));\n const errLog: unknown = logger.error(err, { method: label, durationMs: Date.now() - start });\n if (errLog && typeof (errLog as Promise<void>).catch === 'function') {\n (errLog as Promise<void>).catch((e: unknown) => reportLogFailure('error', e));\n }\n };\n\n descriptor.value = function (this: { logger?: LogixiaLoggerService }, ...args: unknown[]) {\n // Prefer the instance's own logger; fall back to the global module logger.\n const logger: LogixiaLoggerService | undefined =\n this.logger ?? LogixiaLoggerModule._globalLogger ?? undefined;\n\n if (!logger && !_warnedNoLogger) {\n _warnedNoLogger = true;\n internalWarn(\n `@LogMethod on ${label}: no logger available. ` +\n `Either inject LogixiaLoggerService as this.logger or ensure LogixiaLoggerModule is initialised.`\n );\n }\n\n const start = Date.now();\n const entry: Record<string, unknown> = { method: label };\n if (logArgs && args.length > 0) entry['args'] = args;\n // Entry log is fire-and-forget so a SYNC method is not forced to become\n // async just to await it.\n if (logger) emit(logger, 'entry', `→ ${label}`, entry);\n\n const buildExit = (result: unknown): Record<string, unknown> => {\n const exit: Record<string, unknown> = { method: label, durationMs: Date.now() - start };\n if (logResult) exit['result'] = result;\n return exit;\n };\n\n let result: unknown;\n try {\n result = originalMethod.apply(this, args);\n } catch (error) {\n // Synchronous throw.\n if (logger && logErrors) emitError(logger, error, start);\n throw error;\n }\n\n // Async method → await via the returned thenable so exit/error reflect the\n // resolved outcome, and preserve the Promise return type.\n if (result && typeof (result as PromiseLike<unknown>).then === 'function') {\n return (result as Promise<unknown>).then(\n (resolved) => {\n if (logger) emit(logger, 'exit', `← ${label}`, buildExit(resolved));\n return resolved;\n },\n (error: unknown) => {\n if (logger && logErrors) emitError(logger, error, start);\n throw error;\n }\n );\n }\n\n // Synchronous method → log exit fire-and-forget and return the value as-is,\n // preserving the original synchronous contract.\n if (logger) emit(logger, 'exit', `← ${label}`, buildExit(result));\n return result;\n };\n\n return descriptor;\n };\n}\n\n// ── LogixiaExceptionFilter ───────────────────────────────────────────────────\n\n/**\n * Global NestJS exception filter that converts any exception into the standard\n * `LogixiaErrorResponse` wire format and logs it with full request context.\n *\n * Handles three exception types in priority order:\n * 1. `LogixiaException` — typed fields used directly\n * 2. NestJS `HttpException` — status + message extracted\n * 3. Unknown / plain Error — falls back to 500 `server_error`\n *\n * **Debug block (off by default):**\n * Responses never include the `debug` block (stack trace, service, duration)\n * unless `exposeDebug: true` is passed in the filter options. The underlying\n * `cause` is only added when `exposeCause: true` is also set. Enable explicitly\n * for local development only, e.g.\n * `new LogixiaExceptionFilter(logger, undefined, { exposeDebug: process.env.NODE_ENV === 'development' })`.\n *\n * **Trace ID headers:**\n * `X-Trace-ID` and `X-Request-ID` are echoed back on every error response so\n * clients can correlate with server logs.\n *\n * **Retry-After header:**\n * Automatically added for `429` responses (`Retry-After: 60`).\n *\n * Register in `main.ts`:\n * ```ts\n * const logger = app.get(LogixiaLoggerService);\n * app.useGlobalFilters(new LogixiaExceptionFilter(logger));\n * ```\n */\nexport interface LogixiaExceptionFilterOptions {\n /**\n * Include the `debug` block (stack trace, service, duration) in error responses.\n * @default false\n */\n exposeDebug?: boolean;\n /**\n * Include `debug.cause` as well. Requires `exposeDebug`.\n * @default false\n */\n exposeCause?: boolean;\n}\n\n/** Injection token for {@link LogixiaExceptionFilterOptions}. */\nexport const LOGIXIA_EXCEPTION_FILTER_OPTIONS = 'LOGIXIA_EXCEPTION_FILTER_OPTIONS';\n\n@Catch()\nexport class LogixiaExceptionFilter implements ExceptionFilter {\n private readonly _logger: LogixiaLoggerService | undefined;\n private readonly _traceConfig: TraceIdConfig | undefined;\n private readonly _options: LogixiaExceptionFilterOptions;\n\n constructor(\n @Optional()\n @Inject(`${LOGIXIA_LOGGER_PREFIX}SERVICE`)\n logger?: LogixiaLoggerService,\n @Optional()\n @Inject(LOGIXIA_LOGGER_CONFIG)\n loggerConfig?: Partial<LoggerConfig>,\n @Optional()\n @Inject(LOGIXIA_EXCEPTION_FILTER_OPTIONS)\n options?: LogixiaExceptionFilterOptions\n ) {\n this._options = options ?? {};\n // Prefer the injected logger; fall back to the global module logger so\n // `new LogixiaExceptionFilter()` (registered in main.ts before DI resolves)\n // still logs without needing an explicit logger argument.\n this._logger = logger ?? LogixiaLoggerModule._globalLogger ?? undefined;\n // Pick up the user-configured trace settings (response header name, etc.)\n // so the filter echoes the same header the middleware writes.\n this._traceConfig =\n typeof loggerConfig?.traceId === 'object' ? loggerConfig.traceId : undefined;\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n\n const request = ctx.getRequest<{\n method?: string;\n url?: string;\n id?: string;\n startTime?: number;\n headers?: Record<string, string | string[] | undefined>;\n }>();\n\n interface MinimalResponse {\n status(code: number): MinimalResponse;\n json(body: unknown): void;\n setHeader(name: string, value: string): void;\n }\n const response = ctx.getResponse<MinimalResponse>();\n\n // ALS is the single source of truth (set by TraceMiddleware).\n // Fall back to header/request.id only if ALS has nothing (e.g. traceId disabled).\n const traceId =\n TraceContext.instance.getCurrentTraceId() ??\n sanitizeIncomingId(request.headers?.['x-trace-id']) ??\n sanitizeIncomingId(request.id) ??\n undefined;\n\n const { response: errorResponse, httpStatus } = ErrorResponseBuilder.build({\n exception,\n traceId,\n path: request.url ?? '/',\n startTime: request.startTime,\n exposeDebug: this._options.exposeDebug === true,\n exposeCause: this._options.exposeCause === true,\n });\n\n // ── Logging ──────────────────────────────────────────────────────────────\n if (this._logger) {\n const requestMeta: Record<string, unknown> = {\n method: request.method ?? '',\n url: request.url ?? '',\n status: httpStatus,\n // Only include trace_id when it exists — keeps log records honest when\n // tracing is disabled (instead of writing `trace_id: undefined`).\n ...(errorResponse.meta.trace_id !== undefined\n ? { trace_id: errorResponse.meta.trace_id }\n : {}),\n };\n\n // `error()` / `warn()` return Promise<void> for the structured overload.\n // We cannot await inside a synchronous ExceptionFilter.catch(), so attach\n // a `.catch()` to prevent unhandledRejection if a transport fails — and\n // fall back to stderr so the error is never silently swallowed.\n const onLogFailure = (err: unknown): void => {\n internalError(`ExceptionFilter failed to write log entry: ${String(err)}`);\n };\n\n let logPromise: Promise<void> | void;\n if (httpStatus >= 500) {\n const err = exception instanceof Error ? exception : new Error(String(exception));\n logPromise = this._logger.error(err, requestMeta);\n } else if (isLogixiaException(exception)) {\n logPromise = this._logger.warn(\n `[${errorResponse.error.code}] ${errorResponse.error.message}`,\n requestMeta\n );\n } else {\n logPromise = this._logger.warn(\n `[${httpStatus}] ${errorResponse.error.message}`,\n requestMeta\n );\n }\n\n if (logPromise && typeof (logPromise as Promise<void>).catch === 'function') {\n (logPromise as Promise<void>).catch(onLogFailure);\n }\n }\n\n // ── Response headers ──────────────────────────────────────────────────\n if (errorResponse.meta.trace_id) {\n const traceHeader = resolveResponseHeader(this._traceConfig);\n if (traceHeader) {\n try {\n response.setHeader(traceHeader, errorResponse.meta.trace_id);\n } catch {\n /* headers already sent or invalid — the body still carries the trace id */\n }\n }\n }\n if (httpStatus === 429) {\n try {\n response.setHeader('Retry-After', '60');\n } catch {\n /* headers already sent */\n }\n }\n\n response.status(httpStatus).json(errorResponse);\n }\n}\n","/**\n * logixia/nest — NestJS integration\n *\n * @example\n * import { LogixiaLoggerModule, LogixiaLoggerService } from 'logixia/nest';\n *\n * @Module({\n * imports: [LogixiaLoggerModule.forRoot({ level: 'info' })],\n * })\n * export class AppModule {}\n */\n\nimport { DEFAULT_CONFIG } from './core/default-config';\nimport { LogixiaLoggerService } from './core/logitron-nestjs.service';\nimport type { LoggerConfig } from './types';\n\n// Everything NestJS-specific. These were exported from the root `logixia`\n// entry before 2.0.0; keep this list a superset of what the root used to export.\nexport * from './core/logitron-logger.module';\nexport * from './core/logitron-nestjs.service';\nexport type { LogixiaExceptionFilterOptions, LogMethodOptions } from './core/nestjs-extras';\nexport {\n InjectLogger,\n LOGIXIA_EXCEPTION_FILTER_OPTIONS,\n LogixiaExceptionFilter,\n LogMethod,\n} from './core/nestjs-extras';\nexport { TraceMiddleware } from './core/trace.middleware';\n\n/**\n * Create a new Logixia logger service for NestJS\n * @param config - Logger configuration\n * @returns LogixiaLoggerService instance\n */\nexport function createLoggerService(config?: Partial<LoggerConfig>): LogixiaLoggerService {\n return new LogixiaLoggerService({ ...DEFAULT_CONFIG, ...config });\n}\n"],"mappings":"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"}
@@ -1,5 +1,24 @@
1
- import { t as safeToString } from "./coerce.utils-Dxv4_ikC.mjs";
1
+ import { t as safeToString } from "./coerce.utils-Cu6IUTgX.mjs";
2
2
 
3
+ //#region src/utils/csv.utils.ts
4
+ const CSV_FORMULA_PREFIX = /^[=+\-@\t\r]/;
5
+ /**
6
+ * Render one CSV field. String values that a spreadsheet would treat as a
7
+ * formula (leading `=`, `+`, `-`, `@`, tab or CR) are prefixed with `'`.
8
+ * Objects are JSON-encoded. Fields containing a comma, quote, CR or LF are quoted;
9
+ * `alwaysQuote` quotes every field. `null` / `undefined` render as empty.
10
+ */
11
+ function csvField(value, alwaysQuote = false) {
12
+ if (value === void 0 || value === null) return alwaysQuote ? "\"\"" : "";
13
+ let str;
14
+ if (typeof value === "string") str = CSV_FORMULA_PREFIX.test(value) ? `'${value}` : value;
15
+ else if (typeof value === "object") str = JSON.stringify(value);
16
+ else str = String(value);
17
+ if (alwaysQuote || /[",\r\n]/.test(str)) return `"${str.replace(/"/g, "\"\"")}"`;
18
+ return str;
19
+ }
20
+
21
+ //#endregion
3
22
  //#region src/search/core/basic-log-indexer.ts
4
23
  /**
5
24
  * Basic log indexer implementation
@@ -1166,6 +1185,14 @@ var NLPSearchEngine = class extends BasicSearchEngine {
1166
1185
 
1167
1186
  //#endregion
1168
1187
  //#region src/search/engines/pattern-recognition-engine.ts
1188
+ const STACK_FRAME_TAIL = /:\d+:\d+\)?$/;
1189
+ /** True when any line is a real stack frame, e.g. ` at fn (/app/file.js:10:5)`. */
1190
+ function hasStackFrame(message) {
1191
+ return message.split("\n").some((line) => {
1192
+ const t = line.trim();
1193
+ return t.startsWith("at ") && STACK_FRAME_TAIL.test(t);
1194
+ });
1195
+ }
1169
1196
  /**
1170
1197
  * Pattern recognition engine for log analysis
1171
1198
  */
@@ -1265,6 +1292,7 @@ var PatternRecognitionEngine = class {
1265
1292
  }
1266
1293
  extractErrorPatterns(logs) {
1267
1294
  const errorLogs = logs.filter((log) => log.level === "error" || log.error);
1295
+ this.patternFrequencies.clear();
1268
1296
  const patternMap = /* @__PURE__ */ new Map();
1269
1297
  for (const log of errorLogs) {
1270
1298
  const errorPattern = this.extractErrorPattern(log);
@@ -1275,6 +1303,7 @@ var PatternRecognitionEngine = class {
1275
1303
  const pattern = patternMap.get(errorPattern);
1276
1304
  if (pattern.examples.length < 3) pattern.examples.push(log);
1277
1305
  pattern.count++;
1306
+ this.patternFrequencies.set(errorPattern, pattern.count);
1278
1307
  }
1279
1308
  return Array.from(patternMap.entries()).map(([pattern, data], index) => {
1280
1309
  var _data$examples2;
@@ -1308,7 +1337,7 @@ var PatternRecognitionEngine = class {
1308
1337
  return patterns;
1309
1338
  }
1310
1339
  normalizeMessage(message) {
1311
- return message.replace(/\d+/g, "<NUM>").replace(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi, "<UUID>").replace(/[a-f0-9]{32}/gi, "<HASH>").replace(/"[^"]*"/g, "<STRING>").replace(/\b\w+@\w+\.\w+\b/g, "<EMAIL>").trim();
1340
+ return message.replace(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi, "<UUID>").replace(/[a-f0-9]{32}/gi, "<HASH>").replace(/\d+/g, "<NUM>").replace(/"[^"]*"/g, "<STRING>").replace(/\b\w+@\w+\.\w+\b/g, "<EMAIL>").trim();
1312
1341
  }
1313
1342
  extractErrorPattern(log) {
1314
1343
  if (log.error) return `${log.error.name}: ${this.normalizeMessage(log.error.message || "")}`;
@@ -1341,7 +1370,7 @@ var PatternRecognitionEngine = class {
1341
1370
  if (!log.traceId) deviations.push("Missing trace ID");
1342
1371
  if (!log.context) deviations.push("Missing context");
1343
1372
  if (log.payload && Object.keys(log.payload).length > 20) deviations.push("Unusually large payload");
1344
- if (log.level !== "error" && log.message.includes("at ")) deviations.push("Stack trace in non-error log");
1373
+ if (log.level !== "error" && hasStackFrame(log.message)) deviations.push("Stack trace in non-error log");
1345
1374
  return deviations;
1346
1375
  }
1347
1376
  doesLogMatchPattern(log, pattern) {
@@ -1550,10 +1579,10 @@ var SearchManager = class {
1550
1579
  "appName",
1551
1580
  "message"
1552
1581
  ];
1553
- return [fields.join(","), ...logs.map((log) => {
1582
+ return [fields.map((f) => csvField(f)).join(","), ...logs.map((log) => {
1554
1583
  return fields.map((field) => {
1555
1584
  const value = log[field];
1556
- return this.escapeCSVValue(value);
1585
+ return csvField(value);
1557
1586
  }).join(",");
1558
1587
  })].join("\n");
1559
1588
  }
@@ -1583,14 +1612,8 @@ var SearchManager = class {
1583
1612
  return current;
1584
1613
  }, obj);
1585
1614
  }
1586
- escapeCSVValue(value) {
1587
- if (value === null || value === void 0) return "";
1588
- const str = typeof value === "object" ? JSON.stringify(value) : String(value);
1589
- if (str.includes(",") || str.includes("\n") || str.includes("\"")) return `"${str.replace(/"/g, "\"\"")}"`;
1590
- return str;
1591
- }
1592
1615
  };
1593
1616
 
1594
1617
  //#endregion
1595
1618
  export { BasicSearchEngine as a, CorrelationEngine as i, PatternRecognitionEngine as n, BasicLogIndexer as o, NLPSearchEngine as r, SearchManager as t };
1596
- //# sourceMappingURL=search-CFQRISUv.mjs.map
1619
+ //# sourceMappingURL=search-BFbu_oVn.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-BFbu_oVn.mjs","names":["str: string","options?: {\n maxIndexSize?: number;\n autoOptimize?: boolean;\n optimizeThreshold?: number;\n }","options?: { maxHistorySize?: number; cacheSize?: number; maxLogs?: number }","timeline: TimelineEvent[]","eventType: TimelineEvent['eventType']","summary: LogCorrelationSummary","similarities: SimilarLog[]","suggestions: SearchSuggestion[]","filters: SearchFilters","levels: string[]","intent: ParsedNLQuery['intent']","fullPreset: SearchPreset","results: SearchResult[]","highlights: SearchHighlight[]","matchedTerms: string[]","result: { log: typeof log; score: number; highlights?: typeof highlights }","fragments: string[]","comparison: number","patterns: string[]","reasons: string[]","options?: {\n maxCorrelationDistance?: number;\n temporalWindowMs?: number;\n minSimilarityScore?: number;\n }","related: RelatedLog[]","timeline: TimelineEvent[]","event: TimelineEvent","currentGroup: LogEntry[]","groupStartTime: number | null","cascade: LogEntry[]","relationships: RelationshipType[]","unique: RelatedLog[]","duration: number | undefined","entities: QueryEntity[]","filters: SearchFilters","options: SearchOptions","detectedIntent: QueryIntent","baseOptions: SearchOptions","options?: {\n minFrequency?: number;\n maxPatterns?: number;\n anomalyThreshold?: number;\n }","anomalies: AnomalyDetection[]","matching: LogPattern[]","patterns: LogPattern[]","reasons: string[]","deviations: string[]","filtered: Record<string, unknown>"],"sources":["../src/utils/csv.utils.ts","../src/search/core/basic-log-indexer.ts","../src/search/core/basic-search-engine.ts","../src/search/engines/correlation-engine.ts","../src/search/engines/nlp-search-engine.ts","../src/search/engines/pattern-recognition-engine.ts","../src/search/search-manager.ts"],"sourcesContent":["const CSV_FORMULA_PREFIX = /^[=+\\-@\\t\\r]/;\n\n/**\n * Render one CSV field. String values that a spreadsheet would treat as a\n * formula (leading `=`, `+`, `-`, `@`, tab or CR) are prefixed with `'`.\n * Objects are JSON-encoded. Fields containing a comma, quote, CR or LF are quoted;\n * `alwaysQuote` quotes every field. `null` / `undefined` render as empty.\n */\nexport function csvField(value: unknown, alwaysQuote = false): string {\n if (value === undefined || value === null) return alwaysQuote ? '\"\"' : '';\n let str: string;\n if (typeof value === 'string') {\n str = CSV_FORMULA_PREFIX.test(value) ? `'${value}` : value;\n } else if (typeof value === 'object') {\n str = JSON.stringify(value);\n } else {\n str = String(value);\n }\n if (alwaysQuote || /[\",\\r\\n]/.test(str)) return `\"${str.replace(/\"/g, '\"\"')}\"`;\n return str;\n}\n","/**\n * Basic log indexer implementation for indexing and managing log entries\n */\n\nimport type { LogEntry } from '../../types';\nimport type { LogCluster, SearchQuery, SemanticIndex } from '../types';\nimport type { ILogIndexer } from './log-indexer.interface';\n\n/**\n * Basic log indexer implementation\n */\nexport class BasicLogIndexer implements ILogIndexer {\n private index: Map<string, LogEntry> = new Map();\n private fieldIndices: Map<string, Map<string, Set<string>>> = new Map();\n private semanticIndex: SemanticIndex | undefined;\n private lastOptimized?: Date;\n /**\n * Running estimate of the serialized index size in bytes, maintained\n * incrementally. The previous implementation JSON.stringify'd EVERY log on\n * each getIndexStats() call — O(n) per call, which for the default 1M-entry\n * cap means stringifying a million objects and blocking the event loop.\n * We keep a per-log byte estimate so the lookup is O(1).\n */\n private indexSizeBytes = 0;\n private readonly logSizeById = new Map<string, number>();\n\n constructor(\n private options?: {\n maxIndexSize?: number;\n autoOptimize?: boolean;\n optimizeThreshold?: number;\n }\n ) {\n this.options = {\n maxIndexSize: 1000000,\n autoOptimize: true,\n optimizeThreshold: 10000,\n ...options,\n };\n\n // Initialize field indices\n this.initializeFieldIndices();\n }\n\n /**\n * Index a single log entry\n */\n async indexLog(log: LogEntry): Promise<void> {\n const logId = this.generateLogId(log);\n\n // Add to main index\n this.trackInsert(logId, log);\n\n // Update field indices\n this.updateFieldIndices(logId, log);\n\n // Auto-optimize if threshold reached\n if (\n this.options?.autoOptimize &&\n this.index.size % (this.options.optimizeThreshold || 10000) === 0\n ) {\n await this.optimizeIndex();\n }\n\n // Enforce max size\n if (this.index.size > (this.options?.maxIndexSize || 1000000)) {\n await this.removeOldestLogs(Math.floor((this.options?.maxIndexSize || 1000000) * 0.1));\n }\n }\n\n /**\n * Index multiple log entries in batch\n */\n async indexBatch(logs: LogEntry[]): Promise<void> {\n for (const log of logs) {\n const logId = this.generateLogId(log);\n this.trackInsert(logId, log);\n this.updateFieldIndices(logId, log);\n }\n\n // Optimize after batch\n if (this.options?.autoOptimize) {\n await this.optimizeIndex();\n }\n }\n\n /**\n * Build semantic index for intelligent search\n */\n async buildSemanticIndex(logs: LogEntry[]): Promise<SemanticIndex> {\n // Build clusters based on log patterns\n const clusters = await this.clusterLogs(logs);\n\n this.semanticIndex = {\n version: '1.0.0',\n indexedCount: logs.length,\n lastUpdated: new Date(),\n clusters,\n };\n\n return this.semanticIndex;\n }\n\n /**\n * Update search suggestions based on search history\n */\n async updateSearchSuggestions(searchHistory: SearchQuery[]): Promise<void> {\n // Extract common patterns from search history\n const patterns = new Map<string, number>();\n\n for (const query of searchHistory) {\n const normalizedQuery = query.query.toLowerCase().trim();\n patterns.set(normalizedQuery, (patterns.get(normalizedQuery) || 0) + 1);\n }\n\n // In a real implementation, this would persist top patterns to storage\n // Top patterns (sorted by frequency) would be stored here\n }\n\n /**\n * Optimize the index for better performance\n */\n async optimizeIndex(): Promise<void> {\n // Rebuild field indices\n this.fieldIndices.clear();\n this.initializeFieldIndices();\n\n for (const [logId, log] of this.index.entries()) {\n this.updateFieldIndices(logId, log);\n }\n\n this.lastOptimized = new Date();\n }\n\n /**\n * Clear the index\n */\n async clearIndex(): Promise<void> {\n this.index.clear();\n this.fieldIndices.clear();\n this.semanticIndex = undefined;\n this.indexSizeBytes = 0;\n this.logSizeById.clear();\n this.initializeFieldIndices();\n }\n\n /**\n * Get index statistics\n */\n async getIndexStats(): Promise<{\n totalDocuments: number;\n indexSize: number;\n lastOptimized?: Date;\n }> {\n return {\n totalDocuments: this.index.size,\n indexSize: this.calculateIndexSize(),\n ...(this.lastOptimized !== undefined ? { lastOptimized: this.lastOptimized } : {}),\n };\n }\n\n /**\n * Remove logs older than specified time\n */\n async removeOldLogs(olderThan: Date): Promise<number> {\n const cutoffTime = olderThan.getTime();\n let removedCount = 0;\n\n for (const [logId, log] of this.index.entries()) {\n const logTime = new Date(log.timestamp).getTime();\n if (logTime < cutoffTime) {\n this.trackDelete(logId);\n this.removeFromFieldIndices(logId);\n removedCount++;\n }\n }\n\n return removedCount;\n }\n\n /**\n * Search logs by field\n */\n public searchByField(field: string, value: string): LogEntry[] {\n const fieldIndex = this.fieldIndices.get(field);\n if (!fieldIndex) return [];\n\n const logIds = fieldIndex.get(value.toLowerCase());\n if (!logIds) return [];\n\n return Array.from(logIds)\n .map((id) => this.index.get(id))\n .filter((log): log is LogEntry => log !== undefined);\n }\n\n /**\n * Get all indexed logs\n */\n public getAllLogs(): LogEntry[] {\n return Array.from(this.index.values());\n }\n\n // Private helper methods\n\n private initializeFieldIndices(): void {\n const fields = ['level', 'appName', 'traceId', 'context', 'environment'];\n for (const field of fields) {\n this.fieldIndices.set(field, new Map());\n }\n }\n\n private updateFieldIndices(logId: string, log: LogEntry): void {\n // Index level\n this.addToFieldIndex('level', log.level, logId);\n\n // Index appName\n if (log.appName) {\n this.addToFieldIndex('appName', log.appName, logId);\n }\n\n // Index traceId\n if (log.traceId) {\n this.addToFieldIndex('traceId', log.traceId, logId);\n }\n\n // Index context\n if (log.context) {\n this.addToFieldIndex('context', log.context, logId);\n }\n\n // Index environment\n if (log.environment) {\n this.addToFieldIndex('environment', log.environment, logId);\n }\n }\n\n private addToFieldIndex(field: string, value: string, logId: string): void {\n const fieldIndex = this.fieldIndices.get(field);\n if (!fieldIndex) return;\n\n const normalizedValue = value.toLowerCase();\n if (!fieldIndex.has(normalizedValue)) {\n fieldIndex.set(normalizedValue, new Set());\n }\n fieldIndex.get(normalizedValue)!.add(logId);\n }\n\n private removeFromFieldIndices(logId: string): void {\n for (const fieldIndex of this.fieldIndices.values()) {\n for (const logIds of fieldIndex.values()) {\n logIds.delete(logId);\n }\n }\n }\n\n private generateLogId(log: LogEntry): string {\n // eslint-disable-next-line sonarjs/pseudo-random -- non-security log ID suffix\n return `${log.timestamp}_${log.level}_${Math.random().toString(36).slice(2, 11)}`;\n }\n\n private calculateIndexSize(): number {\n // O(1): return the incrementally-maintained running total instead of\n // re-stringifying every entry on each call.\n return this.indexSizeBytes;\n }\n\n /** Insert into the main index and update the running size estimate. */\n private trackInsert(logId: string, log: LogEntry): void {\n // If this id somehow already exists, subtract its old size first.\n const existing = this.logSizeById.get(logId);\n if (existing !== undefined) this.indexSizeBytes -= existing;\n\n const size = JSON.stringify(log).length;\n this.index.set(logId, log);\n this.logSizeById.set(logId, size);\n this.indexSizeBytes += size;\n }\n\n /** Delete from the main index and update the running size estimate. */\n private trackDelete(logId: string): void {\n const size = this.logSizeById.get(logId);\n if (size !== undefined) {\n this.indexSizeBytes -= size;\n this.logSizeById.delete(logId);\n }\n this.index.delete(logId);\n }\n\n private async removeOldestLogs(count: number): Promise<void> {\n const logs = Array.from(this.index.entries())\n .sort((a, b) => new Date(a[1].timestamp).getTime() - new Date(b[1].timestamp).getTime())\n .slice(0, count);\n\n for (const [logId] of logs) {\n this.trackDelete(logId);\n this.removeFromFieldIndices(logId);\n }\n }\n\n private async clusterLogs(logs: LogEntry[]): Promise<LogCluster[]> {\n // Simple clustering based on log patterns\n const clusters = new Map<string, LogEntry[]>();\n\n for (const log of logs) {\n // Create a pattern key based on level and service\n const patternKey = `${log.level}_${log.appName}`;\n\n if (!clusters.has(patternKey)) {\n clusters.set(patternKey, []);\n }\n clusters.get(patternKey)!.push(log);\n }\n\n // Convert to LogCluster format\n return Array.from(clusters.entries()).map(([pattern, clusterLogs], index) => ({\n id: `cluster_${index}`,\n centroid: [], // Would be calculated in a real implementation\n logs: clusterLogs,\n pattern,\n frequency: clusterLogs.length,\n labels: [pattern],\n }));\n }\n}\n","/**\n * Basic search engine implementation with full-text search and filtering\n */\n\nimport type { LogEntry } from '../../types';\nimport { safeToString } from '../../utils/coerce.utils';\nimport type {\n CorrelatedLogs,\n LogCorrelationSummary,\n ParsedNLQuery,\n SearchFilters,\n SearchHighlight,\n SearchOptions,\n SearchPreset,\n SearchResult,\n SearchStats,\n SearchSuggestion,\n SimilarLog,\n TimelineEvent,\n TimeRange,\n} from '../types';\nimport type { ILogSearchEngine } from './search-engine.interface';\n\n/**\n * Basic search engine implementation\n */\nexport class BasicSearchEngine implements ILogSearchEngine {\n private logs: LogEntry[] = [];\n private presets: Map<string, SearchPreset> = new Map();\n private searchHistory: string[] = [];\n private suggestionCache: Map<string, SearchSuggestion[]> = new Map();\n\n constructor(private options?: { maxHistorySize?: number; cacheSize?: number; maxLogs?: number }) {\n this.options = {\n maxHistorySize: 1000,\n cacheSize: 100,\n maxLogs: 100_000,\n ...options,\n };\n }\n\n /**\n * Add logs to the search index.\n *\n * Bounded to `maxLogs` (default 100k): the buffer previously grew without\n * limit, leaking memory in any long-running process feeding it logs. When the\n * cap is exceeded the oldest entries are dropped (FIFO). We also append with a\n * loop rather than `push(...logs)` to avoid a RangeError from spreading a very\n * large array onto the call stack.\n */\n public addLogs(logs: LogEntry[]): void {\n for (const log of logs) this.logs.push(log);\n\n const maxLogs = this.options?.maxLogs ?? 100_000;\n if (this.logs.length > maxLogs) {\n this.logs.splice(0, this.logs.length - maxLogs);\n }\n }\n\n /**\n * Clear all logs from the index\n */\n public clearLogs(): void {\n this.logs = [];\n }\n\n /**\n * Get all indexed logs\n */\n public getLogs(): LogEntry[] {\n return this.logs;\n }\n\n /**\n * Perform a full-text search across logs\n */\n async search(\n query: string,\n filters?: SearchFilters,\n options?: SearchOptions\n ): Promise<SearchResult[]> {\n // Apply filters first\n const filteredLogs = this.applyFilters(this.logs, filters);\n\n // Perform text search\n const results = this.performTextSearch(filteredLogs, query, options);\n\n // Add to search history\n this.addToSearchHistory(query);\n\n // Apply sorting\n const sorted = this.applySorting(results, options?.sortBy, options?.sortOrder);\n\n // Apply pagination\n const paginated = this.applyPagination(sorted, options?.offset, options?.limit);\n\n // Add context if requested\n if (options?.includeContext) {\n await this.enrichWithContext(paginated, options.contextSize);\n }\n\n return paginated;\n }\n\n /**\n * Natural language search (basic implementation)\n */\n async naturalLanguageSearch(query: string): Promise<SearchResult[]> {\n const parsed = await this.parseNaturalLanguageQuery(query);\n return this.search(parsed.originalQuery, parsed.filters, {\n semanticSearch: true,\n includeContext: true,\n });\n }\n\n /**\n * Find logs correlated by trace ID\n */\n async correlateByTraceId(traceId: string): Promise<CorrelatedLogs> {\n const correlatedLogs = this.logs.filter((log) => log.traceId === traceId);\n\n // Sort by timestamp\n correlatedLogs.sort(\n (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n\n // Build timeline\n const timeline: TimelineEvent[] = correlatedLogs.map((log) => {\n let eventType: TimelineEvent['eventType'] = 'info';\n\n if (log.level === 'error') eventType = 'error';\n else if (log.message.toLowerCase().includes('start')) eventType = 'start';\n else if (\n log.message.toLowerCase().includes('end') ||\n log.message.toLowerCase().includes('complete')\n )\n eventType = 'end';\n else if (log.message.toLowerCase().includes('milestone')) eventType = 'milestone';\n\n return {\n timestamp: new Date(log.timestamp),\n log,\n eventType,\n };\n });\n\n // Generate summary\n const summary: LogCorrelationSummary = {\n totalLogs: correlatedLogs.length,\n errorCount: correlatedLogs.filter((l) => l.level === 'error').length,\n warningCount: correlatedLogs.filter((l) => l.level === 'warn').length,\n services: [...new Set(correlatedLogs.map((l) => l.appName))],\n };\n\n // Calculate duration if we have start and end\n if (timeline.length > 0) {\n const start = timeline[0]!.timestamp.getTime();\n const end = timeline[timeline.length - 1]!.timestamp.getTime();\n summary.duration = end - start;\n }\n\n return {\n traceId,\n correlationKey: traceId,\n logs: correlatedLogs,\n timeline,\n summary,\n };\n }\n\n /**\n * Find similar logs based on content similarity\n */\n async findSimilarLogs(logEntry: LogEntry, limit: number = 10): Promise<SimilarLog[]> {\n const similarities: SimilarLog[] = [];\n\n for (const log of this.logs) {\n if (log === logEntry) continue;\n\n const similarity = this.calculateSimilarity(logEntry, log);\n if (similarity > 0.3) {\n // Threshold for similarity\n similarities.push({\n log,\n similarity,\n matchedPatterns: this.findMatchedPatterns(logEntry, log),\n reason: this.generateSimilarityReason(logEntry, log, similarity),\n });\n }\n }\n\n // Sort by similarity and return top results\n return similarities.sort((a, b) => b.similarity - a.similarity).slice(0, limit);\n }\n\n /**\n * Get search suggestions\n */\n async getSuggestions(partialQuery: string, limit: number = 10): Promise<SearchSuggestion[]> {\n const cacheKey = partialQuery.toLowerCase();\n\n // Check cache\n if (this.suggestionCache.has(cacheKey)) {\n return this.suggestionCache.get(cacheKey)!.slice(0, limit);\n }\n\n const suggestions: SearchSuggestion[] = [];\n\n // Field suggestions\n const fields = ['level', 'appName', 'traceId', 'message', 'timestamp'];\n for (const field of fields) {\n if (field.toLowerCase().includes(partialQuery.toLowerCase())) {\n suggestions.push({\n text: field,\n type: 'field',\n category: 'field',\n });\n }\n }\n\n // Value suggestions from logs\n const values = new Set<string>();\n for (const log of this.logs.slice(-1000)) {\n // Recent logs only\n if (log.level?.toLowerCase().includes(partialQuery.toLowerCase())) {\n values.add(log.level);\n }\n if (log.appName?.toLowerCase().includes(partialQuery.toLowerCase())) {\n values.add(log.appName);\n }\n }\n\n for (const value of values) {\n suggestions.push({\n text: value,\n type: 'value',\n category: 'value',\n });\n }\n\n // History suggestions\n for (const historyItem of this.searchHistory.slice(-50)) {\n if (historyItem.toLowerCase().includes(partialQuery.toLowerCase())) {\n suggestions.push({\n text: historyItem,\n type: 'query_history',\n category: 'history',\n });\n }\n }\n\n // Cache suggestions\n this.suggestionCache.set(cacheKey, suggestions);\n\n // Trim cache if too large\n if (this.suggestionCache.size > (this.options?.cacheSize || 100)) {\n const firstKey = this.suggestionCache.keys().next().value as string | undefined;\n if (firstKey !== undefined) this.suggestionCache.delete(firstKey);\n }\n\n return suggestions.slice(0, limit);\n }\n\n /**\n * Get search statistics\n */\n async getStats(): Promise<SearchStats> {\n return {\n totalResults: this.logs.length,\n executionTime: 0,\n indexSize: this.logs.length,\n topTerms: this.getTopTerms(),\n };\n }\n\n /**\n * Parse natural language query\n */\n async parseNaturalLanguageQuery(query: string): Promise<ParsedNLQuery> {\n const filters: SearchFilters = {};\n const lowerQuery = query.toLowerCase();\n\n // Extract levels\n const levels: string[] = [];\n if (lowerQuery.includes('error')) levels.push('error');\n if (lowerQuery.includes('warn')) levels.push('warn');\n if (lowerQuery.includes('info')) levels.push('info');\n if (levels.length > 0) filters.levels = levels;\n\n // Extract time range\n const timeRange = this.extractTimeRange(query);\n if (timeRange) filters.timeRange = timeRange;\n\n // Extract service names (basic pattern matching)\n const serviceMatch = query.match(/from\\s+(?:the\\s+)?(\\w+)\\s+service/i);\n if (serviceMatch?.[1]) {\n filters.services = [serviceMatch[1]];\n }\n\n // Extract user ID\n const userMatch = query.match(/user\\s+(?:id\\s+)?(\\w+)/i);\n if (userMatch?.[1]) {\n filters.userIds = [userMatch[1]];\n }\n\n // Determine intent\n let intent: ParsedNLQuery['intent'] = 'general_search';\n if (lowerQuery.includes('error')) intent = 'find_errors';\n if (lowerQuery.includes('trace') || lowerQuery.includes('request')) intent = 'trace_request';\n if (lowerQuery.includes('user')) intent = 'find_user_activity';\n if (lowerQuery.includes('slow') || lowerQuery.includes('performance'))\n intent = 'performance_analysis';\n\n return {\n originalQuery: query,\n intent,\n entities: [],\n filters,\n confidence: 0.7,\n };\n }\n\n /**\n * Save a search preset\n */\n async savePreset(\n preset: Omit<SearchPreset, 'id' | 'createdAt' | 'updatedAt'>\n ): Promise<SearchPreset> {\n const id = this.generateId();\n const now = new Date();\n\n const fullPreset: SearchPreset = {\n ...preset,\n id,\n createdAt: now,\n updatedAt: now,\n };\n\n this.presets.set(id, fullPreset);\n return fullPreset;\n }\n\n /**\n * Get saved presets\n */\n async getPresets(userId?: string): Promise<SearchPreset[]> {\n const allPresets = Array.from(this.presets.values());\n\n if (userId) {\n return allPresets.filter((p) => p.userId === userId || p.shared);\n }\n\n return allPresets;\n }\n\n /**\n * Delete a preset\n */\n async deletePreset(presetId: string): Promise<void> {\n this.presets.delete(presetId);\n }\n\n // Private helper methods\n\n private applyFilters(logs: LogEntry[], filters?: SearchFilters): LogEntry[] {\n if (!filters) return logs;\n\n return logs.filter((log) => {\n // Level filter\n if (filters.levels && !filters.levels.includes(log.level)) {\n return false;\n }\n\n // Service filter\n if (filters.services && !filters.services.includes(log.appName)) {\n return false;\n }\n\n // Trace ID filter\n if (filters.traceIds && log.traceId && !filters.traceIds.includes(log.traceId)) {\n return false;\n }\n\n // Time range filter\n if (filters.timeRange) {\n const logTime = new Date(log.timestamp).getTime();\n const start =\n typeof filters.timeRange.start === 'number'\n ? filters.timeRange.start\n : filters.timeRange.start.getTime();\n\n if (logTime < start) return false;\n\n if (filters.timeRange.end) {\n const end =\n typeof filters.timeRange.end === 'number'\n ? filters.timeRange.end\n : filters.timeRange.end.getTime();\n if (logTime > end) return false;\n }\n }\n\n // Error filter\n if (filters.hasError !== undefined) {\n const hasError = log.level === 'error' || !!log.error;\n if (filters.hasError !== hasError) return false;\n }\n\n // Context filter\n if (filters.contexts && log.context && !filters.contexts.includes(log.context)) {\n return false;\n }\n\n return true;\n });\n }\n\n private performTextSearch(\n logs: LogEntry[],\n query: string,\n options?: SearchOptions\n ): SearchResult[] {\n if (!query) {\n return logs.map((log) => ({ log, score: 1 }));\n }\n\n const queryTerms = query.toLowerCase().split(/\\s+/);\n const results: SearchResult[] = [];\n\n for (const log of logs) {\n const searchableText = this.getSearchableText(log).toLowerCase();\n let score = 0;\n const highlights: SearchHighlight[] = [];\n const matchedTerms: string[] = [];\n\n for (const term of queryTerms) {\n if (searchableText.includes(term)) {\n score += 1;\n matchedTerms.push(term);\n }\n }\n\n if (score > 0) {\n // Add highlights if requested\n if (options?.highlightMatches) {\n highlights.push({\n field: 'message',\n fragments: this.getHighlightFragments(log.message, matchedTerms),\n matchedTerms,\n });\n }\n\n const result: { log: typeof log; score: number; highlights?: typeof highlights } = {\n log,\n score: score / queryTerms.length, // Normalize score\n };\n if (highlights.length > 0) result.highlights = highlights;\n results.push(result as Parameters<typeof results.push>[0]);\n }\n }\n\n return results;\n }\n\n private getSearchableText(log: LogEntry): string {\n // safeToString is circular-safe — a stored log with a cyclic payload (an\n // Express req/res, a DB handle) would otherwise make JSON.stringify throw and\n // crash the ENTIRE search, since this runs for every candidate log.\n const payloadText = log.payload ? safeToString(log.payload) : '';\n return [log.message, log.level, log.appName, log.context, payloadText]\n .filter(Boolean)\n .join(' ');\n }\n\n private getHighlightFragments(text: string, terms: string[]): string[] {\n const fragments: string[] = [];\n const lowerText = text.toLowerCase();\n\n for (const term of terms) {\n const index = lowerText.indexOf(term);\n if (index !== -1) {\n const start = Math.max(0, index - 30);\n const end = Math.min(text.length, index + term.length + 30);\n fragments.push(text.slice(start, end));\n }\n }\n\n return fragments;\n }\n\n private applySorting(\n results: SearchResult[],\n sortBy?: string,\n sortOrder: 'asc' | 'desc' = 'desc'\n ): SearchResult[] {\n const sorted = [...results];\n\n sorted.sort((a, b) => {\n let comparison: number;\n\n switch (sortBy) {\n case 'timestamp':\n comparison = new Date(a.log.timestamp).getTime() - new Date(b.log.timestamp).getTime();\n break;\n case 'level':\n comparison = a.log.level.localeCompare(b.log.level);\n break;\n case 'score':\n case 'relevance':\n default:\n comparison = a.score - b.score;\n break;\n }\n\n return sortOrder === 'asc' ? comparison : -comparison;\n });\n\n return sorted;\n }\n\n private applyPagination(\n results: SearchResult[],\n offset: number = 0,\n limit: number = 100\n ): SearchResult[] {\n return results.slice(offset, offset + limit);\n }\n\n private async enrichWithContext(results: SearchResult[], contextSize: number = 5): Promise<void> {\n for (const result of results) {\n const logIndex = this.logs.indexOf(result.log);\n if (logIndex !== -1) {\n const start = Math.max(0, logIndex - contextSize);\n const end = Math.min(this.logs.length, logIndex + contextSize + 1);\n result.context = this.logs.slice(start, end).filter((l) => l !== result.log);\n }\n }\n }\n\n private calculateSimilarity(log1: LogEntry, log2: LogEntry): number {\n let score = 0;\n let factors = 0;\n\n // Same level\n if (log1.level === log2.level) {\n score += 0.3;\n }\n factors++;\n\n // Same service\n if (log1.appName === log2.appName) {\n score += 0.2;\n }\n factors++;\n\n // Same trace\n if (log1.traceId && log1.traceId === log2.traceId) {\n score += 0.3;\n }\n factors++;\n\n // Message similarity\n const messageSimilarity = this.calculateTextSimilarity(log1.message, log2.message);\n score += messageSimilarity * 0.2;\n factors++;\n\n return score / factors;\n }\n\n private calculateTextSimilarity(text1: string, text2: string): number {\n const words1 = new Set(text1.toLowerCase().split(/\\s+/));\n const words2 = new Set(text2.toLowerCase().split(/\\s+/));\n\n const intersection = new Set([...words1].filter((x) => words2.has(x)));\n const union = new Set([...words1, ...words2]);\n\n return union.size > 0 ? intersection.size / union.size : 0;\n }\n\n private findMatchedPatterns(log1: LogEntry, log2: LogEntry): string[] {\n const patterns: string[] = [];\n\n if (log1.level === log2.level) patterns.push('same_level');\n if (log1.appName === log2.appName) patterns.push('same_service');\n if (log1.traceId === log2.traceId) patterns.push('same_trace');\n if (log1.context === log2.context) patterns.push('same_context');\n\n return patterns;\n }\n\n private generateSimilarityReason(log1: LogEntry, log2: LogEntry, similarity: number): string {\n const reasons: string[] = [];\n\n if (log1.level === log2.level) reasons.push('same log level');\n if (log1.appName === log2.appName) reasons.push('same service');\n if (log1.traceId === log2.traceId) reasons.push('same trace ID');\n\n return reasons.length > 0\n ? `Similar because: ${reasons.join(', ')}`\n : `${Math.round(similarity * 100)}% content similarity`;\n }\n\n private extractTimeRange(query: string): TimeRange | undefined {\n const lowerQuery = query.toLowerCase();\n\n // Last hour\n if (lowerQuery.includes('last hour') || lowerQuery.includes('past hour')) {\n return {\n start: new Date(Date.now() - 60 * 60 * 1000),\n };\n }\n\n // Last N hours\n const hoursMatch = query.match(/last\\s+(\\d+)\\s+hours?/i);\n if (hoursMatch) {\n return {\n start: new Date(Date.now() - Number.parseInt(hoursMatch[1] ?? '0') * 60 * 60 * 1000),\n };\n }\n\n // Today\n if (lowerQuery.includes('today')) {\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n return {\n start: today,\n };\n }\n\n return undefined;\n }\n\n private addToSearchHistory(query: string): void {\n this.searchHistory.push(query);\n\n // Trim history if too large\n const maxSize = this.options?.maxHistorySize || 1000;\n if (this.searchHistory.length > maxSize) {\n this.searchHistory = this.searchHistory.slice(-maxSize);\n }\n }\n\n private getTopTerms(): string[] {\n const termCounts = new Map<string, number>();\n\n for (const log of this.logs.slice(-1000)) {\n const words = log.message.toLowerCase().split(/\\s+/);\n for (const word of words) {\n if (word.length > 3) {\n // Ignore short words\n termCounts.set(word, (termCounts.get(word) || 0) + 1);\n }\n }\n }\n\n return Array.from(termCounts.entries())\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([term]) => term);\n }\n\n private generateId(): string {\n // eslint-disable-next-line sonarjs/pseudo-random -- non-security preset ID generation\n return `preset_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;\n }\n}\n","/**\n * Correlation engine for finding relationships between log entries\n */\n\nimport type { LogEntry } from '../../types';\nimport type {\n CorrelatedLogs,\n LogCorrelationSummary,\n RelatedLog,\n RelationshipType,\n TimelineEvent,\n} from '../types';\n\n/**\n * Correlation engine for log analysis\n */\nexport class CorrelationEngine {\n constructor(\n private options?: {\n maxCorrelationDistance?: number;\n temporalWindowMs?: number;\n minSimilarityScore?: number;\n }\n ) {\n this.options = {\n maxCorrelationDistance: 100,\n temporalWindowMs: 5 * 60 * 1000, // 5 minutes\n minSimilarityScore: 0.3,\n ...options,\n };\n }\n\n /**\n * Find logs related to a given log entry\n */\n async findRelatedLogs(\n log: LogEntry,\n allLogs: LogEntry[],\n limit: number = 50\n ): Promise<RelatedLog[]> {\n const related: RelatedLog[] = [];\n\n for (const otherLog of allLogs) {\n if (otherLog === log) continue;\n\n const relationships = this.findRelationships(log, otherLog);\n\n for (const relationship of relationships) {\n const score = this.calculateRelationshipScore(relationship, log, otherLog);\n\n if (score > (this.options?.minSimilarityScore || 0.3)) {\n related.push({\n log: otherLog,\n relationship,\n score,\n });\n }\n }\n }\n\n // Deduplicate and sort by score\n const uniqueRelated = this.deduplicateRelatedLogs(related);\n return uniqueRelated.sort((a, b) => b.score - a.score).slice(0, limit);\n }\n\n /**\n * Correlate logs by multiple criteria\n */\n async correlateByMultipleCriteria(\n logs: LogEntry[],\n criteria: {\n traceId?: boolean;\n userId?: boolean;\n sessionId?: boolean;\n temporal?: boolean;\n errorCascade?: boolean;\n }\n ): Promise<Map<string, CorrelatedLogs>> {\n const correlations = new Map<string, CorrelatedLogs>();\n\n // Correlate by trace ID\n if (criteria.traceId) {\n const traceCorrelations = this.correlateByTraceId(logs);\n for (const [key, value] of traceCorrelations) {\n correlations.set(`trace_${key}`, value);\n }\n }\n\n // Correlate by user ID\n if (criteria.userId) {\n const userCorrelations = this.correlateByUserId(logs);\n for (const [key, value] of userCorrelations) {\n correlations.set(`user_${key}`, value);\n }\n }\n\n // Correlate by session ID\n if (criteria.sessionId) {\n const sessionCorrelations = this.correlateBySessionId(logs);\n for (const [key, value] of sessionCorrelations) {\n correlations.set(`session_${key}`, value);\n }\n }\n\n // Correlate by temporal proximity\n if (criteria.temporal) {\n const temporalCorrelations = this.correlateByTemporalProximity(logs);\n for (const [key, value] of temporalCorrelations) {\n correlations.set(`temporal_${key}`, value);\n }\n }\n\n // Correlate error cascades\n if (criteria.errorCascade) {\n const errorCorrelations = this.correlateErrorCascades(logs);\n for (const [key, value] of errorCorrelations) {\n correlations.set(`error_${key}`, value);\n }\n }\n\n return correlations;\n }\n\n /**\n * Build a timeline from correlated logs\n */\n buildTimeline(logs: LogEntry[]): TimelineEvent[] {\n const timeline: TimelineEvent[] = [];\n\n // Sort logs by timestamp\n const sortedLogs = [...logs].sort(\n (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n\n for (let i = 0; i < sortedLogs.length; i++) {\n const log = sortedLogs[i] as LogEntry; // noUncheckedIndexedAccess: guarded by loop condition\n const eventType = this.determineEventType(log, sortedLogs, i);\n\n const event: TimelineEvent = {\n timestamp: new Date(log.timestamp),\n log,\n eventType,\n };\n\n // Calculate duration for start/end events\n if (eventType === 'start' && i < sortedLogs.length - 1) {\n const endEvent = sortedLogs\n .slice(i + 1)\n .find((l) => this.determineEventType(l, sortedLogs, sortedLogs.indexOf(l)) === 'end');\n\n if (endEvent) {\n event.duration =\n new Date(endEvent.timestamp).getTime() - new Date(log.timestamp).getTime();\n }\n }\n\n timeline.push(event);\n }\n\n return timeline;\n }\n\n /**\n * Analyze error cascades\n */\n async analyzeErrorCascade(\n logs: LogEntry[]\n ): Promise<{ rootCause?: LogEntry; cascade: LogEntry[]; impactedServices: string[] }> {\n const errors = logs.filter((log) => log.level === 'error');\n\n if (errors.length === 0) {\n return { cascade: [], impactedServices: [] };\n }\n\n // Find root cause (earliest error)\n const rootCause = errors.reduce((earliest, current) =>\n new Date(current.timestamp) < new Date(earliest.timestamp) ? current : earliest\n );\n\n // Build cascade\n const cascade = this.buildErrorCascade(rootCause, errors);\n\n // Get impacted services\n const impactedServices = [...new Set(cascade.map((log) => log.appName))];\n\n return {\n rootCause,\n cascade,\n impactedServices,\n };\n }\n\n // Private methods\n\n private correlateByTraceId(logs: LogEntry[]): Map<string, CorrelatedLogs> {\n const correlations = new Map<string, LogEntry[]>();\n\n for (const log of logs) {\n if (!log.traceId) continue;\n\n if (!correlations.has(log.traceId)) {\n correlations.set(log.traceId, []);\n }\n correlations.get(log.traceId)!.push(log);\n }\n\n return this.convertToCorrelatedLogs(correlations, 'trace');\n }\n\n private correlateByUserId(logs: LogEntry[]): Map<string, CorrelatedLogs> {\n const correlations = new Map<string, LogEntry[]>();\n\n for (const log of logs) {\n const userId = log.payload?.userId as string | undefined;\n if (!userId) continue;\n\n if (!correlations.has(userId)) {\n correlations.set(userId, []);\n }\n correlations.get(userId)!.push(log);\n }\n\n return this.convertToCorrelatedLogs(correlations, 'user');\n }\n\n private correlateBySessionId(logs: LogEntry[]): Map<string, CorrelatedLogs> {\n const correlations = new Map<string, LogEntry[]>();\n\n for (const log of logs) {\n const sessionId = log.payload?.sessionId as string | undefined;\n if (!sessionId) continue;\n\n if (!correlations.has(sessionId)) {\n correlations.set(sessionId, []);\n }\n correlations.get(sessionId)!.push(log);\n }\n\n return this.convertToCorrelatedLogs(correlations, 'session');\n }\n\n private correlateByTemporalProximity(logs: LogEntry[]): Map<string, CorrelatedLogs> {\n const correlations = new Map<string, LogEntry[]>();\n const sortedLogs = [...logs].sort(\n (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n\n let currentGroup: LogEntry[] = [];\n let groupStartTime: number | null = null;\n\n for (const log of sortedLogs) {\n const logTime = new Date(log.timestamp).getTime();\n\n if (groupStartTime === null) {\n groupStartTime = logTime;\n currentGroup = [log];\n } else if (logTime - groupStartTime <= (this.options?.temporalWindowMs || 300000)) {\n currentGroup.push(log);\n } else {\n // Save current group\n if (currentGroup.length > 1) {\n const groupKey = `${groupStartTime}`;\n correlations.set(groupKey, currentGroup);\n }\n\n // Start new group\n groupStartTime = logTime;\n currentGroup = [log];\n }\n }\n\n // Save last group\n if (currentGroup.length > 1 && groupStartTime !== null) {\n correlations.set(`${groupStartTime}`, currentGroup);\n }\n\n return this.convertToCorrelatedLogs(correlations, 'temporal');\n }\n\n private correlateErrorCascades(logs: LogEntry[]): Map<string, CorrelatedLogs> {\n const correlations = new Map<string, LogEntry[]>();\n const errors = logs.filter((log) => log.level === 'error');\n\n for (const error of errors) {\n const cascade = this.buildErrorCascade(error, logs);\n\n if (cascade.length > 1) {\n const key = `${error.timestamp}_${error.message.slice(0, 20)}`;\n correlations.set(key, cascade);\n }\n }\n\n return this.convertToCorrelatedLogs(correlations, 'error_cascade');\n }\n\n private buildErrorCascade(rootError: LogEntry, allLogs: LogEntry[]): LogEntry[] {\n const cascade: LogEntry[] = [rootError];\n const rootTime = new Date(rootError.timestamp).getTime();\n const windowMs = this.options?.temporalWindowMs || 300000;\n\n // Find related errors within time window\n for (const log of allLogs) {\n if (log === rootError) continue;\n\n const logTime = new Date(log.timestamp).getTime();\n const timeDiff = logTime - rootTime;\n\n if (\n timeDiff > 0 &&\n timeDiff <= windowMs &&\n (log.level === 'error' || log.level === 'warn') &&\n (log.traceId === rootError.traceId || log.appName === rootError.appName)\n ) {\n cascade.push(log);\n }\n }\n\n return cascade.sort(\n (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n }\n\n private findRelationships(log1: LogEntry, log2: LogEntry): RelationshipType[] {\n const relationships: RelationshipType[] = [];\n\n // Same trace\n if (log1.traceId && log1.traceId === log2.traceId) {\n relationships.push('same_trace');\n }\n\n // Same user\n const user1 = log1.payload?.userId;\n const user2 = log2.payload?.userId;\n if (user1 && user1 === user2) {\n relationships.push('same_user');\n }\n\n // Same session\n const session1 = log1.payload?.sessionId;\n const session2 = log2.payload?.sessionId;\n if (session1 && session1 === session2) {\n relationships.push('same_session');\n }\n\n // Temporal proximity\n const time1 = new Date(log1.timestamp).getTime();\n const time2 = new Date(log2.timestamp).getTime();\n if (Math.abs(time1 - time2) <= (this.options?.temporalWindowMs || 300000)) {\n relationships.push('temporal_proximity');\n }\n\n // Error cascade\n if (\n (log1.level === 'error' || log2.level === 'error') &&\n time2 > time1 &&\n time2 - time1 <= (this.options?.temporalWindowMs || 300000)\n ) {\n relationships.push('error_cascade');\n }\n\n // Similar pattern\n if (this.haveSimilarPattern(log1, log2)) {\n relationships.push('similar_pattern');\n }\n\n return relationships;\n }\n\n private calculateRelationshipScore(\n relationship: RelationshipType,\n log1: LogEntry,\n log2: LogEntry\n ): number {\n const weights: Record<RelationshipType, number> = {\n same_trace: 0.9,\n same_user: 0.7,\n same_session: 0.8,\n temporal_proximity: 0.4,\n error_cascade: 0.8,\n similar_pattern: 0.5,\n };\n\n let score = weights[relationship] || 0.3;\n\n // Boost score for same service\n if (log1.appName === log2.appName) {\n score += 0.1;\n }\n\n return Math.min(score, 1.0);\n }\n\n private haveSimilarPattern(log1: LogEntry, log2: LogEntry): boolean {\n const normalized1 = this.normalizeMessage(log1.message);\n const normalized2 = this.normalizeMessage(log2.message);\n\n return normalized1 === normalized2;\n }\n\n private normalizeMessage(message: string): string {\n return message\n .replace(/\\d+/g, '<NUM>')\n .replace(/[a-f0-9-]{36}/gi, '<UUID>')\n .toLowerCase()\n .trim();\n }\n\n private determineEventType(\n log: LogEntry,\n _allLogs: LogEntry[],\n _index: number\n ): TimelineEvent['eventType'] {\n const message = log.message.toLowerCase();\n\n if (message.includes('start') || message.includes('begin') || message.includes('initiated')) {\n return 'start';\n }\n\n if (message.includes('end') || message.includes('complete') || message.includes('finished')) {\n return 'end';\n }\n\n if (log.level === 'error') {\n return 'error';\n }\n\n if (message.includes('milestone') || message.includes('checkpoint')) {\n return 'milestone';\n }\n\n return 'info';\n }\n\n private deduplicateRelatedLogs(related: RelatedLog[]): RelatedLog[] {\n const seen = new Set<LogEntry>();\n const unique: RelatedLog[] = [];\n\n for (const item of related) {\n if (!seen.has(item.log)) {\n seen.add(item.log);\n unique.push(item);\n }\n }\n\n return unique;\n }\n\n private convertToCorrelatedLogs(\n correlations: Map<string, LogEntry[]>,\n type: string\n ): Map<string, CorrelatedLogs> {\n const result = new Map<string, CorrelatedLogs>();\n\n for (const [key, logs] of correlations.entries()) {\n if (logs.length < 2) continue; // Skip single log entries\n\n const timeline = this.buildTimeline(logs);\n const summary = this.generateSummary(logs);\n\n result.set(key, {\n correlationKey: key,\n ...(type === 'trace' ? { traceId: key } : {}),\n logs,\n timeline,\n summary,\n });\n }\n\n return result;\n }\n\n private generateSummary(logs: LogEntry[]): LogCorrelationSummary {\n const errorCount = logs.filter((l) => l.level === 'error').length;\n const warningCount = logs.filter((l) => l.level === 'warn').length;\n const services = [...new Set(logs.map((l) => l.appName))];\n\n // Calculate duration\n let duration: number | undefined;\n if (logs.length > 1) {\n const sorted = [...logs].sort(\n (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n const start = new Date((sorted[0] as LogEntry).timestamp).getTime();\n const end = new Date((sorted[sorted.length - 1] as LogEntry).timestamp).getTime();\n duration = end - start;\n }\n\n return {\n totalLogs: logs.length,\n errorCount,\n warningCount,\n services,\n ...(duration !== undefined ? { duration } : {}),\n };\n }\n}\n","/**\n * Advanced search engine with Natural Language Processing capabilities\n */\n\nimport { BasicSearchEngine } from '../core/basic-search-engine';\nimport type {\n EntityType,\n ParsedNLQuery,\n QueryEntity,\n QueryIntent,\n SearchFilters,\n SearchOptions,\n SearchResult,\n TimeRange,\n} from '../types';\n\n/**\n * NLP-enhanced search engine\n */\nexport class NLPSearchEngine extends BasicSearchEngine {\n private intentPatterns!: Map<QueryIntent, RegExp[]>;\n private entityPatterns!: Map<EntityType, RegExp>;\n\n constructor(options?: Record<string, unknown>) {\n super(options);\n this.initializePatterns();\n }\n\n /**\n * Enhanced natural language query parsing\n */\n override async parseNaturalLanguageQuery(query: string): Promise<ParsedNLQuery> {\n const entities: QueryEntity[] = [];\n const filters: SearchFilters = {};\n\n // Detect intent\n const intent = this.detectIntent(query);\n\n // Extract entities\n const extractedEntities = this.extractEntities(query);\n entities.push(...extractedEntities);\n\n // Build filters from entities\n for (const entity of entities) {\n this.applyEntityToFilter(entity, filters);\n }\n\n // Extract time range\n const timeRange = this.extractAdvancedTimeRange(query);\n if (timeRange) {\n filters.timeRange = timeRange;\n }\n\n // Calculate confidence\n const confidence = this.calculateConfidence(intent, entities, query);\n\n return {\n originalQuery: query,\n intent,\n entities,\n filters,\n ...(timeRange !== undefined ? { timeRange } : {}),\n confidence,\n };\n }\n\n /**\n * Enhanced natural language search\n */\n override async naturalLanguageSearch(query: string): Promise<SearchResult[]> {\n const parsed = await this.parseNaturalLanguageQuery(query);\n\n // Adjust search options based on intent\n const options: SearchOptions = this.getOptionsForIntent(parsed.intent);\n\n // Extract clean search query (remove filter terms)\n const cleanQuery = this.extractCleanQuery(query, parsed.entities);\n\n return this.search(cleanQuery, parsed.filters, options);\n }\n\n // Private methods\n\n private initializePatterns(): void {\n // Initialize intent patterns\n this.intentPatterns = new Map([\n [\n 'find_errors',\n [\n /show.*errors?/i,\n /find.*errors?/i,\n /all.*errors?/i,\n /errors?\\s+(?:in|from|for)/i,\n /what.*went wrong/i,\n /failures?/i,\n ],\n ],\n [\n 'trace_request',\n [\n /trace\\s+(?:request|id)/i,\n /follow\\s+request/i,\n /track\\s+request/i,\n /request\\s+(?:flow|path)/i,\n /trace.*across/i,\n ],\n ],\n [\n 'find_user_activity',\n [\n /user\\s+(?:\\w+|id)/i,\n /activity\\s+(?:for|of)\\s+user/i,\n /what\\s+did\\s+user/i,\n /user\\s+journey/i,\n /user\\s+session/i,\n ],\n ],\n [\n 'performance_analysis',\n [\n /slow\\s+(?:queries?|requests?|operations?)/i,\n /performance\\s+issues?/i,\n /latency/i,\n /response\\s+time/i,\n /took\\s+(?:too\\s+)?long/i,\n ],\n ],\n [\n 'time_range_query',\n [\n /(?:in|during|from)\\s+the\\s+last/i,\n /(?:today|yesterday|this\\s+week)/i,\n /between.*and/i,\n /in\\s+the\\s+past/i,\n ],\n ],\n [\n 'correlation',\n [\n /related\\s+to/i,\n /connected\\s+with/i,\n /caused\\s+by/i,\n /before.*happened/i,\n /after.*occurred/i,\n ],\n ],\n ]);\n\n // Initialize entity patterns\n this.entityPatterns = new Map([\n ['level', /(error|warn|warning|info|debug|trace|verbose)/i],\n ['service', /(?:from|in)\\s+(?:the\\s+)?(\\w+)\\s+(?:service|app|application)/i],\n ['user_id', /user\\s+(?:id\\s+)?['\"]?(\\w+)['\"]?/i],\n ['trace_id', /trace\\s+(?:id\\s+)?['\"]?([\\w-]+)['\"]?/i],\n ['time', /(?:last|past|previous)\\s+(\\d+)\\s+(second|minute|hour|day|week)s?/i],\n // eslint-disable-next-line sonarjs/super-linear-regex -- bounded pattern, DoS risk is acceptable for log search\n ['error_type', /(\\w+Error|\\w+Exception)/i],\n ]);\n }\n\n private detectIntent(query: string): QueryIntent {\n let maxScore = 0;\n let detectedIntent: QueryIntent = 'general_search';\n\n for (const [intent, patterns] of this.intentPatterns.entries()) {\n let score = 0;\n for (const pattern of patterns) {\n if (pattern.test(query)) {\n score++;\n }\n }\n\n if (score > maxScore) {\n maxScore = score;\n detectedIntent = intent;\n }\n }\n\n return detectedIntent;\n }\n\n private extractEntities(query: string): QueryEntity[] {\n const entities: QueryEntity[] = [];\n\n for (const [type, pattern] of this.entityPatterns.entries()) {\n const matches = query.matchAll(new RegExp(pattern, 'gi'));\n\n for (const match of matches) {\n const value = match[1] || match[0];\n entities.push({\n type,\n value: value.trim(),\n confidence: 0.8,\n });\n }\n }\n\n return entities;\n }\n\n private applyEntityToFilter(entity: QueryEntity, filters: SearchFilters): void {\n switch (entity.type) {\n case 'level':\n if (!filters.levels) filters.levels = [];\n filters.levels.push(entity.value.toLowerCase());\n break;\n\n case 'service':\n if (!filters.services) filters.services = [];\n filters.services.push(entity.value);\n break;\n\n case 'user_id':\n if (!filters.userIds) filters.userIds = [];\n filters.userIds.push(entity.value);\n break;\n\n case 'trace_id':\n if (!filters.traceIds) filters.traceIds = [];\n filters.traceIds.push(entity.value);\n break;\n\n case 'error_type':\n // Could be used for more specific filtering\n break;\n }\n }\n\n private extractAdvancedTimeRange(query: string): TimeRange | undefined {\n const lowerQuery = query.toLowerCase();\n\n // Relative time patterns\n const relativePatterns = [\n { pattern: /last\\s+(\\d+)\\s+second/i, unit: 'seconds' as const },\n { pattern: /last\\s+(\\d+)\\s+minute/i, unit: 'minutes' as const },\n { pattern: /last\\s+(\\d+)\\s+hour/i, unit: 'hours' as const },\n { pattern: /last\\s+(\\d+)\\s+day/i, unit: 'days' as const },\n ];\n\n for (const { pattern, unit } of relativePatterns) {\n const match = query.match(pattern);\n if (match) {\n const value = Number.parseInt(match[1] ?? '0');\n const multiplier = {\n seconds: 1000,\n minutes: 60 * 1000,\n hours: 60 * 60 * 1000,\n days: 24 * 60 * 60 * 1000,\n }[unit];\n\n return {\n start: new Date(Date.now() - value * multiplier),\n relative: { value, unit },\n };\n }\n }\n\n // Named time ranges\n if (lowerQuery.includes('today')) {\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n return { start: today };\n }\n\n if (lowerQuery.includes('yesterday')) {\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n yesterday.setHours(0, 0, 0, 0);\n const endOfYesterday = new Date(yesterday);\n endOfYesterday.setHours(23, 59, 59, 999);\n return { start: yesterday, end: endOfYesterday };\n }\n\n if (lowerQuery.includes('this week')) {\n const now = new Date();\n const startOfWeek = new Date(now);\n startOfWeek.setDate(now.getDate() - now.getDay());\n startOfWeek.setHours(0, 0, 0, 0);\n return { start: startOfWeek };\n }\n\n return undefined;\n }\n\n private calculateConfidence(intent: QueryIntent, entities: QueryEntity[], query: string): number {\n let confidence = 0.5; // Base confidence\n\n // Boost confidence for specific intents\n if (intent !== 'general_search') {\n confidence += 0.2;\n }\n\n // Boost for number of entities found\n confidence += Math.min(entities.length * 0.1, 0.3);\n\n // Reduce confidence for very short or very long queries\n const wordCount = query.split(/\\s+/).length;\n if (wordCount < 3 || wordCount > 20) {\n confidence -= 0.1;\n }\n\n return Math.max(0, Math.min(1, confidence));\n }\n\n private getOptionsForIntent(intent: QueryIntent): SearchOptions {\n const baseOptions: SearchOptions = {\n limit: 100,\n highlightMatches: true,\n };\n\n switch (intent) {\n case 'find_errors':\n return {\n ...baseOptions,\n includeContext: true,\n contextSize: 3,\n findSimilar: true,\n };\n\n case 'trace_request':\n return {\n ...baseOptions,\n includeContext: true,\n contextSize: 10,\n correlate: true,\n sortBy: 'timestamp',\n sortOrder: 'asc',\n };\n\n case 'find_user_activity':\n return {\n ...baseOptions,\n includeContext: true,\n sortBy: 'timestamp',\n sortOrder: 'asc',\n limit: 200,\n };\n\n case 'performance_analysis':\n return {\n ...baseOptions,\n includeContext: true,\n contextSize: 5,\n sortBy: 'timestamp',\n };\n\n case 'correlation':\n return {\n ...baseOptions,\n includeContext: true,\n contextSize: 5,\n correlate: true,\n findSimilar: true,\n };\n\n default:\n return baseOptions;\n }\n }\n\n private extractCleanQuery(query: string, entities: QueryEntity[]): string {\n let cleanQuery = query;\n\n // Remove entity text from query\n for (const entity of entities) {\n // Remove common patterns\n cleanQuery = cleanQuery.replace(new RegExp(`\\\\b${entity.value}\\\\b`, 'gi'), '');\n }\n\n // Remove common filter words\n const filterWords = [\n 'show',\n 'find',\n 'get',\n 'all',\n 'from',\n 'in',\n 'the',\n 'for',\n 'with',\n 'last',\n 'past',\n 'today',\n 'yesterday',\n 'service',\n 'user',\n 'trace',\n 'error',\n 'errors',\n ];\n\n for (const word of filterWords) {\n cleanQuery = cleanQuery.replace(new RegExp(`\\\\b${word}\\\\b`, 'gi'), '');\n }\n\n // Clean up extra whitespace\n cleanQuery = cleanQuery.replace(/\\s+/g, ' ').trim();\n\n return cleanQuery || query; // Fall back to original if nothing left\n }\n}\n","/**\n * Pattern recognition engine for detecting and analyzing log patterns\n */\n\nimport type { LogEntry } from '../../types';\nimport type { AnomalyDetection, LogPattern } from '../types';\n\nconst STACK_FRAME_TAIL = /:\\d+:\\d+\\)?$/;\n\n/** True when any line is a real stack frame, e.g. ` at fn (/app/file.js:10:5)`. */\nfunction hasStackFrame(message: string): boolean {\n return message.split('\\n').some((line) => {\n const t = line.trim();\n return t.startsWith('at ') && STACK_FRAME_TAIL.test(t);\n });\n}\n\n/**\n * Pattern recognition engine for log analysis\n */\nexport class PatternRecognitionEngine {\n private patterns: Map<string, LogPattern> = new Map();\n private patternFrequencies: Map<string, number> = new Map();\n\n constructor(\n private options?: {\n minFrequency?: number;\n maxPatterns?: number;\n anomalyThreshold?: number;\n }\n ) {\n this.options = {\n minFrequency: 3,\n maxPatterns: 1000,\n anomalyThreshold: 0.3,\n ...options,\n };\n }\n\n /**\n * Analyze logs and detect patterns\n */\n async analyzePatterns(logs: LogEntry[]): Promise<LogPattern[]> {\n // Extract patterns from log messages\n const messagePatterns = this.extractMessagePatterns(logs);\n\n // Extract error patterns\n const errorPatterns = this.extractErrorPatterns(logs);\n\n // Extract timing patterns\n const timingPatterns = this.extractTimingPatterns(logs);\n\n // Combine all patterns\n const allPatterns = [...messagePatterns, ...errorPatterns, ...timingPatterns];\n\n // Filter by frequency\n const frequentPatterns = allPatterns.filter(\n (p) => p.frequency >= (this.options?.minFrequency || 3)\n );\n\n // Sort by frequency\n frequentPatterns.sort((a, b) => b.frequency - a.frequency);\n\n // Limit number of patterns\n const limitedPatterns = frequentPatterns.slice(0, this.options?.maxPatterns || 1000);\n\n // Store patterns\n for (const pattern of limitedPatterns) {\n this.patterns.set(pattern.id, pattern);\n }\n\n return limitedPatterns;\n }\n\n /**\n * Detect anomalies in logs\n */\n async detectAnomalies(logs: LogEntry[]): Promise<AnomalyDetection[]> {\n const anomalies: AnomalyDetection[] = [];\n\n for (const log of logs) {\n const anomalyScore = await this.calculateAnomalyScore(log);\n\n if (anomalyScore > (this.options?.anomalyThreshold || 0.3)) {\n anomalies.push({\n log,\n anomalyScore,\n reason: this.generateAnomalyReason(log, anomalyScore),\n deviations: this.findDeviations(log),\n });\n }\n }\n\n return anomalies.sort((a, b) => b.anomalyScore - a.anomalyScore);\n }\n\n /**\n * Find patterns matching a log entry\n */\n findMatchingPatterns(log: LogEntry): LogPattern[] {\n const matching: LogPattern[] = [];\n\n for (const pattern of this.patterns.values()) {\n if (this.doesLogMatchPattern(log, pattern)) {\n matching.push(pattern);\n }\n }\n\n return matching;\n }\n\n /**\n * Get all detected patterns\n */\n getPatterns(): LogPattern[] {\n return Array.from(this.patterns.values());\n }\n\n /**\n * Get pattern by ID\n */\n getPattern(patternId: string): LogPattern | undefined {\n return this.patterns.get(patternId);\n }\n\n // Private methods\n\n private extractMessagePatterns(logs: LogEntry[]): LogPattern[] {\n const patternMap = new Map<string, { examples: LogEntry[]; count: number }>();\n\n for (const log of logs) {\n // Normalize message by replacing numbers and IDs\n const normalizedMessage = this.normalizeMessage(log.message);\n\n if (!patternMap.has(normalizedMessage)) {\n patternMap.set(normalizedMessage, { examples: [], count: 0 });\n }\n\n const pattern = patternMap.get(normalizedMessage)!;\n if (pattern.examples.length < 3) {\n pattern.examples.push(log);\n }\n pattern.count++;\n }\n\n // Convert to LogPattern array\n return Array.from(patternMap.entries()).map(([pattern, data], index) => ({\n id: `msg_pattern_${index}`,\n pattern,\n examples: data.examples,\n frequency: data.count,\n lastSeen: data.examples[data.examples.length - 1]?.timestamp\n ? new Date((data.examples[data.examples.length - 1] as (typeof data.examples)[0]).timestamp)\n : new Date(),\n category: 'message',\n }));\n }\n\n private extractErrorPatterns(logs: LogEntry[]): LogPattern[] {\n const errorLogs = logs.filter((log) => log.level === 'error' || log.error);\n this.patternFrequencies.clear();\n const patternMap = new Map<string, { examples: LogEntry[]; count: number }>();\n\n for (const log of errorLogs) {\n const errorPattern = this.extractErrorPattern(log);\n\n if (!patternMap.has(errorPattern)) {\n patternMap.set(errorPattern, { examples: [], count: 0 });\n }\n\n const pattern = patternMap.get(errorPattern)!;\n if (pattern.examples.length < 3) {\n pattern.examples.push(log);\n }\n pattern.count++;\n this.patternFrequencies.set(errorPattern, pattern.count);\n }\n\n return Array.from(patternMap.entries()).map(([pattern, data], index) => ({\n id: `error_pattern_${index}`,\n pattern,\n examples: data.examples,\n frequency: data.count,\n lastSeen: data.examples[data.examples.length - 1]?.timestamp\n ? new Date((data.examples[data.examples.length - 1] as (typeof data.examples)[0]).timestamp)\n : new Date(),\n category: 'error',\n severity: 'high',\n }));\n }\n\n private extractTimingPatterns(logs: LogEntry[]): LogPattern[] {\n const patterns: LogPattern[] = [];\n const hourCounts = new Map<number, number>();\n\n // Analyze temporal patterns\n for (const log of logs) {\n const hour = new Date(log.timestamp).getHours();\n hourCounts.set(hour, (hourCounts.get(hour) || 0) + 1);\n }\n\n // Find peak hours\n const peakHour = Array.from(hourCounts.entries()).sort((a, b) => b[1] - a[1])[0];\n\n if (peakHour) {\n patterns.push({\n id: 'timing_peak',\n pattern: `Peak activity at hour ${peakHour[0]}`,\n examples: logs.slice(0, 3),\n frequency: peakHour[1],\n lastSeen: new Date(),\n category: 'timing',\n });\n }\n\n return patterns;\n }\n\n private normalizeMessage(message: string): string {\n return message\n .replace(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi, '<UUID>') // Replace UUIDs\n .replace(/[a-f0-9]{32}/gi, '<HASH>') // Replace hashes\n .replace(/\\d+/g, '<NUM>') // Replace numbers\n .replace(/\"[^\"]*\"/g, '<STRING>') // Replace quoted strings\n .replace(/\\b\\w+@\\w+\\.\\w+\\b/g, '<EMAIL>') // Replace emails\n .trim();\n }\n\n private extractErrorPattern(log: LogEntry): string {\n if (log.error) {\n return `${log.error.name}: ${this.normalizeMessage(log.error.message || '')}`;\n }\n return this.normalizeMessage(log.message);\n }\n\n private async calculateAnomalyScore(log: LogEntry): Promise<number> {\n let score = 0;\n\n // Check if log matches known patterns\n const matchingPatterns = this.findMatchingPatterns(log);\n if (matchingPatterns.length === 0) {\n score += 0.3; // Unknown pattern\n }\n\n // Check error frequency\n if (log.level === 'error') {\n const errorPattern = this.extractErrorPattern(log);\n const frequency = this.patternFrequencies.get(errorPattern) || 0;\n if (frequency < 2) {\n score += 0.3; // Rare error\n }\n }\n\n // Check time of day\n const hour = new Date(log.timestamp).getHours();\n if (hour < 6 || hour > 22) {\n score += 0.2; // Off-hours activity\n }\n\n return Math.min(score, 1.0);\n }\n\n private generateAnomalyReason(log: LogEntry, score: number): string {\n const reasons: string[] = [];\n\n if (score > 0.7) {\n reasons.push('Highly unusual log entry');\n } else if (score > 0.5) {\n reasons.push('Moderately unusual log entry');\n } else {\n reasons.push('Slightly unusual log entry');\n }\n\n const matchingPatterns = this.findMatchingPatterns(log);\n if (matchingPatterns.length === 0) {\n reasons.push('does not match any known patterns');\n }\n\n if (log.level === 'error') {\n reasons.push('rare error type');\n }\n\n const hour = new Date(log.timestamp).getHours();\n if (hour < 6 || hour > 22) {\n reasons.push('occurred during off-hours');\n }\n\n return reasons.join(', ');\n }\n\n private findDeviations(log: LogEntry): string[] {\n const deviations: string[] = [];\n\n // Check for missing standard fields\n if (!log.traceId) deviations.push('Missing trace ID');\n if (!log.context) deviations.push('Missing context');\n\n // Check for unusual payload\n if (log.payload && Object.keys(log.payload).length > 20) {\n deviations.push('Unusually large payload');\n }\n\n // Check for stack trace in non-error logs\n if (log.level !== 'error' && hasStackFrame(log.message)) {\n deviations.push('Stack trace in non-error log');\n }\n\n return deviations;\n }\n\n private doesLogMatchPattern(log: LogEntry, pattern: LogPattern): boolean {\n const normalizedMessage = this.normalizeMessage(log.message);\n\n if (pattern.regex) {\n return pattern.regex.test(log.message);\n }\n\n return normalizedMessage === pattern.pattern;\n }\n}\n","/**\n * Main search manager that orchestrates all search capabilities\n */\n\nimport type { LogEntry } from '../types';\nimport { csvField } from '../utils/csv.utils';\nimport { BasicLogIndexer } from './core/basic-log-indexer';\nimport { BasicSearchEngine } from './core/basic-search-engine';\nimport { CorrelationEngine } from './engines/correlation-engine';\nimport { NLPSearchEngine } from './engines/nlp-search-engine';\nimport { PatternRecognitionEngine } from './engines/pattern-recognition-engine';\nimport type {\n AnomalyDetection,\n CorrelatedLogs,\n ExportOptions,\n LogPattern,\n ParsedNLQuery,\n RelatedLog,\n SearchFilters,\n SearchOptions,\n SearchPreset,\n SearchResult,\n SearchStats,\n SearchSuggestion,\n SimilarLog,\n} from './types';\n\n/**\n * Configuration for search manager\n */\nexport interface SearchManagerConfig {\n enableNLP?: boolean;\n enablePatternRecognition?: boolean;\n enableCorrelation?: boolean;\n maxIndexSize?: number;\n autoOptimize?: boolean;\n}\n\n/**\n * Main search manager class\n */\nexport class SearchManager {\n private searchEngine: BasicSearchEngine | NLPSearchEngine;\n private indexer: BasicLogIndexer;\n private patternEngine?: PatternRecognitionEngine;\n private correlationEngine?: CorrelationEngine;\n private config: Required<SearchManagerConfig>;\n\n constructor(config?: SearchManagerConfig) {\n this.config = {\n enableNLP: true,\n enablePatternRecognition: true,\n enableCorrelation: true,\n maxIndexSize: 1000000,\n autoOptimize: true,\n ...config,\n };\n\n // Initialize components\n this.searchEngine = this.config.enableNLP ? new NLPSearchEngine() : new BasicSearchEngine();\n\n this.indexer = new BasicLogIndexer({\n maxIndexSize: this.config.maxIndexSize,\n autoOptimize: this.config.autoOptimize,\n });\n\n if (this.config.enablePatternRecognition) {\n this.patternEngine = new PatternRecognitionEngine();\n }\n\n if (this.config.enableCorrelation) {\n this.correlationEngine = new CorrelationEngine();\n }\n }\n\n /**\n * Index new logs\n */\n async indexLogs(logs: LogEntry[]): Promise<void> {\n await this.indexer.indexBatch(logs);\n this.searchEngine.addLogs(logs);\n\n // Analyze patterns if enabled\n if (this.patternEngine && logs.length > 10) {\n await this.patternEngine.analyzePatterns(logs);\n }\n }\n\n /**\n * Add a single log to the index\n */\n async indexLog(log: LogEntry): Promise<void> {\n await this.indexer.indexLog(log);\n this.searchEngine.addLogs([log]);\n }\n\n /**\n * Perform a search\n */\n async search(\n query: string,\n filters?: SearchFilters,\n options?: SearchOptions\n ): Promise<SearchResult[]> {\n return this.searchEngine.search(query, filters, options);\n }\n\n /**\n * Perform a natural language search\n */\n async naturalLanguageSearch(query: string): Promise<SearchResult[]> {\n return this.searchEngine.naturalLanguageSearch(query);\n }\n\n /**\n * Find logs correlated by trace ID\n */\n async correlateByTraceId(traceId: string): Promise<CorrelatedLogs> {\n return this.searchEngine.correlateByTraceId(traceId);\n }\n\n /**\n * Find similar logs\n */\n async findSimilarLogs(logEntry: LogEntry, limit?: number): Promise<SimilarLog[]> {\n return this.searchEngine.findSimilarLogs(logEntry, limit);\n }\n\n /**\n * Find logs related to a given log\n */\n async findRelatedLogs(log: LogEntry, limit?: number): Promise<RelatedLog[]> {\n if (!this.correlationEngine) {\n throw new Error('Correlation engine not enabled');\n }\n\n const allLogs = this.searchEngine.getLogs();\n return this.correlationEngine.findRelatedLogs(log, allLogs, limit);\n }\n\n /**\n * Get search suggestions\n */\n async getSuggestions(partialQuery: string, limit?: number): Promise<SearchSuggestion[]> {\n return this.searchEngine.getSuggestions(partialQuery, limit);\n }\n\n /**\n * Get search statistics\n */\n async getStats(): Promise<SearchStats> {\n return this.searchEngine.getStats();\n }\n\n /**\n * Parse natural language query\n */\n async parseNaturalLanguageQuery(query: string): Promise<ParsedNLQuery> {\n return this.searchEngine.parseNaturalLanguageQuery(query);\n }\n\n /**\n * Save a search preset\n */\n async savePreset(\n preset: Omit<SearchPreset, 'id' | 'createdAt' | 'updatedAt'>\n ): Promise<SearchPreset> {\n return this.searchEngine.savePreset(preset);\n }\n\n /**\n * Get saved presets\n */\n async getPresets(userId?: string): Promise<SearchPreset[]> {\n return this.searchEngine.getPresets(userId);\n }\n\n /**\n * Delete a preset\n */\n async deletePreset(presetId: string): Promise<void> {\n return this.searchEngine.deletePreset(presetId);\n }\n\n /**\n * Detect log patterns\n */\n async detectPatterns(): Promise<LogPattern[]> {\n if (!this.patternEngine) {\n throw new Error('Pattern recognition not enabled');\n }\n\n const allLogs = this.searchEngine.getLogs();\n return this.patternEngine.analyzePatterns(allLogs);\n }\n\n /**\n * Get detected patterns\n */\n getPatterns(): LogPattern[] {\n if (!this.patternEngine) {\n return [];\n }\n\n return this.patternEngine.getPatterns();\n }\n\n /**\n * Detect anomalies in logs\n */\n async detectAnomalies(): Promise<AnomalyDetection[]> {\n if (!this.patternEngine) {\n throw new Error('Pattern recognition not enabled');\n }\n\n const allLogs = this.searchEngine.getLogs();\n return this.patternEngine.detectAnomalies(allLogs);\n }\n\n /**\n * Correlate logs by multiple criteria\n */\n async correlateByMultipleCriteria(criteria: {\n traceId?: boolean;\n userId?: boolean;\n sessionId?: boolean;\n temporal?: boolean;\n errorCascade?: boolean;\n }): Promise<Map<string, CorrelatedLogs>> {\n if (!this.correlationEngine) {\n throw new Error('Correlation engine not enabled');\n }\n\n const allLogs = this.searchEngine.getLogs();\n return this.correlationEngine.correlateByMultipleCriteria(allLogs, criteria);\n }\n\n /**\n * Analyze error cascades\n */\n async analyzeErrorCascade(traceId: string): Promise<{\n rootCause?: LogEntry;\n cascade: LogEntry[];\n impactedServices: string[];\n }> {\n if (!this.correlationEngine) {\n throw new Error('Correlation engine not enabled');\n }\n\n const correlated = await this.correlateByTraceId(traceId);\n return this.correlationEngine.analyzeErrorCascade(correlated.logs);\n }\n\n /**\n * Export search results\n */\n async exportResults(results: SearchResult[], options: ExportOptions): Promise<string> {\n switch (options.format) {\n case 'json':\n return this.exportAsJSON(results, options);\n case 'csv':\n return this.exportAsCSV(results, options);\n case 'text':\n return this.exportAsText(results, options);\n default:\n throw new Error(`Unsupported export format: ${options.format}`);\n }\n }\n\n /**\n * Clear all indexed data\n */\n async clearIndex(): Promise<void> {\n await this.indexer.clearIndex();\n this.searchEngine.clearLogs();\n }\n\n /**\n * Optimize the index\n */\n async optimizeIndex(): Promise<void> {\n await this.indexer.optimizeIndex();\n }\n\n /**\n * Get index statistics\n */\n async getIndexStats(): Promise<{\n totalDocuments: number;\n indexSize: number;\n lastOptimized?: Date;\n }> {\n return this.indexer.getIndexStats();\n }\n\n /**\n * Remove old logs\n */\n async removeOldLogs(olderThan: Date): Promise<number> {\n const removed = await this.indexer.removeOldLogs(olderThan);\n\n // Also remove from search engine\n const allLogs = this.searchEngine.getLogs();\n const filteredLogs = allLogs.filter((log) => new Date(log.timestamp) >= olderThan);\n\n this.searchEngine.clearLogs();\n this.searchEngine.addLogs(filteredLogs);\n\n return removed;\n }\n\n // Private export methods\n\n private exportAsJSON(results: SearchResult[], options: ExportOptions): string {\n const data = options.includeMetadata ? results : results.map((r) => r.log);\n\n if (options.fields) {\n return JSON.stringify(\n data.map((item) => this.filterFields(item, options.fields!)),\n null,\n 2\n );\n }\n\n return JSON.stringify(data, null, 2);\n }\n\n private exportAsCSV(results: SearchResult[], options: ExportOptions): string {\n const logs = results.map((r) => r.log);\n\n if (logs.length === 0) {\n return '';\n }\n\n const fields = options.fields || ['timestamp', 'level', 'appName', 'message'];\n const headers = fields.map((f) => csvField(f)).join(',');\n\n const rows = logs.map((log) => {\n return fields\n .map((field) => {\n const value = (log as unknown as Record<string, unknown>)[field];\n return csvField(value);\n })\n .join(',');\n });\n\n return [headers, ...rows].join('\\n');\n }\n\n private exportAsText(results: SearchResult[], options: ExportOptions): string {\n return results\n .map((result) => {\n const log = result.log;\n let text = `[${log.timestamp}] [${log.level.toUpperCase()}] ${log.appName}: ${log.message}`;\n\n if (options.includeMetadata) {\n text += `\\n Score: ${result.score.toFixed(2)}`;\n if (result.highlights) {\n text += `\\n Matches: ${result.highlights.length}`;\n }\n }\n\n return text;\n })\n .join('\\n\\n');\n }\n\n private filterFields(obj: unknown, fields: string[]): Record<string, unknown> {\n const filtered: Record<string, unknown> = {};\n\n for (const field of fields) {\n if (obj !== null && typeof obj === 'object' && field in obj) {\n filtered[field] = (obj as Record<string, unknown>)[field];\n } else if (field.includes('.')) {\n // Handle nested fields\n const value = this.getNestedValue(obj, field);\n if (value !== undefined) {\n filtered[field] = value;\n }\n }\n }\n\n return filtered;\n }\n\n private getNestedValue(obj: unknown, path: string): unknown {\n return path.split('.').reduce((current: unknown, key) => {\n if (current !== null && typeof current === 'object') {\n return (current as Record<string, unknown>)[key];\n }\n // Not an object — path lookup stops here\n return current;\n }, obj);\n }\n}\n"],"mappings":"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"}