evlog 2.14.0 → 2.14.1

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 (129) hide show
  1. package/README.md +45 -15
  2. package/dist/{_http-CHSsrWDJ.mjs → _http-BY1e9pwC.mjs} +9 -2
  3. package/dist/_http-BY1e9pwC.mjs.map +1 -0
  4. package/dist/adapters/axiom.d.mts +1 -1
  5. package/dist/adapters/axiom.mjs +1 -1
  6. package/dist/adapters/axiom.mjs.map +1 -1
  7. package/dist/adapters/better-stack.d.mts +1 -1
  8. package/dist/adapters/better-stack.mjs +1 -1
  9. package/dist/adapters/better-stack.mjs.map +1 -1
  10. package/dist/adapters/datadog.d.mts +1 -1
  11. package/dist/adapters/datadog.mjs +1 -1
  12. package/dist/adapters/datadog.mjs.map +1 -1
  13. package/dist/adapters/fs.d.mts +1 -1
  14. package/dist/adapters/fs.mjs.map +1 -1
  15. package/dist/adapters/hyperdx.d.mts +1 -1
  16. package/dist/adapters/hyperdx.mjs +1 -1
  17. package/dist/adapters/otlp.d.mts +1 -1
  18. package/dist/adapters/otlp.mjs +1 -1
  19. package/dist/adapters/otlp.mjs.map +1 -1
  20. package/dist/adapters/posthog.d.mts +1 -1
  21. package/dist/adapters/posthog.mjs +1 -1
  22. package/dist/adapters/posthog.mjs.map +1 -1
  23. package/dist/adapters/sentry.d.mts +1 -1
  24. package/dist/adapters/sentry.mjs +1 -1
  25. package/dist/adapters/sentry.mjs.map +1 -1
  26. package/dist/ai/index.d.mts +1 -1
  27. package/dist/{audit-mUutdf6A.d.mts → audit-CTIviX3P.d.mts} +11 -1
  28. package/dist/audit-CTIviX3P.d.mts.map +1 -0
  29. package/dist/{audit-d9esRZOK.mjs → audit-DQoBo7Dl.mjs} +56 -13
  30. package/dist/audit-DQoBo7Dl.mjs.map +1 -0
  31. package/dist/better-auth/index.d.mts +1 -1
  32. package/dist/better-auth/index.mjs.map +1 -1
  33. package/dist/browser.d.mts +1 -1
  34. package/dist/elysia/index.d.mts +2 -2
  35. package/dist/elysia/index.mjs +2 -2
  36. package/dist/enrichers.d.mts +1 -1
  37. package/dist/enrichers.mjs.map +1 -1
  38. package/dist/{error-D1FZI2Kd.d.mts → error-C7gSQVqk.d.mts} +2 -2
  39. package/dist/{error-D1FZI2Kd.d.mts.map → error-C7gSQVqk.d.mts.map} +1 -1
  40. package/dist/error.d.mts +1 -1
  41. package/dist/{errors-NIXCyk6I.d.mts → errors-4MPmTzjY.d.mts} +2 -2
  42. package/dist/{errors-NIXCyk6I.d.mts.map → errors-4MPmTzjY.d.mts.map} +1 -1
  43. package/dist/express/index.d.mts +2 -2
  44. package/dist/express/index.mjs +2 -2
  45. package/dist/fastify/index.d.mts +2 -2
  46. package/dist/fastify/index.mjs +2 -2
  47. package/dist/{fork-CTJXnpl8.mjs → fork-D1j1Fuzy.mjs} +3 -3
  48. package/dist/{fork-CTJXnpl8.mjs.map → fork-D1j1Fuzy.mjs.map} +1 -1
  49. package/dist/hono/index.d.mts +2 -2
  50. package/dist/hono/index.mjs +1 -1
  51. package/dist/http.d.mts +1 -1
  52. package/dist/http.d.mts.map +1 -1
  53. package/dist/http.mjs +3 -2
  54. package/dist/http.mjs.map +1 -1
  55. package/dist/index.d.mts +6 -6
  56. package/dist/index.mjs +1 -1
  57. package/dist/{logger-b3epPH0N.d.mts → logger-DttRJRGa.d.mts} +21 -2
  58. package/dist/logger-DttRJRGa.d.mts.map +1 -0
  59. package/dist/logger.d.mts +1 -1
  60. package/dist/logger.mjs +1 -1
  61. package/dist/{middleware-BYf26Lfu.d.mts → middleware-CTnDsST-.d.mts} +2 -2
  62. package/dist/{middleware-BYf26Lfu.d.mts.map → middleware-CTnDsST-.d.mts.map} +1 -1
  63. package/dist/{middleware-BWOJ7JI0.mjs → middleware-oAccqyPp.mjs} +2 -2
  64. package/dist/{middleware-BWOJ7JI0.mjs.map → middleware-oAccqyPp.mjs.map} +1 -1
  65. package/dist/nestjs/index.d.mts +2 -2
  66. package/dist/nestjs/index.mjs +2 -2
  67. package/dist/next/client.d.mts +1 -1
  68. package/dist/next/index.d.mts +4 -4
  69. package/dist/next/index.mjs +2 -2
  70. package/dist/next/index.mjs.map +1 -1
  71. package/dist/next/instrumentation.d.mts +1 -1
  72. package/dist/next/instrumentation.mjs +1 -1
  73. package/dist/next/instrumentation.mjs.map +1 -1
  74. package/dist/nitro/errorHandler.mjs.map +1 -1
  75. package/dist/nitro/module.d.mts +2 -2
  76. package/dist/nitro/plugin.mjs +1 -1
  77. package/dist/nitro/plugin.mjs.map +1 -1
  78. package/dist/nitro/v3/index.d.mts +2 -2
  79. package/dist/nitro/v3/middleware.mjs.map +1 -1
  80. package/dist/nitro/v3/module.d.mts +1 -1
  81. package/dist/nitro/v3/plugin.mjs +1 -1
  82. package/dist/nitro/v3/plugin.mjs.map +1 -1
  83. package/dist/nitro/v3/useLogger.d.mts +1 -1
  84. package/dist/nitro/v3/useLogger.mjs.map +1 -1
  85. package/dist/{nitro-DenB86W6.d.mts → nitro-CPPRCPbG.d.mts} +2 -2
  86. package/dist/{nitro-DenB86W6.d.mts.map → nitro-CPPRCPbG.d.mts.map} +1 -1
  87. package/dist/nuxt/module.d.mts +1 -1
  88. package/dist/nuxt/module.mjs +1 -1
  89. package/dist/{parseError-BR9pocvY.d.mts → parseError-o1GpZEOR.d.mts} +2 -2
  90. package/dist/parseError-o1GpZEOR.d.mts.map +1 -0
  91. package/dist/pipeline.mjs.map +1 -1
  92. package/dist/react-router/index.d.mts +2 -2
  93. package/dist/react-router/index.mjs +2 -2
  94. package/dist/runtime/client/log.d.mts +1 -1
  95. package/dist/runtime/client/log.mjs +2 -2
  96. package/dist/runtime/client/log.mjs.map +1 -1
  97. package/dist/runtime/client/plugin.mjs.map +1 -1
  98. package/dist/runtime/server/routes/_evlog/ingest.post.mjs +1 -1
  99. package/dist/runtime/server/routes/_evlog/ingest.post.mjs.map +1 -1
  100. package/dist/runtime/server/useLogger.d.mts +1 -1
  101. package/dist/runtime/server/useLogger.mjs.map +1 -1
  102. package/dist/runtime/utils/parseError.d.mts +2 -2
  103. package/dist/source-location-DRvDDqfq.mjs.map +1 -1
  104. package/dist/sveltekit/index.d.mts +2 -2
  105. package/dist/sveltekit/index.mjs +2 -2
  106. package/dist/sveltekit/index.mjs.map +1 -1
  107. package/dist/toolkit.d.mts +3 -3
  108. package/dist/toolkit.mjs +2 -2
  109. package/dist/types.d.mts +1 -1
  110. package/dist/{useLogger-C56tDPwf.d.mts → useLogger-CyPP1sVB.d.mts} +2 -2
  111. package/dist/{useLogger-C56tDPwf.d.mts.map → useLogger-CyPP1sVB.d.mts.map} +1 -1
  112. package/dist/{utils-DzGCLRFe.d.mts → utils-Dmin7wVL.d.mts} +4 -3
  113. package/dist/utils-Dmin7wVL.d.mts.map +1 -0
  114. package/dist/utils.d.mts +2 -2
  115. package/dist/utils.mjs +7 -1
  116. package/dist/utils.mjs.map +1 -1
  117. package/dist/vite/index.d.mts +1 -1
  118. package/dist/vite/index.mjs.map +1 -1
  119. package/dist/workers.d.mts +48 -4
  120. package/dist/workers.d.mts.map +1 -1
  121. package/dist/workers.mjs +32 -5
  122. package/dist/workers.mjs.map +1 -1
  123. package/package.json +17 -21
  124. package/dist/_http-CHSsrWDJ.mjs.map +0 -1
  125. package/dist/audit-d9esRZOK.mjs.map +0 -1
  126. package/dist/audit-mUutdf6A.d.mts.map +0 -1
  127. package/dist/logger-b3epPH0N.d.mts.map +0 -1
  128. package/dist/parseError-BR9pocvY.d.mts.map +0 -1
  129. package/dist/utils-DzGCLRFe.d.mts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { R as ErrorOptions } from "./audit-mUutdf6A.mjs";
1
+ import { R as ErrorOptions } from "./audit-CTIviX3P.mjs";
2
2
 
3
3
  //#region src/error.d.ts
