evlog 2.14.1 → 2.16.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 (187) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -4
  3. package/dist/adapters/axiom.d.mts +18 -27
  4. package/dist/adapters/axiom.d.mts.map +1 -1
  5. package/dist/adapters/axiom.mjs +40 -30
  6. package/dist/adapters/axiom.mjs.map +1 -1
  7. package/dist/adapters/better-stack.d.mts +11 -24
  8. package/dist/adapters/better-stack.d.mts.map +1 -1
  9. package/dist/adapters/better-stack.mjs +34 -29
  10. package/dist/adapters/better-stack.mjs.map +1 -1
  11. package/dist/adapters/datadog.d.mts +1 -1
  12. package/dist/adapters/datadog.d.mts.map +1 -1
  13. package/dist/adapters/datadog.mjs +10 -4
  14. package/dist/adapters/datadog.mjs.map +1 -1
  15. package/dist/adapters/fs.d.mts +2 -2
  16. package/dist/adapters/fs.d.mts.map +1 -1
  17. package/dist/adapters/fs.mjs +19 -7
  18. package/dist/adapters/fs.mjs.map +1 -1
  19. package/dist/adapters/hyperdx.d.mts +1 -1
  20. package/dist/adapters/hyperdx.mjs +1 -2
  21. package/dist/adapters/hyperdx.mjs.map +1 -1
  22. package/dist/adapters/otlp.d.mts +1 -1
  23. package/dist/adapters/otlp.d.mts.map +1 -1
  24. package/dist/adapters/otlp.mjs +36 -31
  25. package/dist/adapters/otlp.mjs.map +1 -1
  26. package/dist/adapters/posthog.d.mts +50 -70
  27. package/dist/adapters/posthog.d.mts.map +1 -1
  28. package/dist/adapters/posthog.mjs +50 -85
  29. package/dist/adapters/posthog.mjs.map +1 -1
  30. package/dist/adapters/sentry.d.mts +1 -1
  31. package/dist/adapters/sentry.d.mts.map +1 -1
  32. package/dist/adapters/sentry.mjs +15 -5
  33. package/dist/adapters/sentry.mjs.map +1 -1
  34. package/dist/ai/index.d.mts +15 -1
  35. package/dist/ai/index.d.mts.map +1 -1
  36. package/dist/ai/index.mjs +48 -16
  37. package/dist/ai/index.mjs.map +1 -1
  38. package/dist/{audit-CTIviX3P.d.mts → audit-X1uUukm3.d.mts} +145 -2
  39. package/dist/audit-X1uUukm3.d.mts.map +1 -0
  40. package/dist/{audit-DQoBo7Dl.mjs → audit-pV5aLGP0.mjs} +153 -13
  41. package/dist/audit-pV5aLGP0.mjs.map +1 -0
  42. package/dist/better-auth/index.d.mts +1 -1
  43. package/dist/browser.d.mts +1 -1
  44. package/dist/define-CuXOqecD.d.mts +57 -0
  45. package/dist/define-CuXOqecD.d.mts.map +1 -0
  46. package/dist/define-D6OJdSUH.mjs +63 -0
  47. package/dist/define-D6OJdSUH.mjs.map +1 -0
  48. package/dist/{dist-Do8P4zWd.mjs → dist-BIlS38vi.mjs} +1 -1
  49. package/dist/dist-BIlS38vi.mjs.map +1 -0
  50. package/dist/drain-ByWUeOQC.mjs +160 -0
  51. package/dist/drain-ByWUeOQC.mjs.map +1 -0
  52. package/dist/elysia/index.d.mts +25 -2
  53. package/dist/elysia/index.d.mts.map +1 -1
  54. package/dist/elysia/index.mjs +53 -20
  55. package/dist/elysia/index.mjs.map +1 -1
  56. package/dist/enricher-DYTr9I16.d.mts +42 -0
  57. package/dist/enricher-DYTr9I16.d.mts.map +1 -0
  58. package/dist/enricher-Dy06T17G.mjs +95 -0
  59. package/dist/enricher-Dy06T17G.mjs.map +1 -0
  60. package/dist/enrichers.d.mts +16 -9
  61. package/dist/enrichers.d.mts.map +1 -1
  62. package/dist/enrichers.mjs +81 -64
  63. package/dist/enrichers.mjs.map +1 -1
  64. package/dist/{error-C7gSQVqk.d.mts → error-Cpc7RVz6.d.mts} +7 -2
  65. package/dist/error-Cpc7RVz6.d.mts.map +1 -0
  66. package/dist/error.d.mts +1 -1
  67. package/dist/error.mjs +8 -1
  68. package/dist/error.mjs.map +1 -1
  69. package/dist/{errors-BJRXUfMg.mjs → errors-BQgyQ9xe.mjs} +1 -1
  70. package/dist/{errors-BJRXUfMg.mjs.map → errors-BQgyQ9xe.mjs.map} +1 -1
  71. package/dist/{errors-4MPmTzjY.d.mts → errors-prnQ3kES.d.mts} +2 -2
  72. package/dist/{errors-4MPmTzjY.d.mts.map → errors-prnQ3kES.d.mts.map} +1 -1
  73. package/dist/event-DcHmEm3O.mjs +55 -0
  74. package/dist/event-DcHmEm3O.mjs.map +1 -0
  75. package/dist/express/index.d.mts +2 -2
  76. package/dist/express/index.d.mts.map +1 -1
  77. package/dist/express/index.mjs +17 -15
  78. package/dist/express/index.mjs.map +1 -1
  79. package/dist/fastify/index.d.mts +2 -2
  80. package/dist/fastify/index.d.mts.map +1 -1
  81. package/dist/fastify/index.mjs +19 -20
  82. package/dist/fastify/index.mjs.map +1 -1
  83. package/dist/fork-DPN8aL8O.mjs +227 -0
  84. package/dist/fork-DPN8aL8O.mjs.map +1 -0
  85. package/dist/{headers-D74M0wsg.mjs → headers-CU-QqnYg.mjs} +19 -2
  86. package/dist/headers-CU-QqnYg.mjs.map +1 -0
  87. package/dist/hono/index.d.mts +2 -2
  88. package/dist/hono/index.d.mts.map +1 -1
  89. package/dist/hono/index.mjs +14 -10
  90. package/dist/hono/index.mjs.map +1 -1
  91. package/dist/http.d.mts +1 -1
  92. package/dist/index.d.mts +8 -7
  93. package/dist/index.mjs +3 -2
  94. package/dist/integration-DSZPbI9N.mjs +75 -0
  95. package/dist/integration-DSZPbI9N.mjs.map +1 -0
  96. package/dist/{logger-DttRJRGa.d.mts → logger-U8lgdc9x.d.mts} +9 -3
  97. package/dist/logger-U8lgdc9x.d.mts.map +1 -0
  98. package/dist/logger.d.mts +2 -2
  99. package/dist/logger.mjs +2 -2
  100. package/dist/middleware-CAQHJRN1.d.mts +72 -0
  101. package/dist/middleware-CAQHJRN1.d.mts.map +1 -0
  102. package/dist/nestjs/index.d.mts +2 -2
  103. package/dist/nestjs/index.mjs +3 -4
  104. package/dist/nestjs/index.mjs.map +1 -1
  105. package/dist/next/client.d.mts +1 -1
  106. package/dist/next/index.d.mts +4 -4
  107. package/dist/next/index.mjs +3 -3
  108. package/dist/next/instrumentation.d.mts +1 -1
  109. package/dist/next/instrumentation.mjs +1 -1
  110. package/dist/nitro/errorHandler.mjs +2 -2
  111. package/dist/nitro/module.d.mts +2 -2
  112. package/dist/nitro/plugin.mjs +21 -11
  113. package/dist/nitro/plugin.mjs.map +1 -1
  114. package/dist/nitro/v3/errorHandler.mjs +3 -3
  115. package/dist/nitro/v3/index.d.mts +2 -2
  116. package/dist/nitro/v3/module.d.mts +1 -1
  117. package/dist/nitro/v3/plugin.mjs +29 -17
  118. package/dist/nitro/v3/plugin.mjs.map +1 -1
  119. package/dist/nitro/v3/useLogger.d.mts +1 -1
  120. package/dist/{nitro-CPPRCPbG.d.mts → nitro-C6Bd682U.d.mts} +2 -2
  121. package/dist/{nitro-CPPRCPbG.d.mts.map → nitro-C6Bd682U.d.mts.map} +1 -1
  122. package/dist/{nitro-OmT_M4Pb.mjs → nitro-DavLelNz.mjs} +2 -2
  123. package/dist/nitro-DavLelNz.mjs.map +1 -0
  124. package/dist/{nitroConfigBridge-C37lXaNm.mjs → nitroConfigBridge-aZ1e5upQ.mjs} +1 -1
  125. package/dist/nitroConfigBridge-aZ1e5upQ.mjs.map +1 -0
  126. package/dist/nuxt/module.d.mts +1 -1
  127. package/dist/nuxt/module.mjs +2 -2
  128. package/dist/{parseError-o1GpZEOR.d.mts → parseError-B-dKF6Fd.d.mts} +2 -2
  129. package/dist/parseError-B-dKF6Fd.d.mts.map +1 -0
  130. package/dist/react-router/index.d.mts +2 -2
  131. package/dist/react-router/index.mjs +3 -4
  132. package/dist/react-router/index.mjs.map +1 -1
  133. package/dist/{routes-CGPmbzCZ.mjs → routes-B48wm7Pb.mjs} +1 -1
  134. package/dist/{routes-CGPmbzCZ.mjs.map → routes-B48wm7Pb.mjs.map} +1 -1
  135. package/dist/runtime/client/log.d.mts +1 -1
  136. package/dist/runtime/server/routes/_evlog/ingest.post.mjs +21 -10
  137. package/dist/runtime/server/routes/_evlog/ingest.post.mjs.map +1 -1
  138. package/dist/runtime/server/useLogger.d.mts +1 -1
  139. package/dist/runtime/utils/parseError.d.mts +2 -2
  140. package/dist/runtime/utils/parseError.mjs +9 -1
  141. package/dist/runtime/utils/parseError.mjs.map +1 -1
  142. package/dist/{_severity-CQijvfhU.mjs → severity-BYWZ96Sb.mjs} +6 -2
  143. package/dist/severity-BYWZ96Sb.mjs.map +1 -0
  144. package/dist/{source-location-DRvDDqfq.mjs → source-location-Dco0cRTz.mjs} +3 -3
  145. package/dist/source-location-Dco0cRTz.mjs.map +1 -0
  146. package/dist/storage-BT-3fT1-.mjs +27 -0
  147. package/dist/storage-BT-3fT1-.mjs.map +1 -0
  148. package/dist/sveltekit/index.d.mts +2 -2
  149. package/dist/sveltekit/index.mjs +5 -6
  150. package/dist/sveltekit/index.mjs.map +1 -1
  151. package/dist/toolkit.d.mts +288 -12
  152. package/dist/toolkit.d.mts.map +1 -1
  153. package/dist/toolkit.mjs +13 -7
  154. package/dist/types.d.mts +1 -1
  155. package/dist/{useLogger-CyPP1sVB.d.mts → useLogger-CoNgTjp5.d.mts} +2 -2
  156. package/dist/{useLogger-CyPP1sVB.d.mts.map → useLogger-CoNgTjp5.d.mts.map} +1 -1
  157. package/dist/{utils-Dmin7wVL.d.mts → utils-Db4qhBWn.d.mts} +2 -2
  158. package/dist/{utils-Dmin7wVL.d.mts.map → utils-Db4qhBWn.d.mts.map} +1 -1
  159. package/dist/utils.d.mts +1 -1
  160. package/dist/vite/index.d.mts +1 -1
  161. package/dist/vite/index.mjs +1 -1
  162. package/dist/workers.d.mts +1 -1
  163. package/dist/workers.mjs +1 -1
  164. package/package.json +22 -19
  165. package/dist/_drain-CmCtsuF6.mjs +0 -23
  166. package/dist/_drain-CmCtsuF6.mjs.map +0 -1
  167. package/dist/_http-BY1e9pwC.mjs +0 -78
  168. package/dist/_http-BY1e9pwC.mjs.map +0 -1
  169. package/dist/_severity-CQijvfhU.mjs.map +0 -1
  170. package/dist/audit-CTIviX3P.d.mts.map +0 -1
  171. package/dist/audit-DQoBo7Dl.mjs.map +0 -1
  172. package/dist/dist-Do8P4zWd.mjs.map +0 -1
  173. package/dist/error-C7gSQVqk.d.mts.map +0 -1
  174. package/dist/fork-D1j1Fuzy.mjs +0 -72
  175. package/dist/fork-D1j1Fuzy.mjs.map +0 -1
  176. package/dist/headers-D74M0wsg.mjs.map +0 -1
  177. package/dist/logger-DttRJRGa.d.mts.map +0 -1
  178. package/dist/middleware-CTnDsST-.d.mts +0 -93
  179. package/dist/middleware-CTnDsST-.d.mts.map +0 -1
  180. package/dist/middleware-oAccqyPp.mjs +0 -123
  181. package/dist/middleware-oAccqyPp.mjs.map +0 -1
  182. package/dist/nitro-OmT_M4Pb.mjs.map +0 -1
  183. package/dist/nitroConfigBridge-C37lXaNm.mjs.map +0 -1
  184. package/dist/parseError-o1GpZEOR.d.mts.map +0 -1
  185. package/dist/source-location-DRvDDqfq.mjs.map +0 -1
  186. package/dist/storage-CFGTn37X.mjs +0 -46
  187. package/dist/storage-CFGTn37X.mjs.map +0 -1