4
4
  /**
@@ -67,4 +67,4 @@ declare class EvlogError extends Error {
67
67
  declare function createError(options: ErrorOptions | string): EvlogError;
68
68
  //#endregion
69
69
  export { createError as n, EvlogError as t };
70
- //# sourceMappingURL=error-D1FZI2Kd.d.mts.map
70
+ //# sourceMappingURL=error-C7gSQVqk.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-D1FZI2Kd.d.mts","names":[],"sources":["../src/error.ts"],"mappings":";;;;;AAqBA;;;;;;;;;;;;;cAAa,UAAA,SAAmB,KAAA;EAY1B;EAAA,SATK,MAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;EAAA,SACA,IAAA;EAqCL;;;;EAAA,IA/BA,QAAA,CAAA,GAAY,MAAA;cAIJ,OAAA,EAAS,YAAA;EA0CqB;EAAA,IAftC,UAAA,CAAA;EAuDJ;EAAA,IAlDI,UAAA,CAAA;EAkDY;EAAA,IA7CZ,aAAA,CAAA;EAiFU;EAAA,IA5EV,IAAA,CAAA;IAAU,GAAA;IAAc,GAAA;IAAc,IAAA;EAAA;EAOjC,QAAA,CAAA;EAiCT,MAAA,CAAA,GAAU,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;iBAoCI,WAAA,CAAY,OAAA,EAAS,YAAA,YAAwB,UAAA"}
1
+ {"version":3,"file":"error-C7gSQVqk.d.mts","names":[],"sources":["../src/error.ts"],"mappings":";;;;;AAqBA;;;;;;;;;;;;;cAAa,UAAA,SAAmB,KAAA;EAY1B;EAAA,SATK,MAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;EAAA,SACA,IAAA;EAqCL;;;;EAAA,IA/BA,QAAA,CAAA,GAAY,MAAA;cAIJ,OAAA,EAAS,YAAA;EA0CqB;EAAA,IAftC,UAAA,CAAA;EAuDJ;EAAA,IAlDI,UAAA,CAAA;EAkDY;EAAA,IA7CZ,aAAA,CAAA;EAiFU;EAAA,IA5EV,IAAA,CAAA;IAAU,GAAA;IAAc,GAAA;IAAc,IAAA;EAAA;EAOjC,QAAA,CAAA;EAiCT,MAAA,CAAA,GAAU,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;iBAoCI,WAAA,CAAY,OAAA,EAAS,YAAA,YAAwB,UAAA"}
package/dist/error.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as createError, t as EvlogError } from "./error-D1FZI2Kd.mjs";
1
+ import { n as createError, t as EvlogError } from "./error-C7gSQVqk.mjs";
2
2
  export { EvlogError, createError, createError as createEvlogError };
@@ -1,4 +1,4 @@
1
- import { Z as RouteConfig } from "./audit-mUutdf6A.mjs";
1
+ import { Z as RouteConfig } from "./audit-CTIviX3P.mjs";
2
2
 
3
3
  //#region src/shared/routes.d.ts
4
4
  declare function shouldLog(path: string, include?: string[], exclude?: string[]): boolean;
@@ -36,4 +36,4 @@ declare function getServiceForPath(path: string, routes?: Record<string, RouteCo
36
36
  declare function extractErrorStatus(error: unknown): number;
37
37
  //#endregion
38
38
  export { getServiceForPath as n, shouldLog as r, extractErrorStatus as t };
39
- //# sourceMappingURL=errors-NIXCyk6I.d.mts.map
39
+ //# sourceMappingURL=errors-4MPmTzjY.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors-NIXCyk6I.d.mts","names":[],"sources":["../src/shared/routes.ts","../src/shared/errors.ts"],"mappings":";;;iBAGgB,SAAA,CAAU,IAAA,UAAc,OAAA,aAAoB,OAAA;;AAA5D;;;;;;;;;AAsCA;;;;;;;;;;;iBAAgB,iBAAA,CAAkB,IAAA,UAAc,MAAA,GAAS,MAAA,SAAe,WAAA;;;;;;AAtCxE;;;;iBCIgB,kBAAA,CAAmB,KAAA"}
1
+ {"version":3,"file":"errors-4MPmTzjY.d.mts","names":[],"sources":["../src/shared/routes.ts","../src/shared/errors.ts"],"mappings":";;;iBAGgB,SAAA,CAAU,IAAA,UAAc,OAAA,aAAoB,OAAA;;AAA5D;;;;;;;;;AAsCA;;;;;;;;;;;iBAAgB,iBAAA,CAAkB,IAAA,UAAc,MAAA,GAAS,MAAA,SAAe,WAAA;;;;;;AAtCxE;;;;iBCIgB,kBAAA,CAAmB,KAAA"}
@@ -1,5 +1,5 @@
1
- import { Y as RequestLogger } from "../audit-mUutdf6A.mjs";
2
- import { t as BaseEvlogOptions } from "../middleware-BYf26Lfu.mjs";
1
+ import { Y as RequestLogger } from "../audit-CTIviX3P.mjs";
2
+ import { t as BaseEvlogOptions } from "../middleware-CTnDsST-.mjs";
3
3
  import { RequestHandler } from "express";
4
4
 
5
5
  //#region src/express/index.d.ts
@@ -1,5 +1,5 @@
1
- import { t as createMiddlewareLogger } from "../middleware-BWOJ7JI0.mjs";
2
- import { t as attachForkToLogger } from "../fork-CTJXnpl8.mjs";
1
+ import { t as createMiddlewareLogger } from "../middleware-oAccqyPp.mjs";
2
+ import { t as attachForkToLogger } from "../fork-D1j1Fuzy.mjs";
3
3
  import { n as extractSafeNodeHeaders } from "../headers-D74M0wsg.mjs";
4
4
  import { t as createLoggerStorage } from "../storage-CFGTn37X.mjs";
5
5
  //#region src/express/index.ts
@@ -1,5 +1,5 @@
1
- import { Y as RequestLogger } from "../audit-mUutdf6A.mjs";
2
- import { t as BaseEvlogOptions } from "../middleware-BYf26Lfu.mjs";
1
+ import { Y as RequestLogger } from "../audit-CTIviX3P.mjs";
2
+ import { t as BaseEvlogOptions } from "../middleware-CTnDsST-.mjs";
3
3
  import { FastifyPluginCallback } from "fastify";
4
4
 
5
5
  //#region src/fastify/index.d.ts
@@ -1,5 +1,5 @@
1
- import { t as createMiddlewareLogger } from "../middleware-BWOJ7JI0.mjs";
2
- import { t as attachForkToLogger } from "../fork-CTJXnpl8.mjs";
1
+ import { t as createMiddlewareLogger } from "../middleware-oAccqyPp.mjs";
2
+ import { t as attachForkToLogger } from "../fork-D1j1Fuzy.mjs";
3
3
  import { n as extractSafeNodeHeaders } from "../headers-D74M0wsg.mjs";
4
4
  import { t as createLoggerStorage } from "../storage-CFGTn37X.mjs";
5
5
  //#region src/fastify/index.ts
@@ -1,6 +1,6 @@
1
- import { g as createRequestLogger, v as getGlobalDrain } from "./audit-d9esRZOK.mjs";
1
+ import { g as createRequestLogger, v as getGlobalDrain } from "./audit-DQoBo7Dl.mjs";
2
2
  import { t as extractErrorStatus } from "./errors-BJRXUfMg.mjs";
3
- import { n as runEnrichAndDrain } from "./middleware-BWOJ7JI0.mjs";
3
+ import { n as runEnrichAndDrain } from "./middleware-oAccqyPp.mjs";
4
4
  //#region src/shared/fork.ts
5
5
  /**
6
6
  * Attach {@link RequestLogger.fork} to a request logger. Replaces any existing `fork`.
@@ -69,4 +69,4 @@ function forkBackgroundLogger(options) {
69
69
  //#endregion
70
70
  export { forkBackgroundLogger as n, attachForkToLogger as t };
71
71
 
72
- //# sourceMappingURL=fork-CTJXnpl8.mjs.map
72
+ //# sourceMappingURL=fork-D1j1Fuzy.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"fork-CTJXnpl8.mjs","names":[],"sources":["../src/shared/fork.ts"],"sourcesContent":["import type { AsyncLocalStorage } from 'node:async_hooks'\nimport type { RequestLogger } from '../types'\nimport { createRequestLogger, getGlobalDrain } from '../logger'\nimport { extractErrorStatus } from './errors'\nimport type { MiddlewareLoggerOptions } from './middleware'\nimport { runEnrichAndDrain } from './middleware'\n\n/**\n * Optional hooks for integrations that track active loggers (e.g. Elysia `activeLoggers`).\n */\nexport interface ForkLifecycle {\n /** Called after the child logger is installed in storage, before `fn` runs. */\n onChildEnter?: (child: RequestLogger) => void\n /** Called after the child has finished (emit + enrich/drain), success or failure. */\n onChildExit?: (child: RequestLogger) => void\n}\n\n/**\n * Options for {@link forkBackgroundLogger}.\n *\n * @beta Part of `evlog/toolkit`\n */\nexport interface ForkBackgroundLoggerOptions {\n storage: AsyncLocalStorage<RequestLogger>\n parent: RequestLogger\n middlewareOptions: MiddlewareLoggerOptions\n label: string\n fn: () => void | Promise<void>\n lifecycle?: ForkLifecycle\n}\n\n/**\n * Attach {@link RequestLogger.fork} to a request logger. Replaces any existing `fork`.\n */\nexport function attachForkToLogger(\n storage: AsyncLocalStorage<RequestLogger>,\n parent: RequestLogger,\n middlewareOptions: MiddlewareLoggerOptions,\n lifecycle?: ForkLifecycle,\n): void {\n const log = parent as RequestLogger & { fork?: (label: string, fn: () => void | Promise<void>) => void }\n log.fork = (label: string, fn: () => void | Promise<void>) => {\n forkBackgroundLogger({ storage, parent, middlewareOptions, label, fn, lifecycle })\n }\n}\n\n/**\n * Run background work under a child request logger so `useLogger()` resolves to the\n * child while `fn` runs. The child emits a separate wide event when `fn` settles,\n * with `operation` and `_parentRequestId` set for correlation.\n *\n * @beta Part of `evlog/toolkit` — used by framework integrations; prefer `log.fork()`\n * on the request logger when available.\n */\nexport function forkBackgroundLogger(options: ForkBackgroundLoggerOptions): void {\n const { storage, parent, middlewareOptions, label, fn, lifecycle } = options\n\n const parentCtx = parent.getContext() as Record<string, unknown>\n const parentRequestId = parentCtx.requestId\n if (typeof parentRequestId !== 'string' || parentRequestId.length === 0) {\n throw new Error(\n '[evlog] log.fork() requires the parent logger to have a requestId. '\n + 'Ensure the request was created by evlog middleware.',\n )\n }\n\n const method = String(parentCtx.method ?? middlewareOptions.method)\n const path = String(parentCtx.path ?? middlewareOptions.path)\n\n const child = createRequestLogger(\n {\n method,\n path,\n requestId: crypto.randomUUID(),\n },\n { _deferDrain: true },\n )\n\n child.set({\n operation: label,\n _parentRequestId: parentRequestId,\n })\n\n const childRequestInfo = {\n method,\n path,\n requestId: child.getContext().requestId as string,\n }\n\n storage.run(child, () => {\n lifecycle?.onChildEnter?.(child)\n void Promise.resolve()\n .then(() => fn())\n .then(async () => {\n const emittedEvent = child.emit()\n const ctxStatus = child.getContext().status\n const status = (emittedEvent?.status\n ?? (typeof ctxStatus === 'number' ? ctxStatus : undefined)) as number | undefined\n if (\n emittedEvent\n && (middlewareOptions.enrich || middlewareOptions.drain || getGlobalDrain())\n ) {\n await runEnrichAndDrain(emittedEvent, middlewareOptions, childRequestInfo, status)\n }\n })\n .catch(async (err: unknown) => {\n const error = err instanceof Error ? err : new Error(String(err))\n child.error(error)\n child.set({ status: extractErrorStatus(error) })\n const emittedEvent = child.emit()\n const status = extractErrorStatus(error)\n if (\n emittedEvent\n && (middlewareOptions.enrich || middlewareOptions.drain || getGlobalDrain())\n ) {\n await runEnrichAndDrain(emittedEvent, middlewareOptions, childRequestInfo, status)\n }\n })\n .finally(() => {\n lifecycle?.onChildExit?.(child)\n })\n })\n}\n"],"mappings":";;;;;;;AAkCA,SAAgB,mBACd,SACA,QACA,mBACA,WACM;CACN,MAAM,MAAM;AACZ,KAAI,QAAQ,OAAe,OAAmC;AAC5D,uBAAqB;GAAE;GAAS;GAAQ;GAAmB;GAAO;GAAI;GAAW,CAAC;;;;;;;;;;;AAYtF,SAAgB,qBAAqB,SAA4C;CAC/E,MAAM,EAAE,SAAS,QAAQ,mBAAmB,OAAO,IAAI,cAAc;CAErE,MAAM,YAAY,OAAO,YAAY;CACrC,MAAM,kBAAkB,UAAU;AAClC,KAAI,OAAO,oBAAoB,YAAY,gBAAgB,WAAW,EACpE,OAAM,IAAI,MACR,yHAED;CAGH,MAAM,SAAS,OAAO,UAAU,UAAU,kBAAkB,OAAO;CACnE,MAAM,OAAO,OAAO,UAAU,QAAQ,kBAAkB,KAAK;CAE7D,MAAM,QAAQ,oBACZ;EACE;EACA;EACA,WAAW,OAAO,YAAY;EAC/B,EACD,EAAE,aAAa,MAAM,CACtB;AAED,OAAM,IAAI;EACR,WAAW;EACX,kBAAkB;EACnB,CAAC;CAEF,MAAM,mBAAmB;EACvB;EACA;EACA,WAAW,MAAM,YAAY,CAAC;EAC/B;AAED,SAAQ,IAAI,aAAa;AACvB,aAAW,eAAe,MAAM;AAC3B,UAAQ,SAAS,CACnB,WAAW,IAAI,CAAC,CAChB,KAAK,YAAY;GAChB,MAAM,eAAe,MAAM,MAAM;GACjC,MAAM,YAAY,MAAM,YAAY,CAAC;GACrC,MAAM,SAAU,cAAc,WACxB,OAAO,cAAc,WAAW,YAAY,KAAA;AAClD,OACE,iBACI,kBAAkB,UAAU,kBAAkB,SAAS,gBAAgB,EAE3E,OAAM,kBAAkB,cAAc,mBAAmB,kBAAkB,OAAO;IAEpF,CACD,MAAM,OAAO,QAAiB;GAC7B,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;AACjE,SAAM,MAAM,MAAM;AAClB,SAAM,IAAI,EAAE,QAAQ,mBAAmB,MAAM,EAAE,CAAC;GAChD,MAAM,eAAe,MAAM,MAAM;GACjC,MAAM,SAAS,mBAAmB,MAAM;AACxC,OACE,iBACI,kBAAkB,UAAU,kBAAkB,SAAS,gBAAgB,EAE3E,OAAM,kBAAkB,cAAc,mBAAmB,kBAAkB,OAAO;IAEpF,CACD,cAAc;AACb,cAAW,cAAc,MAAM;IAC/B;GACJ"}
1
+ {"version":3,"file":"fork-D1j1Fuzy.mjs","names":[],"sources":["../src/shared/fork.ts"],"sourcesContent":["import type { AsyncLocalStorage } from 'node:async_hooks'\nimport type { RequestLogger } from '../types'\nimport { createRequestLogger, getGlobalDrain } from '../logger'\nimport { extractErrorStatus } from './errors'\nimport type { MiddlewareLoggerOptions } from './middleware'\nimport { runEnrichAndDrain } from './middleware'\n\n/**\n * Optional hooks for integrations that track active loggers (e.g. Elysia `activeLoggers`).\n */\nexport interface ForkLifecycle {\n /** Called after the child logger is installed in storage, before `fn` runs. */\n onChildEnter?: (child: RequestLogger) => void\n /** Called after the child has finished (emit + enrich/drain), success or failure. */\n onChildExit?: (child: RequestLogger) => void\n}\n\n/**\n * Options for {@link forkBackgroundLogger}.\n *\n * @beta Part of `evlog/toolkit`\n */\nexport interface ForkBackgroundLoggerOptions {\n storage: AsyncLocalStorage<RequestLogger>\n parent: RequestLogger\n middlewareOptions: MiddlewareLoggerOptions\n label: string\n fn: () => void | Promise<void>\n lifecycle?: ForkLifecycle\n}\n\n/**\n * Attach {@link RequestLogger.fork} to a request logger. Replaces any existing `fork`.\n */\nexport function attachForkToLogger(\n storage: AsyncLocalStorage<RequestLogger>,\n parent: RequestLogger,\n middlewareOptions: MiddlewareLoggerOptions,\n lifecycle?: ForkLifecycle,\n): void {\n const log = parent as RequestLogger & { fork?: (label: string, fn: () => void | Promise<void>) => void }\n log.fork = (label: string, fn: () => void | Promise<void>) => {\n forkBackgroundLogger({ storage, parent, middlewareOptions, label, fn, lifecycle })\n }\n}\n\n/**\n * Run background work under a child request logger so `useLogger()` resolves to the\n * child while `fn` runs. The child emits a separate wide event when `fn` settles,\n * with `operation` and `_parentRequestId` set for correlation.\n *\n * @beta Part of `evlog/toolkit` — used by framework integrations; prefer `log.fork()`\n * on the request logger when available.\n */\nexport function forkBackgroundLogger(options: ForkBackgroundLoggerOptions): void {\n const { storage, parent, middlewareOptions, label, fn, lifecycle } = options\n\n const parentCtx = parent.getContext() as Record<string, unknown>\n const parentRequestId = parentCtx.requestId\n if (typeof parentRequestId !== 'string' || parentRequestId.length === 0) {\n throw new Error(\n '[evlog] log.fork() requires the parent logger to have a requestId. '\n + 'Ensure the request was created by evlog middleware.',\n )\n }\n\n const method = String(parentCtx.method ?? middlewareOptions.method)\n const path = String(parentCtx.path ?? middlewareOptions.path)\n\n const child = createRequestLogger(\n {\n method,\n path,\n requestId: crypto.randomUUID(),\n },\n { _deferDrain: true },\n )\n\n child.set({\n operation: label,\n _parentRequestId: parentRequestId,\n })\n\n const childRequestInfo = {\n method,\n path,\n requestId: child.getContext().requestId as string,\n }\n\n storage.run(child, () => {\n lifecycle?.onChildEnter?.(child)\n void Promise.resolve()\n .then(() => fn())\n .then(async () => {\n const emittedEvent = child.emit()\n const ctxStatus = child.getContext().status\n const status = (emittedEvent?.status\n ?? (typeof ctxStatus === 'number' ? ctxStatus : undefined)) as number | undefined\n if (\n emittedEvent\n && (middlewareOptions.enrich || middlewareOptions.drain || getGlobalDrain())\n ) {\n await runEnrichAndDrain(emittedEvent, middlewareOptions, childRequestInfo, status)\n }\n })\n .catch(async (err: unknown) => {\n const error = err instanceof Error ? err : new Error(String(err))\n child.error(error)\n child.set({ status: extractErrorStatus(error) })\n const emittedEvent = child.emit()\n const status = extractErrorStatus(error)\n if (\n emittedEvent\n && (middlewareOptions.enrich || middlewareOptions.drain || getGlobalDrain())\n ) {\n await runEnrichAndDrain(emittedEvent, middlewareOptions, childRequestInfo, status)\n }\n })\n .finally(() => {\n lifecycle?.onChildExit?.(child)\n })\n })\n}\n"],"mappings":";;;;;;;AAkCA,SAAgB,mBACd,SACA,QACA,mBACA,WACM;CACN,MAAM,MAAM;AACZ,KAAI,QAAQ,OAAe,OAAmC;AAC5D,uBAAqB;GAAE;GAAS;GAAQ;GAAmB;GAAO;GAAI;GAAW,CAAC;;;;;;;;;;;AAYtF,SAAgB,qBAAqB,SAA4C;CAC/E,MAAM,EAAE,SAAS,QAAQ,mBAAmB,OAAO,IAAI,cAAc;CAErE,MAAM,YAAY,OAAO,YAAY;CACrC,MAAM,kBAAkB,UAAU;AAClC,KAAI,OAAO,oBAAoB,YAAY,gBAAgB,WAAW,EACpE,OAAM,IAAI,MACR,yHAED;CAGH,MAAM,SAAS,OAAO,UAAU,UAAU,kBAAkB,OAAO;CACnE,MAAM,OAAO,OAAO,UAAU,QAAQ,kBAAkB,KAAK;CAE7D,MAAM,QAAQ,oBACZ;EACE;EACA;EACA,WAAW,OAAO,YAAY;EAC/B,EACD,EAAE,aAAa,MAAM,CACtB;AAED,OAAM,IAAI;EACR,WAAW;EACX,kBAAkB;EACnB,CAAC;CAEF,MAAM,mBAAmB;EACvB;EACA;EACA,WAAW,MAAM,YAAY,CAAC;EAC/B;AAED,SAAQ,IAAI,aAAa;AACvB,aAAW,eAAe,MAAM;AAC3B,UAAQ,SAAS,CACnB,WAAW,IAAI,CAAC,CAChB,KAAK,YAAY;GAChB,MAAM,eAAe,MAAM,MAAM;GACjC,MAAM,YAAY,MAAM,YAAY,CAAC;GACrC,MAAM,SAAU,cAAc,WACxB,OAAO,cAAc,WAAW,YAAY,KAAA;AAClD,OACE,iBACI,kBAAkB,UAAU,kBAAkB,SAAS,gBAAgB,EAE3E,OAAM,kBAAkB,cAAc,mBAAmB,kBAAkB,OAAO;IAEpF,CACD,MAAM,OAAO,QAAiB;GAC7B,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;AACjE,SAAM,MAAM,MAAM;AAClB,SAAM,IAAI,EAAE,QAAQ,mBAAmB,MAAM,EAAE,CAAC;GAChD,MAAM,eAAe,MAAM,MAAM;GACjC,MAAM,SAAS,mBAAmB,MAAM;AACxC,OACE,iBACI,kBAAkB,UAAU,kBAAkB,SAAS,gBAAgB,EAE3E,OAAM,kBAAkB,cAAc,mBAAmB,kBAAkB,OAAO;IAEpF,CACD,cAAc;AACb,cAAW,cAAc,MAAM;IAC/B;GACJ"}
@@ -1,5 +1,5 @@
1
- import { Y as RequestLogger } from "../audit-mUutdf6A.mjs";
2
- import { t as BaseEvlogOptions } from "../middleware-BYf26Lfu.mjs";
1
+ import { Y as RequestLogger } from "../audit-CTIviX3P.mjs";
2
+ import { t as BaseEvlogOptions } from "../middleware-CTnDsST-.mjs";
3
3
  import { MiddlewareHandler } from "hono";
4
4
 