@@ -0,0 +1,72 @@
1
+ import { F as DrainContext, I as EnrichContext, Y as RequestLogger, Z as RouteConfig, it as WideEvent, nt as TailSamplingContext, ot as EvlogPlugin, q as RedactConfig, st as PluginRunner } from "./audit-X1uUukm3.mjs";
2
+
3
+ //#region src/shared/middleware.d.ts
4
+ /**
5
+ * Base options shared by every framework integration. Re-exported via
6
+ * `evlog/toolkit` so custom integrations can extend it.
7
+ */
8
+ interface BaseEvlogOptions {
9
+ /** Route glob patterns to include. If unset, all routes are logged. */
10
+ include?: string[];
11
+ /** Route glob patterns to exclude. Takes precedence over `include`. */
12
+ exclude?: string[];
13
+ /** Per-route service overrides. */
14
+ routes?: Record<string, RouteConfig>;
15
+ /** Drain callback invoked with every emitted event. */
16
+ drain?: (ctx: DrainContext) => void | Promise<void>;
17
+ /** Enrich callback invoked after emit, before drain. */
18
+ enrich?: (ctx: EnrichContext) => void | Promise<void>;
19
+ /** Tail sampling callback. Set `ctx.shouldKeep = true` to force-keep. */
20
+ keep?: (ctx: TailSamplingContext) => void | Promise<void>;
21
+ /**
22
+ * PII auto-redaction. `true` enables built-in patterns; pass an object for
23
+ * fine-grained control. Applied before enrich/drain.
24
+ */
25
+ redact?: boolean | RedactConfig;
26
+ /** Plugins for this middleware, merged with globally-registered ones. */
27
+ plugins?: EvlogPlugin[];
28
+ }
29
+ /** Internal options accepted by `createMiddlewareLogger`. */
30
+ interface MiddlewareLoggerOptions extends BaseEvlogOptions {
31
+ method: string;
32
+ path: string;
33
+ requestId?: string;
34
+ /** Pre-filtered safe request headers used for enrich/drain context. */
35
+ headers?: Record<string, string>;
36
+ }
37
+ interface MiddlewareLoggerResult {
38
+ logger: RequestLogger;
39
+ finish: (opts?: {
40
+ status?: number;
41
+ error?: Error;
42
+ }) => Promise<WideEvent | null>;
43
+ skipped: boolean;
44
+ }
45
+ /**
46
+ * Resolve the plugin runner for a middleware invocation by merging local
47
+ * plugins with the globally-registered ones (deduplicated by `name`).
48
+ */
49
+ declare function resolveMiddlewarePluginRunner(options: {
50
+ plugins?: EvlogPlugin[];
51
+ }): PluginRunner;
52
+ /**
53
+ * Apply redact, enrich, and drain to an emitted wide event — the same
54
+ * pipeline used by {@link createMiddlewareLogger}'s `finish`.
55
+ */
56
+ declare function runEnrichAndDrain(emittedEvent: WideEvent, options: MiddlewareLoggerOptions, requestInfo: {
57
+ method: string;
58
+ path: string;
59
+ requestId?: string;
60
+ }, responseStatus?: number, plugins?: PluginRunner): Promise<void>;
61
+ /**
62
+ * Create a request logger with the full middleware pipeline: route filtering,
63
+ * service overrides, duration tracking, tail sampling, emit, enrich, drain.
64
+ *
65
+ * Framework adapters extract method/path/requestId/headers, call this once
66
+ * per request, and call `finish({ status | error })` when the response ends.
67
+ * If `skipped` is `true`, the route was filtered out — bypass logging.
68
+ */
69
+ declare function createMiddlewareLogger(options: MiddlewareLoggerOptions): MiddlewareLoggerResult;
70
+ //#endregion
71
+ export { resolveMiddlewarePluginRunner as a, createMiddlewareLogger as i, MiddlewareLoggerOptions as n, runEnrichAndDrain as o, MiddlewareLoggerResult as r, BaseEvlogOptions as t };
72
+ //# sourceMappingURL=middleware-CAQHJRN1.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware-CAQHJRN1.d.mts","names":[],"sources":["../src/shared/middleware.ts"],"mappings":";;;;AAYA;;;UAAiB,gBAAA;EAMN;EAJT,OAAA;EAMsC;EAJtC,OAAA;EAMwC;EAJxC,MAAA,GAAS,MAAA,SAAe,WAAA;EAMoB;EAJ5C,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAW5B;EATV,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EASnB;EAPrB,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;EAR5C;;;;EAaA,MAAA,aAAmB,YAAA;EATL;EAWd,OAAA,GAAU,WAAA;AAAA;;UAIK,uBAAA,SAAgC,gBAAA;EAC/C,MAAA;EACA,IAAA;EACA,SAAA;EAda;EAgBb,OAAA,GAAU,MAAA;AAAA;AAAA,UAGK,sBAAA;EACf,MAAA,EAAQ,aAAA;EACR,MAAA,GAAS,IAAA;IAAS,MAAA;IAAiB,KAAA,GAAQ,KAAA;EAAA,MAAY,OAAA,CAAQ,SAAA;EAC/D,OAAA;AAAA;;;;;iBA6Bc,6BAAA,CAA8B,OAAA;EAAW,OAAA,GAAU,WAAA;AAAA,IAAkB,YAAA;;;;AAhCrF;iBAuDsB,iBAAA,CACpB,YAAA,EAAc,SAAA,EACd,OAAA,EAAS,uBAAA,EACT,WAAA;EAAe,MAAA;EAAgB,IAAA;EAAc,SAAA;AAAA,GAC7C,cAAA,WACA,OAAA,GAAU,YAAA,GACT,OAAA;;;;;;;;;iBA8Da,sBAAA,CAAuB,OAAA,EAAS,uBAAA,GAA0B,sBAAA"}
@@ -1,5 +1,5 @@
1
- import { Y as RequestLogger } from "../audit-CTIviX3P.mjs";
2
- import { t as BaseEvlogOptions } from "../middleware-CTnDsST-.mjs";
1
+ import { Y as RequestLogger } from "../audit-X1uUukm3.mjs";
2
+ import { t as BaseEvlogOptions } from "../middleware-CAQHJRN1.mjs";
3
3
  import { DynamicModule, MiddlewareConsumer, NestModule } from "@nestjs/common";
4
4
 
5
5
  //#region src/nestjs/index.d.ts
@@ -1,7 +1,6 @@
1
- import { t as createMiddlewareLogger } from "../middleware-oAccqyPp.mjs";
2
- import { t as attachForkToLogger } from "../fork-D1j1Fuzy.mjs";
3
- import { n as extractSafeNodeHeaders } from "../headers-D74M0wsg.mjs";
4
- import { t as createLoggerStorage } from "../storage-CFGTn37X.mjs";
1
+ import { n as extractSafeNodeHeaders } from "../headers-CU-QqnYg.mjs";
2
+ import { r as createMiddlewareLogger, t as attachForkToLogger } from "../fork-DPN8aL8O.mjs";
3
+ import { t as createLoggerStorage } from "../storage-BT-3fT1-.mjs";
5
4
  //#region src/nestjs/index.ts
6
5
  const { storage, useLogger } = createLoggerStorage("middleware context. Make sure EvlogModule.forRoot() is imported in your AppModule.");