5
5
  //#region src/hono/index.d.ts
@@ -1,4 +1,4 @@
1
- import { t as createMiddlewareLogger } from "../middleware-BWOJ7JI0.mjs";
1
+ import { t as createMiddlewareLogger } from "../middleware-oAccqyPp.mjs";
2
2
  import { t as extractSafeHeaders } from "../headers-D74M0wsg.mjs";
3
3
  //#region src/hono/index.ts
4
4
  /**
package/dist/http.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { F as DrainContext } from "./audit-mUutdf6A.mjs";
1
+ import { F as DrainContext } from "./audit-CTIviX3P.mjs";
2
2
  import { DrainPipelineOptions, PipelineDrainFn } from "./pipeline.mjs";
3
3
 
4
4
  //#region src/http.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.mts","names":[],"sources":["../src/http.ts"],"mappings":";;;;UAIiB,eAAA;;EAEf,QAAA;EAF8B;EAI9B,OAAA,GAAU,MAAA;EAMsB;EAJhC,OAAA;EAFA;EAIA,SAAA;EAFA;EAIA,WAAA,GAAc,kBAAA;AAAA;AAAA,UAGC,mBAAA;EAHiB;EAKhC,KAAA,EAAO,eAAA;EAFQ;EAIf,QAAA,GAAW,oBAAA,CAAqB,YAAA;;EAEhC,SAAA;AAAA;;;;;;;;;;;;AAmBF;;;;;iBAAgB,eAAA,CAAgB,MAAA,EAAQ,eAAA,IAAmB,KAAA,EAAO,YAAA,OAAmB,OAAA;;;;;;;;;;AA8DrF;;;;;;;;;iBAAgB,kBAAA,CAAmB,OAAA,EAAS,mBAAA,GAAsB,eAAA,CAAgB,YAAA;EAAkB,OAAA;AAAA"}
1
+ {"version":3,"file":"http.d.mts","names":[],"sources":["../src/http.ts"],"mappings":";;;;UAKiB,eAAA;;EAEf,QAAA;EAF8B;EAI9B,OAAA,GAAU,MAAA;EAMsB;EAJhC,OAAA;EAFA;EAIA,SAAA;EAFA;EAIA,WAAA,GAAc,kBAAA;AAAA;AAAA,UAGC,mBAAA;EAHiB;EAKhC,KAAA,EAAO,eAAA;EAFQ;EAIf,QAAA,GAAW,oBAAA,CAAqB,YAAA;;EAEhC,SAAA;AAAA;;;;;;;;;;;;AAmBF;;;;;iBAAgB,eAAA,CAAgB,MAAA,EAAQ,eAAA,IAAmB,KAAA,EAAO,YAAA,OAAmB,OAAA;;;;;;;;;;AA6DrF;;;;;;;;;iBAAgB,kBAAA,CAAmB,OAAA,EAAS,mBAAA,GAAsB,eAAA,CAAgB,YAAA;EAAkB,OAAA;AAAA"}
package/dist/http.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { isBrowser } from "./utils.mjs";
1
2
  import { createDrainPipeline } from "./pipeline.mjs";
2
3
  //#region src/http.ts
3
4
  /**
@@ -21,7 +22,7 @@ function createHttpDrain(config) {
21
22
  return async (batch) => {
22
23
  if (batch.length === 0) return;
23
24
  const body = JSON.stringify(batch);
24
- if (useBeacon && typeof document !== "undefined" && document.visibilityState === "hidden" && typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
25
+ if (useBeacon && isBrowser() && document.visibilityState === "hidden" && typeof navigator.sendBeacon === "function") {
25
26
  if (!navigator.sendBeacon(endpoint, new Blob([body], { type: "application/json" }))) throw new Error("[evlog/http] sendBeacon failed — payload may exceed browser limit");
26
27
  return;
27
28
  }
@@ -74,7 +75,7 @@ function createHttpLogDrain(options) {
74
75
  ...options.pipeline
75
76
  })(createHttpDrain(options.drain));
76
77
  let onVisibilityChange;
77
- if (autoFlush && typeof document !== "undefined") {
78
+ if (autoFlush && isBrowser()) {
78
79
  onVisibilityChange = () => {
79
80
  if (document.visibilityState === "hidden") drain.flush();
80
81
  };
package/dist/http.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"http.mjs","names":[],"sources":["../src/http.ts"],"sourcesContent":["import type { DrainContext } from './types'\nimport type { DrainPipelineOptions, PipelineDrainFn } from './pipeline'\nimport { createDrainPipeline } from './pipeline'\n\nexport interface HttpDrainConfig {\n /** URL of the server ingest endpoint */\n endpoint: string\n /** Custom headers sent with each fetch request (e.g. Authorization, X-API-Key). Not applied to sendBeacon — see `useBeacon`. */\n headers?: Record<string, string>\n /** Request timeout in milliseconds. @default 5000 */\n timeout?: number\n /** Use sendBeacon when the page is hidden. @default true */\n useBeacon?: boolean\n /** Fetch credentials mode. @default 'same-origin' */\n credentials?: RequestCredentials\n}\n\nexport interface HttpLogDrainOptions {\n /** HTTP drain configuration (endpoint is required) */\n drain: HttpDrainConfig\n /** Pipeline configuration overrides */\n pipeline?: DrainPipelineOptions<DrainContext>\n /** Auto-register visibilitychange flush listener. @default true */\n autoFlush?: boolean\n}\n\n/**\n * Create a low-level HTTP drain transport function (fetch / sendBeacon).\n *\n * Returns a function compatible with `createDrainPipeline` that sends batches\n * to the configured endpoint via `fetch` (with `keepalive: true`) or\n * `navigator.sendBeacon` when the page is hidden.\n *\n * @example\n * ```ts\n * import { createHttpDrain } from 'evlog/http'\n * import { createDrainPipeline } from 'evlog/pipeline'\n *\n * const pipeline = createDrainPipeline({ batch: { size: 50 } })\n * const drain = pipeline(createHttpDrain({ endpoint: '/api/logs' }))\n * ```\n */\nexport function createHttpDrain(config: HttpDrainConfig): (batch: DrainContext[]) => Promise<void> {\n const { endpoint, headers: customHeaders, timeout = 5000, useBeacon = true, credentials = 'same-origin' } = config\n\n return async (batch: DrainContext[]): Promise<void> => {\n if (batch.length === 0) return\n\n const body = JSON.stringify(batch)\n\n if (\n useBeacon\n && typeof document !== 'undefined'\n && document.visibilityState === 'hidden'\n && typeof navigator !== 'undefined'\n && typeof navigator.sendBeacon === 'function'\n ) {\n const queued = navigator.sendBeacon(endpoint, new Blob([body], { type: 'application/json' }))\n if (!queued) {\n throw new Error('[evlog/http] sendBeacon failed — payload may exceed browser limit')\n }\n return\n }\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body,\n signal: controller.signal,\n keepalive: true,\n credentials,\n })\n\n if (!response.ok) {\n throw new Error(`[evlog/http] Server responded with ${response.status}`)\n }\n } finally {\n clearTimeout(timeoutId)\n }\n }\n}\n\n/**\n * Create a pre-composed HTTP log drain with pipeline, batching, and auto-flush.\n *\n * Returns a `PipelineDrainFn<DrainContext>` directly usable with `initLogger({ drain })`.\n *\n * @example\n * ```ts\n * import { initLogger, log } from 'evlog'\n * import { createHttpLogDrain } from 'evlog/http'\n *\n * const drain = createHttpLogDrain({\n * drain: { endpoint: '/api/logs' },\n * })\n * initLogger({ drain })\n *\n * log.info({ action: 'page_view', path: location.pathname })\n * ```\n */\nexport function createHttpLogDrain(options: HttpLogDrainOptions): PipelineDrainFn<DrainContext> & { dispose: () => void } {\n const { autoFlush = true } = options\n\n const pipeline = createDrainPipeline<DrainContext>({\n batch: { size: 25, intervalMs: 2000 },\n retry: { maxAttempts: 2 },\n ...options.pipeline,\n })\n\n const drain = pipeline(createHttpDrain(options.drain)) as PipelineDrainFn<DrainContext> & { dispose: () => void }\n\n let onVisibilityChange: (() => void) | undefined\n\n if (autoFlush && typeof document !== 'undefined') {\n onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n drain.flush()\n }\n }\n document.addEventListener('visibilitychange', onVisibilityChange)\n }\n\n drain.dispose = () => {\n if (onVisibilityChange) {\n document.removeEventListener('visibilitychange', onVisibilityChange)\n onVisibilityChange = undefined\n }\n }\n\n return drain\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA0CA,SAAgB,gBAAgB,QAAmE;CACjG,MAAM,EAAE,UAAU,SAAS,eAAe,UAAU,KAAM,YAAY,MAAM,cAAc,kBAAkB;AAE5G,QAAO,OAAO,UAAyC;AACrD,MAAI,MAAM,WAAW,EAAG;EAExB,MAAM,OAAO,KAAK,UAAU,MAAM;AAElC,MACE,aACG,OAAO,aAAa,eACpB,SAAS,oBAAoB,YAC7B,OAAO,cAAc,eACrB,OAAO,UAAU,eAAe,YACnC;AAEA,OAAI,CADW,UAAU,WAAW,UAAU,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,oBAAoB,CAAC,CAAC,CAE3F,OAAM,IAAI,MAAM,oEAAoE;AAEtF;;EAGF,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,QAAQ;AAE/D,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,UAAU;IACrC,QAAQ;IACR,SAAS;KAAE,gBAAgB;KAAoB,GAAG;KAAe;IACjE;IACA,QAAQ,WAAW;IACnB,WAAW;IACX;IACD,CAAC;AAEF,OAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,sCAAsC,SAAS,SAAS;YAElE;AACR,gBAAa,UAAU;;;;;;;;;;;;;;;;;;;;;;AAuB7B,SAAgB,mBAAmB,SAAuF;CACxH,MAAM,EAAE,YAAY,SAAS;CAQ7B,MAAM,QANW,oBAAkC;EACjD,OAAO;GAAE,MAAM;GAAI,YAAY;GAAM;EACrC,OAAO,EAAE,aAAa,GAAG;EACzB,GAAG,QAAQ;EACZ,CAAC,CAEqB,gBAAgB,QAAQ,MAAM,CAAC;CAEtD,IAAI;AAEJ,KAAI,aAAa,OAAO,aAAa,aAAa;AAChD,6BAA2B;AACzB,OAAI,SAAS,oBAAoB,SAC/B,OAAM,OAAO;;AAGjB,WAAS,iBAAiB,oBAAoB,mBAAmB;;AAGnE,OAAM,gBAAgB;AACpB,MAAI,oBAAoB;AACtB,YAAS,oBAAoB,oBAAoB,mBAAmB;AACpE,wBAAqB,KAAA;;;AAIzB,QAAO"}
1
+ {"version":3,"file":"http.mjs","names":[],"sources":["../src/http.ts"],"sourcesContent":["import type { DrainContext } from './types'\nimport type { DrainPipelineOptions, PipelineDrainFn } from './pipeline'\nimport { createDrainPipeline } from './pipeline'\nimport { isBrowser } from './utils'\n\nexport interface HttpDrainConfig {\n /** URL of the server ingest endpoint */\n endpoint: string\n /** Custom headers sent with each fetch request (e.g. Authorization, X-API-Key). Not applied to sendBeacon — see `useBeacon`. */\n headers?: Record<string, string>\n /** Request timeout in milliseconds. @default 5000 */\n timeout?: number\n /** Use sendBeacon when the page is hidden. @default true */\n useBeacon?: boolean\n /** Fetch credentials mode. @default 'same-origin' */\n credentials?: RequestCredentials\n}\n\nexport interface HttpLogDrainOptions {\n /** HTTP drain configuration (endpoint is required) */\n drain: HttpDrainConfig\n /** Pipeline configuration overrides */\n pipeline?: DrainPipelineOptions<DrainContext>\n /** Auto-register visibilitychange flush listener. @default true */\n autoFlush?: boolean\n}\n\n/**\n * Create a low-level HTTP drain transport function (fetch / sendBeacon).\n *\n * Returns a function compatible with `createDrainPipeline` that sends batches\n * to the configured endpoint via `fetch` (with `keepalive: true`) or\n * `navigator.sendBeacon` when the page is hidden.\n *\n * @example\n * ```ts\n * import { createHttpDrain } from 'evlog/http'\n * import { createDrainPipeline } from 'evlog/pipeline'\n *\n * const pipeline = createDrainPipeline({ batch: { size: 50 } })\n * const drain = pipeline(createHttpDrain({ endpoint: '/api/logs' }))\n * ```\n */\nexport function createHttpDrain(config: HttpDrainConfig): (batch: DrainContext[]) => Promise<void> {\n const { endpoint, headers: customHeaders, timeout = 5000, useBeacon = true, credentials = 'same-origin' } = config\n\n return async (batch: DrainContext[]): Promise<void> => {\n if (batch.length === 0) return\n\n const body = JSON.stringify(batch)\n\n if (\n useBeacon\n && isBrowser()\n && document.visibilityState === 'hidden'\n && typeof navigator.sendBeacon === 'function'\n ) {\n const queued = navigator.sendBeacon(endpoint, new Blob([body], { type: 'application/json' }))\n if (!queued) {\n throw new Error('[evlog/http] sendBeacon failed — payload may exceed browser limit')\n }\n return\n }\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body,\n signal: controller.signal,\n keepalive: true,\n credentials,\n })\n\n if (!response.ok) {\n throw new Error(`[evlog/http] Server responded with ${response.status}`)\n }\n } finally {\n clearTimeout(timeoutId)\n }\n }\n}\n\n/**\n * Create a pre-composed HTTP log drain with pipeline, batching, and auto-flush.\n *\n * Returns a `PipelineDrainFn<DrainContext>` directly usable with `initLogger({ drain })`.\n *\n * @example\n * ```ts\n * import { initLogger, log } from 'evlog'\n * import { createHttpLogDrain } from 'evlog/http'\n *\n * const drain = createHttpLogDrain({\n * drain: { endpoint: '/api/logs' },\n * })\n * initLogger({ drain })\n *\n * log.info({ action: 'page_view', path: location.pathname })\n * ```\n */\nexport function createHttpLogDrain(options: HttpLogDrainOptions): PipelineDrainFn<DrainContext> & { dispose: () => void } {\n const { autoFlush = true } = options\n\n const pipeline = createDrainPipeline<DrainContext>({\n batch: { size: 25, intervalMs: 2000 },\n retry: { maxAttempts: 2 },\n ...options.pipeline,\n })\n\n const drain = pipeline(createHttpDrain(options.drain)) as PipelineDrainFn<DrainContext> & { dispose: () => void }\n\n let onVisibilityChange: (() => void) | undefined\n\n if (autoFlush && isBrowser()) {\n onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n drain.flush()\n }\n }\n document.addEventListener('visibilitychange', onVisibilityChange)\n }\n\n drain.dispose = () => {\n if (onVisibilityChange) {\n document.removeEventListener('visibilitychange', onVisibilityChange)\n onVisibilityChange = undefined\n }\n }\n\n return drain\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA2CA,SAAgB,gBAAgB,QAAmE;CACjG,MAAM,EAAE,UAAU,SAAS,eAAe,UAAU,KAAM,YAAY,MAAM,cAAc,kBAAkB;AAE5G,QAAO,OAAO,UAAyC;AACrD,MAAI,MAAM,WAAW,EAAG;EAExB,MAAM,OAAO,KAAK,UAAU,MAAM;AAElC,MACE,aACG,WAAW,IACX,SAAS,oBAAoB,YAC7B,OAAO,UAAU,eAAe,YACnC;AAEA,OAAI,CADW,UAAU,WAAW,UAAU,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,oBAAoB,CAAC,CACjF,CACT,OAAM,IAAI,MAAM,oEAAoE;AAEtF;;EAGF,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,QAAQ;AAE/D,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,UAAU;IACrC,QAAQ;IACR,SAAS;KAAE,gBAAgB;KAAoB,GAAG;KAAe;IACjE;IACA,QAAQ,WAAW;IACnB,WAAW;IACX;IACD,CAAC;AAEF,OAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,sCAAsC,SAAS,SAAS;YAElE;AACR,gBAAa,UAAU;;;;;;;;;;;;;;;;;;;;;;AAuB7B,SAAgB,mBAAmB,SAAuF;CACxH,MAAM,EAAE,YAAY,SAAS;CAQ7B,MAAM,QANW,oBAAkC;EACjD,OAAO;GAAE,MAAM;GAAI,YAAY;GAAM;EACrC,OAAO,EAAE,aAAa,GAAG;EACzB,GAAG,QAAQ;EACZ,CAEqB,CAAC,gBAAgB,QAAQ,MAAM,CAAC;CAEtD,IAAI;AAEJ,KAAI,aAAa,WAAW,EAAE;AAC5B,6BAA2B;AACzB,OAAI,SAAS,oBAAoB,SAC/B,OAAM,OAAO;;AAGjB,WAAS,iBAAiB,oBAAoB,mBAAmB;;AAGnE,OAAM,gBAAgB;AACpB,MAAI,oBAAoB;AACtB,YAAS,oBAAoB,oBAAoB,mBAAmB;AACpE,wBAAqB,KAAA;;;AAIzB,QAAO"}
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { $ as SamplingRates, A as AuditFields, B as H3EventContext, C as buildAuditFields, D as withAudit, E as signed, F as DrainContext, G as LoggerConfig, H as InternalFields, I as EnrichContext, K as ParsedError, L as EnvironmentContext, M as AuditTarget, N as BaseWideEvent, O as withAuditMethods, P as DeepPartial, Q as SamplingConfig, R as ErrorOptions, S as auditRedactPreset, T as mockAudit, U as Log, V as IngestPayload, W as LogLevel, X as RequestLoggerOptions, Y as RequestLogger, _ as WithAuditOptions, a as AuditInput, b as auditEnricher, c as AuditOnlyOptions, d as DefinedAuditAction, et as ServerEvent, f as DrainFn, g as WithAuditContext, h as SignedOptions, i as AuditEnricherOptions, it as WideEvent, j as AuditLoggerMethod, k as AuditActor, l as AuditPatchOp, m as SignedChainState, n as AuditDeniedError, nt as TailSamplingContext, o as AuditMatcher, p as MockAudit, q as RedactConfig, r as AuditDiffOptions, rt as TransportConfig, s as AuditMethod, t as AUDIT_SCHEMA_VERSION, tt as TailSamplingCondition, u as AuditableLogger, v as audit, w as defineAuditAction, x as auditOnly, y as auditDiff, z as FieldContext } from "./audit-mUutdf6A.mjs";
2
- import { n as createError, t as EvlogError } from "./error-D1FZI2Kd.mjs";
3
- import { i as getEnvironment, n as createLogger, o as initLogger, r as createRequestLogger, s as isEnabled, t as _log, u as shouldKeep } from "./logger-b3epPH0N.mjs";
4
- import { p as isLevelEnabled } from "./utils-DzGCLRFe.mjs";
5
- import { t as useLogger } from "./useLogger-C56tDPwf.mjs";
6
- import { t as parseError } from "./parseError-BR9pocvY.mjs";
1
+ import { $ as SamplingRates, A as AuditFields, B as H3EventContext, C as buildAuditFields, D as withAudit, E as signed, F as DrainContext, G as LoggerConfig, H as InternalFields, I as EnrichContext, K as ParsedError, L as EnvironmentContext, M as AuditTarget, N as BaseWideEvent, O as withAuditMethods, P as DeepPartial, Q as SamplingConfig, R as ErrorOptions, S as auditRedactPreset, T as mockAudit, U as Log, V as IngestPayload, W as LogLevel, X as RequestLoggerOptions, Y as RequestLogger, _ as WithAuditOptions, a as AuditInput, b as auditEnricher, c as AuditOnlyOptions, d as DefinedAuditAction, et as ServerEvent, f as DrainFn, g as WithAuditContext, h as SignedOptions, i as AuditEnricherOptions, it as WideEvent, j as AuditLoggerMethod, k as AuditActor, l as AuditPatchOp, m as SignedChainState, n as AuditDeniedError, nt as TailSamplingContext, o as AuditMatcher, p as MockAudit, q as RedactConfig, r as AuditDiffOptions, rt as TransportConfig, s as AuditMethod, t as AUDIT_SCHEMA_VERSION, tt as TailSamplingCondition, u as AuditableLogger, v as audit, w as defineAuditAction, x as auditOnly, y as auditDiff, z as FieldContext } from "./audit-CTIviX3P.mjs";
2
+ import { n as createError, t as EvlogError } from "./error-C7gSQVqk.mjs";
3
+ import { i as getEnvironment, n as createLogger, o as initLogger, r as createRequestLogger, s as isEnabled, t as _log, u as shouldKeep } from "./logger-DttRJRGa.mjs";
4
+ import { m as isLevelEnabled } from "./utils-Dmin7wVL.mjs";
5
+ import { t as useLogger } from "./useLogger-CyPP1sVB.mjs";
6
+ import { t as parseError } from "./parseError-o1GpZEOR.mjs";
7
7
  export { AUDIT_SCHEMA_VERSION, type AuditActor, AuditDeniedError, type AuditDiffOptions, type AuditEnricherOptions, type AuditFields, type AuditInput, type AuditLoggerMethod, type AuditMatcher, type AuditMethod, type AuditOnlyOptions, type AuditPatchOp, type AuditTarget, type AuditableLogger, type BaseWideEvent, type DeepPartial, type DefinedAuditAction, type DrainContext, type DrainFn, type EnrichContext, type EnvironmentContext, type ErrorOptions, EvlogError, type FieldContext, type H3EventContext, type IngestPayload, type InternalFields, type Log, type LogLevel, type LoggerConfig, type MockAudit, type ParsedError, type RedactConfig, type RequestLogger, type RequestLoggerOptions, type SamplingConfig, type SamplingRates, type ServerEvent, type SignedChainState, type SignedOptions, type TailSamplingCondition, type TailSamplingContext, type TransportConfig, type WideEvent, type WithAuditContext, type WithAuditOptions, audit, auditDiff, auditEnricher, auditOnly, auditRedactPreset, buildAuditFields, createError, createError as createEvlogError, createLogger, createRequestLogger, defineAuditAction, getEnvironment, initLogger, isEnabled, isLevelEnabled, _log as log, mockAudit, parseError, shouldKeep, signed, useLogger, withAudit, withAuditMethods };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { C as shouldKeep, _ as getEnvironment, a as auditEnricher, b as isEnabled, c as buildAuditFields, d as signed, f as withAudit, g as createRequestLogger, h as createLogger, i as auditDiff, l as defineAuditAction, m as _log, n as AuditDeniedError, o as auditOnly, p as withAuditMethods, r as audit, s as auditRedactPreset, t as AUDIT_SCHEMA_VERSION, u as mockAudit, y as initLogger } from "./audit-d9esRZOK.mjs";
1
+ import { C as shouldKeep, _ as getEnvironment, a as auditEnricher, b as isEnabled, c as buildAuditFields, d as signed, f as withAudit, g as createRequestLogger, h as createLogger, i as auditDiff, l as defineAuditAction, m as _log, n as AuditDeniedError, o as auditOnly, p as withAuditMethods, r as audit, s as auditRedactPreset, t as AUDIT_SCHEMA_VERSION, u as mockAudit, y as initLogger } from "./audit-DQoBo7Dl.mjs";
2
2
  import { isLevelEnabled } from "./utils.mjs";
3
3
  import { EvlogError, createError } from "./error.mjs";
4
4
  import { useLogger } from "./runtime/server/useLogger.mjs";
@@ -1,4 +1,4 @@
1
- import { F as DrainContext, G as LoggerConfig, L as EnvironmentContext, U as Log, X as RequestLoggerOptions, nt as TailSamplingContext, u as AuditableLogger } from "./audit-mUutdf6A.mjs";
1
+ import { F as DrainContext, G as LoggerConfig, L as EnvironmentContext, U as Log, X as RequestLoggerOptions, nt as TailSamplingContext, u as AuditableLogger } from "./audit-CTIviX3P.mjs";
2
2
 
3
3
  //#region src/logger.d.ts
4
4
  /**
@@ -50,6 +50,10 @@ interface CreateLoggerInternalOptions {
50
50
  * Used by framework middleware that runs its own enrich+drain pipeline.
51
51
  */
52
52
  _deferDrain?: boolean;
53
+ /**
54
+ * @see {@link RequestLoggerOptions.waitUntil}
55
+ */
56
+ waitUntil?: (promise: Promise<unknown>) => void;
53
57
  }