7
6
  function createEvlogMiddleware(getOptions) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import type { ServerResponse } from 'node:http'\nimport type { Request } from 'express'\nimport type { DynamicModule, MiddlewareConsumer, NestModule } from '@nestjs/common'\nimport type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'\nimport { attachForkToLogger } from '../shared/fork'\nimport { extractSafeNodeHeaders } from '../shared/headers'\nimport { createLoggerStorage } from '../shared/storage'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'middleware context. Make sure EvlogModule.forRoot() is imported in your AppModule.',\n)\n\nexport type EvlogNestJSOptions = BaseEvlogOptions\n\nexport { useLogger }\n\nexport interface EvlogModuleAsyncOptions {\n /** Modules to import (for dependency injection into the factory) */\n imports?: any[]\n /** Factory function that returns evlog options. Can be async. */\n useFactory: (...args: any[]) => EvlogNestJSOptions | Promise<EvlogNestJSOptions>\n /** Injection tokens to resolve and pass to the factory */\n inject?: any[]\n}\n\ndeclare module 'http' {\n interface IncomingMessage {\n log?: RequestLogger\n }\n}\n\ndeclare module 'express-serve-static-core' {\n interface Request {\n log?: RequestLogger\n }\n}\n\nfunction createEvlogMiddleware(getOptions: () => EvlogNestJSOptions) {\n return (req: Request, res: ServerResponse, next: () => void) => {\n const options = getOptions()\n const headers = extractSafeNodeHeaders(req.headers)\n const url = new URL(req.originalUrl || req.url || '/', 'http://localhost')\n\n const middlewareOpts = {\n method: req.method || 'GET',\n path: url.pathname,\n requestId: headers['x-request-id'] || crypto.randomUUID(),\n headers,\n ...options,\n }\n const { logger, finish, skipped } = createMiddlewareLogger(middlewareOpts)\n\n if (skipped) {\n next()\n return\n }\n\n attachForkToLogger(storage, logger, middlewareOpts)\n req.log = logger\n\n res.on('finish', () => {\n finish({ status: res.statusCode }).catch(() => {})\n })\n\n storage.run(logger, () => next())\n }\n}\n\n/**\n * NestJS module for evlog wide event logging.\n *\n * Registers a global middleware that creates a request-scoped logger\n * for every incoming request. Use `useLogger()` to access it anywhere\n * in the call stack, or `req.log` directly in controllers.\n *\n * @example\n * ```ts\n * import { Module } from '@nestjs/common'\n * import { EvlogModule } from 'evlog/nestjs'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * @Module({\n * imports: [\n * EvlogModule.forRoot({\n * drain: createAxiomDrain(),\n * exclude: ['/health'],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class EvlogModule implements NestModule {\n\n private static options: EvlogNestJSOptions = {}\n\n /**\n * Register evlog with static configuration.\n *\n * @example\n * ```ts\n * EvlogModule.forRoot({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => { ctx.event.region = process.env.FLY_REGION },\n * })\n * ```\n */\n static forRoot(options: EvlogNestJSOptions = {}): DynamicModule {\n EvlogModule.options = options\n return {\n module: EvlogModule,\n global: true,\n }\n }\n\n /**\n * Register evlog with async configuration (e.g. from `ConfigService`).\n *\n * @example\n * ```ts\n * EvlogModule.forRootAsync({\n * imports: [ConfigModule],\n * inject: [ConfigService],\n * useFactory: (config: ConfigService) => ({\n * drain: createAxiomDrain({ token: config.get('AXIOM_TOKEN') }),\n * }),\n * })\n * ```\n */\n static forRootAsync(asyncOptions: EvlogModuleAsyncOptions): DynamicModule {\n return {\n module: EvlogModule,\n imports: asyncOptions.imports || [],\n providers: [\n {\n provide: 'EVLOG_OPTIONS',\n useFactory: async (...args: any[]) => {\n EvlogModule.options = await asyncOptions.useFactory(...args)\n return EvlogModule.options\n },\n inject: asyncOptions.inject || [],\n },\n ],\n global: true,\n }\n }\n\n configure(consumer: MiddlewareConsumer): void {\n consumer\n .apply(createEvlogMiddleware(() => EvlogModule.options))\n .forRoutes('*')\n }\n\n}\n"],"mappings":";;;;;AASA,MAAM,EAAE,SAAS,cAAc,oBAC7B,qFACD;AA2BD,SAAS,sBAAsB,YAAsC;AACnE,SAAQ,KAAc,KAAqB,SAAqB;EAC9D,MAAM,UAAU,YAAY;EAC5B,MAAM,UAAU,uBAAuB,IAAI,QAAQ;EACnD,MAAM,MAAM,IAAI,IAAI,IAAI,eAAe,IAAI,OAAO,KAAK,mBAAmB;EAE1E,MAAM,iBAAiB;GACrB,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI;GACV,WAAW,QAAQ,mBAAmB,OAAO,YAAY;GACzD;GACA,GAAG;GACJ;EACD,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB,eAAe;AAE1E,MAAI,SAAS;AACX,SAAM;AACN;;AAGF,qBAAmB,SAAS,QAAQ,eAAe;AACnD,MAAI,MAAM;AAEV,MAAI,GAAG,gBAAgB;AACrB,UAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,CAAC,YAAY,GAAG;IAClD;AAEF,UAAQ,IAAI,cAAc,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BrC,IAAa,cAAb,MAAa,YAAkC;CAE7C,OAAe,UAA8B,EAAE;;;;;;;;;;;;CAa/C,OAAO,QAAQ,UAA8B,EAAE,EAAiB;AAC9D,cAAY,UAAU;AACtB,SAAO;GACL,QAAQ;GACR,QAAQ;GACT;;;;;;;;;;;;;;;;CAiBH,OAAO,aAAa,cAAsD;AACxE,SAAO;GACL,QAAQ;GACR,SAAS,aAAa,WAAW,EAAE;GACnC,WAAW,CACT;IACE,SAAS;IACT,YAAY,OAAO,GAAG,SAAgB;AACpC,iBAAY,UAAU,MAAM,aAAa,WAAW,GAAG,KAAK;AAC5D,YAAO,YAAY;;IAErB,QAAQ,aAAa,UAAU,EAAE;IAClC,CACF;GACD,QAAQ;GACT;;CAGH,UAAU,UAAoC;AAC5C,WACG,MAAM,4BAA4B,YAAY,QAAQ,CAAC,CACvD,UAAU,IAAI"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import type { ServerResponse } from 'node:http'\nimport type { Request } from 'express'\nimport type { DynamicModule, MiddlewareConsumer, NestModule } from '@nestjs/common'\nimport type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'\nimport { attachForkToLogger } from '../shared/fork'\nimport { extractSafeNodeHeaders } from '../shared/headers'\nimport { createLoggerStorage } from '../shared/storage'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'middleware context. Make sure EvlogModule.forRoot() is imported in your AppModule.',\n)\n\nexport type EvlogNestJSOptions = BaseEvlogOptions\n\nexport { useLogger }\n\nexport interface EvlogModuleAsyncOptions {\n /** Modules to import (for dependency injection into the factory) */\n imports?: any[]\n /** Factory function that returns evlog options. Can be async. */\n useFactory: (...args: any[]) => EvlogNestJSOptions | Promise<EvlogNestJSOptions>\n /** Injection tokens to resolve and pass to the factory */\n inject?: any[]\n}\n\ndeclare module 'http' {\n interface IncomingMessage {\n log?: RequestLogger\n }\n}\n\ndeclare module 'express-serve-static-core' {\n interface Request {\n log?: RequestLogger\n }\n}\n\nfunction createEvlogMiddleware(getOptions: () => EvlogNestJSOptions) {\n return (req: Request, res: ServerResponse, next: () => void) => {\n const options = getOptions()\n const headers = extractSafeNodeHeaders(req.headers)\n const url = new URL(req.originalUrl || req.url || '/', 'http://localhost')\n\n const middlewareOpts = {\n method: req.method || 'GET',\n path: url.pathname,\n requestId: headers['x-request-id'] || crypto.randomUUID(),\n headers,\n ...options,\n }\n const { logger, finish, skipped } = createMiddlewareLogger(middlewareOpts)\n\n if (skipped) {\n next()\n return\n }\n\n attachForkToLogger(storage, logger, middlewareOpts)\n req.log = logger\n\n res.on('finish', () => {\n finish({ status: res.statusCode }).catch(() => {})\n })\n\n storage.run(logger, () => next())\n }\n}\n\n/**\n * NestJS module for evlog wide event logging.\n *\n * Registers a global middleware that creates a request-scoped logger\n * for every incoming request. Use `useLogger()` to access it anywhere\n * in the call stack, or `req.log` directly in controllers.\n *\n * @example\n * ```ts\n * import { Module } from '@nestjs/common'\n * import { EvlogModule } from 'evlog/nestjs'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * @Module({\n * imports: [\n * EvlogModule.forRoot({\n * drain: createAxiomDrain(),\n * exclude: ['/health'],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class EvlogModule implements NestModule {\n\n private static options: EvlogNestJSOptions = {}\n\n /**\n * Register evlog with static configuration.\n *\n * @example\n * ```ts\n * EvlogModule.forRoot({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => { ctx.event.region = process.env.FLY_REGION },\n * })\n * ```\n */\n static forRoot(options: EvlogNestJSOptions = {}): DynamicModule {\n EvlogModule.options = options\n return {\n module: EvlogModule,\n global: true,\n }\n }\n\n /**\n * Register evlog with async configuration (e.g. from `ConfigService`).\n *\n * @example\n * ```ts\n * EvlogModule.forRootAsync({\n * imports: [ConfigModule],\n * inject: [ConfigService],\n * useFactory: (config: ConfigService) => ({\n * drain: createAxiomDrain({ token: config.get('AXIOM_TOKEN') }),\n * }),\n * })\n * ```\n */\n static forRootAsync(asyncOptions: EvlogModuleAsyncOptions): DynamicModule {\n return {\n module: EvlogModule,\n imports: asyncOptions.imports || [],\n providers: [\n {\n provide: 'EVLOG_OPTIONS',\n useFactory: async (...args: any[]) => {\n EvlogModule.options = await asyncOptions.useFactory(...args)\n return EvlogModule.options\n },\n inject: asyncOptions.inject || [],\n },\n ],\n global: true,\n }\n }\n\n configure(consumer: MiddlewareConsumer): void {\n consumer\n .apply(createEvlogMiddleware(() => EvlogModule.options))\n .forRoutes('*')\n }\n\n}\n"],"mappings":";;;;AASA,MAAM,EAAE,SAAS,cAAc,oBAC7B,qFACD;AA2BD,SAAS,sBAAsB,YAAsC;AACnE,SAAQ,KAAc,KAAqB,SAAqB;EAC9D,MAAM,UAAU,YAAY;EAC5B,MAAM,UAAU,uBAAuB,IAAI,QAAQ;EACnD,MAAM,MAAM,IAAI,IAAI,IAAI,eAAe,IAAI,OAAO,KAAK,mBAAmB;EAE1E,MAAM,iBAAiB;GACrB,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI;GACV,WAAW,QAAQ,mBAAmB,OAAO,YAAY;GACzD;GACA,GAAG;GACJ;EACD,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB,eAAe;AAE1E,MAAI,SAAS;AACX,SAAM;AACN;;AAGF,qBAAmB,SAAS,QAAQ,eAAe;AACnD,MAAI,MAAM;AAEV,MAAI,GAAG,gBAAgB;AACrB,UAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,CAAC,YAAY,GAAG;IAClD;AAEF,UAAQ,IAAI,cAAc,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BrC,IAAa,cAAb,MAAa,YAAkC;CAE7C,OAAe,UAA8B,EAAE;;;;;;;;;;;;CAa/C,OAAO,QAAQ,UAA8B,EAAE,EAAiB;AAC9D,cAAY,UAAU;AACtB,SAAO;GACL,QAAQ;GACR,QAAQ;GACT;;;;;;;;;;;;;;;;CAiBH,OAAO,aAAa,cAAsD;AACxE,SAAO;GACL,QAAQ;GACR,SAAS,aAAa,WAAW,EAAE;GACnC,WAAW,CACT;IACE,SAAS;IACT,YAAY,OAAO,GAAG,SAAgB;AACpC,iBAAY,UAAU,MAAM,aAAa,WAAW,GAAG,KAAK;AAC5D,YAAO,YAAY;;IAErB,QAAQ,aAAa,UAAU,EAAE;IAClC,CACF;GACD,QAAQ;GACT;;CAGH,UAAU,UAAoC;AAC5C,WACG,MAAM,4BAA4B,YAAY,QAAQ,CAAC,CACvD,UAAU,IAAI"}
@@ -1,4 +1,4 @@
1
- import { W as LogLevel, rt as TransportConfig } from "../audit-CTIviX3P.mjs";
1
+ import { W as LogLevel, rt as TransportConfig } from "../audit-X1uUukm3.mjs";
2
2
  import { clearIdentity, log as _clientLog, setIdentity, setMinLevel } from "../runtime/client/log.mjs";
3
3
  import * as _$react from "react";
4
4
 
@@ -1,7 +1,7 @@
1
- import { L as EnvironmentContext, Q as SamplingConfig, U as Log, W as LogLevel, Y as RequestLogger } from "../audit-CTIviX3P.mjs";
2
- import { n as createError } from "../error-C7gSQVqk.mjs";
3
- import { t as _log } from "../logger-DttRJRGa.mjs";
4
- import { t as BaseEvlogOptions } from "../middleware-CTnDsST-.mjs";
1
+ import { L as EnvironmentContext, Q as SamplingConfig, U as Log, W as LogLevel, Y as RequestLogger } from "../audit-X1uUukm3.mjs";
2
+ import { n as createError } from "../error-Cpc7RVz6.mjs";
3
+ import { t as _log } from "../logger-U8lgdc9x.mjs";
4
+ import { t as BaseEvlogOptions } from "../middleware-CAQHJRN1.mjs";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
 
7
7
  //#region src/next/types.d.ts
@@ -1,8 +1,8 @@
1
- import { b as isEnabled, g as createRequestLogger, m as _log, v as getGlobalDrain, x as isLoggerLocked, y as initLogger } from "../audit-DQoBo7Dl.mjs";
1
+ import { S as isLoggerLocked, b as initLogger, g as createRequestLogger, m as _log, v as getGlobalDrain, x as isEnabled } from "../audit-pV5aLGP0.mjs";
2
2
  import { filterSafeHeaders } from "../utils.mjs";
3
3
  import { EvlogError, createError } from "../error.mjs";
4
- import { n as shouldLog, t as getServiceForPath } from "../routes-CGPmbzCZ.mjs";
5
- import { t as attachForkToLogger } from "../fork-D1j1Fuzy.mjs";
4
+ import { n as shouldLog, t as getServiceForPath } from "../routes-B48wm7Pb.mjs";
5
+ import { t as attachForkToLogger } from "../fork-DPN8aL8O.mjs";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
  //#region src/next/storage.ts
8
8
  const evlogStorage = new AsyncLocalStorage();
@@ -1,4 +1,4 @@
1
- import { F as DrainContext, L as EnvironmentContext, Q as SamplingConfig, W as LogLevel } from "../audit-CTIviX3P.mjs";
1
+ import { F as DrainContext, L as EnvironmentContext, Q as SamplingConfig, W as LogLevel } from "../audit-X1uUukm3.mjs";
2
2
 
3
3
  //#region src/next/instrumentation.d.ts
4
4
  /** Request payload passed to Next.js `onRequestError` (App Router). */
@@ -1,4 +1,4 @@
1
- import { S as lockLogger, m as _log, y as initLogger } from "../audit-DQoBo7Dl.mjs";
1
+ import { C as lockLogger, b as initLogger, m as _log } from "../audit-pV5aLGP0.mjs";
2
2
  //#region src/next/instrumentation.ts
3
3
  /**
4
4
  * Root `instrumentation.ts` entry: load your real config only in the Node.js runtime so Edge
@@ -1,5 +1,5 @@
1
- import { t as extractErrorStatus } from "../errors-BJRXUfMg.mjs";
2
- import { n as serializeEvlogErrorResponse, t as resolveEvlogError } from "../nitro-OmT_M4Pb.mjs";
1
+ import { t as extractErrorStatus } from "../errors-BQgyQ9xe.mjs";
2
+ import { n as serializeEvlogErrorResponse, t as resolveEvlogError } from "../nitro-DavLelNz.mjs";
3
3
  import { getRequestURL, send, setResponseHeader, setResponseStatus } from "h3";
4
4
  import { defineNitroErrorHandler } from "nitropack/runtime/internal/error/utils";
5
5
  //#region src/nitro/errorHandler.ts
@@ -1,5 +1,5 @@
1
- import { t as useLogger } from "../useLogger-CyPP1sVB.mjs";
2
- import { t as NitroModuleOptions } from "../nitro-CPPRCPbG.mjs";
1
+ import { t as useLogger } from "../useLogger-CoNgTjp5.mjs";
2
+ import { t as NitroModuleOptions } from "../nitro-C6Bd682U.mjs";
3
3
  import { Nitro } from "nitropack";
4
4
 
5
5
  //#region src/nitro/module.d.ts
@@ -1,8 +1,8 @@
1
- import { b as isEnabled, g as createRequestLogger, w as normalizeRedactConfig, y as initLogger } from "../audit-DQoBo7Dl.mjs";
1
+ import { A as normalizeRedactConfig, b as initLogger, g as createRequestLogger, x as isEnabled, y as getGlobalPluginRunner } from "../audit-pV5aLGP0.mjs";
2
2
  import { filterSafeHeaders } from "../utils.mjs";
3
- import { t as extractErrorStatus } from "../errors-BJRXUfMg.mjs";
4
- import { n as shouldLog, t as getServiceForPath } from "../routes-CGPmbzCZ.mjs";
5
- import { n as resolveEvlogConfigForNitroPlugin } from "../nitroConfigBridge-C37lXaNm.mjs";
3
+ import { t as extractErrorStatus } from "../errors-BQgyQ9xe.mjs";
4
+ import { n as shouldLog, t as getServiceForPath } from "../routes-B48wm7Pb.mjs";
5
+ import { n as resolveEvlogConfigForNitroPlugin } from "../nitroConfigBridge-aZ1e5upQ.mjs";
6
6
  import { defineNitroPlugin } from "nitropack/runtime/internal/plugin";
7
7
  import { getHeaders } from "h3";
8
8
  //#region src/nitro/plugin.ts
@@ -45,21 +45,27 @@ function buildHookContext(event) {
45
45
  async function callEnrichAndDrain(nitroApp, emittedEvent, event) {
46
46
  if (!emittedEvent) return;
47
47
  const hookContext = buildHookContext(event);
48
+ const enrichCtx = {
49
+ event: emittedEvent,
50
+ ...hookContext
51
+ };
52
+ const runner = getGlobalPluginRunner();
48
53
  try {
49
- await nitroApp.hooks.callHook("evlog:enrich", {
50
- event: emittedEvent,
51
- ...hookContext
52
- });
54
+ await nitroApp.hooks.callHook("evlog:enrich", enrichCtx);
53
55
  } catch (err) {
54
56
  console.error("[evlog] enrich failed:", err);
55
57
  }
56
- const drainPromise = nitroApp.hooks.callHook("evlog:drain", {
58
+ if (runner.hasEnrich) await runner.runEnrich(enrichCtx);
59
+ const drainCtx = {
57
60
  event: emittedEvent,
58
61
  request: hookContext.request,
59
62
  headers: hookContext.headers
60
- }).catch((err) => {
63
+ };
64
+ const drainTasks = [nitroApp.hooks.callHook("evlog:drain", drainCtx).catch((err) => {
61
65
  console.error("[evlog] drain failed:", err);
62
- });
66
+ })];
67
+ if (runner.hasDrain) drainTasks.push(runner.runDrain(drainCtx));
68
+ const drainPromise = Promise.all(drainTasks);
63
69
  const waitUntilCtx = event.context.cloudflare?.context ?? event.context;
64
70
  if (typeof waitUntilCtx?.waitUntil === "function") waitUntilCtx.waitUntil(drainPromise);
65
71
  else await drainPromise;
@@ -130,6 +136,8 @@ var plugin_default = defineNitroPlugin(async (nitroApp) => {
130
136
  shouldKeep: false
131
137
  };
132
138
  await nitroApp.hooks.callHook("evlog:emit:keep", tailCtx);
139
+ const runner = getGlobalPluginRunner();
140
+ if (runner.hasKeep) await runner.runKeep(tailCtx);
133
141
  e.context._evlogEmitted = true;
134
142
  await callEnrichAndDrain(nitroApp, requestLog.emit({ _forceKeep: tailCtx.shouldKeep }), e);
135
143
  }
@@ -151,6 +159,8 @@ var plugin_default = defineNitroPlugin(async (nitroApp) => {
151
159
  shouldKeep: false
152
160
  };
153
161
  await nitroApp.hooks.callHook("evlog:emit:keep", tailCtx);
162
+ const runner = getGlobalPluginRunner();
163
+ if (runner.hasKeep) await runner.runKeep(tailCtx);
154
164
  await callEnrichAndDrain(nitroApp, requestLog.emit({ _forceKeep: tailCtx.shouldKeep }), e);
155
165
  }
156
166
  });
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/nitro/plugin.ts"],"sourcesContent":["import type { NitroApp } from 'nitropack/types'\n// Import from specific subpaths to avoid the barrel 'nitropack/runtime' which\n// re-exports from internal/app.mjs — that file imports #nitro-internal-virtual/*\n// modules that only exist inside rollup builds and crash when loaded externally\n// (nitropack dev loads plugins outside the bundle via Worker threads).\nimport { defineNitroPlugin } from 'nitropack/runtime/internal/plugin'\nimport { getHeaders } from 'h3'\nimport { createRequestLogger, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport { normalizeRedactConfig } from '../redact'\nimport { resolveEvlogConfigForNitroPlugin } from '../shared/nitroConfigBridge'\nimport type { EnrichContext, RequestLogger, ServerEvent, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\nfunction getSafeHeaders(event: ServerEvent): Record<string, string> {\n const allHeaders = getHeaders(event as Parameters<typeof getHeaders>[0])\n return filterSafeHeaders(allHeaders)\n}\n\nfunction getSafeResponseHeaders(event: ServerEvent): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n const nodeRes = event.node?.res as { getHeaders?: () => Record<string, unknown> } | undefined\n\n if (nodeRes?.getHeaders) {\n for (const [key, value] of Object.entries(nodeRes.getHeaders())) {\n if (value === undefined) continue\n headers[key] = Array.isArray(value) ? value.join(', ') : String(value)\n }\n }\n\n if (event.response?.headers) {\n event.response.headers.forEach((value, key) => {\n headers[key] = value\n })\n }\n\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction getResponseStatus(event: ServerEvent): number {\n // Node.js style\n if (event.node?.res?.statusCode) {\n return event.node.res.statusCode\n }\n\n // Web Standard\n if (event.response?.status) {\n return event.response.status\n }\n\n // Context-based\n if (typeof event.context.status === 'number') {\n return event.context.status\n }\n\n return 200\n}\n\nfunction buildHookContext(event: ServerEvent): Omit<EnrichContext, 'event'> {\n const responseHeaders = getSafeResponseHeaders(event)\n return {\n request: { method: event.method, path: event.path },\n headers: getSafeHeaders(event),\n response: {\n status: getResponseStatus(event),\n headers: responseHeaders,\n },\n }\n}\n\nasync function callEnrichAndDrain(\n nitroApp: NitroApp,\n emittedEvent: WideEvent | null,\n event: ServerEvent,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event)\n\n try {\n await nitroApp.hooks.callHook('evlog:enrich', { event: emittedEvent, ...hookContext })\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n const drainPromise = nitroApp.hooks.callHook('evlog:drain', {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n }).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n\n // Use waitUntil if available (Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n const waitUntilCtx = event.context.cloudflare?.context ?? event.context\n if (typeof waitUntilCtx?.waitUntil === 'function') {\n waitUntilCtx.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from\n // afterResponse (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nexport default defineNitroPlugin(async (nitroApp) => {\n const evlogConfig = await resolveEvlogConfigForNitroPlugin()\n\n const redact = normalizeRedactConfig(evlogConfig?.redact as boolean | Record<string, unknown> | undefined)\n\n initLogger({\n enabled: evlogConfig?.enabled,\n env: evlogConfig?.env,\n pretty: evlogConfig?.pretty,\n silent: evlogConfig?.silent,\n sampling: evlogConfig?.sampling,\n minLevel: evlogConfig?.minLevel,\n redact,\n _suppressDrainWarning: true,\n })\n\n // When globally disabled, createRequestLogger returns a no-op logger — still\n // attach it so handlers can call useLogger(event) without throwing.\n if (!isEnabled()) {\n nitroApp.hooks.hook('request', (event) => {\n const e = event as ServerEvent\n let requestIdOverride: string | undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = getSafeHeaders(e)?.['cf-ray']\n if (cfRay) requestIdOverride = cfRay\n }\n e.context.log = createRequestLogger({\n method: e.method,\n path: e.path,\n requestId: requestIdOverride || e.context.requestId || crypto.randomUUID(),\n }, { _deferDrain: true })\n })\n return\n }\n\n nitroApp.hooks.hook('request', (event) => {\n const e = event as ServerEvent\n\n // Evaluate route filtering but always create the logger so that server\n // middleware (which runs for every request) can call useLogger(event)\n // without throwing. Filtering is enforced at emit time instead.\n e.context._evlogShouldEmit = shouldLog(e.path, evlogConfig?.include, evlogConfig?.exclude)\n\n // Store start time for duration calculation in tail sampling\n e.context._evlogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = getSafeHeaders(e)?.['cf-ray']\n if (cfRay) requestIdOverride = cfRay\n }\n\n const requestLog = createRequestLogger({\n method: e.method,\n path: e.path,\n requestId: requestIdOverride || e.context.requestId || crypto.randomUUID(),\n }, { _deferDrain: true })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(e.path, evlogConfig?.routes)\n if (routeService) {\n requestLog.set({ service: routeService })\n }\n\n e.context.log = requestLog\n })\n\n nitroApp.hooks.hook('error', async (error, { event }) => {\n const e = event as ServerEvent | undefined\n if (!e) return\n if (!e.context._evlogShouldEmit) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n requestLog.error(error as Error)\n\n const errorStatus = extractErrorStatus(error)\n requestLog.set({ status: errorStatus })\n\n // Build tail sampling context\n const startTime = e.context._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n // Call evlog:emit:keep hook\n await nitroApp.hooks.callHook('evlog:emit:keep', tailCtx)\n\n e.context._evlogEmitted = true\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n\n nitroApp.hooks.hook('afterResponse', async (event) => {\n const e = event as ServerEvent\n // Skip if already emitted by error hook or route was filtered out\n if (e.context._evlogEmitted || !e.context._evlogShouldEmit) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n const status = getResponseStatus(e)\n requestLog.set({ status })\n\n const startTime = e.context._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n await nitroApp.hooks.callHook('evlog:emit:keep', tailCtx)\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/nitro/plugin.ts"],"sourcesContent":["import type { NitroApp } from 'nitropack/types'\n// Import from specific subpaths to avoid the barrel 'nitropack/runtime' which\n// re-exports from internal/app.mjs — that file imports #nitro-internal-virtual/*\n// modules that only exist inside rollup builds and crash when loaded externally\n// (nitropack dev loads plugins outside the bundle via Worker threads).\nimport { defineNitroPlugin } from 'nitropack/runtime/internal/plugin'\nimport { getHeaders } from 'h3'\nimport { createRequestLogger, getGlobalPluginRunner, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport { normalizeRedactConfig } from '../redact'\nimport { resolveEvlogConfigForNitroPlugin } from '../shared/nitroConfigBridge'\nimport type { EnrichContext, RequestLogger, ServerEvent, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\nfunction getSafeHeaders(event: ServerEvent): Record<string, string> {\n const allHeaders = getHeaders(event as Parameters<typeof getHeaders>[0])\n return filterSafeHeaders(allHeaders)\n}\n\nfunction getSafeResponseHeaders(event: ServerEvent): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n const nodeRes = event.node?.res as { getHeaders?: () => Record<string, unknown> } | undefined\n\n if (nodeRes?.getHeaders) {\n for (const [key, value] of Object.entries(nodeRes.getHeaders())) {\n if (value === undefined) continue\n headers[key] = Array.isArray(value) ? value.join(', ') : String(value)\n }\n }\n\n if (event.response?.headers) {\n event.response.headers.forEach((value, key) => {\n headers[key] = value\n })\n }\n\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction getResponseStatus(event: ServerEvent): number {\n // Node.js style\n if (event.node?.res?.statusCode) {\n return event.node.res.statusCode\n }\n\n // Web Standard\n if (event.response?.status) {\n return event.response.status\n }\n\n // Context-based\n if (typeof event.context.status === 'number') {\n return event.context.status\n }\n\n return 200\n}\n\nfunction buildHookContext(event: ServerEvent): Omit<EnrichContext, 'event'> {\n const responseHeaders = getSafeResponseHeaders(event)\n return {\n request: { method: event.method, path: event.path },\n headers: getSafeHeaders(event),\n response: {\n status: getResponseStatus(event),\n headers: responseHeaders,\n },\n }\n}\n\nasync function callEnrichAndDrain(\n nitroApp: NitroApp,\n emittedEvent: WideEvent | null,\n event: ServerEvent,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event)\n const enrichCtx: EnrichContext = { event: emittedEvent, ...hookContext }\n const runner = getGlobalPluginRunner()\n\n try {\n await nitroApp.hooks.callHook('evlog:enrich', enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n if (runner.hasEnrich) {\n await runner.runEnrich(enrichCtx)\n }\n\n const drainCtx = {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n }\n const drainTasks: Array<Promise<unknown>> = [\n nitroApp.hooks.callHook('evlog:drain', drainCtx).catch((err) => {\n console.error('[evlog] drain failed:', err)\n }),\n ]\n if (runner.hasDrain) {\n drainTasks.push(runner.runDrain(drainCtx))\n }\n const drainPromise = Promise.all(drainTasks)\n\n // Use waitUntil if available (Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n const waitUntilCtx = event.context.cloudflare?.context ?? event.context\n if (typeof waitUntilCtx?.waitUntil === 'function') {\n waitUntilCtx.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from\n // afterResponse (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nexport default defineNitroPlugin(async (nitroApp) => {\n const evlogConfig = await resolveEvlogConfigForNitroPlugin()\n\n const redact = normalizeRedactConfig(evlogConfig?.redact as boolean | Record<string, unknown> | undefined)\n\n initLogger({\n enabled: evlogConfig?.enabled,\n env: evlogConfig?.env,\n pretty: evlogConfig?.pretty,\n silent: evlogConfig?.silent,\n sampling: evlogConfig?.sampling,\n minLevel: evlogConfig?.minLevel,\n redact,\n _suppressDrainWarning: true,\n })\n\n // When globally disabled, createRequestLogger returns a no-op logger — still\n // attach it so handlers can call useLogger(event) without throwing.\n if (!isEnabled()) {\n nitroApp.hooks.hook('request', (event) => {\n const e = event as ServerEvent\n let requestIdOverride: string | undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = getSafeHeaders(e)?.['cf-ray']\n if (cfRay) requestIdOverride = cfRay\n }\n e.context.log = createRequestLogger({\n method: e.method,\n path: e.path,\n requestId: requestIdOverride || e.context.requestId || crypto.randomUUID(),\n }, { _deferDrain: true })\n })\n return\n }\n\n nitroApp.hooks.hook('request', (event) => {\n const e = event as ServerEvent\n\n // Evaluate route filtering but always create the logger so that server\n // middleware (which runs for every request) can call useLogger(event)\n // without throwing. Filtering is enforced at emit time instead.\n e.context._evlogShouldEmit = shouldLog(e.path, evlogConfig?.include, evlogConfig?.exclude)\n\n // Store start time for duration calculation in tail sampling\n e.context._evlogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = getSafeHeaders(e)?.['cf-ray']\n if (cfRay) requestIdOverride = cfRay\n }\n\n const requestLog = createRequestLogger({\n method: e.method,\n path: e.path,\n requestId: requestIdOverride || e.context.requestId || crypto.randomUUID(),\n }, { _deferDrain: true })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(e.path, evlogConfig?.routes)\n if (routeService) {\n requestLog.set({ service: routeService })\n }\n\n e.context.log = requestLog\n })\n\n nitroApp.hooks.hook('error', async (error, { event }) => {\n const e = event as ServerEvent | undefined\n if (!e) return\n if (!e.context._evlogShouldEmit) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n requestLog.error(error as Error)\n\n const errorStatus = extractErrorStatus(error)\n requestLog.set({ status: errorStatus })\n\n // Build tail sampling context\n const startTime = e.context._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n // Call evlog:emit:keep hook + plugin runner keep hook\n await nitroApp.hooks.callHook('evlog:emit:keep', tailCtx)\n const runner = getGlobalPluginRunner()\n if (runner.hasKeep) await runner.runKeep(tailCtx)\n\n e.context._evlogEmitted = true\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n\n nitroApp.hooks.hook('afterResponse', async (event) => {\n const e = event as ServerEvent\n // Skip if already emitted by error hook or route was filtered out\n if (e.context._evlogEmitted || !e.context._evlogShouldEmit) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n const status = getResponseStatus(e)\n requestLog.set({ status })\n\n const startTime = e.context._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n await nitroApp.hooks.callHook('evlog:emit:keep', tailCtx)\n const runner = getGlobalPluginRunner()\n if (runner.hasKeep) await runner.runKeep(tailCtx)\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n})\n"],"mappings":";;;;;;;;AAcA,SAAS,eAAe,OAA4C;AAElE,QAAO,kBADY,WAAW,MACK,CAAC;;AAGtC,SAAS,uBAAuB,OAAwD;CACtF,MAAM,UAAkC,EAAE;CAC1C,MAAM,UAAU,MAAM,MAAM;AAE5B,KAAI,SAAS,WACX,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,YAAY,CAAC,EAAE;AAC/D,MAAI,UAAU,KAAA,EAAW;AACzB,UAAQ,OAAO,MAAM,QAAQ,MAAM,GAAG,MAAM,KAAK,KAAK,GAAG,OAAO,MAAM;;AAI1E,KAAI,MAAM,UAAU,QAClB,OAAM,SAAS,QAAQ,SAAS,OAAO,QAAQ;AAC7C,UAAQ,OAAO;GACf;AAGJ,KAAI,OAAO,KAAK,QAAQ,CAAC,WAAW,EAAG,QAAO,KAAA;AAC9C,QAAO,kBAAkB,QAAQ;;AAGnC,SAAS,kBAAkB,OAA4B;AAErD,KAAI,MAAM,MAAM,KAAK,WACnB,QAAO,MAAM,KAAK,IAAI;AAIxB,KAAI,MAAM,UAAU,OAClB,QAAO,MAAM,SAAS;AAIxB,KAAI,OAAO,MAAM,QAAQ,WAAW,SAClC,QAAO,MAAM,QAAQ;AAGvB,QAAO;;AAGT,SAAS,iBAAiB,OAAkD;CAC1E,MAAM,kBAAkB,uBAAuB,MAAM;AACrD,QAAO;EACL,SAAS;GAAE,QAAQ,MAAM;GAAQ,MAAM,MAAM;GAAM;EACnD,SAAS,eAAe,MAAM;EAC9B,UAAU;GACR,QAAQ,kBAAkB,MAAM;GAChC,SAAS;GACV;EACF;;AAGH,eAAe,mBACb,UACA,cACA,OACe;AACf,KAAI,CAAC,aAAc;CAEnB,MAAM,cAAc,iBAAiB,MAAM;CAC3C,MAAM,YAA2B;EAAE,OAAO;EAAc,GAAG;EAAa;CACxE,MAAM,SAAS,uBAAuB;AAEtC,KAAI;AACF,QAAM,SAAS,MAAM,SAAS,gBAAgB,UAAU;UACjD,KAAK;AACZ,UAAQ,MAAM,0BAA0B,IAAI;;AAE9C,KAAI,OAAO,UACT,OAAM,OAAO,UAAU,UAAU;CAGnC,MAAM,WAAW;EACf,OAAO;EACP,SAAS,YAAY;EACrB,SAAS,YAAY;EACtB;CACD,MAAM,aAAsC,CAC1C,SAAS,MAAM,SAAS,eAAe,SAAS,CAAC,OAAO,QAAQ;AAC9D,UAAQ,MAAM,yBAAyB,IAAI;GAC3C,CACH;AACD,KAAI,OAAO,SACT,YAAW,KAAK,OAAO,SAAS,SAAS,CAAC;CAE5C,MAAM,eAAe,QAAQ,IAAI,WAAW;CAI5C,MAAM,eAAe,MAAM,QAAQ,YAAY,WAAW,MAAM;AAChE,KAAI,OAAO,cAAc,cAAc,WACrC,cAAa,UAAU,aAAa;KAMpC,OAAM;;AAIV,IAAA,iBAAe,kBAAkB,OAAO,aAAa;CACnD,MAAM,cAAc,MAAM,kCAAkC;CAE5D,MAAM,SAAS,sBAAsB,aAAa,OAAwD;AAE1G,YAAW;EACT,SAAS,aAAa;EACtB,KAAK,aAAa;EAClB,QAAQ,aAAa;EACrB,QAAQ,aAAa;EACrB,UAAU,aAAa;EACvB,UAAU,aAAa;EACvB;EACA,uBAAuB;EACxB,CAAC;AAIF,KAAI,CAAC,WAAW,EAAE;AAChB,WAAS,MAAM,KAAK,YAAY,UAAU;GACxC,MAAM,IAAI;GACV,IAAI;AACJ,OAAI,WAAW,WAAW,cAAc,sBAAsB;IAC5D,MAAM,QAAQ,eAAe,EAAE,GAAG;AAClC,QAAI,MAAO,qBAAoB;;AAEjC,KAAE,QAAQ,MAAM,oBAAoB;IAClC,QAAQ,EAAE;IACV,MAAM,EAAE;IACR,WAAW,qBAAqB,EAAE,QAAQ,aAAa,OAAO,YAAY;IAC3E,EAAE,EAAE,aAAa,MAAM,CAAC;IACzB;AACF;;AAGF,UAAS,MAAM,KAAK,YAAY,UAAU;EACxC,MAAM,IAAI;AAKV,IAAE,QAAQ,mBAAmB,UAAU,EAAE,MAAM,aAAa,SAAS,aAAa,QAAQ;AAG1F,IAAE,QAAQ,kBAAkB,KAAK,KAAK;EAEtC,IAAI,oBAAwC,KAAA;AAC5C,MAAI,WAAW,WAAW,cAAc,sBAAsB;GAC5D,MAAM,QAAQ,eAAe,EAAE,GAAG;AAClC,OAAI,MAAO,qBAAoB;;EAGjC,MAAM,aAAa,oBAAoB;GACrC,QAAQ,EAAE;GACV,MAAM,EAAE;GACR,WAAW,qBAAqB,EAAE,QAAQ,aAAa,OAAO,YAAY;GAC3E,EAAE,EAAE,aAAa,MAAM,CAAC;EAGzB,MAAM,eAAe,kBAAkB,EAAE,MAAM,aAAa,OAAO;AACnE,MAAI,aACF,YAAW,IAAI,EAAE,SAAS,cAAc,CAAC;AAG3C,IAAE,QAAQ,MAAM;GAChB;AAEF,UAAS,MAAM,KAAK,SAAS,OAAO,OAAO,EAAE,YAAY;EACvD,MAAM,IAAI;AACV,MAAI,CAAC,EAAG;AACR,MAAI,CAAC,EAAE,QAAQ,iBAAkB;EAEjC,MAAM,aAAa,EAAE,QAAQ;AAC7B,MAAI,YAAY;AACd,cAAW,MAAM,MAAe;GAEhC,MAAM,cAAc,mBAAmB,MAAM;AAC7C,cAAW,IAAI,EAAE,QAAQ,aAAa,CAAC;GAGvC,MAAM,YAAY,EAAE,QAAQ;GAG5B,MAAM,UAA+B;IACnC,QAAQ;IACR,UAJiB,YAAY,KAAK,KAAK,GAAG,YAAY,KAAA;IAKtD,MAAM,EAAE;IACR,QAAQ,EAAE;IACV,SAAS,WAAW,YAAY;IAChC,YAAY;IACb;AAGD,SAAM,SAAS,MAAM,SAAS,mBAAmB,QAAQ;GACzD,MAAM,SAAS,uBAAuB;AACtC,OAAI,OAAO,QAAS,OAAM,OAAO,QAAQ,QAAQ;AAEjD,KAAE,QAAQ,gBAAgB;AAG1B,SAAM,mBAAmB,UADJ,WAAW,KAAK,EAAE,YAAY,QAAQ,YAAY,CACxB,EAAE,EAAE;;GAErD;AAEF,UAAS,MAAM,KAAK,iBAAiB,OAAO,UAAU;EACpD,MAAM,IAAI;AAEV,MAAI,EAAE,QAAQ,iBAAiB,CAAC,EAAE,QAAQ,iBAAkB;EAE5D,MAAM,aAAa,EAAE,QAAQ;AAC7B,MAAI,YAAY;GACd,MAAM,SAAS,kBAAkB,EAAE;AACnC,cAAW,IAAI,EAAE,QAAQ,CAAC;GAE1B,MAAM,YAAY,EAAE,QAAQ;GAG5B,MAAM,UAA+B;IACnC;IACA,UAJiB,YAAY,KAAK,KAAK,GAAG,YAAY,KAAA;IAKtD,MAAM,EAAE;IACR,QAAQ,EAAE;IACV,SAAS,WAAW,YAAY;IAChC,YAAY;IACb;AAED,SAAM,SAAS,MAAM,SAAS,mBAAmB,QAAQ;GACzD,MAAM,SAAS,uBAAuB;AACtC,OAAI,OAAO,QAAS,OAAM,OAAO,QAAQ,QAAQ;AAGjD,SAAM,mBAAmB,UADJ,WAAW,KAAK,EAAE,YAAY,QAAQ,YAAY,CACxB,EAAE,EAAE;;GAErD;EACF"}
@@ -1,6 +1,6 @@
1
- import { t as extractErrorStatus } from "../../errors-BJRXUfMg.mjs";
2
- import { n as serializeEvlogErrorResponse, t as resolveEvlogError } from "../../nitro-OmT_M4Pb.mjs";
3
- import { t as parseURL } from "../../dist-Do8P4zWd.mjs";
1
+ import { t as extractErrorStatus } from "../../errors-BQgyQ9xe.mjs";
2
+ import { n as serializeEvlogErrorResponse, t as resolveEvlogError } from "../../nitro-DavLelNz.mjs";
3
+ import { t as parseURL } from "../../dist-BIlS38vi.mjs";
4
4
  import { defineErrorHandler } from "nitro";
5
5
  //#region src/nitro-v3/errorHandler.ts
6
6
  /**
@@ -1,5 +1,5 @@
1
- import { n as createError, t as EvlogError } from "../../error-C7gSQVqk.mjs";
2
- import { t as parseError } from "../../parseError-o1GpZEOR.mjs";
1
+ import { n as createError, t as EvlogError } from "../../error-Cpc7RVz6.mjs";
2
+ import { t as parseError } from "../../parseError-B-dKF6Fd.mjs";
3
3
  import evlog from "./module.mjs";
4
4
  import { useLogger } from "./useLogger.mjs";
5
5
  import { evlogErrorHandler } from "./middleware.mjs";
@@ -1,4 +1,4 @@
1
- import { t as NitroModuleOptions } from "../../nitro-CPPRCPbG.mjs";
1
+ import { t as NitroModuleOptions } from "../../nitro-C6Bd682U.mjs";
2
2
  import { Nitro } from "nitro/types";
3
3
 
4
4
  //#region src/nitro-v3/module.d.ts
@@ -1,9 +1,9 @@
1
- import { b as isEnabled, g as createRequestLogger, w as normalizeRedactConfig, y as initLogger } from "../../audit-DQoBo7Dl.mjs";
1
+ import { A as normalizeRedactConfig, b as initLogger, g as createRequestLogger, x as isEnabled, y as getGlobalPluginRunner } from "../../audit-pV5aLGP0.mjs";
2
2
  import { filterSafeHeaders } from "../../utils.mjs";
3
- import { t as extractErrorStatus } from "../../errors-BJRXUfMg.mjs";
4
- import { n as shouldLog, t as getServiceForPath } from "../../routes-CGPmbzCZ.mjs";
5
- import { n as resolveEvlogConfigForNitroPlugin } from "../../nitroConfigBridge-C37lXaNm.mjs";
6
- import { t as parseURL } from "../../dist-Do8P4zWd.mjs";
3
+ import { t as extractErrorStatus } from "../../errors-BQgyQ9xe.mjs";
4
+ import { n as shouldLog, t as getServiceForPath } from "../../routes-B48wm7Pb.mjs";
5
+ import { n as resolveEvlogConfigForNitroPlugin } from "../../nitroConfigBridge-aZ1e5upQ.mjs";
6
+ import { t as parseURL } from "../../dist-BIlS38vi.mjs";
7
7
  import { definePlugin } from "nitro";
8
8
  //#region src/nitro-v3/plugin.ts
9
9
  function getContext(event) {
@@ -42,33 +42,41 @@ function buildHookContext(event, res) {
42
42
  }
43
43
  async function callDrainHook(hooks, emittedEvent, event, hookContext) {
44
44
  if (!emittedEvent) return;
45
- let drainPromise;
45
+ const drainCtx = {
46
+ event: emittedEvent,
47
+ request: hookContext.request,
48
+ headers: hookContext.headers
49
+ };
50
+ const drainTasks = [];
46
51
  try {
47
- drainPromise = hooks.callHook("evlog:drain", {
48
- event: emittedEvent,
49
- request: hookContext.request,
50
- headers: hookContext.headers
51
- })?.catch?.((err) => {
52
+ const result = hooks.callHook("evlog:drain", drainCtx);
53
+ if (result?.catch) drainTasks.push(result.catch((err) => {
52
54
  console.error("[evlog] drain failed:", err);
53
- });
55
+ }));
54
56
  } catch (err) {
55
57
  console.error("[evlog] drain failed:", err);
56
58
  }
57
- if (!drainPromise) return;
59
+ const runner = getGlobalPluginRunner();
60
+ if (runner.hasDrain) drainTasks.push(runner.runDrain(drainCtx));
61
+ if (drainTasks.length === 0) return;
62
+ const drainPromise = Promise.all(drainTasks);
58
63
  if (typeof event.req.waitUntil === "function") event.req.waitUntil(drainPromise);
59
64
  else await drainPromise;
60
65
  }
61
66
  async function callEnrichAndDrain(hooks, emittedEvent, event, res) {
62
67
  if (!emittedEvent) return;
63
68
  const hookContext = buildHookContext(event, res);
69
+ const enrichCtx = {
70
+ event: emittedEvent,
71
+ ...hookContext
72
+ };
64
73
  try {
65
- await hooks.callHook("evlog:enrich", {
66
- event: emittedEvent,
67
- ...hookContext
68
- });
74
+ await hooks.callHook("evlog:enrich", enrichCtx);
69
75
  } catch (err) {
70
76
  console.error("[evlog] enrich failed:", err);
71
77
  }
78
+ const runner = getGlobalPluginRunner();
79
+ if (runner.hasEnrich) await runner.runEnrich(enrichCtx);
72
80
  await callDrainHook(hooks, emittedEvent, event, hookContext);
73
81
  }
74
82
  /**
@@ -149,6 +157,8 @@ var plugin_default = definePlugin(async (nitroApp) => {
149
157
  shouldKeep: false
150
158
  };
151
159
  await hooks.callHook("evlog:emit:keep", tailCtx);
160
+ const runner = getGlobalPluginRunner();
161
+ if (runner.hasKeep) await runner.runKeep(tailCtx);
152
162
  await callEnrichAndDrain(hooks, log.emit({ _forceKeep: tailCtx.shouldKeep }), event, res);
153
163
  });
154
164
  hooks.hook("error", async (error, { event }) => {
@@ -173,6 +183,8 @@ var plugin_default = definePlugin(async (nitroApp) => {
173
183
  shouldKeep: false
174
184
  };
175
185
  await hooks.callHook("evlog:emit:keep", tailCtx);
186
+ const runner = getGlobalPluginRunner();
187
+ if (runner.hasKeep) await runner.runKeep(tailCtx);
176
188
  ctx._evlogEmitted = true;
177
189
  await callEnrichAndDrain(hooks, log.emit({ _forceKeep: tailCtx.shouldKeep }), e);
178
190
  });
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.mjs","names":[],"sources":["../../../src/nitro-v3/plugin.ts"],"sourcesContent":["import { definePlugin } from 'nitro'\nimport type { CaptureError } from 'nitro/types'\nimport type { HTTPEvent } from 'nitro/h3'\nimport { parseURL } from 'ufo'\nimport { createRequestLogger, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport { normalizeRedactConfig } from '../redact'\nimport { resolveEvlogConfigForNitroPlugin } from '../shared/nitroConfigBridge'\nimport type { EnrichContext, RequestLogger, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\n// Nitro v3 doesn't fully export hook types yet\n// https://github.com/nitrojs/nitro/blob/8882bc9e1dbf2d342e73097f22a2156f70f50575/src/types/runtime/nitro.ts#L48-L53\ninterface NitroV3Hooks {\n close: () => void\n error: CaptureError\n request: (event: HTTPEvent) => void | Promise<void>\n response: (res: Response, event: HTTPEvent) => void | Promise<void>\n 'evlog:emit:keep': (ctx: TailSamplingContext) => void | Promise<void>\n 'evlog:enrich': (ctx: EnrichContext) => void | Promise<void>\n 'evlog:drain': (ctx: { event: WideEvent; request?: { method?: string; path: string; requestId?: string }; headers?: Record<string, string> }) => void | Promise<void>\n}\n\ntype Hooks = {\n hook: <T extends keyof NitroV3Hooks>(name: T, listener: NitroV3Hooks[T]) => void\n callHook: <T extends keyof NitroV3Hooks>(name: T, ...args: Parameters<NitroV3Hooks[T]>) => Promise<void>\n}\n\nfunction getContext(event: HTTPEvent): Record<string, unknown> {\n if (!event.req.context) {\n event.req.context = {}\n }\n return event.req.context\n}\n\nfunction getSafeRequestHeaders(event: HTTPEvent): Record<string, string> {\n const headers: Record<string, string> = {}\n event.req.headers.forEach((value, key) => {\n headers[key] = value\n })\n return filterSafeHeaders(headers)\n}\n\nfunction getSafeResponseHeaders(res: Response): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n res.headers.forEach((value, key) => {\n headers[key] = value\n })\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction buildHookContext(\n event: HTTPEvent,\n res?: Response,\n): Omit<EnrichContext, 'event'> {\n const { pathname } = parseURL(event.req.url)\n const responseHeaders = res ? getSafeResponseHeaders(res) : undefined\n return {\n request: { method: event.req.method, path: pathname },\n headers: getSafeRequestHeaders(event),\n response: {\n status: res?.status ?? 200,\n headers: responseHeaders,\n },\n }\n}\n\nasync function callDrainHook(\n hooks: Hooks,\n emittedEvent: WideEvent | null,\n event: HTTPEvent,\n hookContext: Omit<EnrichContext, 'event'>,\n): Promise<void> {\n if (!emittedEvent) return\n\n let drainPromise: Promise<unknown> | undefined\n try {\n const result = hooks.callHook('evlog:drain', {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n })\n drainPromise = result?.catch?.((err: unknown) => {\n console.error('[evlog] drain failed:', err)\n })\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n\n if (!drainPromise) return\n\n // Use waitUntil if available (srvx native — Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n if (typeof event.req.waitUntil === 'function') {\n event.req.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from the\n // response hook (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nasync function callEnrichAndDrain(\n hooks: Hooks,\n emittedEvent: WideEvent | null,\n event: HTTPEvent,\n res?: Response,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event, res)\n\n try {\n await hooks.callHook('evlog:enrich', { event: emittedEvent, ...hookContext })\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n await callDrainHook(hooks, emittedEvent, event, hookContext)\n}\n\n/**\n * Nitro v3 plugin entry point.\n *\n * Usage in Nitro v3:\n * ```ts\n * // plugins/evlog.ts\n * export { default } from 'evlog/nitro/v3'\n * ```\n */\nexport default definePlugin(async (nitroApp) => {\n const evlogConfig = await resolveEvlogConfigForNitroPlugin()\n\n const redact = normalizeRedactConfig(evlogConfig?.redact as boolean | Record<string, unknown> | undefined)\n\n initLogger({\n enabled: evlogConfig?.enabled,\n env: evlogConfig?.env,\n pretty: evlogConfig?.pretty,\n silent: evlogConfig?.silent,\n sampling: evlogConfig?.sampling,\n minLevel: evlogConfig?.minLevel,\n redact,\n _suppressDrainWarning: true,\n })\n\n const hooks = nitroApp.hooks as unknown as Hooks\n\n // When globally disabled, createRequestLogger returns a no-op logger — still\n // attach it so handlers can call useLogger without throwing.\n if (!isEnabled()) {\n hooks.hook('request', (event) => {\n const { pathname } = parseURL(event.req.url)\n const ctx = getContext(event)\n let requestIdOverride: string | undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = event.req.headers.get('cf-ray')\n if (cfRay) requestIdOverride = cfRay\n }\n ctx.log = createRequestLogger({\n method: event.req.method,\n path: pathname,\n requestId: requestIdOverride || ctx.requestId as string | undefined || crypto.randomUUID(),\n }, { _deferDrain: true })\n })\n return\n }\n\n hooks.hook('request', (event) => {\n const { pathname } = parseURL(event.req.url)\n const ctx = getContext(event)\n\n // Evaluate route filtering but always create the logger so that server\n // middleware (which runs for every request) can call useLogger(event)\n // without throwing. Filtering is enforced at emit time instead.\n ctx._evlogShouldEmit = shouldLog(pathname, evlogConfig?.include, evlogConfig?.exclude)\n\n // Store start time for duration calculation in tail sampling\n ctx._evlogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = event.req.headers.get('cf-ray')\n if (cfRay) requestIdOverride = cfRay\n }\n\n const log = createRequestLogger({\n method: event.req.method,\n path: pathname,\n requestId: requestIdOverride || ctx.requestId as string | undefined || crypto.randomUUID(),\n }, { _deferDrain: true })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(pathname, evlogConfig?.routes)\n if (routeService) {\n log.set({ service: routeService })\n }\n\n ctx.log = log\n })\n\n hooks.hook('response', async (res, event) => {\n const ctx = event.req.context\n // Skip if already emitted by error hook or route was filtered out\n if (ctx?._evlogEmitted || !ctx?._evlogShouldEmit) return\n\n const log = ctx?.log as RequestLogger | undefined\n if (!log || !ctx) return\n\n const { status } = res\n log.set({ status })\n\n const startTime = ctx._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const { pathname } = parseURL(event.req.url)\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: pathname,\n method: event.req.method,\n context: log.getContext(),\n shouldKeep: false,\n }\n\n await hooks.callHook('evlog:emit:keep', tailCtx)\n\n const emittedEvent = log.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(hooks, emittedEvent, event, res)\n })\n\n hooks.hook('error', async (error, { event }) => {\n if (!event) return\n const e = event as HTTPEvent\n\n const ctx = e.req.context\n if (!ctx?._evlogShouldEmit) return\n const log = ctx.log as RequestLogger | undefined\n if (!log) return\n\n // Check if error.cause is an EvlogError (thrown errors get wrapped in HTTPError by nitro)\n const actualError = (error.cause as Error)?.name === 'EvlogError' \n ? error.cause as Error \n : error as Error\n\n log.error(actualError)\n\n const errorStatus = extractErrorStatus(actualError)\n log.set({ status: errorStatus })\n\n const { pathname } = parseURL(e.req.url)\n const startTime = ctx._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: pathname,\n method: e.req.method,\n context: log.getContext(),\n shouldKeep: false,\n }\n\n await hooks.callHook('evlog:emit:keep', tailCtx)\n\n ctx._evlogEmitted = true\n\n const emittedEvent = log.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(hooks, emittedEvent, e)\n })\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../../../src/nitro-v3/plugin.ts"],"sourcesContent":["import { definePlugin } from 'nitro'\nimport type { CaptureError } from 'nitro/types'\nimport type { HTTPEvent } from 'nitro/h3'\nimport { parseURL } from 'ufo'\nimport { createRequestLogger, getGlobalPluginRunner, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport { normalizeRedactConfig } from '../redact'\nimport { resolveEvlogConfigForNitroPlugin } from '../shared/nitroConfigBridge'\nimport type { EnrichContext, RequestLogger, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\n// Nitro v3 doesn't fully export hook types yet\n// https://github.com/nitrojs/nitro/blob/8882bc9e1dbf2d342e73097f22a2156f70f50575/src/types/runtime/nitro.ts#L48-L53\ninterface NitroV3Hooks {\n close: () => void\n error: CaptureError\n request: (event: HTTPEvent) => void | Promise<void>\n response: (res: Response, event: HTTPEvent) => void | Promise<void>\n 'evlog:emit:keep': (ctx: TailSamplingContext) => void | Promise<void>\n 'evlog:enrich': (ctx: EnrichContext) => void | Promise<void>\n 'evlog:drain': (ctx: { event: WideEvent; request?: { method?: string; path: string; requestId?: string }; headers?: Record<string, string> }) => void | Promise<void>\n}\n\ntype Hooks = {\n hook: <T extends keyof NitroV3Hooks>(name: T, listener: NitroV3Hooks[T]) => void\n callHook: <T extends keyof NitroV3Hooks>(name: T, ...args: Parameters<NitroV3Hooks[T]>) => Promise<void>\n}\n\nfunction getContext(event: HTTPEvent): Record<string, unknown> {\n if (!event.req.context) {\n event.req.context = {}\n }\n return event.req.context\n}\n\nfunction getSafeRequestHeaders(event: HTTPEvent): Record<string, string> {\n const headers: Record<string, string> = {}\n event.req.headers.forEach((value, key) => {\n headers[key] = value\n })\n return filterSafeHeaders(headers)\n}\n\nfunction getSafeResponseHeaders(res: Response): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n res.headers.forEach((value, key) => {\n headers[key] = value\n })\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction buildHookContext(\n event: HTTPEvent,\n res?: Response,\n): Omit<EnrichContext, 'event'> {\n const { pathname } = parseURL(event.req.url)\n const responseHeaders = res ? getSafeResponseHeaders(res) : undefined\n return {\n request: { method: event.req.method, path: pathname },\n headers: getSafeRequestHeaders(event),\n response: {\n status: res?.status ?? 200,\n headers: responseHeaders,\n },\n }\n}\n\nasync function callDrainHook(\n hooks: Hooks,\n emittedEvent: WideEvent | null,\n event: HTTPEvent,\n hookContext: Omit<EnrichContext, 'event'>,\n): Promise<void> {\n if (!emittedEvent) return\n\n const drainCtx = {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n }\n\n const drainTasks: Array<Promise<unknown>> = []\n try {\n const result = hooks.callHook('evlog:drain', drainCtx)\n if (result?.catch) {\n drainTasks.push(\n result.catch((err: unknown) => {\n console.error('[evlog] drain failed:', err)\n }),\n )\n }\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n\n const runner = getGlobalPluginRunner()\n if (runner.hasDrain) {\n drainTasks.push(runner.runDrain(drainCtx))\n }\n\n if (drainTasks.length === 0) return\n const drainPromise = Promise.all(drainTasks)\n\n // Use waitUntil if available (srvx native — Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n if (typeof event.req.waitUntil === 'function') {\n event.req.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from the\n // response hook (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nasync function callEnrichAndDrain(\n hooks: Hooks,\n emittedEvent: WideEvent | null,\n event: HTTPEvent,\n res?: Response,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event, res)\n const enrichCtx: EnrichContext = { event: emittedEvent, ...hookContext }\n\n try {\n await hooks.callHook('evlog:enrich', enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n const runner = getGlobalPluginRunner()\n if (runner.hasEnrich) {\n await runner.runEnrich(enrichCtx)\n }\n\n await callDrainHook(hooks, emittedEvent, event, hookContext)\n}\n\n/**\n * Nitro v3 plugin entry point.\n *\n * Usage in Nitro v3:\n * ```ts\n * // plugins/evlog.ts\n * export { default } from 'evlog/nitro/v3'\n * ```\n */\nexport default definePlugin(async (nitroApp) => {\n const evlogConfig = await resolveEvlogConfigForNitroPlugin()\n\n const redact = normalizeRedactConfig(evlogConfig?.redact as boolean | Record<string, unknown> | undefined)\n\n initLogger({\n enabled: evlogConfig?.enabled,\n env: evlogConfig?.env,\n pretty: evlogConfig?.pretty,\n silent: evlogConfig?.silent,\n sampling: evlogConfig?.sampling,\n minLevel: evlogConfig?.minLevel,\n redact,\n _suppressDrainWarning: true,\n })\n\n const hooks = nitroApp.hooks as unknown as Hooks\n\n // When globally disabled, createRequestLogger returns a no-op logger — still\n // attach it so handlers can call useLogger without throwing.\n if (!isEnabled()) {\n hooks.hook('request', (event) => {\n const { pathname } = parseURL(event.req.url)\n const ctx = getContext(event)\n let requestIdOverride: string | undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = event.req.headers.get('cf-ray')\n if (cfRay) requestIdOverride = cfRay\n }\n ctx.log = createRequestLogger({\n method: event.req.method,\n path: pathname,\n requestId: requestIdOverride || ctx.requestId as string | undefined || crypto.randomUUID(),\n }, { _deferDrain: true })\n })\n return\n }\n\n hooks.hook('request', (event) => {\n const { pathname } = parseURL(event.req.url)\n const ctx = getContext(event)\n\n // Evaluate route filtering but always create the logger so that server\n // middleware (which runs for every request) can call useLogger(event)\n // without throwing. Filtering is enforced at emit time instead.\n ctx._evlogShouldEmit = shouldLog(pathname, evlogConfig?.include, evlogConfig?.exclude)\n\n // Store start time for duration calculation in tail sampling\n ctx._evlogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = event.req.headers.get('cf-ray')\n if (cfRay) requestIdOverride = cfRay\n }\n\n const log = createRequestLogger({\n method: event.req.method,\n path: pathname,\n requestId: requestIdOverride || ctx.requestId as string | undefined || crypto.randomUUID(),\n }, { _deferDrain: true })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(pathname, evlogConfig?.routes)\n if (routeService) {\n log.set({ service: routeService })\n }\n\n ctx.log = log\n })\n\n hooks.hook('response', async (res, event) => {\n const ctx = event.req.context\n // Skip if already emitted by error hook or route was filtered out\n if (ctx?._evlogEmitted || !ctx?._evlogShouldEmit) return\n\n const log = ctx?.log as RequestLogger | undefined\n if (!log || !ctx) return\n\n const { status } = res\n log.set({ status })\n\n const startTime = ctx._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const { pathname } = parseURL(event.req.url)\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: pathname,\n method: event.req.method,\n context: log.getContext(),\n shouldKeep: false,\n }\n\n await hooks.callHook('evlog:emit:keep', tailCtx)\n const runner = getGlobalPluginRunner()\n if (runner.hasKeep) await runner.runKeep(tailCtx)\n\n const emittedEvent = log.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(hooks, emittedEvent, event, res)\n })\n\n hooks.hook('error', async (error, { event }) => {\n if (!event) return\n const e = event as HTTPEvent\n\n const ctx = e.req.context\n if (!ctx?._evlogShouldEmit) return\n const log = ctx.log as RequestLogger | undefined\n if (!log) return\n\n // Check if error.cause is an EvlogError (thrown errors get wrapped in HTTPError by nitro)\n const actualError = (error.cause as Error)?.name === 'EvlogError' \n ? error.cause as Error \n : error as Error\n\n log.error(actualError)\n\n const errorStatus = extractErrorStatus(actualError)\n log.set({ status: errorStatus })\n\n const { pathname } = parseURL(e.req.url)\n const startTime = ctx._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: pathname,\n method: e.req.method,\n context: log.getContext(),\n shouldKeep: false,\n }\n\n await hooks.callHook('evlog:emit:keep', tailCtx)\n const runner = getGlobalPluginRunner()\n if (runner.hasKeep) await runner.runKeep(tailCtx)\n\n ctx._evlogEmitted = true\n\n const emittedEvent = log.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(hooks, emittedEvent, e)\n })\n})\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Y as RequestLogger } from "../../audit-CTIviX3P.mjs";
1
+ import { Y as RequestLogger } from "../../audit-X1uUukm3.mjs";
2
2
  import { HTTPEvent } from "nitro/h3";
3
3
 
4
4
  //#region src/nitro-v3/useLogger.d.ts
@@ -1,4 +1,4 @@
1
- import { L as EnvironmentContext, Q as SamplingConfig, W as LogLevel, Z as RouteConfig, q as RedactConfig } from "./audit-CTIviX3P.mjs";
1
+ import { L as EnvironmentContext, Q as SamplingConfig, W as LogLevel, Z as RouteConfig, q as RedactConfig } from "./audit-X1uUukm3.mjs";
2
2
  //#region src/nitro.d.ts
3
3
  interface NitroModuleOptions {
4
4
  /**
@@ -57,4 +57,4 @@ interface NitroModuleOptions {
57
57
  }
58
58
  //#endregion
59
59
  export { NitroModuleOptions as t };
60
- //# sourceMappingURL=nitro-CPPRCPbG.d.mts.map
60
+ //# sourceMappingURL=nitro-C6Bd682U.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nitro-CPPRCPbG.d.mts","names":[],"sources":["../src/nitro.ts"],"mappings":";;UAKiB,kBAAA;;AAAjB;;;EAKE,OAAA;EAKM;;;EAAN,GAAA,GAAM,OAAA,CAAQ,kBAAA;EA8CH;;;;EAxCX,MAAA;EANA;;;;;;;EAeA,MAAA;EAmBS;;;;;EAZT,OAAA;EA8BA;;;;;EAvBA,OAAA;;;;EAKA,MAAA,GAAS,MAAA,SAAe,WAAA;;;;EAKxB,QAAA,GAAW,cAAA;;;;;;EAOX,QAAA,GAAW,QAAA;;;;;EAMX,MAAA,aAAmB,YAAA;AAAA"}
1
+ {"version":3,"file":"nitro-C6Bd682U.d.mts","names":[],"sources":["../src/nitro.ts"],"mappings":";;UAKiB,kBAAA;;AAAjB;;;EAKE,OAAA;EAKM;;;EAAN,GAAA,GAAM,OAAA,CAAQ,kBAAA;EA8CH;;;;EAxCX,MAAA;EANA;;;;;;;EAeA,MAAA;EAmBS;;;;;EAZT,OAAA;EA8BA;;;;;EAvBA,OAAA;;;;EAKA,MAAA,GAAS,MAAA,SAAe,WAAA;;;;EAKxB,QAAA,GAAW,cAAA;;;;;;EAOX,QAAA,GAAW,QAAA;;;;;EAMX,MAAA,aAAmB,YAAA;AAAA"}
@@ -1,4 +1,4 @@
1
- import { t as extractErrorStatus } from "./errors-BJRXUfMg.mjs";
1
+ import { t as extractErrorStatus } from "./errors-BQgyQ9xe.mjs";
2
2
  //#region src/nitro.ts
3
3
  /**
4
4
  * Resolve an EvlogError from an error or its cause chain.
@@ -31,4 +31,4 @@ function serializeEvlogErrorResponse(error, url) {
31
31
  //#endregion
32
32
  export { serializeEvlogErrorResponse as n, resolveEvlogError as t };
33
33
 
34
- //# sourceMappingURL=nitro-OmT_M4Pb.mjs.map
34
+ //# sourceMappingURL=nitro-DavLelNz.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nitro-DavLelNz.mjs","names":[],"sources":["../src/nitro.ts"],"sourcesContent":["import type { EnvironmentContext, LogLevel, RedactConfig, RouteConfig, SamplingConfig } from './types'\nimport { extractErrorStatus } from './shared/errors'\n\nexport { shouldLog, getServiceForPath } from './shared/routes'\n\nexport interface NitroModuleOptions {\n /**\n * Enable or disable all logging globally.\n * @default true\n */\n enabled?: boolean\n\n /**\n * Environment context overrides.\n */\n env?: Partial<EnvironmentContext>\n\n /**\n * Enable pretty printing.\n * @default true in development, false in production\n */\n pretty?: boolean\n\n /**\n * Suppress built-in console output.\n * When true, events are still built, sampled, and passed to drains,\n * but nothing is written to console. Use when drains own the output\n * channel (e.g., stdout-based platforms like GCP Cloud Run, AWS Lambda).\n * @default false\n */\n silent?: boolean\n\n /**\n * Route patterns to include in logging.\n * Supports glob patterns like '/api/**'.\n * If not set, all routes are logged.\n */\n include?: string[]\n\n /**\n * Route patterns to exclude from logging.\n * Supports glob patterns like '/_nitro/**'.\n * Exclusions take precedence over inclusions.\n */\n exclude?: string[]\n\n /**\n * Route-specific service configuration.\n */\n routes?: Record<string, RouteConfig>\n\n /**\n * Sampling configuration for filtering logs.\n */\n sampling?: SamplingConfig\n\n /**\n * Minimum severity for the global `log` API (not request wide events).\n * Order: debug < info < warn < error.\n * @default 'debug'\n */\n minLevel?: LogLevel\n\n /**\n * Auto-redaction configuration for PII protection.\n * `true` enables all built-in PII patterns. Pass an object for fine-grained control.\n */\n redact?: boolean | RedactConfig\n}\n\n/**\n * JSON-friendly subset of evlog Nitro plugin options consumed by the Nitro/Nuxt\n * runtime (read from `runtimeConfig.evlog` or the `__EVLOG_CONFIG` env bridge).\n *\n * @internal Internal Nitro contract — do not use from application code. Use\n * {@link import('./shared/define').EvlogConfig} for the canonical user-facing\n * config shape.\n */\nexport interface NitroPluginEvlogConfig {\n enabled?: boolean\n env?: Record<string, unknown>\n pretty?: boolean\n silent?: boolean\n include?: string[]\n exclude?: string[]\n routes?: Record<string, RouteConfig>\n sampling?: SamplingConfig\n minLevel?: LogLevel\n redact?: boolean | RedactConfig | Record<string, unknown>\n}\n\n/** @deprecated Renamed to {@link NitroPluginEvlogConfig}. Kept for backward compat. */\nexport type EvlogConfig = NitroPluginEvlogConfig\n\n/**\n * Resolve an EvlogError from an error or its cause chain.\n * Both Nitro v2 (h3) and v3 wrap thrown errors — this unwraps them.\n */\nexport function resolveEvlogError(error: Error): Error | null {\n if (error.name === 'EvlogError') return error\n if ((error.cause as Error)?.name === 'EvlogError') return error.cause as Error\n return null\n}\n\nexport { extractErrorStatus } from './shared/errors'\n\n/**\n * Build a standard evlog error JSON response body.\n * Used by both v2 and v3 error handlers to ensure consistent shape.\n */\nexport function serializeEvlogErrorResponse(error: Error, url: string): Record<string, unknown> {\n const status = extractErrorStatus(error)\n const { data } = error as { data?: unknown }\n const statusMessage = (error as { statusMessage?: string }).statusMessage || error.message\n return {\n url,\n status,\n statusCode: status,\n statusText: statusMessage,\n statusMessage,\n message: error.message,\n error: true,\n ...(data !== undefined && { data }),\n }\n}\n\n"],"mappings":";;;;;;AAkGA,SAAgB,kBAAkB,OAA4B;AAC5D,KAAI,MAAM,SAAS,aAAc,QAAO;AACxC,KAAK,MAAM,OAAiB,SAAS,aAAc,QAAO,MAAM;AAChE,QAAO;;;;;;AAST,SAAgB,4BAA4B,OAAc,KAAsC;CAC9F,MAAM,SAAS,mBAAmB,MAAM;CACxC,MAAM,EAAE,SAAS;CACjB,MAAM,gBAAiB,MAAqC,iBAAiB,MAAM;AACnF,QAAO;EACL;EACA;EACA,YAAY;EACZ,YAAY;EACZ;EACA,SAAS,MAAM;EACf,OAAO;EACP,GAAI,SAAS,KAAA,KAAa,EAAE,MAAM;EACnC"}
@@ -89,4 +89,4 @@ async function getNitroRuntimeConfigRecord() {
89
89
  //#endregion
90
90
  export { resolveEvlogConfigForNitroPlugin as n, getNitroRuntimeConfigRecord as t };
91
91
 
92
- //# sourceMappingURL=nitroConfigBridge-C37lXaNm.mjs.map
92
+ //# sourceMappingURL=nitroConfigBridge-aZ1e5upQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nitroConfigBridge-aZ1e5upQ.mjs","names":[],"sources":["../src/shared/nitroConfigBridge.ts"],"sourcesContent":["/**\n * How evlog reads Nitro runtime config from **published** ESM.\n *\n * **Why not** `import('nitro/runtime-config')` as a string literal in source?\n * Those subpaths are virtual or specially resolved. App Rollup can resolve them\n * for first-party code; for dependency chunks (`node_modules/evlog/dist/...`),\n * strict presets (e.g. `cloudflare-durable`) may fail with “externals are not\n * allowed”. A literal dynamic import is enough for Rollup to pre-resolve.\n *\n * **Strategy**\n *\n * 1. `process.env.__EVLOG_CONFIG` — JSON set by evlog Nitro modules (no virtual\n * modules; preferred in production Workers builds).\n * 2. Computed module IDs — `['a','b'].join('/')` passed to `import()` so emitted\n * JS does not contain a static `import(\"a/b\")`.\n * 3. Plugin resolution tries Nitro v3 first, then nitropack internal config (v2).\n * 4. Adapter resolution keeps historical order: nitropack runtime barrel, then v3.\n *\n * Not exported from `evlog/toolkit` — package-internal only.\n */\n\nimport type { NitroPluginEvlogConfig } from '../nitro'\n\ntype EvlogConfig = NitroPluginEvlogConfig\n\nconst EVLOG_NITRO_ENV = '__EVLOG_CONFIG' as const\n\ntype NitroRuntimeConfigModule = {\n useRuntimeConfig: () => Record<string, any>\n}\n\nfunction nitroV3RuntimeConfigSpecifier(): string {\n return ['nitro', 'runtime-config'].join('/')\n}\n\nfunction nitropackRuntimeSpecifier(): string {\n return ['nitropack', 'runtime'].join('/')\n}\n\nfunction nitropackInternalRuntimeConfigSpecifier(): string {\n return ['nitropack', 'runtime', 'internal', 'config'].join('/')\n}\n\nasync function importOrNull(specifier: string): Promise<unknown> {\n try {\n return await import(specifier)\n } catch {\n return null\n }\n}\n\nfunction isRuntimeConfigModule(mod: unknown): mod is NitroRuntimeConfigModule {\n return (\n typeof mod === 'object'\n && mod !== null\n && 'useRuntimeConfig' in mod\n && typeof (mod as NitroRuntimeConfigModule).useRuntimeConfig === 'function'\n )\n}\n\n/** Snapshot from env, or `undefined` if unset / invalid JSON. */\nexport function readEvlogConfigFromNitroEnv(): EvlogConfig | undefined {\n const raw = process.env[EVLOG_NITRO_ENV]\n if (raw === undefined || raw === '') return undefined\n try {\n return JSON.parse(raw) as EvlogConfig\n } catch {\n return undefined\n }\n}\n\nlet cachedNitropackRuntime: NitroRuntimeConfigModule | null | undefined\nlet cachedNitroV3Runtime: NitroRuntimeConfigModule | null | undefined\nlet cachedNitropackInternalConfig: NitroRuntimeConfigModule | null | undefined\n\nasync function getNitropackRuntime(): Promise<NitroRuntimeConfigModule | null> {\n if (cachedNitropackRuntime !== undefined) return cachedNitropackRuntime\n const mod = await importOrNull(nitropackRuntimeSpecifier())\n cachedNitropackRuntime = isRuntimeConfigModule(mod) ? mod : null\n return cachedNitropackRuntime\n}\n\nasync function getNitroV3Runtime(): Promise<NitroRuntimeConfigModule | null> {\n if (cachedNitroV3Runtime !== undefined) return cachedNitroV3Runtime\n const mod = await importOrNull(nitroV3RuntimeConfigSpecifier())\n cachedNitroV3Runtime = isRuntimeConfigModule(mod) ? mod : null\n return cachedNitroV3Runtime\n}\n\nasync function getNitropackInternalRuntimeConfig(): Promise<NitroRuntimeConfigModule | null> {\n if (cachedNitropackInternalConfig !== undefined) return cachedNitropackInternalConfig\n const mod = await importOrNull(nitropackInternalRuntimeConfigSpecifier())\n cachedNitropackInternalConfig = isRuntimeConfigModule(mod) ? mod : null\n return cachedNitropackInternalConfig\n}\n\nfunction evlogSlice(config: Record<string, any>): EvlogConfig | undefined {\n const { evlog } = config\n if (evlog && typeof evlog === 'object') return evlog as EvlogConfig\n return undefined\n}\n\n/**\n * Options for evlog Nitro plugins (nitropack v2 and Nitro v3).\n * Env bridge first; then Nitro v3 `runtime-config`; then nitropack internal config.\n */\nexport async function resolveEvlogConfigForNitroPlugin(): Promise<EvlogConfig | undefined> {\n const fromEnv = readEvlogConfigFromNitroEnv()\n if (fromEnv !== undefined) return fromEnv\n\n const v3 = await getNitroV3Runtime()\n if (v3) {\n const slice = evlogSlice(v3.useRuntimeConfig())\n if (slice !== undefined) return slice\n }\n\n const internal = await getNitropackInternalRuntimeConfig()\n if (internal) {\n const slice = evlogSlice(internal.useRuntimeConfig())\n if (slice !== undefined) return slice\n }\n\n return undefined\n}\n\n/**\n * Full `useRuntimeConfig()` object for drain adapters (nitropack first, then v3).\n */\nexport async function getNitroRuntimeConfigRecord(): Promise<Record<string, any> | undefined> {\n const nitropack = await getNitropackRuntime()\n if (nitropack) return nitropack.useRuntimeConfig()\n\n const v3 = await getNitroV3Runtime()\n if (v3) return v3.useRuntimeConfig()\n\n return undefined\n}\n"],"mappings":";AAyBA,MAAM,kBAAkB;AAMxB,SAAS,gCAAwC;AAC/C,QAAO,CAAC,SAAS,iBAAiB,CAAC,KAAK,IAAI;;AAG9C,SAAS,4BAAoC;AAC3C,QAAO,CAAC,aAAa,UAAU,CAAC,KAAK,IAAI;;AAG3C,SAAS,0CAAkD;AACzD,QAAO;EAAC;EAAa;EAAW;EAAY;EAAS,CAAC,KAAK,IAAI;;AAGjE,eAAe,aAAa,WAAqC;AAC/D,KAAI;AACF,SAAO,MAAM,OAAO;SACd;AACN,SAAO;;;AAIX,SAAS,sBAAsB,KAA+C;AAC5E,QACE,OAAO,QAAQ,YACZ,QAAQ,QACR,sBAAsB,OACtB,OAAQ,IAAiC,qBAAqB;;;AAKrE,SAAgB,8BAAuD;CACrE,MAAM,MAAM,QAAQ,IAAI;AACxB,KAAI,QAAQ,KAAA,KAAa,QAAQ,GAAI,QAAO,KAAA;AAC5C,KAAI;AACF,SAAO,KAAK,MAAM,IAAI;SAChB;AACN;;;AAIJ,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,eAAe,sBAAgE;AAC7E,KAAI,2BAA2B,KAAA,EAAW,QAAO;CACjD,MAAM,MAAM,MAAM,aAAa,2BAA2B,CAAC;AAC3D,0BAAyB,sBAAsB,IAAI,GAAG,MAAM;AAC5D,QAAO;;AAGT,eAAe,oBAA8D;AAC3E,KAAI,yBAAyB,KAAA,EAAW,QAAO;CAC/C,MAAM,MAAM,MAAM,aAAa,+BAA+B,CAAC;AAC/D,wBAAuB,sBAAsB,IAAI,GAAG,MAAM;AAC1D,QAAO;;AAGT,eAAe,oCAA8E;AAC3F,KAAI,kCAAkC,KAAA,EAAW,QAAO;CACxD,MAAM,MAAM,MAAM,aAAa,yCAAyC,CAAC;AACzE,iCAAgC,sBAAsB,IAAI,GAAG,MAAM;AACnE,QAAO;;AAGT,SAAS,WAAW,QAAsD;CACxE,MAAM,EAAE,UAAU;AAClB,KAAI,SAAS,OAAO,UAAU,SAAU,QAAO;;;;;;AAQjD,eAAsB,mCAAqE;CACzF,MAAM,UAAU,6BAA6B;AAC7C,KAAI,YAAY,KAAA,EAAW,QAAO;CAElC,MAAM,KAAK,MAAM,mBAAmB;AACpC,KAAI,IAAI;EACN,MAAM,QAAQ,WAAW,GAAG,kBAAkB,CAAC;AAC/C,MAAI,UAAU,KAAA,EAAW,QAAO;;CAGlC,MAAM,WAAW,MAAM,mCAAmC;AAC1D,KAAI,UAAU;EACZ,MAAM,QAAQ,WAAW,SAAS,kBAAkB,CAAC;AACrD,MAAI,UAAU,KAAA,EAAW,QAAO;;;;;;AASpC,eAAsB,8BAAwE;CAC5F,MAAM,YAAY,MAAM,qBAAqB;AAC7C,KAAI,UAAW,QAAO,UAAU,kBAAkB;CAElD,MAAM,KAAK,MAAM,mBAAmB;AACpC,KAAI,GAAI,QAAO,GAAG,kBAAkB"}
@@ -1,4 +1,4 @@
1
- import { L as EnvironmentContext, Q as SamplingConfig, W as LogLevel, Z as RouteConfig, q as RedactConfig, rt as TransportConfig } from "../audit-CTIviX3P.mjs";
1
+ import { L as EnvironmentContext, Q as SamplingConfig, W as LogLevel, Z as RouteConfig, q as RedactConfig, rt as TransportConfig } from "../audit-X1uUukm3.mjs";
2
2
  import * as _$_nuxt_schema0 from "@nuxt/schema";
3
3
 
4
4
  //#region src/nuxt/module.d.ts
@@ -1,4 +1,4 @@
1
- import { n as createStripPlugin, t as createSourceLocationPlugin } from "../source-location-DRvDDqfq.mjs";
1
+ import { n as createStripPlugin, t as createSourceLocationPlugin } from "../source-location-Dco0cRTz.mjs";
2
2
  import { addImports, addPlugin, addServerHandler, addServerImports, addServerPlugin, addVitePlugin, createResolver, defineNuxtModule } from "@nuxt/kit";
3
3
  //#region package.json
4
4
  var name = "evlog";
@@ -7,7 +7,7 @@ var name = "evlog";
7
7
  var module_default = defineNuxtModule({
8
8
  meta: {
9
9
  name,
10
- version: "2.14.1",
10
+ version: "2.16.0",
11
11
  configKey: name,
12
12
  docs: "https://evlog.dev"
13
13
  },