54
58
  /**
55
59
  * Create a scoped logger for building wide events.
@@ -78,6 +82,21 @@ declare function createLogger<T extends object = Record<string, unknown>>(initia
78
82
  * log.set({ cart: { items: 3 } })
79
83
  * log.emit()
80
84
  * ```
85
+ *
86
+ * @example Cloudflare Workers — pass `waitUntil` so `initLogger({ drain })` completes after the response:
87
+ * ```ts
88
+ * export default {
89
+ * async fetch(request, env, ctx) {
90
+ * const log = createRequestLogger({
91
+ * method: request.method,
92
+ * path: new URL(request.url).pathname,
93
+ * waitUntil: ctx.waitUntil.bind(ctx),
94
+ * })
95
+ * log.emit()
96
+ * return new Response('ok')
97
+ * },
98
+ * }
99
+ * ```
81
100
  */
82
101
  declare function createRequestLogger<T extends object = Record<string, unknown>>(options?: RequestLoggerOptions, internalOptions?: CreateLoggerInternalOptions): AuditableLogger<T>;
83
102
  /**
@@ -86,4 +105,4 @@ declare function createRequestLogger<T extends object = Record<string, unknown>>
86
105
  declare function getEnvironment(): EnvironmentContext;
87
106
  //#endregion
88
107
  export { getGlobalDrain as a, isLoggerLocked as c, getEnvironment as i, lockLogger as l, createLogger as n, initLogger as o, createRequestLogger as r, isEnabled as s, _log as t, shouldKeep as u };
89
- //# sourceMappingURL=logger-b3epPH0N.d.mts.map
108
+ //# sourceMappingURL=logger-DttRJRGa.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger-DttRJRGa.d.mts","names":[],"sources":["../src/logger.ts"],"mappings":";;;;AA6DA;;;iBAAgB,UAAA,CAAW,MAAA,GAAQ,YAAA;;AA4BnC;;iBAAgB,SAAA,CAAA;;;AAShB;;;iBAAgB,UAAA,CAAA;;AAOhB;;iBAAgB,cAAA,CAAA;;;AAShB;;;iBAAgB,cAAA,CAAA,KAAoB,GAAA,EAAK,YAAA,YAAwB,OAAA;;;;;iBA8BjD,UAAA,CAAW,GAAA,EAAK,mBAAA;AAAhC;;;;;AAgBC;;;;AAhBD,cA8XM,IAAA,EAAM,GAAA;;;;UA2BF,2BAAA;EASR;;;;EAJA,WAAA;EAsBc;;;EAlBd,SAAA,IAAa,OAAA,EAAS,OAAA;AAAA;;;;;;;;;;;;;;;;iBAkBR,YAAA,oBAAgC,MAAA,kBAAA,CAAyB,cAAA,GAAgB,MAAA,mBAA8B,eAAA,GAAkB,2BAAA,GAA8B,eAAA,CAAgB,CAAA;;;;;;;;;;;;;;;;;;;;AA6MvL;;;;;;;;iBAfgB,mBAAA,oBAAuC,MAAA,kBAAA,CAAyB,OAAA,GAAS,oBAAA,EAA2B,eAAA,GAAkB,2BAAA,GAA8B,eAAA,CAAgB,CAAA;;;;iBAepK,cAAA,CAAA,GAAkB,kBAAA"}
package/dist/logger.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as getGlobalDrain, c as isLoggerLocked, i as getEnvironment, l as lockLogger, n as createLogger, o as initLogger, r as createRequestLogger, s as isEnabled, t as _log, u as shouldKeep } from "./logger-b3epPH0N.mjs";
1
+ import { a as getGlobalDrain, c as isLoggerLocked, i as getEnvironment, l as lockLogger, n as createLogger, o as initLogger, r as createRequestLogger, s as isEnabled, t as _log, u as shouldKeep } from "./logger-DttRJRGa.mjs";
2
2
  export { createLogger, createRequestLogger, getEnvironment, getGlobalDrain, initLogger, isEnabled, isLoggerLocked, lockLogger, _log as log, shouldKeep };
package/dist/logger.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { C as shouldKeep, S as lockLogger, _ as getEnvironment, b as isEnabled, g as createRequestLogger, h as createLogger, m as _log, v as getGlobalDrain, x as isLoggerLocked, y as initLogger } from "./audit-d9esRZOK.mjs";
1
+ import { C as shouldKeep, S as lockLogger, _ as getEnvironment, b as isEnabled, g as createRequestLogger, h as createLogger, m as _log, v as getGlobalDrain, x as isLoggerLocked, y as initLogger } from "./audit-DQoBo7Dl.mjs";
2
2
  export { createLogger, createRequestLogger, getEnvironment, getGlobalDrain, initLogger, isEnabled, isLoggerLocked, lockLogger, _log as log, shouldKeep };
@@ -1,4 +1,4 @@
1
- import { F as DrainContext, I as EnrichContext, Y as RequestLogger, Z as RouteConfig, it as WideEvent, nt as TailSamplingContext, q as RedactConfig } from "./audit-mUutdf6A.mjs";
1
+ import { F as DrainContext, I as EnrichContext, Y as RequestLogger, Z as RouteConfig, it as WideEvent, nt as TailSamplingContext, q as RedactConfig } from "./audit-CTIviX3P.mjs";
2
2
 
3
3
  //#region src/shared/middleware.d.ts
4
4
  /**
@@ -90,4 +90,4 @@ declare function runEnrichAndDrain(emittedEvent: WideEvent, options: MiddlewareL
90
90
  declare function createMiddlewareLogger(options: MiddlewareLoggerOptions): MiddlewareLoggerResult;
91
91
  //#endregion
92
92
  export { runEnrichAndDrain as a, createMiddlewareLogger as i, MiddlewareLoggerOptions as n, MiddlewareLoggerResult as r, BaseEvlogOptions as t };
93
- //# sourceMappingURL=middleware-BYf26Lfu.d.mts.map
93
+ //# sourceMappingURL=middleware-CTnDsST-.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"middleware-BYf26Lfu.d.mts","names":[],"sources":["../src/shared/middleware.ts"],"mappings":";;;;;AAeA;;;;;;;UAAiB,gBAAA;EAgByB;EAdxC,OAAA;EAmB4C;EAjB5C,OAAA;EAwB+B;EAtB/B,MAAA,GAAS,MAAA,SAAe,WAAA;EAJxB;;;;EASA,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAAtC;;;;EAKA,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAAzB;;;;EAKf,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;EAApC;;;;;;EAOR,MAAA,aAAmB,YAAA;AAAA;;;;;;UAQJ,uBAAA,SAAgC,gBAAA;EAC/C,MAAA;EACA,IAAA;EACA,SAAA;EAEgB;EAAhB,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;;;;;;;iBA0BoB,iBAAA,CACpB,YAAA,EAAc,SAAA,EACd,OAAA,EAAS,uBAAA,EACT,WAAA;EAAe,MAAA;EAAgB,IAAA;EAAc,SAAA;AAAA,GAC7C,cAAA,YACC,OAAA;AALH;;;;;;;;;;;;;;;;AAAA,iBAwDgB,sBAAA,CAAuB,OAAA,EAAS,uBAAA,GAA0B,sBAAA"}
1
+ {"version":3,"file":"middleware-CTnDsST-.d.mts","names":[],"sources":["../src/shared/middleware.ts"],"mappings":";;;;;AAeA;;;;;;;UAAiB,gBAAA;EAgByB;EAdxC,OAAA;EAmB4C;EAjB5C,OAAA;EAwB+B;EAtB/B,MAAA,GAAS,MAAA,SAAe,WAAA;EAJxB;;;;EASA,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAAtC;;;;EAKA,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAAzB;;;;EAKf,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;EAApC;;;;;;EAOR,MAAA,aAAmB,YAAA;AAAA;;;;;;UAQJ,uBAAA,SAAgC,gBAAA;EAC/C,MAAA;EACA,IAAA;EACA,SAAA;EAEgB;EAAhB,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;;;;;;;iBA0BoB,iBAAA,CACpB,YAAA,EAAc,SAAA,EACd,OAAA,EAAS,uBAAA,EACT,WAAA;EAAe,MAAA;EAAgB,IAAA;EAAc,SAAA;AAAA,GAC7C,cAAA,YACC,OAAA;AALH;;;;;;;;;;;;;;;;AAAA,iBAwDgB,sBAAA,CAAuB,OAAA,EAAS,uBAAA,GAA0B,sBAAA"}
@@ -1,4 +1,4 @@
1
- import { C as shouldKeep, E as resolveRedactConfig, T as redactEvent, b as isEnabled, g as createRequestLogger, v as getGlobalDrain } from "./audit-d9esRZOK.mjs";
1
+ import { C as shouldKeep, E as resolveRedactConfig, T as redactEvent, b as isEnabled, g as createRequestLogger, v as getGlobalDrain } from "./audit-DQoBo7Dl.mjs";
2
2
  import { t as extractErrorStatus } from "./errors-BJRXUfMg.mjs";
3
3
  import { n as shouldLog, t as getServiceForPath } from "./routes-CGPmbzCZ.mjs";
4
4
  //#region src/shared/middleware.ts
@@ -120,4 +120,4 @@ function createMiddlewareLogger(options) {
120
120
  //#endregion
121
121
  export { runEnrichAndDrain as n, createMiddlewareLogger as t };
122
122
 
123
- //# sourceMappingURL=middleware-BWOJ7JI0.mjs.map
123
+ //# sourceMappingURL=middleware-oAccqyPp.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"middleware-BWOJ7JI0.mjs","names":[],"sources":["../src/shared/middleware.ts"],"sourcesContent":["import type { DrainContext, EnrichContext, RedactConfig, RequestLogger, RouteConfig, TailSamplingContext, WideEvent } from '../types'\nimport { createRequestLogger, getGlobalDrain, isEnabled, shouldKeep } from '../logger'\nimport { redactEvent, resolveRedactConfig } from '../redact'\nimport { extractErrorStatus } from './errors'\nimport { shouldLog, getServiceForPath } from './routes'\n\n/**\n * Base options shared by all framework integrations.\n *\n * Every framework-specific options interface (e.g. `EvlogExpressOptions`)\n * extends this type. If a framework needs extra fields it can add them\n * on top; otherwise the base is used as-is.\n *\n * @beta Part of `evlog/toolkit` — the public API for building custom integrations.\n */\nexport interface BaseEvlogOptions {\n /** Route patterns to include in logging (glob). If not set, all routes are logged */\n include?: string[]\n /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */\n exclude?: string[]\n /** Route-specific service configuration */\n routes?: Record<string, RouteConfig>\n /**\n * Drain callback called with every emitted event.\n * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.\n */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /**\n * Enrich callback called after emit, before drain.\n * Use to add derived context (geo, deployment info, user agent, etc.).\n */\n enrich?: (ctx: EnrichContext) => void | Promise<void>\n /**\n * Custom tail sampling callback.\n * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.\n */\n keep?: (ctx: TailSamplingContext) => void | Promise<void>\n /**\n * Auto-redaction configuration for PII protection.\n * `true` enables all built-in PII patterns. Pass an object for fine-grained control.\n * Applied before enrich/drain. Also applied at the core `emitWideEvent` level\n * when configured via `initLogger()`.\n */\n redact?: boolean | RedactConfig\n}\n\n/**\n * Internal options consumed by `createMiddlewareLogger`.\n * Extends `BaseEvlogOptions` with the request-specific fields\n * that framework adapters must provide.\n */\nexport interface MiddlewareLoggerOptions extends BaseEvlogOptions {\n method: string\n path: string\n requestId?: string\n /** Pre-filtered safe request headers (used for enrich/drain context) */\n headers?: Record<string, string>\n}\n\nexport interface MiddlewareLoggerResult {\n logger: RequestLogger\n finish: (opts?: { status?: number; error?: Error }) => Promise<WideEvent | null>\n skipped: boolean\n}\n\nconst noopResult: MiddlewareLoggerResult = {\n logger: {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null \n },\n getContext() {\n return {} \n },\n },\n finish: () => Promise.resolve(null),\n skipped: true,\n}\n\n/**\n * Apply redact, enrich, and drain to an emitted wide event — same pipeline as\n * {@link createMiddlewareLogger}'s `finish`.\n *\n * @beta Part of `evlog/toolkit` — used by framework integrations and `fork()`.\n */\nexport async function runEnrichAndDrain(\n emittedEvent: WideEvent,\n options: MiddlewareLoggerOptions,\n requestInfo: { method: string; path: string; requestId?: string },\n responseStatus?: number,\n): Promise<void> {\n const resolvedRedact = resolveRedactConfig(options.redact)\n if (resolvedRedact) {\n redactEvent(emittedEvent, resolvedRedact)\n }\n\n if (options.enrich) {\n const enrichCtx: EnrichContext = {\n event: emittedEvent,\n request: requestInfo,\n headers: options.headers,\n response: { status: responseStatus },\n }\n try {\n await options.enrich(enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n }\n\n const drain = options.drain ?? getGlobalDrain()\n if (drain) {\n const drainCtx: DrainContext = {\n event: emittedEvent,\n request: requestInfo,\n headers: options.headers,\n }\n try {\n await drain(drainCtx)\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n }\n}\n\n/**\n * Create a middleware-aware request logger with full lifecycle management.\n *\n * Handles the complete pipeline shared across all framework integrations:\n * route filtering, logger creation, service overrides, duration tracking,\n * tail sampling evaluation, event emission, enrichment, and draining.\n *\n * Framework adapters only need to:\n * 1. Extract method/path/requestId/headers from the framework request\n * 2. Call `createMiddlewareLogger()` with those + user options\n * 3. Check `skipped` — if true, skip to next middleware\n * 4. Store `logger` in framework-specific context (e.g., `c.set('log', logger)`)\n * 5. Call `finish({ status })` or `finish({ error })` at response end\n *\n * @beta Part of `evlog/toolkit` — the public API for building custom integrations.\n */\nexport function createMiddlewareLogger(options: MiddlewareLoggerOptions): MiddlewareLoggerResult {\n if (!isEnabled()) return noopResult\n\n const { method, path, requestId, include, exclude, routes, keep } = options\n\n if (!shouldLog(path, include, exclude)) {\n return noopResult\n }\n\n const resolvedRequestId = requestId || crypto.randomUUID()\n\n const logger = createRequestLogger({\n method,\n path,\n requestId: resolvedRequestId,\n }, { _deferDrain: true })\n\n const routeService = getServiceForPath(path, routes)\n if (routeService) {\n logger.set({ service: routeService })\n }\n\n const startTime = Date.now()\n const requestInfo = { method, path, requestId: resolvedRequestId }\n\n const finish = async (opts?: { status?: number; error?: Error }): Promise<WideEvent | null> => {\n const { status, error } = opts ?? {}\n\n if (error) {\n logger.error(error)\n const errorStatus = extractErrorStatus(error)\n logger.set({ status: errorStatus })\n } else if (status !== undefined) {\n logger.set({ status })\n }\n\n const durationMs = Date.now() - startTime\n\n const resolvedStatus = error\n ? extractErrorStatus(error)\n : status ?? (logger.getContext().status as number | undefined)\n\n const tailCtx: TailSamplingContext = {\n status: resolvedStatus,\n duration: durationMs,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n\n if (keep) {\n await keep(tailCtx)\n }\n\n const forceKeep = tailCtx.shouldKeep || shouldKeep(tailCtx)\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n\n if (emittedEvent && (options.enrich || options.drain || getGlobalDrain())) {\n await runEnrichAndDrain(emittedEvent, options, requestInfo, resolvedStatus)\n }\n\n return emittedEvent\n }\n\n return { logger, finish, skipped: false }\n}\n"],"mappings":";;;;AAiEA,MAAM,aAAqC;CACzC,QAAQ;EACN,MAAM;EACN,QAAQ;EACR,OAAO;EACP,OAAO;EACP,OAAO;AACL,UAAO;;EAET,aAAa;AACX,UAAO,EAAE;;EAEZ;CACD,cAAc,QAAQ,QAAQ,KAAK;CACnC,SAAS;CACV;;;;;;;AAQD,eAAsB,kBACpB,cACA,SACA,aACA,gBACe;CACf,MAAM,iBAAiB,oBAAoB,QAAQ,OAAO;AAC1D,KAAI,eACF,aAAY,cAAc,eAAe;AAG3C,KAAI,QAAQ,QAAQ;EAClB,MAAM,YAA2B;GAC/B,OAAO;GACP,SAAS;GACT,SAAS,QAAQ;GACjB,UAAU,EAAE,QAAQ,gBAAgB;GACrC;AACD,MAAI;AACF,SAAM,QAAQ,OAAO,UAAU;WACxB,KAAK;AACZ,WAAQ,MAAM,0BAA0B,IAAI;;;CAIhD,MAAM,QAAQ,QAAQ,SAAS,gBAAgB;AAC/C,KAAI,OAAO;EACT,MAAM,WAAyB;GAC7B,OAAO;GACP,SAAS;GACT,SAAS,QAAQ;GAClB;AACD,MAAI;AACF,SAAM,MAAM,SAAS;WACd,KAAK;AACZ,WAAQ,MAAM,yBAAyB,IAAI;;;;;;;;;;;;;;;;;;;;AAqBjD,SAAgB,uBAAuB,SAA0D;AAC/F,KAAI,CAAC,WAAW,CAAE,QAAO;CAEzB,MAAM,EAAE,QAAQ,MAAM,WAAW,SAAS,SAAS,QAAQ,SAAS;AAEpE,KAAI,CAAC,UAAU,MAAM,SAAS,QAAQ,CACpC,QAAO;CAGT,MAAM,oBAAoB,aAAa,OAAO,YAAY;CAE1D,MAAM,SAAS,oBAAoB;EACjC;EACA;EACA,WAAW;EACZ,EAAE,EAAE,aAAa,MAAM,CAAC;CAEzB,MAAM,eAAe,kBAAkB,MAAM,OAAO;AACpD,KAAI,aACF,QAAO,IAAI,EAAE,SAAS,cAAc,CAAC;CAGvC,MAAM,YAAY,KAAK,KAAK;CAC5B,MAAM,cAAc;EAAE;EAAQ;EAAM,WAAW;EAAmB;CAElE,MAAM,SAAS,OAAO,SAAyE;EAC7F,MAAM,EAAE,QAAQ,UAAU,QAAQ,EAAE;AAEpC,MAAI,OAAO;AACT,UAAO,MAAM,MAAM;GACnB,MAAM,cAAc,mBAAmB,MAAM;AAC7C,UAAO,IAAI,EAAE,QAAQ,aAAa,CAAC;aAC1B,WAAW,KAAA,EACpB,QAAO,IAAI,EAAE,QAAQ,CAAC;EAGxB,MAAM,aAAa,KAAK,KAAK,GAAG;EAEhC,MAAM,iBAAiB,QACnB,mBAAmB,MAAM,GACzB,UAAW,OAAO,YAAY,CAAC;EAEnC,MAAM,UAA+B;GACnC,QAAQ;GACR,UAAU;GACV;GACA;GACA,SAAS,OAAO,YAAY;GAC5B,YAAY;GACb;AAED,MAAI,KACF,OAAM,KAAK,QAAQ;EAGrB,MAAM,YAAY,QAAQ,cAAc,WAAW,QAAQ;EAC3D,MAAM,eAAe,OAAO,KAAK,EAAE,YAAY,WAAW,CAAC;AAE3D,MAAI,iBAAiB,QAAQ,UAAU,QAAQ,SAAS,gBAAgB,EACtE,OAAM,kBAAkB,cAAc,SAAS,aAAa,eAAe;AAG7E,SAAO;;AAGT,QAAO;EAAE;EAAQ;EAAQ,SAAS;EAAO"}
1
+ {"version":3,"file":"middleware-oAccqyPp.mjs","names":[],"sources":["../src/shared/middleware.ts"],"sourcesContent":["import type { DrainContext, EnrichContext, RedactConfig, RequestLogger, RouteConfig, TailSamplingContext, WideEvent } from '../types'\nimport { createRequestLogger, getGlobalDrain, isEnabled, shouldKeep } from '../logger'\nimport { redactEvent, resolveRedactConfig } from '../redact'\nimport { extractErrorStatus } from './errors'\nimport { shouldLog, getServiceForPath } from './routes'\n\n/**\n * Base options shared by all framework integrations.\n *\n * Every framework-specific options interface (e.g. `EvlogExpressOptions`)\n * extends this type. If a framework needs extra fields it can add them\n * on top; otherwise the base is used as-is.\n *\n * @beta Part of `evlog/toolkit` — the public API for building custom integrations.\n */\nexport interface BaseEvlogOptions {\n /** Route patterns to include in logging (glob). If not set, all routes are logged */\n include?: string[]\n /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */\n exclude?: string[]\n /** Route-specific service configuration */\n routes?: Record<string, RouteConfig>\n /**\n * Drain callback called with every emitted event.\n * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.\n */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /**\n * Enrich callback called after emit, before drain.\n * Use to add derived context (geo, deployment info, user agent, etc.).\n */\n enrich?: (ctx: EnrichContext) => void | Promise<void>\n /**\n * Custom tail sampling callback.\n * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.\n */\n keep?: (ctx: TailSamplingContext) => void | Promise<void>\n /**\n * Auto-redaction configuration for PII protection.\n * `true` enables all built-in PII patterns. Pass an object for fine-grained control.\n * Applied before enrich/drain. Also applied at the core `emitWideEvent` level\n * when configured via `initLogger()`.\n */\n redact?: boolean | RedactConfig\n}\n\n/**\n * Internal options consumed by `createMiddlewareLogger`.\n * Extends `BaseEvlogOptions` with the request-specific fields\n * that framework adapters must provide.\n */\nexport interface MiddlewareLoggerOptions extends BaseEvlogOptions {\n method: string\n path: string\n requestId?: string\n /** Pre-filtered safe request headers (used for enrich/drain context) */\n headers?: Record<string, string>\n}\n\nexport interface MiddlewareLoggerResult {\n logger: RequestLogger\n finish: (opts?: { status?: number; error?: Error }) => Promise<WideEvent | null>\n skipped: boolean\n}\n\nconst noopResult: MiddlewareLoggerResult = {\n logger: {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null \n },\n getContext() {\n return {} \n },\n },\n finish: () => Promise.resolve(null),\n skipped: true,\n}\n\n/**\n * Apply redact, enrich, and drain to an emitted wide event — same pipeline as\n * {@link createMiddlewareLogger}'s `finish`.\n *\n * @beta Part of `evlog/toolkit` — used by framework integrations and `fork()`.\n */\nexport async function runEnrichAndDrain(\n emittedEvent: WideEvent,\n options: MiddlewareLoggerOptions,\n requestInfo: { method: string; path: string; requestId?: string },\n responseStatus?: number,\n): Promise<void> {\n const resolvedRedact = resolveRedactConfig(options.redact)\n if (resolvedRedact) {\n redactEvent(emittedEvent, resolvedRedact)\n }\n\n if (options.enrich) {\n const enrichCtx: EnrichContext = {\n event: emittedEvent,\n request: requestInfo,\n headers: options.headers,\n response: { status: responseStatus },\n }\n try {\n await options.enrich(enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n }\n\n const drain = options.drain ?? getGlobalDrain()\n if (drain) {\n const drainCtx: DrainContext = {\n event: emittedEvent,\n request: requestInfo,\n headers: options.headers,\n }\n try {\n await drain(drainCtx)\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n }\n}\n\n/**\n * Create a middleware-aware request logger with full lifecycle management.\n *\n * Handles the complete pipeline shared across all framework integrations:\n * route filtering, logger creation, service overrides, duration tracking,\n * tail sampling evaluation, event emission, enrichment, and draining.\n *\n * Framework adapters only need to:\n * 1. Extract method/path/requestId/headers from the framework request\n * 2. Call `createMiddlewareLogger()` with those + user options\n * 3. Check `skipped` — if true, skip to next middleware\n * 4. Store `logger` in framework-specific context (e.g., `c.set('log', logger)`)\n * 5. Call `finish({ status })` or `finish({ error })` at response end\n *\n * @beta Part of `evlog/toolkit` — the public API for building custom integrations.\n */\nexport function createMiddlewareLogger(options: MiddlewareLoggerOptions): MiddlewareLoggerResult {\n if (!isEnabled()) return noopResult\n\n const { method, path, requestId, include, exclude, routes, keep } = options\n\n if (!shouldLog(path, include, exclude)) {\n return noopResult\n }\n\n const resolvedRequestId = requestId || crypto.randomUUID()\n\n const logger = createRequestLogger({\n method,\n path,\n requestId: resolvedRequestId,\n }, { _deferDrain: true })\n\n const routeService = getServiceForPath(path, routes)\n if (routeService) {\n logger.set({ service: routeService })\n }\n\n const startTime = Date.now()\n const requestInfo = { method, path, requestId: resolvedRequestId }\n\n const finish = async (opts?: { status?: number; error?: Error }): Promise<WideEvent | null> => {\n const { status, error } = opts ?? {}\n\n if (error) {\n logger.error(error)\n const errorStatus = extractErrorStatus(error)\n logger.set({ status: errorStatus })\n } else if (status !== undefined) {\n logger.set({ status })\n }\n\n const durationMs = Date.now() - startTime\n\n const resolvedStatus = error\n ? extractErrorStatus(error)\n : status ?? (logger.getContext().status as number | undefined)\n\n const tailCtx: TailSamplingContext = {\n status: resolvedStatus,\n duration: durationMs,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n\n if (keep) {\n await keep(tailCtx)\n }\n\n const forceKeep = tailCtx.shouldKeep || shouldKeep(tailCtx)\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n\n if (emittedEvent && (options.enrich || options.drain || getGlobalDrain())) {\n await runEnrichAndDrain(emittedEvent, options, requestInfo, resolvedStatus)\n }\n\n return emittedEvent\n }\n\n return { logger, finish, skipped: false }\n}\n"],"mappings":";;;;AAiEA,MAAM,aAAqC;CACzC,QAAQ;EACN,MAAM;EACN,QAAQ;EACR,OAAO;EACP,OAAO;EACP,OAAO;AACL,UAAO;;EAET,aAAa;AACX,UAAO,EAAE;;EAEZ;CACD,cAAc,QAAQ,QAAQ,KAAK;CACnC,SAAS;CACV;;;;;;;AAQD,eAAsB,kBACpB,cACA,SACA,aACA,gBACe;CACf,MAAM,iBAAiB,oBAAoB,QAAQ,OAAO;AAC1D,KAAI,eACF,aAAY,cAAc,eAAe;AAG3C,KAAI,QAAQ,QAAQ;EAClB,MAAM,YAA2B;GAC/B,OAAO;GACP,SAAS;GACT,SAAS,QAAQ;GACjB,UAAU,EAAE,QAAQ,gBAAgB;GACrC;AACD,MAAI;AACF,SAAM,QAAQ,OAAO,UAAU;WACxB,KAAK;AACZ,WAAQ,MAAM,0BAA0B,IAAI;;;CAIhD,MAAM,QAAQ,QAAQ,SAAS,gBAAgB;AAC/C,KAAI,OAAO;EACT,MAAM,WAAyB;GAC7B,OAAO;GACP,SAAS;GACT,SAAS,QAAQ;GAClB;AACD,MAAI;AACF,SAAM,MAAM,SAAS;WACd,KAAK;AACZ,WAAQ,MAAM,yBAAyB,IAAI;;;;;;;;;;;;;;;;;;;;AAqBjD,SAAgB,uBAAuB,SAA0D;AAC/F,KAAI,CAAC,WAAW,CAAE,QAAO;CAEzB,MAAM,EAAE,QAAQ,MAAM,WAAW,SAAS,SAAS,QAAQ,SAAS;AAEpE,KAAI,CAAC,UAAU,MAAM,SAAS,QAAQ,CACpC,QAAO;CAGT,MAAM,oBAAoB,aAAa,OAAO,YAAY;CAE1D,MAAM,SAAS,oBAAoB;EACjC;EACA;EACA,WAAW;EACZ,EAAE,EAAE,aAAa,MAAM,CAAC;CAEzB,MAAM,eAAe,kBAAkB,MAAM,OAAO;AACpD,KAAI,aACF,QAAO,IAAI,EAAE,SAAS,cAAc,CAAC;CAGvC,MAAM,YAAY,KAAK,KAAK;CAC5B,MAAM,cAAc;EAAE;EAAQ;EAAM,WAAW;EAAmB;CAElE,MAAM,SAAS,OAAO,SAAyE;EAC7F,MAAM,EAAE,QAAQ,UAAU,QAAQ,EAAE;AAEpC,MAAI,OAAO;AACT,UAAO,MAAM,MAAM;GACnB,MAAM,cAAc,mBAAmB,MAAM;AAC7C,UAAO,IAAI,EAAE,QAAQ,aAAa,CAAC;aAC1B,WAAW,KAAA,EACpB,QAAO,IAAI,EAAE,QAAQ,CAAC;EAGxB,MAAM,aAAa,KAAK,KAAK,GAAG;EAEhC,MAAM,iBAAiB,QACnB,mBAAmB,MAAM,GACzB,UAAW,OAAO,YAAY,CAAC;EAEnC,MAAM,UAA+B;GACnC,QAAQ;GACR,UAAU;GACV;GACA;GACA,SAAS,OAAO,YAAY;GAC5B,YAAY;GACb;AAED,MAAI,KACF,OAAM,KAAK,QAAQ;EAGrB,MAAM,YAAY,QAAQ,cAAc,WAAW,QAAQ;EAC3D,MAAM,eAAe,OAAO,KAAK,EAAE,YAAY,WAAW,CAAC;AAE3D,MAAI,iBAAiB,QAAQ,UAAU,QAAQ,SAAS,gBAAgB,EACtE,OAAM,kBAAkB,cAAc,SAAS,aAAa,eAAe;AAG7E,SAAO;;AAGT,QAAO;EAAE;EAAQ;EAAQ,SAAS;EAAO"}
@@ -1,5 +1,5 @@
1
- import { Y as RequestLogger } from "../audit-mUutdf6A.mjs";
2
- import { t as BaseEvlogOptions } from "../middleware-BYf26Lfu.mjs";
1
+ import { Y as RequestLogger } from "../audit-CTIviX3P.mjs";
2
+ import { t as BaseEvlogOptions } from "../middleware-CTnDsST-.mjs";
3
3
  import { DynamicModule, MiddlewareConsumer, NestModule } from "@nestjs/common";
4
4
 
5
5
  //#region src/nestjs/index.d.ts
@@ -1,5 +1,5 @@
1
- import { t as createMiddlewareLogger } from "../middleware-BWOJ7JI0.mjs";
2
- import { t as attachForkToLogger } from "../fork-CTJXnpl8.mjs";
1
+ import { t as createMiddlewareLogger } from "../middleware-oAccqyPp.mjs";
2
+ import { t as attachForkToLogger } from "../fork-D1j1Fuzy.mjs";
3
3
  import { n as extractSafeNodeHeaders } from "../headers-D74M0wsg.mjs";
4
4
  import { t as createLoggerStorage } from "../storage-CFGTn37X.mjs";
5
5
  //#region src/nestjs/index.ts
@@ -1,4 +1,4 @@
1
- import { W as LogLevel, rt as TransportConfig } from "../audit-mUutdf6A.mjs";
1
+ import { W as LogLevel, rt as TransportConfig } from "../audit-CTIviX3P.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-mUutdf6A.mjs";
2
- import { n as createError } from "../error-D1FZI2Kd.mjs";
3
- import { t as _log } from "../logger-b3epPH0N.mjs";
4
- import { t as BaseEvlogOptions } from "../middleware-BYf26Lfu.mjs";
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";
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-d9esRZOK.mjs";
1
+ import { b as isEnabled, g as createRequestLogger, m as _log, v as getGlobalDrain, x as isLoggerLocked, y as initLogger } from "../audit-DQoBo7Dl.mjs";
2
2
  import { filterSafeHeaders } from "../utils.mjs";
3
3
  import { EvlogError, createError } from "../error.mjs";
4
4
  import { n as shouldLog, t as getServiceForPath } from "../routes-CGPmbzCZ.mjs";
5
- import { t as attachForkToLogger } from "../fork-CTJXnpl8.mjs";
5
+ import { t as attachForkToLogger } from "../fork-D1j1Fuzy.mjs";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
  //#region src/next/storage.ts
8
8
  const evlogStorage = new AsyncLocalStorage();
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/next/storage.ts","../../src/next/handler.ts","../../src/next/middleware.ts","../../src/next/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { RequestLogger } from '../types'\n\nexport const evlogStorage = new AsyncLocalStorage<RequestLogger>()\n\n/**\n * Get the current request-scoped logger.\n * Must be called inside a `withEvlog()` wrapper.\n *\n * @throws {Error} if called outside of `withEvlog()` context\n *\n * @example\n * ```ts\n * export const POST = withEvlog(async (request) => {\n * const log = useLogger()\n * log.set({ user: { id: '123' } })\n * return Response.json({ ok: true })\n * })\n * ```\n */\nexport function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T> {\n const logger = evlogStorage.getStore()\n if (!logger) {\n throw new Error(\n '[evlog] useLogger() was called outside of a withEvlog() context. '\n + 'Wrap your route handler or server action with withEvlog().',\n )\n }\n return logger as RequestLogger<T>\n}\n","import type { DrainContext, EnrichContext, TailSamplingContext, WideEvent } from '../types'\nimport { createRequestLogger, getGlobalDrain, initLogger, isEnabled, isLoggerLocked } from '../logger'\nimport { attachForkToLogger } from '../shared/fork'\nimport type { MiddlewareLoggerOptions } from '../shared/middleware'\nimport { shouldLog, getServiceForPath } from '../shared/routes'\nimport { filterSafeHeaders } from '../utils'\nimport { EvlogError } from '../error'\nimport type { NextEvlogOptions } from './types'\nimport { evlogStorage } from './storage'\n\ninterface WithEvlogState {\n initialized: boolean\n options: NextEvlogOptions\n}\n\nconst state: WithEvlogState = {\n initialized: false,\n options: {},\n}\n\nexport function configureHandler(options: NextEvlogOptions): void {\n state.options = options\n state.initialized = true\n\n // Skip if instrumentation register() already configured the logger.\n // Re-initializing would wipe the global drain.\n if (isLoggerLocked()) return\n\n // Don't pass drain to initLogger — the global drain fires inside emitWideEvent\n // which doesn't have request/header context. Instead, we call drain ourselves\n // in callEnrichAndDrain after enrich, with full context.\n initLogger({\n enabled: options.enabled,\n env: {\n service: options.service,\n ...options.env,\n },\n pretty: options.pretty,\n silent: options.silent,\n sampling: options.sampling,\n minLevel: options.minLevel,\n stringify: options.stringify,\n _suppressDrainWarning: true,\n })\n}\n\nfunction extractRequestInfo(request: Request): { method: string, path: string, headers: Record<string, string> } {\n const { method } = request\n const url = new URL(request.url, 'http://localhost')\n const path = url.pathname\n\n const headers: Record<string, string> = {}\n request.headers.forEach((value, key) => {\n headers[key] = value\n })\n\n return { method, path, headers: filterSafeHeaders(headers) }\n}\n\nasync function callEnrichAndDrain(\n emittedEvent: WideEvent | null,\n requestInfo: { method: string, path: string, requestId: string },\n headers: Record<string, string>,\n responseStatus?: number,\n): Promise<void> {\n if (!emittedEvent) return\n\n const { enrich } = state.options\n const drain = state.options.drain ?? getGlobalDrain()\n\n const run = async () => {\n if (enrich) {\n const enrichCtx: EnrichContext = {\n event: emittedEvent,\n request: requestInfo,\n headers,\n response: { status: responseStatus },\n }\n try {\n await enrich(enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n }\n\n if (drain) {\n const drainCtx: DrainContext = {\n event: emittedEvent,\n request: requestInfo,\n headers,\n }\n try {\n await drain(drainCtx)\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n }\n }\n\n // Use next/server after() if available to run enrich+drain after response\n try {\n const { after } = await import('next/server')\n if (typeof after === 'function') {\n after(run)\n return\n }\n } catch {\n // next/server not available or after() not exported — run inline\n }\n\n // Fallback: fire-and-forget (enrich still awaited for correctness)\n run().catch(() => {})\n}\n\n/**\n * Wrap a Next.js route handler or server action with evlog request-scoped logging.\n *\n * @example\n * ```ts\n * // Route handler\n * export const POST = withEvlog(async (request: NextRequest) => {\n * const log = useLogger()\n * log.set({ user: { id: '123' } })\n * return Response.json({ success: true })\n * })\n *\n * // Server action\n * export const checkout = withEvlog(async (formData: FormData) => {\n * const log = useLogger()\n * log.set({ action: 'checkout' })\n * })\n * ```\n */\nexport function createWithEvlog(options: NextEvlogOptions) {\n configureHandler(options)\n\n return function withEvlog<TArgs extends unknown[], TReturn>(\n handler: (...args: TArgs) => TReturn,\n ): (...args: TArgs) => Promise<Awaited<TReturn>> {\n return async (...args: TArgs): Promise<Awaited<TReturn>> => {\n if (!isEnabled()) {\n return await handler(...args) as Awaited<TReturn>\n }\n\n // Extract request info from first argument if it's a Request\n const [firstArg] = args\n const isRequest = firstArg instanceof Request\n\n let method = 'UNKNOWN'\n let path = '/'\n let headers: Record<string, string> = {}\n let requestId = crypto.randomUUID()\n\n if (isRequest) {\n ({ method, path, headers } = extractRequestInfo(firstArg))\n\n // Reuse request-id from middleware if present\n const middlewareRequestId = firstArg.headers.get('x-request-id')\n if (middlewareRequestId) requestId = middlewareRequestId\n }\n\n // Check include/exclude patterns\n if (!shouldLog(path, state.options.include, state.options.exclude)) {\n return await handler(...args) as Awaited<TReturn>\n }\n\n const logger = createRequestLogger({ method, path, requestId }, { _deferDrain: true })\n\n const middlewareOpts: MiddlewareLoggerOptions = {\n method,\n path,\n requestId,\n headers,\n include: state.options.include,\n exclude: state.options.exclude,\n routes: state.options.routes,\n drain: state.options.drain,\n enrich: state.options.enrich,\n keep: state.options.keep,\n redact: state.options.redact,\n }\n attachForkToLogger(evlogStorage, logger, middlewareOpts)\n\n // Apply route-based service configuration\n const routeService = getServiceForPath(path, state.options.routes)\n if (routeService) {\n logger.set({ service: routeService })\n }\n\n // Apply start time from middleware if present\n if (isRequest) {\n const startHeader = firstArg.headers.get('x-evlog-start')\n if (startHeader) {\n logger.set({ middlewareStart: Number(startHeader) })\n }\n }\n\n try {\n const result = await evlogStorage.run(logger, () => handler(...args))\n\n // Extract response status\n let { status } = { status: 200 }\n if (result instanceof Response) {\n ({ status } = result)\n }\n logger.set({ status })\n\n // Build tail sampling context and call keep callback\n let forceKeep = false\n if (state.options.keep) {\n try {\n const tailCtx: TailSamplingContext = {\n status,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n await state.options.keep(tailCtx)\n forceKeep = tailCtx.shouldKeep ?? false\n } catch (err) {\n console.error('[evlog] keep callback failed:', err)\n }\n }\n\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n await callEnrichAndDrain(emittedEvent, { method, path, requestId }, headers, status)\n\n return result as Awaited<TReturn>\n } catch (error) {\n logger.error(error instanceof Error ? error : new Error(String(error)))\n\n const errorStatus = (error as { status?: number }).status\n ?? (error as { statusCode?: number }).statusCode\n ?? 500\n logger.set({ status: errorStatus })\n\n // Build tail sampling context and call keep callback\n let forceKeep = false\n if (state.options.keep) {\n try {\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n await state.options.keep(tailCtx)\n forceKeep = tailCtx.shouldKeep ?? false\n } catch (err) {\n console.error('[evlog] keep callback failed:', err)\n }\n }\n\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n await callEnrichAndDrain(emittedEvent, { method, path, requestId }, headers, errorStatus)\n\n // Return structured JSON response for EvlogErrors (like H3 does for Nuxt)\n if (isRequest && error instanceof EvlogError) {\n return Response.json(error.toJSON(), { status: error.status }) as Awaited<TReturn>\n }\n\n throw error\n }\n }\n }\n}\n","import { shouldLog } from '../shared/routes'\nimport type { EvlogMiddlewareConfig } from './types'\n\ntype NextRequest = {\n nextUrl: { pathname: string }\n headers: { get(name: string): string | null }\n}\n\ntype NextResponse = {\n headers: { set(name: string, value: string): void }\n}\n\ntype NextResponseStatic = {\n next(options?: { request?: { headers: Headers } }): NextResponse\n}\n\n/**\n * Create an evlog middleware for Next.js.\n * Sets `x-request-id` and `x-evlog-start` headers so `withEvlog()` can reuse them\n * for timing consistency across the middleware -> handler chain.\n *\n * @example\n * ```ts\n * // middleware.ts\n * import { evlogMiddleware } from 'evlog/next'\n * export const middleware = evlogMiddleware()\n * export const config = { matcher: ['/api/:path*'] }\n * ```\n */\nexport function evlogMiddleware(config?: EvlogMiddlewareConfig) {\n return async (request: NextRequest) => {\n const path = request.nextUrl.pathname\n\n // Check include/exclude patterns\n if (!shouldLog(path, config?.include, config?.exclude)) {\n const { NextResponse: nextResponse } = await import('next/server') as { NextResponse: NextResponseStatic }\n return nextResponse.next()\n }\n\n // Generate or reuse request ID\n const existingId = request.headers.get('x-request-id')\n const requestId = existingId || crypto.randomUUID()\n\n // Forward modified headers to the route handler\n const requestHeaders = new Headers(request.headers as HeadersInit)\n\n requestHeaders.set('x-request-id', requestId)\n requestHeaders.set('x-evlog-start', String(Date.now()))\n\n const { NextResponse: nextResponse } = await import('next/server') as { NextResponse: NextResponseStatic }\n const response = nextResponse.next({\n request: { headers: requestHeaders },\n })\n\n // Also set on response for downstream consumers\n response.headers.set('x-request-id', requestId)\n\n return response\n }\n}\n","import { log } from '../logger'\nimport { createError, createEvlogError } from '../error'\nimport type { NextEvlogOptions } from './types'\nimport { createWithEvlog } from './handler'\nimport { useLogger } from './storage'\n\nexport type { NextEvlogOptions, EvlogMiddlewareConfig } from './types'\n\nexport { evlogMiddleware } from './middleware'\nexport { useLogger } from './storage'\nexport { log } from '../logger'\nexport { createError, createEvlogError } from '../error'\n\n/**\n * Create an evlog instance configured for Next.js.\n * Returns all helpers needed for server-side logging.\n *\n * @example\n * ```ts\n * // lib/evlog.ts\n * import { createEvlog } from 'evlog/next'\n * import { createAxiomDrain } from 'evlog/axiom'\n * import { createDrainPipeline } from 'evlog/pipeline'\n *\n * const pipeline = createDrainPipeline({ batch: { size: 50 } })\n *\n * export const { withEvlog, useLogger, log, createEvlogError } = createEvlog({\n * service: 'my-app',\n * sampling: {\n * rates: { info: 10 },\n * keep: [{ status: 400 }, { duration: 1000 }],\n * },\n * drain: pipeline(createAxiomDrain({\n * dataset: 'logs',\n * token: process.env.AXIOM_TOKEN!,\n * })),\n * enrich: (ctx) => {\n * ctx.event.deploymentId = process.env.VERCEL_DEPLOYMENT_ID\n * },\n * })\n * ```\n */\nexport function createEvlog(options: NextEvlogOptions = {}) {\n const withEvlog = createWithEvlog(options)\n\n return {\n withEvlog,\n useLogger,\n log,\n createError,\n createEvlogError,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/next/storage.ts","../../src/next/handler.ts","../../src/next/middleware.ts","../../src/next/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { RequestLogger } from '../types'\n\nexport const evlogStorage = new AsyncLocalStorage<RequestLogger>()\n\n/**\n * Get the current request-scoped logger.\n * Must be called inside a `withEvlog()` wrapper.\n *\n * @throws {Error} if called outside of `withEvlog()` context\n *\n * @example\n * ```ts\n * export const POST = withEvlog(async (request) => {\n * const log = useLogger()\n * log.set({ user: { id: '123' } })\n * return Response.json({ ok: true })\n * })\n * ```\n */\nexport function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T> {\n const logger = evlogStorage.getStore()\n if (!logger) {\n throw new Error(\n '[evlog] useLogger() was called outside of a withEvlog() context. '\n + 'Wrap your route handler or server action with withEvlog().',\n )\n }\n return logger as RequestLogger<T>\n}\n","import type { DrainContext, EnrichContext, TailSamplingContext, WideEvent } from '../types'\nimport { createRequestLogger, getGlobalDrain, initLogger, isEnabled, isLoggerLocked } from '../logger'\nimport { attachForkToLogger } from '../shared/fork'\nimport type { MiddlewareLoggerOptions } from '../shared/middleware'\nimport { shouldLog, getServiceForPath } from '../shared/routes'\nimport { filterSafeHeaders } from '../utils'\nimport { EvlogError } from '../error'\nimport type { NextEvlogOptions } from './types'\nimport { evlogStorage } from './storage'\n\ninterface WithEvlogState {\n initialized: boolean\n options: NextEvlogOptions\n}\n\nconst state: WithEvlogState = {\n initialized: false,\n options: {},\n}\n\nexport function configureHandler(options: NextEvlogOptions): void {\n state.options = options\n state.initialized = true\n\n // Skip if instrumentation register() already configured the logger.\n // Re-initializing would wipe the global drain.\n if (isLoggerLocked()) return\n\n // Don't pass drain to initLogger — the global drain fires inside emitWideEvent\n // which doesn't have request/header context. Instead, we call drain ourselves\n // in callEnrichAndDrain after enrich, with full context.\n initLogger({\n enabled: options.enabled,\n env: {\n service: options.service,\n ...options.env,\n },\n pretty: options.pretty,\n silent: options.silent,\n sampling: options.sampling,\n minLevel: options.minLevel,\n stringify: options.stringify,\n _suppressDrainWarning: true,\n })\n}\n\nfunction extractRequestInfo(request: Request): { method: string, path: string, headers: Record<string, string> } {\n const { method } = request\n const url = new URL(request.url, 'http://localhost')\n const path = url.pathname\n\n const headers: Record<string, string> = {}\n request.headers.forEach((value, key) => {\n headers[key] = value\n })\n\n return { method, path, headers: filterSafeHeaders(headers) }\n}\n\nasync function callEnrichAndDrain(\n emittedEvent: WideEvent | null,\n requestInfo: { method: string, path: string, requestId: string },\n headers: Record<string, string>,\n responseStatus?: number,\n): Promise<void> {\n if (!emittedEvent) return\n\n const { enrich } = state.options\n const drain = state.options.drain ?? getGlobalDrain()\n\n const run = async () => {\n if (enrich) {\n const enrichCtx: EnrichContext = {\n event: emittedEvent,\n request: requestInfo,\n headers,\n response: { status: responseStatus },\n }\n try {\n await enrich(enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n }\n\n if (drain) {\n const drainCtx: DrainContext = {\n event: emittedEvent,\n request: requestInfo,\n headers,\n }\n try {\n await drain(drainCtx)\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n }\n }\n\n // Use next/server after() if available to run enrich+drain after response\n try {\n const { after } = await import('next/server')\n if (typeof after === 'function') {\n after(run)\n return\n }\n } catch {\n // next/server not available or after() not exported — run inline\n }\n\n // Fallback: fire-and-forget (enrich still awaited for correctness)\n run().catch(() => {})\n}\n\n/**\n * Wrap a Next.js route handler or server action with evlog request-scoped logging.\n *\n * @example\n * ```ts\n * // Route handler\n * export const POST = withEvlog(async (request: NextRequest) => {\n * const log = useLogger()\n * log.set({ user: { id: '123' } })\n * return Response.json({ success: true })\n * })\n *\n * // Server action\n * export const checkout = withEvlog(async (formData: FormData) => {\n * const log = useLogger()\n * log.set({ action: 'checkout' })\n * })\n * ```\n */\nexport function createWithEvlog(options: NextEvlogOptions) {\n configureHandler(options)\n\n return function withEvlog<TArgs extends unknown[], TReturn>(\n handler: (...args: TArgs) => TReturn,\n ): (...args: TArgs) => Promise<Awaited<TReturn>> {\n return async (...args: TArgs): Promise<Awaited<TReturn>> => {\n if (!isEnabled()) {\n return await handler(...args) as Awaited<TReturn>\n }\n\n // Extract request info from first argument if it's a Request\n const [firstArg] = args\n const isRequest = firstArg instanceof Request\n\n let method = 'UNKNOWN'\n let path = '/'\n let headers: Record<string, string> = {}\n let requestId = crypto.randomUUID()\n\n if (isRequest) {\n ({ method, path, headers } = extractRequestInfo(firstArg))\n\n // Reuse request-id from middleware if present\n const middlewareRequestId = firstArg.headers.get('x-request-id')\n if (middlewareRequestId) requestId = middlewareRequestId\n }\n\n // Check include/exclude patterns\n if (!shouldLog(path, state.options.include, state.options.exclude)) {\n return await handler(...args) as Awaited<TReturn>\n }\n\n const logger = createRequestLogger({ method, path, requestId }, { _deferDrain: true })\n\n const middlewareOpts: MiddlewareLoggerOptions = {\n method,\n path,\n requestId,\n headers,\n include: state.options.include,\n exclude: state.options.exclude,\n routes: state.options.routes,\n drain: state.options.drain,\n enrich: state.options.enrich,\n keep: state.options.keep,\n redact: state.options.redact,\n }\n attachForkToLogger(evlogStorage, logger, middlewareOpts)\n\n // Apply route-based service configuration\n const routeService = getServiceForPath(path, state.options.routes)\n if (routeService) {\n logger.set({ service: routeService })\n }\n\n // Apply start time from middleware if present\n if (isRequest) {\n const startHeader = firstArg.headers.get('x-evlog-start')\n if (startHeader) {\n logger.set({ middlewareStart: Number(startHeader) })\n }\n }\n\n try {\n const result = await evlogStorage.run(logger, () => handler(...args))\n\n // Extract response status\n let { status } = { status: 200 }\n if (result instanceof Response) {\n ({ status } = result)\n }\n logger.set({ status })\n\n // Build tail sampling context and call keep callback\n let forceKeep = false\n if (state.options.keep) {\n try {\n const tailCtx: TailSamplingContext = {\n status,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n await state.options.keep(tailCtx)\n forceKeep = tailCtx.shouldKeep ?? false\n } catch (err) {\n console.error('[evlog] keep callback failed:', err)\n }\n }\n\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n await callEnrichAndDrain(emittedEvent, { method, path, requestId }, headers, status)\n\n return result as Awaited<TReturn>\n } catch (error) {\n logger.error(error instanceof Error ? error : new Error(String(error)))\n\n const errorStatus = (error as { status?: number }).status\n ?? (error as { statusCode?: number }).statusCode\n ?? 500\n logger.set({ status: errorStatus })\n\n // Build tail sampling context and call keep callback\n let forceKeep = false\n if (state.options.keep) {\n try {\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n await state.options.keep(tailCtx)\n forceKeep = tailCtx.shouldKeep ?? false\n } catch (err) {\n console.error('[evlog] keep callback failed:', err)\n }\n }\n\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n await callEnrichAndDrain(emittedEvent, { method, path, requestId }, headers, errorStatus)\n\n // Return structured JSON response for EvlogErrors (like H3 does for Nuxt)\n if (isRequest && error instanceof EvlogError) {\n return Response.json(error.toJSON(), { status: error.status }) as Awaited<TReturn>\n }\n\n throw error\n }\n }\n }\n}\n","import { shouldLog } from '../shared/routes'\nimport type { EvlogMiddlewareConfig } from './types'\n\ntype NextRequest = {\n nextUrl: { pathname: string }\n headers: { get(name: string): string | null }\n}\n\ntype NextResponse = {\n headers: { set(name: string, value: string): void }\n}\n\ntype NextResponseStatic = {\n next(options?: { request?: { headers: Headers } }): NextResponse\n}\n\n/**\n * Create an evlog middleware for Next.js.\n * Sets `x-request-id` and `x-evlog-start` headers so `withEvlog()` can reuse them\n * for timing consistency across the middleware -> handler chain.\n *\n * @example\n * ```ts\n * // middleware.ts\n * import { evlogMiddleware } from 'evlog/next'\n * export const middleware = evlogMiddleware()\n * export const config = { matcher: ['/api/:path*'] }\n * ```\n */\nexport function evlogMiddleware(config?: EvlogMiddlewareConfig) {\n return async (request: NextRequest) => {\n const path = request.nextUrl.pathname\n\n // Check include/exclude patterns\n if (!shouldLog(path, config?.include, config?.exclude)) {\n const { NextResponse: nextResponse } = await import('next/server') as { NextResponse: NextResponseStatic }\n return nextResponse.next()\n }\n\n // Generate or reuse request ID\n const existingId = request.headers.get('x-request-id')\n const requestId = existingId || crypto.randomUUID()\n\n // Forward modified headers to the route handler\n const requestHeaders = new Headers(request.headers as HeadersInit)\n\n requestHeaders.set('x-request-id', requestId)\n requestHeaders.set('x-evlog-start', String(Date.now()))\n\n const { NextResponse: nextResponse } = await import('next/server') as { NextResponse: NextResponseStatic }\n const response = nextResponse.next({\n request: { headers: requestHeaders },\n })\n\n // Also set on response for downstream consumers\n response.headers.set('x-request-id', requestId)\n\n return response\n }\n}\n","import { log } from '../logger'\nimport { createError, createEvlogError } from '../error'\nimport type { NextEvlogOptions } from './types'\nimport { createWithEvlog } from './handler'\nimport { useLogger } from './storage'\n\nexport type { NextEvlogOptions, EvlogMiddlewareConfig } from './types'\n\nexport { evlogMiddleware } from './middleware'\nexport { useLogger } from './storage'\nexport { log } from '../logger'\nexport { createError, createEvlogError } from '../error'\n\n/**\n * Create an evlog instance configured for Next.js.\n * Returns all helpers needed for server-side logging.\n *\n * @example\n * ```ts\n * // lib/evlog.ts\n * import { createEvlog } from 'evlog/next'\n * import { createAxiomDrain } from 'evlog/axiom'\n * import { createDrainPipeline } from 'evlog/pipeline'\n *\n * const pipeline = createDrainPipeline({ batch: { size: 50 } })\n *\n * export const { withEvlog, useLogger, log, createEvlogError } = createEvlog({\n * service: 'my-app',\n * sampling: {\n * rates: { info: 10 },\n * keep: [{ status: 400 }, { duration: 1000 }],\n * },\n * drain: pipeline(createAxiomDrain({\n * dataset: 'logs',\n * token: process.env.AXIOM_TOKEN!,\n * })),\n * enrich: (ctx) => {\n * ctx.event.deploymentId = process.env.VERCEL_DEPLOYMENT_ID\n * },\n * })\n * ```\n */\nexport function createEvlog(options: NextEvlogOptions = {}) {\n const withEvlog = createWithEvlog(options)\n\n return {\n withEvlog,\n useLogger,\n log,\n createError,\n createEvlogError,\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { F as DrainContext, L as EnvironmentContext, Q as SamplingConfig, W as LogLevel } from "../audit-mUutdf6A.mjs";
1
+ import { F as DrainContext, L as EnvironmentContext, Q as SamplingConfig, W as LogLevel } from "../audit-CTIviX3P.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-d9esRZOK.mjs";
1
+ import { S as lockLogger, m as _log, y as initLogger } from "../audit-DQoBo7Dl.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 +1 @@
1
- {"version":3,"file":"instrumentation.mjs","names":[],"sources":["../../src/next/instrumentation.ts"],"sourcesContent":["import type { DrainContext, EnvironmentContext, LogLevel, SamplingConfig } from '../types'\nimport { initLogger, log, lockLogger } from '../logger'\n\n/** Request payload passed to Next.js `onRequestError` (App Router). */\nexport interface NextInstrumentationRequest {\n path: string\n method: string\n headers: Record<string, string>\n}\n\n/** Routing context passed to Next.js `onRequestError`. */\nexport interface NextInstrumentationErrorContext {\n routerKind: string\n routePath: string\n routeType: string\n renderSource: string\n}\n\n/**\n * What `lib/evlog.ts` should export for use with {@link defineNodeInstrumentation}\n * (typically the return values of `createInstrumentation()`).\n */\nexport interface NodeInstrumentationModule {\n register: () => void | Promise<void>\n onRequestError: (\n error: { digest?: string } & Error,\n request: NextInstrumentationRequest,\n context: NextInstrumentationErrorContext,\n ) => void | Promise<void>\n}\n\n/**\n * Root `instrumentation.ts` entry: load your real config only in the Node.js runtime so Edge\n * bundles never pull Node-only drains/adapters. Caches the dynamic `import()` so `register` and\n * repeated `onRequestError` calls share one module instance (avoids re-importing on every error).\n *\n * @example\n * ```ts\n * // instrumentation.ts\n * import { defineNodeInstrumentation } from 'evlog/next/instrumentation'\n *\n * export const { register, onRequestError } = defineNodeInstrumentation(() => import('./lib/evlog'))\n * ```\n */\nexport function defineNodeInstrumentation(loader: () => Promise<NodeInstrumentationModule>) {\n let cached: Promise<NodeInstrumentationModule> | undefined\n\n function load(): Promise<NodeInstrumentationModule> {\n cached ??= loader()\n return cached\n }\n\n return {\n async register() {\n if (process.env.NEXT_RUNTIME !== 'nodejs') return\n const mod = await load()\n await mod.register()\n },\n async onRequestError(\n error: { digest?: string } & Error,\n request: NextInstrumentationRequest,\n context: NextInstrumentationErrorContext,\n ) {\n if (process.env.NEXT_RUNTIME !== 'nodejs') return\n const mod = await load()\n await mod.onRequestError(error, request, context)\n },\n }\n}\n\nexport interface InstrumentationOptions {\n /** Enable or disable all logging globally. @default true */\n enabled?: boolean\n /** Service name for all logged events. */\n service?: string\n /** Environment context overrides. */\n env?: Partial<EnvironmentContext>\n /** Enable pretty printing. @default true in development */\n pretty?: boolean\n /** Suppress built-in console output. @default false */\n silent?: boolean\n /** Sampling configuration for filtering logs. */\n sampling?: SamplingConfig\n /** Minimum severity for the global `log` API. @default 'debug' */\n minLevel?: LogLevel\n /** When pretty is disabled, emit JSON strings or raw objects. @default true */\n stringify?: boolean\n /** Drain callback called with every emitted event. */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /** Capture stdout/stderr output as log events (Node.js only). */\n captureOutput?: boolean\n}\n\ninterface InstrumentationResult {\n register: () => void\n onRequestError: (\n error: { digest?: string } & Error,\n request: NextInstrumentationRequest,\n context: NextInstrumentationErrorContext,\n ) => void\n}\n\nlet patching = false\n\nexport function createInstrumentation(options: InstrumentationOptions = {}): InstrumentationResult {\n let registered = false\n\n function register(): void {\n if (registered) return\n registered = true\n\n initLogger({\n enabled: options.enabled,\n env: {\n service: options.service,\n ...options.env,\n },\n pretty: options.pretty,\n silent: options.silent,\n sampling: options.sampling,\n minLevel: options.minLevel,\n stringify: options.stringify,\n drain: options.drain,\n })\n lockLogger()\n\n if (options.captureOutput && process.env.NEXT_RUNTIME === 'nodejs') {\n patchOutput()\n }\n }\n\n function patchOutput(): void {\n const proc = globalThis.process\n const originalStdoutWrite = proc.stdout.write.bind(proc.stdout)\n const originalStderrWrite = proc.stderr.write.bind(proc.stderr)\n\n proc.stdout.write = function(chunk: unknown, ...args: unknown[]): boolean {\n if (!patching) {\n patching = true\n try {\n log.info({ source: 'stdout', message: String(chunk).trimEnd() })\n } finally {\n patching = false\n }\n }\n return originalStdoutWrite(chunk, ...args as [])\n } as typeof process.stdout.write\n\n proc.stderr.write = function(chunk: unknown, ...args: unknown[]): boolean {\n if (!patching) {\n patching = true\n try {\n log.error({ source: 'stderr', message: String(chunk).trimEnd() })\n } finally {\n patching = false\n }\n }\n return originalStderrWrite(chunk, ...args as [])\n } as typeof process.stderr.write\n }\n\n function onRequestError(\n error: { digest?: string } & Error,\n request: { path: string; method: string; headers: Record<string, string> },\n context: { routerKind: string; routePath: string; routeType: string; renderSource: string },\n ): void {\n log.error({\n message: error.message,\n digest: error.digest,\n stack: error.stack,\n path: request.path,\n method: request.method,\n routerKind: context.routerKind,\n routePath: context.routePath,\n routeType: context.routeType,\n renderSource: context.renderSource,\n })\n }\n\n return { register, onRequestError }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4CA,SAAgB,0BAA0B,QAAkD;CAC1F,IAAI;CAEJ,SAAS,OAA2C;AAClD,aAAW,QAAQ;AACnB,SAAO;;AAGT,QAAO;EACL,MAAM,WAAW;AACf,OAAI,QAAQ,IAAI,iBAAiB,SAAU;AAE3C,UADY,MAAM,MAAM,EACd,UAAU;;EAEtB,MAAM,eACJ,OACA,SACA,SACA;AACA,OAAI,QAAQ,IAAI,iBAAiB,SAAU;AAE3C,UADY,MAAM,MAAM,EACd,eAAe,OAAO,SAAS,QAAQ;;EAEpD;;AAmCH,IAAI,WAAW;AAEf,SAAgB,sBAAsB,UAAkC,EAAE,EAAyB;CACjG,IAAI,aAAa;CAEjB,SAAS,WAAiB;AACxB,MAAI,WAAY;AAChB,eAAa;AAEb,aAAW;GACT,SAAS,QAAQ;GACjB,KAAK;IACH,SAAS,QAAQ;IACjB,GAAG,QAAQ;IACZ;GACD,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB,UAAU,QAAQ;GAClB,UAAU,QAAQ;GAClB,WAAW,QAAQ;GACnB,OAAO,QAAQ;GAChB,CAAC;AACF,cAAY;AAEZ,MAAI,QAAQ,iBAAiB,QAAQ,IAAI,iBAAiB,SACxD,cAAa;;CAIjB,SAAS,cAAoB;EAC3B,MAAM,OAAO,WAAW;EACxB,MAAM,sBAAsB,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO;EAC/D,MAAM,sBAAsB,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO;AAE/D,OAAK,OAAO,QAAQ,SAAS,OAAgB,GAAG,MAA0B;AACxE,OAAI,CAAC,UAAU;AACb,eAAW;AACX,QAAI;AACF,UAAI,KAAK;MAAE,QAAQ;MAAU,SAAS,OAAO,MAAM,CAAC,SAAS;MAAE,CAAC;cACxD;AACR,gBAAW;;;AAGf,UAAO,oBAAoB,OAAO,GAAG,KAAW;;AAGlD,OAAK,OAAO,QAAQ,SAAS,OAAgB,GAAG,MAA0B;AACxE,OAAI,CAAC,UAAU;AACb,eAAW;AACX,QAAI;AACF,UAAI,MAAM;MAAE,QAAQ;MAAU,SAAS,OAAO,MAAM,CAAC,SAAS;MAAE,CAAC;cACzD;AACR,gBAAW;;;AAGf,UAAO,oBAAoB,OAAO,GAAG,KAAW;;;CAIpD,SAAS,eACP,OACA,SACA,SACM;AACN,OAAI,MAAM;GACR,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,OAAO,MAAM;GACb,MAAM,QAAQ;GACd,QAAQ,QAAQ;GAChB,YAAY,QAAQ;GACpB,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACnB,cAAc,QAAQ;GACvB,CAAC;;AAGJ,QAAO;EAAE;EAAU;EAAgB"}
1
+ {"version":3,"file":"instrumentation.mjs","names":[],"sources":["../../src/next/instrumentation.ts"],"sourcesContent":["import type { DrainContext, EnvironmentContext, LogLevel, SamplingConfig } from '../types'\nimport { initLogger, log, lockLogger } from '../logger'\n\n/** Request payload passed to Next.js `onRequestError` (App Router). */\nexport interface NextInstrumentationRequest {\n path: string\n method: string\n headers: Record<string, string>\n}\n\n/** Routing context passed to Next.js `onRequestError`. */\nexport interface NextInstrumentationErrorContext {\n routerKind: string\n routePath: string\n routeType: string\n renderSource: string\n}\n\n/**\n * What `lib/evlog.ts` should export for use with {@link defineNodeInstrumentation}\n * (typically the return values of `createInstrumentation()`).\n */\nexport interface NodeInstrumentationModule {\n register: () => void | Promise<void>\n onRequestError: (\n error: { digest?: string } & Error,\n request: NextInstrumentationRequest,\n context: NextInstrumentationErrorContext,\n ) => void | Promise<void>\n}\n\n/**\n * Root `instrumentation.ts` entry: load your real config only in the Node.js runtime so Edge\n * bundles never pull Node-only drains/adapters. Caches the dynamic `import()` so `register` and\n * repeated `onRequestError` calls share one module instance (avoids re-importing on every error).\n *\n * @example\n * ```ts\n * // instrumentation.ts\n * import { defineNodeInstrumentation } from 'evlog/next/instrumentation'\n *\n * export const { register, onRequestError } = defineNodeInstrumentation(() => import('./lib/evlog'))\n * ```\n */\nexport function defineNodeInstrumentation(loader: () => Promise<NodeInstrumentationModule>) {\n let cached: Promise<NodeInstrumentationModule> | undefined\n\n function load(): Promise<NodeInstrumentationModule> {\n cached ??= loader()\n return cached\n }\n\n return {\n async register() {\n if (process.env.NEXT_RUNTIME !== 'nodejs') return\n const mod = await load()\n await mod.register()\n },\n async onRequestError(\n error: { digest?: string } & Error,\n request: NextInstrumentationRequest,\n context: NextInstrumentationErrorContext,\n ) {\n if (process.env.NEXT_RUNTIME !== 'nodejs') return\n const mod = await load()\n await mod.onRequestError(error, request, context)\n },\n }\n}\n\nexport interface InstrumentationOptions {\n /** Enable or disable all logging globally. @default true */\n enabled?: boolean\n /** Service name for all logged events. */\n service?: string\n /** Environment context overrides. */\n env?: Partial<EnvironmentContext>\n /** Enable pretty printing. @default true in development */\n pretty?: boolean\n /** Suppress built-in console output. @default false */\n silent?: boolean\n /** Sampling configuration for filtering logs. */\n sampling?: SamplingConfig\n /** Minimum severity for the global `log` API. @default 'debug' */\n minLevel?: LogLevel\n /** When pretty is disabled, emit JSON strings or raw objects. @default true */\n stringify?: boolean\n /** Drain callback called with every emitted event. */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /** Capture stdout/stderr output as log events (Node.js only). */\n captureOutput?: boolean\n}\n\ninterface InstrumentationResult {\n register: () => void\n onRequestError: (\n error: { digest?: string } & Error,\n request: NextInstrumentationRequest,\n context: NextInstrumentationErrorContext,\n ) => void\n}\n\nlet patching = false\n\nexport function createInstrumentation(options: InstrumentationOptions = {}): InstrumentationResult {\n let registered = false\n\n function register(): void {\n if (registered) return\n registered = true\n\n initLogger({\n enabled: options.enabled,\n env: {\n service: options.service,\n ...options.env,\n },\n pretty: options.pretty,\n silent: options.silent,\n sampling: options.sampling,\n minLevel: options.minLevel,\n stringify: options.stringify,\n drain: options.drain,\n })\n lockLogger()\n\n if (options.captureOutput && process.env.NEXT_RUNTIME === 'nodejs') {\n patchOutput()\n }\n }\n\n function patchOutput(): void {\n const proc = globalThis.process\n const originalStdoutWrite = proc.stdout.write.bind(proc.stdout)\n const originalStderrWrite = proc.stderr.write.bind(proc.stderr)\n\n proc.stdout.write = function(chunk: unknown, ...args: unknown[]): boolean {\n if (!patching) {\n patching = true\n try {\n log.info({ source: 'stdout', message: String(chunk).trimEnd() })\n } finally {\n patching = false\n }\n }\n return originalStdoutWrite(chunk, ...args as [])\n } as typeof process.stdout.write\n\n proc.stderr.write = function(chunk: unknown, ...args: unknown[]): boolean {\n if (!patching) {\n patching = true\n try {\n log.error({ source: 'stderr', message: String(chunk).trimEnd() })\n } finally {\n patching = false\n }\n }\n return originalStderrWrite(chunk, ...args as [])\n } as typeof process.stderr.write\n }\n\n function onRequestError(\n error: { digest?: string } & Error,\n request: { path: string; method: string; headers: Record<string, string> },\n context: { routerKind: string; routePath: string; routeType: string; renderSource: string },\n ): void {\n log.error({\n message: error.message,\n digest: error.digest,\n stack: error.stack,\n path: request.path,\n method: request.method,\n routerKind: context.routerKind,\n routePath: context.routePath,\n routeType: context.routeType,\n renderSource: context.renderSource,\n })\n }\n\n return { register, onRequestError }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4CA,SAAgB,0BAA0B,QAAkD;CAC1F,IAAI;CAEJ,SAAS,OAA2C;AAClD,aAAW,QAAQ;AACnB,SAAO;;AAGT,QAAO;EACL,MAAM,WAAW;AACf,OAAI,QAAQ,IAAI,iBAAiB,SAAU;AAE3C,UAAM,MADY,MAAM,EACd,UAAU;;EAEtB,MAAM,eACJ,OACA,SACA,SACA;AACA,OAAI,QAAQ,IAAI,iBAAiB,SAAU;AAE3C,UAAM,MADY,MAAM,EACd,eAAe,OAAO,SAAS,QAAQ;;EAEpD;;AAmCH,IAAI,WAAW;AAEf,SAAgB,sBAAsB,UAAkC,EAAE,EAAyB;CACjG,IAAI,aAAa;CAEjB,SAAS,WAAiB;AACxB,MAAI,WAAY;AAChB,eAAa;AAEb,aAAW;GACT,SAAS,QAAQ;GACjB,KAAK;IACH,SAAS,QAAQ;IACjB,GAAG,QAAQ;IACZ;GACD,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB,UAAU,QAAQ;GAClB,UAAU,QAAQ;GAClB,WAAW,QAAQ;GACnB,OAAO,QAAQ;GAChB,CAAC;AACF,cAAY;AAEZ,MAAI,QAAQ,iBAAiB,QAAQ,IAAI,iBAAiB,SACxD,cAAa;;CAIjB,SAAS,cAAoB;EAC3B,MAAM,OAAO,WAAW;EACxB,MAAM,sBAAsB,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO;EAC/D,MAAM,sBAAsB,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO;AAE/D,OAAK,OAAO,QAAQ,SAAS,OAAgB,GAAG,MAA0B;AACxE,OAAI,CAAC,UAAU;AACb,eAAW;AACX,QAAI;AACF,UAAI,KAAK;MAAE,QAAQ;MAAU,SAAS,OAAO,MAAM,CAAC,SAAS;MAAE,CAAC;cACxD;AACR,gBAAW;;;AAGf,UAAO,oBAAoB,OAAO,GAAG,KAAW;;AAGlD,OAAK,OAAO,QAAQ,SAAS,OAAgB,GAAG,MAA0B;AACxE,OAAI,CAAC,UAAU;AACb,eAAW;AACX,QAAI;AACF,UAAI,MAAM;MAAE,QAAQ;MAAU,SAAS,OAAO,MAAM,CAAC,SAAS;MAAE,CAAC;cACzD;AACR,gBAAW;;;AAGf,UAAO,oBAAoB,OAAO,GAAG,KAAW;;;CAIpD,SAAS,eACP,OACA,SACA,SACM;AACN,OAAI,MAAM;GACR,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,OAAO,MAAM;GACb,MAAM,QAAQ;GACd,QAAQ,QAAQ;GAChB,YAAY,QAAQ;GACpB,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACnB,cAAc,QAAQ;GACvB,CAAC;;AAGJ,QAAO;EAAE;EAAU;EAAgB"}