evlog 2.18.1 → 2.19.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 (223) hide show
  1. package/README.md +14 -16
  2. package/dist/adapters/axiom.d.mts +3 -3
  3. package/dist/adapters/axiom.d.mts.map +1 -1
  4. package/dist/adapters/axiom.mjs +10 -14
  5. package/dist/adapters/axiom.mjs.map +1 -1
  6. package/dist/adapters/better-stack.d.mts +2 -2
  7. package/dist/adapters/better-stack.d.mts.map +1 -1
  8. package/dist/adapters/better-stack.mjs +9 -13
  9. package/dist/adapters/better-stack.mjs.map +1 -1
  10. package/dist/adapters/datadog.d.mts +3 -3
  11. package/dist/adapters/datadog.mjs +9 -5
  12. package/dist/adapters/datadog.mjs.map +1 -1
  13. package/dist/adapters/fs.d.mts +1 -1
  14. package/dist/adapters/fs.d.mts.map +1 -1
  15. package/dist/adapters/fs.mjs +15 -2
  16. package/dist/adapters/fs.mjs.map +1 -1
  17. package/dist/adapters/hyperdx.d.mts +2 -2
  18. package/dist/adapters/hyperdx.mjs +3 -3
  19. package/dist/adapters/hyperdx.mjs.map +1 -1
  20. package/dist/adapters/memory.d.mts +2 -3
  21. package/dist/adapters/memory.d.mts.map +1 -1
  22. package/dist/adapters/memory.mjs +2 -3
  23. package/dist/adapters/memory.mjs.map +1 -1
  24. package/dist/adapters/otlp.d.mts +4 -4
  25. package/dist/adapters/otlp.mjs +19 -11
  26. package/dist/adapters/otlp.mjs.map +1 -1
  27. package/dist/adapters/posthog.d.mts +2 -2
  28. package/dist/adapters/posthog.mjs +5 -5
  29. package/dist/adapters/posthog.mjs.map +1 -1
  30. package/dist/adapters/sentry.d.mts +3 -3
  31. package/dist/adapters/sentry.mjs +6 -6
  32. package/dist/adapters/sentry.mjs.map +1 -1
  33. package/dist/ai/index.d.mts +1 -1
  34. package/dist/{audit-BUI3af4w.mjs → audit-BQt8yAHo.mjs} +376 -116
  35. package/dist/audit-BQt8yAHo.mjs.map +1 -0
  36. package/dist/{audit-DVdkntSO.d.mts → audit-D7v6JHj0.d.mts} +113 -35
  37. package/dist/audit-D7v6JHj0.d.mts.map +1 -0
  38. package/dist/better-auth/index.d.mts +1 -1
  39. package/dist/browser.d.mts +1 -1
  40. package/dist/deferred-drain-jeajC8QF.mjs +36 -0
  41. package/dist/deferred-drain-jeajC8QF.mjs.map +1 -0
  42. package/dist/{define-D6OJdSUH.mjs → define-Bpaymi-h.mjs} +2 -1
  43. package/dist/define-Bpaymi-h.mjs.map +1 -0
  44. package/dist/{define-D-BVMf2l.d.mts → define-DTQpu4f6.d.mts} +8 -3
  45. package/dist/define-DTQpu4f6.d.mts.map +1 -0
  46. package/dist/dev-terminal-D4UaEm17.mjs +54 -0
  47. package/dist/dev-terminal-D4UaEm17.mjs.map +1 -0
  48. package/dist/{dist-H3GIh-KK.mjs → dist-DdQWiZn8.mjs} +1 -1
  49. package/dist/{dist-H3GIh-KK.mjs.map → dist-DdQWiZn8.mjs.map} +1 -1
  50. package/dist/{drain-7n3K6kPe.mjs → drain-fDb-eNwz.mjs} +35 -4
  51. package/dist/drain-fDb-eNwz.mjs.map +1 -0
  52. package/dist/elysia/index.d.mts +3 -3
  53. package/dist/elysia/index.d.mts.map +1 -1
  54. package/dist/elysia/index.mjs +8 -5
  55. package/dist/elysia/index.mjs.map +1 -1
  56. package/dist/enrich-error-stack-next.node-Dgm_rCf5.mjs +120 -0
  57. package/dist/enrich-error-stack-next.node-Dgm_rCf5.mjs.map +1 -0
  58. package/dist/{enricher-UW9npoB2.d.mts → enricher-CBRmQw6e.d.mts} +2 -2
  59. package/dist/{enricher-UW9npoB2.d.mts.map → enricher-CBRmQw6e.d.mts.map} +1 -1
  60. package/dist/{enricher-N0erZS87.mjs → enricher-DAWf2-Fx.mjs} +2 -2
  61. package/dist/{enricher-N0erZS87.mjs.map → enricher-DAWf2-Fx.mjs.map} +1 -1
  62. package/dist/enrichers.d.mts +2 -2
  63. package/dist/enrichers.mjs +2 -2
  64. package/dist/{error-CVtn5U7b.d.mts → error-CpghjrkY.d.mts} +2 -2
  65. package/dist/{error-CVtn5U7b.d.mts.map → error-CpghjrkY.d.mts.map} +1 -1
  66. package/dist/error.d.mts +1 -1
  67. package/dist/{errors-dEMNQCiL.d.mts → errors-BLU4Tfpe.d.mts} +2 -2
  68. package/dist/{errors-dEMNQCiL.d.mts.map → errors-BLU4Tfpe.d.mts.map} +1 -1
  69. package/dist/{errors-BQgyQ9xe.mjs → errors-DA0cyr8q.mjs} +1 -1
  70. package/dist/{errors-BQgyQ9xe.mjs.map → errors-DA0cyr8q.mjs.map} +1 -1
  71. package/dist/{event-1BMl7o0k.mjs → event-qwAv-7AZ.mjs} +1 -1
  72. package/dist/{event-1BMl7o0k.mjs.map → event-qwAv-7AZ.mjs.map} +1 -1
  73. package/dist/express/index.d.mts +2 -2
  74. package/dist/express/index.mjs +3 -3
  75. package/dist/fastify/index.d.mts +2 -2
  76. package/dist/fastify/index.mjs +2 -2
  77. package/dist/{fork-Bga8x-X4.mjs → fork-CgGlAaHa.mjs} +39 -14
  78. package/dist/fork-CgGlAaHa.mjs.map +1 -0
  79. package/dist/{headers-CU-QqnYg.mjs → headers-VtmnWcfn.mjs} +1 -1
  80. package/dist/{headers-CU-QqnYg.mjs.map → headers-VtmnWcfn.mjs.map} +1 -1
  81. package/dist/hono/index.d.mts +2 -2
  82. package/dist/hono/index.d.mts.map +1 -1
  83. package/dist/hono/index.mjs +10 -2
  84. package/dist/hono/index.mjs.map +1 -1
  85. package/dist/{http-B6YgAhyN.mjs → http-ChVS9GYc.mjs} +2 -2
  86. package/dist/{http-B6YgAhyN.mjs.map → http-ChVS9GYc.mjs.map} +1 -1
  87. package/dist/http.d.mts +1 -1
  88. package/dist/{index-ZSRQP_BI.d.mts → index-EvnrXvQM.d.mts} +15 -8
  89. package/dist/index-EvnrXvQM.d.mts.map +1 -0
  90. package/dist/index.d.mts +9 -9
  91. package/dist/index.mjs +9 -15
  92. package/dist/index.mjs.map +1 -1
  93. package/dist/instrumentation-create-BrjQtSKD.d.mts +115 -0
  94. package/dist/instrumentation-create-BrjQtSKD.d.mts.map +1 -0
  95. package/dist/{integration-Dhig7ae6.mjs → integration-DYp2uw8O.mjs} +3 -3
  96. package/dist/{integration-Dhig7ae6.mjs.map → integration-DYp2uw8O.mjs.map} +1 -1
  97. package/dist/{logger-CTcvd5Cc.d.mts → logger-mHIWxBhJ.d.mts} +12 -4
  98. package/dist/logger-mHIWxBhJ.d.mts.map +1 -0
  99. package/dist/logger.d.mts +2 -2
  100. package/dist/logger.mjs +2 -2
  101. package/dist/{middleware-31KhtiEF.d.mts → middleware-B_k4Mrzg.d.mts} +9 -2
  102. package/dist/middleware-B_k4Mrzg.d.mts.map +1 -0
  103. package/dist/nestjs/index.d.mts +2 -2
  104. package/dist/nestjs/index.mjs +4 -4
  105. package/dist/next/client.d.mts +1 -1
  106. package/dist/next/index.d.mts +4 -4
  107. package/dist/next/index.d.mts.map +1 -1
  108. package/dist/next/index.mjs +49 -38
  109. package/dist/next/index.mjs.map +1 -1
  110. package/dist/next/instrumentation/create.d.mts +2 -0
  111. package/dist/next/instrumentation/create.mjs +155 -0
  112. package/dist/next/instrumentation/create.mjs.map +1 -0
  113. package/dist/next/instrumentation.d.mts +2 -77
  114. package/dist/next/instrumentation.mjs +32 -81
  115. package/dist/next/instrumentation.mjs.map +1 -1
  116. package/dist/next/stream.d.mts +1 -1
  117. package/dist/next/stream.mjs +2 -2
  118. package/dist/next/stream.mjs.map +1 -1
  119. package/dist/nitro/errorHandler.mjs +23 -18
  120. package/dist/nitro/errorHandler.mjs.map +1 -1
  121. package/dist/nitro/module.d.mts +2 -2
  122. package/dist/nitro/module.d.mts.map +1 -1
  123. package/dist/nitro/module.mjs +2 -1
  124. package/dist/nitro/module.mjs.map +1 -1
  125. package/dist/nitro/plugin.mjs +74 -18
  126. package/dist/nitro/plugin.mjs.map +1 -1
  127. package/dist/nitro/v3/errorHandler.d.mts +0 -7
  128. package/dist/nitro/v3/errorHandler.mjs +13 -15
  129. package/dist/nitro/v3/errorHandler.mjs.map +1 -1
  130. package/dist/nitro/v3/index.d.mts +2 -2
  131. package/dist/nitro/v3/module.d.mts +1 -1
  132. package/dist/nitro/v3/module.d.mts.map +1 -1
  133. package/dist/nitro/v3/module.mjs +3 -3
  134. package/dist/nitro/v3/module.mjs.map +1 -1
  135. package/dist/nitro/v3/plugin.mjs +76 -44
  136. package/dist/nitro/v3/plugin.mjs.map +1 -1
  137. package/dist/nitro/v3/useLogger.d.mts +1 -1
  138. package/dist/nitro-ClRZLD1g.mjs +96 -0
  139. package/dist/nitro-ClRZLD1g.mjs.map +1 -0
  140. package/dist/{nitro-BRddgqSb.d.mts → nitro-_Hda8Deo.d.mts} +7 -2
  141. package/dist/nitro-_Hda8Deo.d.mts.map +1 -0
  142. package/dist/{nitroConfigBridge-NbFn-sIK.mjs → nitroConfigBridge-BkVWnSV3.mjs} +9 -2
  143. package/dist/nitroConfigBridge-BkVWnSV3.mjs.map +1 -0
  144. package/dist/{nodeResponse-BkkionWl.mjs → nodeResponse-CIEEbrNE.mjs} +1 -1
  145. package/dist/{nodeResponse-BkkionWl.mjs.map → nodeResponse-CIEEbrNE.mjs.map} +1 -1
  146. package/dist/nuxt/module.d.mts +6 -1
  147. package/dist/nuxt/module.d.mts.map +1 -1
  148. package/dist/nuxt/module.mjs +11 -4
  149. package/dist/nuxt/module.mjs.map +1 -1
  150. package/dist/orpc/index.d.mts +2 -2
  151. package/dist/orpc/index.d.mts.map +1 -1
  152. package/dist/orpc/index.mjs +5 -4
  153. package/dist/orpc/index.mjs.map +1 -1
  154. package/dist/{package-B23bR3tK.mjs → package-CNV_CXs8.mjs} +2 -2
  155. package/dist/package-CNV_CXs8.mjs.map +1 -0
  156. package/dist/{parseError-D4PIxEWo.d.mts → parseError-BeBXEd2V.d.mts} +2 -2
  157. package/dist/parseError-BeBXEd2V.d.mts.map +1 -0
  158. package/dist/pipeline.d.mts +0 -19
  159. package/dist/pipeline.d.mts.map +1 -1
  160. package/dist/pipeline.mjs +12 -0
  161. package/dist/pipeline.mjs.map +1 -1
  162. package/dist/pretty-error-THg0U0w9.mjs +288 -0
  163. package/dist/pretty-error-THg0U0w9.mjs.map +1 -0
  164. package/dist/pretty-error-snippet.node-itfCajBM.mjs +48 -0
  165. package/dist/pretty-error-snippet.node-itfCajBM.mjs.map +1 -0
  166. package/dist/react-router/index.d.mts +2 -2
  167. package/dist/react-router/index.mjs +5 -6
  168. package/dist/react-router/index.mjs.map +1 -1
  169. package/dist/{routes-CnIgYWf8.mjs → routes-4rMzRyTk.mjs} +1 -1
  170. package/dist/{routes-CnIgYWf8.mjs.map → routes-4rMzRyTk.mjs.map} +1 -1
  171. package/dist/runtime/client/log.d.mts +1 -1
  172. package/dist/runtime/server/routes/_evlog/ingest.post.d.mts +7 -0
  173. package/dist/runtime/server/routes/_evlog/ingest.post.mjs +39 -3
  174. package/dist/runtime/server/routes/_evlog/ingest.post.mjs.map +1 -1
  175. package/dist/runtime/server/useLogger.d.mts +1 -1
  176. package/dist/runtime/utils/parseError.d.mts +2 -2
  177. package/dist/runtime/utils/parseError.mjs +1 -1
  178. package/dist/{severity-R5Egq3qz.mjs → severity-CwXUSHt3.mjs} +1 -1
  179. package/dist/{severity-R5Egq3qz.mjs.map → severity-CwXUSHt3.mjs.map} +1 -1
  180. package/dist/{source-location-Dco0cRTz.mjs → source-location-CHOPF2nd.mjs} +2 -1
  181. package/dist/{source-location-Dco0cRTz.mjs.map → source-location-CHOPF2nd.mjs.map} +1 -1
  182. package/dist/{storage-BNubsWwz.mjs → storage-7X37OToT.mjs} +1 -1
  183. package/dist/{storage-BNubsWwz.mjs.map → storage-7X37OToT.mjs.map} +1 -1
  184. package/dist/stream.d.mts +1 -1
  185. package/dist/stream.mjs +1 -1
  186. package/dist/streamResponse-CmQ3qUbF.mjs +94 -0
  187. package/dist/streamResponse-CmQ3qUbF.mjs.map +1 -0
  188. package/dist/sveltekit/index.d.mts +2 -2
  189. package/dist/sveltekit/index.d.mts.map +1 -1
  190. package/dist/sveltekit/index.mjs +7 -8
  191. package/dist/sveltekit/index.mjs.map +1 -1
  192. package/dist/toolkit.d.mts +51 -6
  193. package/dist/toolkit.d.mts.map +1 -1
  194. package/dist/toolkit.mjs +15 -14
  195. package/dist/types.d.mts +2 -2
  196. package/dist/{useLogger-CqvH6qOf.d.mts → useLogger-Cfv8Ck8b.d.mts} +2 -2
  197. package/dist/{useLogger-CqvH6qOf.d.mts.map → useLogger-Cfv8Ck8b.d.mts.map} +1 -1
  198. package/dist/{utils-DxqvIOyR.d.mts → utils-CJJG0ZYW.d.mts} +11 -3
  199. package/dist/{utils-DxqvIOyR.d.mts.map → utils-CJJG0ZYW.d.mts.map} +1 -1
  200. package/dist/utils.d.mts +2 -2
  201. package/dist/utils.mjs +23 -9
  202. package/dist/utils.mjs.map +1 -1
  203. package/dist/vite/index.d.mts +1 -1
  204. package/dist/vite/index.mjs +1 -1
  205. package/dist/workers.d.mts +1 -1
  206. package/dist/workers.mjs +1 -1
  207. package/package.json +12 -1
  208. package/dist/audit-BUI3af4w.mjs.map +0 -1
  209. package/dist/audit-DVdkntSO.d.mts.map +0 -1
  210. package/dist/define-D-BVMf2l.d.mts.map +0 -1
  211. package/dist/define-D6OJdSUH.mjs.map +0 -1
  212. package/dist/drain-7n3K6kPe.mjs.map +0 -1
  213. package/dist/fork-Bga8x-X4.mjs.map +0 -1
  214. package/dist/index-ZSRQP_BI.d.mts.map +0 -1
  215. package/dist/logger-CTcvd5Cc.d.mts.map +0 -1
  216. package/dist/middleware-31KhtiEF.d.mts.map +0 -1
  217. package/dist/next/instrumentation.d.mts.map +0 -1
  218. package/dist/nitro-BRddgqSb.d.mts.map +0 -1
  219. package/dist/nitro-DErMq_Zj.mjs +0 -34
  220. package/dist/nitro-DErMq_Zj.mjs.map +0 -1
  221. package/dist/nitroConfigBridge-NbFn-sIK.mjs.map +0 -1
  222. package/dist/package-B23bR3tK.mjs.map +0 -1
  223. package/dist/parseError-D4PIxEWo.d.mts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { i as resolveAdapterConfig, t as defineDrain } from "../drain-7n3K6kPe.mjs";
1
+ import { i as formatPublicEnvKeys, o as resolveAdapterConfig, t as defineDrain } from "../drain-fDb-eNwz.mjs";
2
2
  import { sendBatchToOTLP } from "./otlp.mjs";
3
3
  //#region src/adapters/hyperdx.ts
4
4
  /**
@@ -52,7 +52,7 @@ function toHyperDXOTLPConfig(config) {
52
52
  * 1. Overrides passed to `createHyperDXDrain()`
53
53
  * 2. `runtimeConfig.evlog.hyperdx`
54
54
  * 3. `runtimeConfig.hyperdx`
55
- * 4. Environment variables: `NUXT_HYPERDX_*`, `HYPERDX_*` (and `OTEL_SERVICE_NAME` for service name)
55
+ * 4. Environment variables: `HYPERDX_*` (and `OTEL_SERVICE_NAME` for service name)
56
56
  *
57
57
  * @example
58
58
  * ```ts
@@ -66,7 +66,7 @@ function createHyperDXDrain(overrides) {
66
66
  resolve: async () => {
67
67
  const config = await resolveAdapterConfig("hyperdx", HYPERDX_FIELDS, overrides);
68
68
  if (!config.apiKey) {
69
- console.error("[evlog/hyperdx] Missing apiKey. Set HYPERDX_API_KEY or NUXT_HYPERDX_API_KEY, or pass to createHyperDXDrain()");
69
+ console.error(`[evlog/hyperdx] Missing apiKey. Set ${formatPublicEnvKeys(["NUXT_HYPERDX_API_KEY", "HYPERDX_API_KEY"])}, or pass to createHyperDXDrain()`);
70
70
  return null;
71
71
  }
72
72
  return config;
@@ -1 +1 @@
1
- {"version":3,"file":"hyperdx.mjs","names":[],"sources":["../../src/adapters/hyperdx.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineDrain } from '../shared/drain'\nimport type { OTLPConfig } from './otlp'\nimport { sendBatchToOTLP } from './otlp'\n\n/**\n * HyperDX cloud OTLP HTTP base URL.\n * @see https://hyperdx.io/docs/install/opentelemetry — “Our OpenTelemetry HTTP endpoint is hosted at `https://in-otel.hyperdx.io` …”\n */\nexport const HYPERDX_DEFAULT_OTLP_HTTP_ENDPOINT = 'https://in-otel.hyperdx.io'\n\nexport interface HyperDXConfig {\n /**\n * Ingestion API key. Sent as the `authorization` header value, matching HyperDX’s OpenTelemetry docs:\n * `authorization: <YOUR_HYPERDX_API_KEY_HERE>`\n * @see https://hyperdx.io/docs/install/opentelemetry\n */\n apiKey: string\n /**\n * OTLP HTTP base URL (evlog appends `/v1/logs`). Defaults to {@link HYPERDX_DEFAULT_OTLP_HTTP_ENDPOINT}.\n * Self-hosted: set to your OTLP HTTP endpoint (same shape as `otlphttp` `endpoint` in HyperDX’s collector example).\n */\n endpoint?: string\n /** Passed through to the OTLP encoder; maps to `service.name`. */\n serviceName?: string\n /** Additional OTLP resource attributes. */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\nconst HYPERDX_FIELDS: ConfigField<HyperDXConfig>[] = [\n { key: 'apiKey', env: ['NUXT_HYPERDX_API_KEY', 'HYPERDX_API_KEY'] },\n { key: 'endpoint', env: ['NUXT_HYPERDX_OTLP_ENDPOINT', 'HYPERDX_OTLP_ENDPOINT'] },\n { key: 'serviceName', env: ['NUXT_HYPERDX_SERVICE_NAME', 'HYPERDX_SERVICE_NAME', 'NUXT_OTLP_SERVICE_NAME', 'OTEL_SERVICE_NAME'] },\n { key: 'resourceAttributes' },\n { key: 'timeout' },\n { key: 'retries' },\n]\n\n/**\n * Map HyperDX config to {@link OTLPConfig}: same wire format as HyperDX’s documented `otlphttp` exporter\n * (`endpoint` + `authorization` header).\n */\nexport function toHyperDXOTLPConfig(config: HyperDXConfig): OTLPConfig {\n return {\n endpoint: config.endpoint ?? HYPERDX_DEFAULT_OTLP_HTTP_ENDPOINT,\n headers: {\n // HyperDX docs (OpenTelemetry): headers.authorization = API key\n authorization: config.apiKey,\n },\n serviceName: config.serviceName,\n resourceAttributes: config.resourceAttributes,\n timeout: config.timeout,\n retries: config.retries,\n }\n}\n\n/**\n * Create a drain that sends wide events to HyperDX via OTLP/HTTP.\n *\n * Matches [HyperDX OpenTelemetry ingest](https://hyperdx.io/docs/install/opentelemetry):\n * HTTP base URL defaults to `https://in-otel.hyperdx.io`; requests use the `authorization` header set to your API key.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to `createHyperDXDrain()`\n * 2. `runtimeConfig.evlog.hyperdx`\n * 3. `runtimeConfig.hyperdx`\n * 4. Environment variables: `NUXT_HYPERDX_*`, `HYPERDX_*` (and `OTEL_SERVICE_NAME` for service name)\n *\n * @example\n * ```ts\n * nitroApp.hooks.hook('evlog:drain', createHyperDXDrain())\n * // HYPERDX_API_KEY in env\n * ```\n */\nexport function createHyperDXDrain(overrides?: Partial<HyperDXConfig>) {\n return defineDrain<HyperDXConfig>({\n name: 'hyperdx',\n resolve: async () => {\n const config = await resolveAdapterConfig<HyperDXConfig>('hyperdx', HYPERDX_FIELDS, overrides)\n if (!config.apiKey) {\n console.error('[evlog/hyperdx] Missing apiKey. Set HYPERDX_API_KEY or NUXT_HYPERDX_API_KEY, or pass to createHyperDXDrain()')\n return null\n }\n return config as HyperDXConfig\n },\n send: (events, config) => sendBatchToOTLP(events, toHyperDXOTLPConfig(config)),\n })\n}\n\n/**\n * Send a single wide event to HyperDX (OTLP/HTTP).\n */\nexport async function sendToHyperDX(event: WideEvent, config: HyperDXConfig): Promise<void> {\n await sendBatchToHyperDX([event], config)\n}\n\n/**\n * Send a batch of wide events to HyperDX (OTLP/HTTP).\n */\nexport async function sendBatchToHyperDX(events: WideEvent[], config: HyperDXConfig): Promise<void> {\n await sendBatchToOTLP(events, toHyperDXOTLPConfig(config))\n}\n"],"mappings":";;;;;;;AAWA,MAAa,qCAAqC;AAwBlD,MAAM,iBAA+C;CACnD;EAAE,KAAK;EAAU,KAAK,CAAC,wBAAwB,kBAAkB;EAAE;CACnE;EAAE,KAAK;EAAY,KAAK,CAAC,8BAA8B,wBAAwB;EAAE;CACjF;EAAE,KAAK;EAAe,KAAK;GAAC;GAA6B;GAAwB;GAA0B;GAAoB;EAAE;CACjI,EAAE,KAAK,sBAAsB;CAC7B,EAAE,KAAK,WAAW;CAClB,EAAE,KAAK,WAAW;CACnB;;;;;AAMD,SAAgB,oBAAoB,QAAmC;AACrE,QAAO;EACL,UAAU,OAAO,YAAA;EACjB,SAAS,EAEP,eAAe,OAAO,QACvB;EACD,aAAa,OAAO;EACpB,oBAAoB,OAAO;EAC3B,SAAS,OAAO;EAChB,SAAS,OAAO;EACjB;;;;;;;;;;;;;;;;;;;;AAqBH,SAAgB,mBAAmB,WAAoC;AACrE,QAAO,YAA2B;EAChC,MAAM;EACN,SAAS,YAAY;GACnB,MAAM,SAAS,MAAM,qBAAoC,WAAW,gBAAgB,UAAU;AAC9F,OAAI,CAAC,OAAO,QAAQ;AAClB,YAAQ,MAAM,+GAA+G;AAC7H,WAAO;;AAET,UAAO;;EAET,OAAO,QAAQ,WAAW,gBAAgB,QAAQ,oBAAoB,OAAO,CAAC;EAC/E,CAAC;;;;;AAMJ,eAAsB,cAAc,OAAkB,QAAsC;AAC1F,OAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO;;;;;AAM3C,eAAsB,mBAAmB,QAAqB,QAAsC;AAClG,OAAM,gBAAgB,QAAQ,oBAAoB,OAAO,CAAC"}
1
+ {"version":3,"file":"hyperdx.mjs","names":[],"sources":["../../src/adapters/hyperdx.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { formatPublicEnvKeys, resolveAdapterConfig } from '../shared/config'\nimport { defineDrain } from '../shared/drain'\nimport type { OTLPConfig } from './otlp'\nimport { sendBatchToOTLP } from './otlp'\n\n/**\n * HyperDX cloud OTLP HTTP base URL.\n * @see https://hyperdx.io/docs/install/opentelemetry — “Our OpenTelemetry HTTP endpoint is hosted at `https://in-otel.hyperdx.io` …”\n */\nexport const HYPERDX_DEFAULT_OTLP_HTTP_ENDPOINT = 'https://in-otel.hyperdx.io'\n\nexport interface HyperDXConfig {\n /**\n * Ingestion API key. Sent as the `authorization` header value, matching HyperDX’s OpenTelemetry docs:\n * `authorization: <YOUR_HYPERDX_API_KEY_HERE>`\n * @see https://hyperdx.io/docs/install/opentelemetry\n */\n apiKey: string\n /**\n * OTLP HTTP base URL (evlog appends `/v1/logs`). Defaults to {@link HYPERDX_DEFAULT_OTLP_HTTP_ENDPOINT}.\n * Self-hosted: set to your OTLP HTTP endpoint (same shape as `otlphttp` `endpoint` in HyperDX’s collector example).\n */\n endpoint?: string\n /** Passed through to the OTLP encoder; maps to `service.name`. */\n serviceName?: string\n /** Additional OTLP resource attributes. */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\nconst HYPERDX_FIELDS: ConfigField<HyperDXConfig>[] = [\n { key: 'apiKey', env: ['NUXT_HYPERDX_API_KEY', 'HYPERDX_API_KEY'] },\n { key: 'endpoint', env: ['NUXT_HYPERDX_OTLP_ENDPOINT', 'HYPERDX_OTLP_ENDPOINT'] },\n { key: 'serviceName', env: ['NUXT_HYPERDX_SERVICE_NAME', 'HYPERDX_SERVICE_NAME', 'NUXT_OTLP_SERVICE_NAME', 'OTEL_SERVICE_NAME'] },\n { key: 'resourceAttributes' },\n { key: 'timeout' },\n { key: 'retries' },\n]\n\n/**\n * Map HyperDX config to {@link OTLPConfig}: same wire format as HyperDX’s documented `otlphttp` exporter\n * (`endpoint` + `authorization` header).\n */\nexport function toHyperDXOTLPConfig(config: HyperDXConfig): OTLPConfig {\n return {\n endpoint: config.endpoint ?? HYPERDX_DEFAULT_OTLP_HTTP_ENDPOINT,\n headers: {\n // HyperDX docs (OpenTelemetry): headers.authorization = API key\n authorization: config.apiKey,\n },\n serviceName: config.serviceName,\n resourceAttributes: config.resourceAttributes,\n timeout: config.timeout,\n retries: config.retries,\n }\n}\n\n/**\n * Create a drain that sends wide events to HyperDX via OTLP/HTTP.\n *\n * Matches [HyperDX OpenTelemetry ingest](https://hyperdx.io/docs/install/opentelemetry):\n * HTTP base URL defaults to `https://in-otel.hyperdx.io`; requests use the `authorization` header set to your API key.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to `createHyperDXDrain()`\n * 2. `runtimeConfig.evlog.hyperdx`\n * 3. `runtimeConfig.hyperdx`\n * 4. Environment variables: `HYPERDX_*` (and `OTEL_SERVICE_NAME` for service name)\n *\n * @example\n * ```ts\n * nitroApp.hooks.hook('evlog:drain', createHyperDXDrain())\n * // HYPERDX_API_KEY in env\n * ```\n */\nexport function createHyperDXDrain(overrides?: Partial<HyperDXConfig>) {\n return defineDrain<HyperDXConfig>({\n name: 'hyperdx',\n resolve: async () => {\n const config = await resolveAdapterConfig<HyperDXConfig>('hyperdx', HYPERDX_FIELDS, overrides)\n if (!config.apiKey) {\n console.error(`[evlog/hyperdx] Missing apiKey. Set ${formatPublicEnvKeys(['NUXT_HYPERDX_API_KEY', 'HYPERDX_API_KEY'])}, or pass to createHyperDXDrain()`)\n return null\n }\n return config as HyperDXConfig\n },\n send: (events, config) => sendBatchToOTLP(events, toHyperDXOTLPConfig(config)),\n })\n}\n\n/**\n * Send a single wide event to HyperDX (OTLP/HTTP).\n */\nexport async function sendToHyperDX(event: WideEvent, config: HyperDXConfig): Promise<void> {\n await sendBatchToHyperDX([event], config)\n}\n\n/**\n * Send a batch of wide events to HyperDX (OTLP/HTTP).\n */\nexport async function sendBatchToHyperDX(events: WideEvent[], config: HyperDXConfig): Promise<void> {\n await sendBatchToOTLP(events, toHyperDXOTLPConfig(config))\n}\n"],"mappings":";;;;;;;AAWA,MAAa,qCAAqC;AAwBlD,MAAM,iBAA+C;CACnD;EAAE,KAAK;EAAU,KAAK,CAAC,wBAAwB,kBAAkB;EAAE;CACnE;EAAE,KAAK;EAAY,KAAK,CAAC,8BAA8B,wBAAwB;EAAE;CACjF;EAAE,KAAK;EAAe,KAAK;GAAC;GAA6B;GAAwB;GAA0B;GAAoB;EAAE;CACjI,EAAE,KAAK,sBAAsB;CAC7B,EAAE,KAAK,WAAW;CAClB,EAAE,KAAK,WAAW;CACnB;;;;;AAMD,SAAgB,oBAAoB,QAAmC;AACrE,QAAO;EACL,UAAU,OAAO,YAAA;EACjB,SAAS,EAEP,eAAe,OAAO,QACvB;EACD,aAAa,OAAO;EACpB,oBAAoB,OAAO;EAC3B,SAAS,OAAO;EAChB,SAAS,OAAO;EACjB;;;;;;;;;;;;;;;;;;;;AAqBH,SAAgB,mBAAmB,WAAoC;AACrE,QAAO,YAA2B;EAChC,MAAM;EACN,SAAS,YAAY;GACnB,MAAM,SAAS,MAAM,qBAAoC,WAAW,gBAAgB,UAAU;AAC9F,OAAI,CAAC,OAAO,QAAQ;AAClB,YAAQ,MAAM,uCAAuC,oBAAoB,CAAC,wBAAwB,kBAAkB,CAAC,CAAC,mCAAmC;AACzJ,WAAO;;AAET,UAAO;;EAET,OAAO,QAAQ,WAAW,gBAAgB,QAAQ,oBAAoB,OAAO,CAAC;EAC/E,CAAC;;;;;AAMJ,eAAsB,cAAc,OAAkB,QAAsC;AAC1F,OAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO;;;;;AAM3C,eAAsB,mBAAmB,QAAqB,QAAsC;AAClG,OAAM,gBAAgB,QAAQ,oBAAoB,OAAO,CAAC"}
@@ -1,4 +1,4 @@
1
- import { I as DrainContext, K as LogLevel, ct as WideEvent } from "../audit-DVdkntSO.mjs";
1
+ import { B as DrainContext, X as LogLevel, ft as WideEvent } from "../audit-D7v6JHj0.mjs";
2
2
  //#region src/adapters/memory.d.ts
3
3
  /**
4
4
  * Configuration for the in-memory drain.
@@ -24,8 +24,7 @@ declare function writeToMemory(events: WideEvent[], config: MemoryConfig): void;
24
24
  * Configuration priority (highest to lowest):
25
25
  * 1. Overrides passed to `createMemoryDrain()`
26
26
  * 2. `runtimeConfig.evlog.memory` / `runtimeConfig.memory` (Nitro)
27
- * 3. Environment variables: `NUXT_EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_STORE`,
28
- * `NUXT_EVLOG_MEMORY_MAX_EVENTS`, `EVLOG_MEMORY_MAX_EVENTS`
27
+ * 3. Environment variables: `EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_MAX_EVENTS`
29
28
  *
30
29
  * @example
31
30
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.mts","names":[],"sources":["../../src/adapters/memory.ts"],"mappings":";;;;;UAQiB,YAAA;EAAY;EAE3B,KAAA;EAAA;EAEA,SAAA;AAAA;;;;;iBA2Cc,aAAA,CAAc,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,YAAA;;;;;AAmC3D;;;;;;;;;;;;;;;;;;;AAYA;;;iBAZgB,iBAAA,CAAkB,SAAA,GAAY,OAAA,CAAQ,YAAA,KAAa,GAAA,EAAd,YAAA,GAAc,YAAA,OAAA,OAAA;;UAYlD,qBAAA;EAQI;EANnB,KAAA;EAQ0B;EAN1B,KAAA,GAAQ,IAAA;EAFR;EAIA,KAAA,GAAQ,IAAA;EAFA;EAIR,KAAA,GAAQ,QAAA,GAAW,QAAA;EAFX;EAIR,MAAA,IAAU,KAAA,EAAO,SAAA;EAFT;EAIR,KAAA;AAAA;;;;;;AA+BF;;;;;;;;;AAuCA;;;;;AA6BA;;iBApEgB,cAAA,CAAe,OAAA,GAAS,qBAAA,GAA6B,SAAA;;;;;;;;;;iBAuCrD,eAAA,CAAgB,KAAA;;;;;;;;;;;;;;;;;;;;;;;iBA6BhB,wBAAA,CACd,KAAA,EAAO,MAAA,0CACN,qBAAA"}
1
+ {"version":3,"file":"memory.d.mts","names":[],"sources":["../../src/adapters/memory.ts"],"mappings":";;;;;UAQiB,YAAA;EAAY;EAE3B,KAAA;EAAA;EAEA,SAAA;AAAA;;;;;iBA2Cc,aAAA,CAAc,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,YAAA;;;;;AAkC3D;;;;;;;;;;;;;;;;;;;AAYA;;iBAZgB,iBAAA,CAAkB,SAAA,GAAY,OAAA,CAAQ,YAAA,KAAa,GAAA,EAAd,YAAA,GAAc,YAAA,OAAA,OAAA;;UAYlD,qBAAA;EAQP;EANR,KAAA;EAQiB;EANjB,KAAA,GAAQ,IAAA;EAMkB;EAJ1B,KAAA,GAAQ,IAAA;EAFR;EAIA,KAAA,GAAQ,QAAA,GAAW,QAAA;EAFnB;EAIA,MAAA,IAAU,KAAA,EAAO,SAAA;EAFjB;EAIA,KAAA;AAAA;;;;;;;AA+BF;;;;;;;;;AAuCA;;;;;AA6BA;iBApEgB,cAAA,CAAe,OAAA,GAAS,qBAAA,GAA6B,SAAA;;;;;;;;;;iBAuCrD,eAAA,CAAgB,KAAA;;;;;;;;;;;;;;;;;;;;;;;iBA6BhB,wBAAA,CACd,KAAA,EAAO,MAAA,0CACN,qBAAA"}
@@ -1,4 +1,4 @@
1
- import { i as resolveAdapterConfig, t as defineDrain } from "../drain-7n3K6kPe.mjs";
1
+ import { o as resolveAdapterConfig, t as defineDrain } from "../drain-fDb-eNwz.mjs";
2
2
  //#region src/adapters/memory.ts
3
3
  const DEFAULT_STORE = "default";
4
4
  const DEFAULT_MAX_EVENTS = 1e3;
@@ -52,8 +52,7 @@ function writeToMemory(events, config) {
52
52
  * Configuration priority (highest to lowest):
53
53
  * 1. Overrides passed to `createMemoryDrain()`
54
54
  * 2. `runtimeConfig.evlog.memory` / `runtimeConfig.memory` (Nitro)
55
- * 3. Environment variables: `NUXT_EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_STORE`,
56
- * `NUXT_EVLOG_MEMORY_MAX_EVENTS`, `EVLOG_MEMORY_MAX_EVENTS`
55
+ * 3. Environment variables: `EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_MAX_EVENTS`
57
56
  *
58
57
  * @example
59
58
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"memory.mjs","names":[],"sources":["../../src/adapters/memory.ts"],"sourcesContent":["import type { LogLevel, WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineDrain } from '../shared/drain'\n\n/**\n * Configuration for the in-memory drain.\n */\nexport interface MemoryConfig {\n /** Named store key. Multiple drains sharing the same key share the same buffer. Default: `'default'` */\n store: string\n /** Maximum number of events to keep in the ring buffer. Oldest events are discarded when the limit is exceeded. Default: `1000` */\n maxEvents: number\n}\n\nconst DEFAULT_STORE = 'default'\nconst DEFAULT_MAX_EVENTS = 1000\n\nconst MEMORY_FIELDS: ConfigField<Partial<MemoryConfig>>[] = [\n { key: 'store', env: ['NUXT_EVLOG_MEMORY_STORE', 'EVLOG_MEMORY_STORE'] },\n { key: 'maxEvents', env: ['NUXT_EVLOG_MEMORY_MAX_EVENTS', 'EVLOG_MEMORY_MAX_EVENTS'] },\n]\n\nconst stores = new Map<string, WideEvent[]>()\n\nfunction getOrCreateStore(name: string): WideEvent[] {\n if (!stores.has(name)) stores.set(name, [])\n return stores.get(name)!\n}\n\nfunction parseMaxEvents(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n const n = Math.floor(value)\n return n > 0 ? n : undefined\n }\n if (typeof value === 'string' && value) {\n const parsed = Number.parseFloat(value)\n if (!Number.isFinite(parsed)) return undefined\n const n = Math.floor(parsed)\n return n > 0 ? n : undefined\n }\n return undefined\n}\n\nfunction resolveMemoryConfig(overrides?: Partial<MemoryConfig>): MemoryConfig {\n return {\n store: overrides?.store ?? DEFAULT_STORE,\n maxEvents: parseMaxEvents(overrides?.maxEvents) ?? DEFAULT_MAX_EVENTS,\n }\n}\n\n/**\n * Write events directly into the named store. Exported for direct use and\n * easier testing without going through the drain pipeline.\n */\nexport function writeToMemory(events: WideEvent[], config: MemoryConfig): void {\n if (events.length === 0) return\n const store = getOrCreateStore(config.store)\n store.push(...events)\n if (store.length > config.maxEvents) {\n store.splice(0, store.length - config.maxEvents)\n }\n}\n\n/**\n * Create a drain that stores wide events in an in-memory ring buffer.\n *\n * Works in **any** runtime — including Cloudflare Workers (workerd) — where\n * the filesystem (`evlog/fs`) is not available. Pair it with a dev-only HTTP\n * endpoint to let agents retrieve the buffer over HTTP.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to `createMemoryDrain()`\n * 2. `runtimeConfig.evlog.memory` / `runtimeConfig.memory` (Nitro)\n * 3. Environment variables: `NUXT_EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_STORE`,\n * `NUXT_EVLOG_MEMORY_MAX_EVENTS`, `EVLOG_MEMORY_MAX_EVENTS`\n *\n * @example\n * ```ts\n * // Hono + Cloudflare Workers\n * import { createMemoryDrain, readMemoryLogs } from 'evlog/memory'\n *\n * app.use(evlog({ drain: createMemoryDrain() }))\n *\n * // Dev-only endpoint for agent retrieval\n * if (env.NODE_ENV === 'development') {\n * app.get('/_evlog/logs', (c) => c.json(readMemoryLogs()))\n * }\n * ```\n */\nexport function createMemoryDrain(overrides?: Partial<MemoryConfig>) {\n return defineDrain<MemoryConfig>({\n name: 'memory',\n resolve: async () => {\n const resolved = await resolveAdapterConfig<Partial<MemoryConfig>>('memory', MEMORY_FIELDS, overrides)\n return resolveMemoryConfig(resolved)\n },\n send: (events, cfg) => Promise.resolve(writeToMemory(events, cfg)),\n })\n}\n\n/** Options accepted by {@link readMemoryLogs}. */\nexport interface ReadMemoryLogsOptions {\n /** Named store to read from. Default: `'default'` */\n store?: string\n /** Only include events with `timestamp >= since`. */\n since?: Date | string\n /** Only include events with `timestamp <= until`. */\n until?: Date | string\n /** Filter by log level. */\n level?: LogLevel | LogLevel[]\n /** Custom predicate — return `false` to skip the event. */\n filter?: (event: WideEvent) => boolean\n /** Return at most this many of the most-recent matching events. */\n limit?: number\n}\n\nfunction normalizeTimestamp(value: Date | string | undefined): number | undefined {\n if (!value) return undefined\n const date = value instanceof Date ? value : new Date(value)\n const ts = date.getTime()\n return Number.isNaN(ts) ? undefined : ts\n}\n\n/**\n * Read events from the named in-memory store. Returns a snapshot of the\n * buffer with optional filtering, ordered oldest-first.\n *\n * @example\n * ```ts\n * import { readMemoryLogs } from 'evlog/memory'\n *\n * // All events\n * const events = readMemoryLogs()\n *\n * // Errors in the last hour\n * const errors = readMemoryLogs({\n * level: 'error',\n * since: new Date(Date.now() - 60 * 60 * 1000),\n * })\n *\n * // Expose as a JSON endpoint\n * app.get('/_evlog/logs', (c) => c.json(readMemoryLogs({ limit: 200 })))\n * ```\n */\nexport function readMemoryLogs(options: ReadMemoryLogsOptions = {}): WideEvent[] {\n const storeName = options.store ?? DEFAULT_STORE\n const events = [...(stores.get(storeName) ?? [])]\n\n const sinceMs = normalizeTimestamp(options.since)\n const untilMs = normalizeTimestamp(options.until)\n const levels = options.level\n ? new Set<LogLevel>(Array.isArray(options.level) ? options.level : [options.level])\n : undefined\n const custom = options.filter\n\n const filtered = events.filter((event) => {\n if (levels && !levels.has(event.level)) return false\n if (sinceMs !== undefined || untilMs !== undefined) {\n const ts = typeof event.timestamp === 'string' ? Date.parse(event.timestamp) : Number.NaN\n if (Number.isNaN(ts)) return false\n if (sinceMs !== undefined && ts < sinceMs) return false\n if (untilMs !== undefined && ts > untilMs) return false\n }\n if (custom && !custom(event)) return false\n return true\n })\n\n if (options.limit !== undefined) {\n if (options.limit <= 0) return []\n if (filtered.length > options.limit) return filtered.slice(-options.limit)\n }\n return filtered\n}\n\n/**\n * Clear all events from a named store (or `'default'`).\n *\n * @example\n * ```ts\n * clearMemoryLogs() // clears the default store\n * clearMemoryLogs('my-store') // clears a named store\n * ```\n */\nexport function clearMemoryLogs(store = DEFAULT_STORE): void {\n const s = stores.get(store)\n if (s) s.length = 0\n}\n\nconst VALID_LEVELS = new Set<LogLevel>(['info', 'error', 'warn', 'debug'])\n\n/**\n * Parse a flat query-string object (e.g. from `c.req.query()` in Hono, or\n * `req.query` in Express) into {@link ReadMemoryLogsOptions} with proper type\n * coercion.\n *\n * This lets agents discover and pass filter parameters through HTTP query\n * strings directly:\n *\n * @example\n * ```ts\n * // Hono — zero glue\n * app.get('/_evlog/logs', (c) =>\n * c.json(readMemoryLogs(parseReadMemoryLogsQuery(c.req.query()))))\n *\n * // Express\n * app.get('/_evlog/logs', (req, res) =>\n * res.json(readMemoryLogs(parseReadMemoryLogsQuery(req.query as Record<string, string>))))\n * ```\n *\n * Supported query params: `store`, `since`, `until`, `level` (comma-separated),\n * `limit`. The `filter` predicate cannot be expressed as a query param.\n */\nexport function parseReadMemoryLogsQuery(\n query: Record<string, string | string[] | undefined>,\n): ReadMemoryLogsOptions {\n const opts: ReadMemoryLogsOptions = {}\n const { store, since, until, level, limit } = query\n\n if (typeof store === 'string' && store) opts.store = store\n if (typeof since === 'string' && since) opts.since = since\n if (typeof until === 'string' && until) opts.until = until\n\n if (level !== undefined) {\n const raw = Array.isArray(level) ? level : level.split(',')\n const levels = raw.map((l) => l.trim()).filter((l): l is LogLevel => VALID_LEVELS.has(l as LogLevel))\n if (levels.length === 1) [opts.level] = levels\n else if (levels.length > 1) opts.level = levels\n }\n\n if (typeof limit === 'string') {\n const n = Number.parseInt(limit, 10)\n if (!Number.isNaN(n)) opts.limit = n\n }\n\n return opts\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"memory.mjs","names":[],"sources":["../../src/adapters/memory.ts"],"sourcesContent":["import type { LogLevel, WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineDrain } from '../shared/drain'\n\n/**\n * Configuration for the in-memory drain.\n */\nexport interface MemoryConfig {\n /** Named store key. Multiple drains sharing the same key share the same buffer. Default: `'default'` */\n store: string\n /** Maximum number of events to keep in the ring buffer. Oldest events are discarded when the limit is exceeded. Default: `1000` */\n maxEvents: number\n}\n\nconst DEFAULT_STORE = 'default'\nconst DEFAULT_MAX_EVENTS = 1000\n\nconst MEMORY_FIELDS: ConfigField<Partial<MemoryConfig>>[] = [\n { key: 'store', env: ['NUXT_EVLOG_MEMORY_STORE', 'EVLOG_MEMORY_STORE'] },\n { key: 'maxEvents', env: ['NUXT_EVLOG_MEMORY_MAX_EVENTS', 'EVLOG_MEMORY_MAX_EVENTS'] },\n]\n\nconst stores = new Map<string, WideEvent[]>()\n\nfunction getOrCreateStore(name: string): WideEvent[] {\n if (!stores.has(name)) stores.set(name, [])\n return stores.get(name)!\n}\n\nfunction parseMaxEvents(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n const n = Math.floor(value)\n return n > 0 ? n : undefined\n }\n if (typeof value === 'string' && value) {\n const parsed = Number.parseFloat(value)\n if (!Number.isFinite(parsed)) return undefined\n const n = Math.floor(parsed)\n return n > 0 ? n : undefined\n }\n return undefined\n}\n\nfunction resolveMemoryConfig(overrides?: Partial<MemoryConfig>): MemoryConfig {\n return {\n store: overrides?.store ?? DEFAULT_STORE,\n maxEvents: parseMaxEvents(overrides?.maxEvents) ?? DEFAULT_MAX_EVENTS,\n }\n}\n\n/**\n * Write events directly into the named store. Exported for direct use and\n * easier testing without going through the drain pipeline.\n */\nexport function writeToMemory(events: WideEvent[], config: MemoryConfig): void {\n if (events.length === 0) return\n const store = getOrCreateStore(config.store)\n store.push(...events)\n if (store.length > config.maxEvents) {\n store.splice(0, store.length - config.maxEvents)\n }\n}\n\n/**\n * Create a drain that stores wide events in an in-memory ring buffer.\n *\n * Works in **any** runtime — including Cloudflare Workers (workerd) — where\n * the filesystem (`evlog/fs`) is not available. Pair it with a dev-only HTTP\n * endpoint to let agents retrieve the buffer over HTTP.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to `createMemoryDrain()`\n * 2. `runtimeConfig.evlog.memory` / `runtimeConfig.memory` (Nitro)\n * 3. Environment variables: `EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_MAX_EVENTS`\n *\n * @example\n * ```ts\n * // Hono + Cloudflare Workers\n * import { createMemoryDrain, readMemoryLogs } from 'evlog/memory'\n *\n * app.use(evlog({ drain: createMemoryDrain() }))\n *\n * // Dev-only endpoint for agent retrieval\n * if (env.NODE_ENV === 'development') {\n * app.get('/_evlog/logs', (c) => c.json(readMemoryLogs()))\n * }\n * ```\n */\nexport function createMemoryDrain(overrides?: Partial<MemoryConfig>) {\n return defineDrain<MemoryConfig>({\n name: 'memory',\n resolve: async () => {\n const resolved = await resolveAdapterConfig<Partial<MemoryConfig>>('memory', MEMORY_FIELDS, overrides)\n return resolveMemoryConfig(resolved)\n },\n send: (events, cfg) => Promise.resolve(writeToMemory(events, cfg)),\n })\n}\n\n/** Options accepted by {@link readMemoryLogs}. */\nexport interface ReadMemoryLogsOptions {\n /** Named store to read from. Default: `'default'` */\n store?: string\n /** Only include events with `timestamp >= since`. */\n since?: Date | string\n /** Only include events with `timestamp <= until`. */\n until?: Date | string\n /** Filter by log level. */\n level?: LogLevel | LogLevel[]\n /** Custom predicate — return `false` to skip the event. */\n filter?: (event: WideEvent) => boolean\n /** Return at most this many of the most-recent matching events. */\n limit?: number\n}\n\nfunction normalizeTimestamp(value: Date | string | undefined): number | undefined {\n if (!value) return undefined\n const date = value instanceof Date ? value : new Date(value)\n const ts = date.getTime()\n return Number.isNaN(ts) ? undefined : ts\n}\n\n/**\n * Read events from the named in-memory store. Returns a snapshot of the\n * buffer with optional filtering, ordered oldest-first.\n *\n * @example\n * ```ts\n * import { readMemoryLogs } from 'evlog/memory'\n *\n * // All events\n * const events = readMemoryLogs()\n *\n * // Errors in the last hour\n * const errors = readMemoryLogs({\n * level: 'error',\n * since: new Date(Date.now() - 60 * 60 * 1000),\n * })\n *\n * // Expose as a JSON endpoint\n * app.get('/_evlog/logs', (c) => c.json(readMemoryLogs({ limit: 200 })))\n * ```\n */\nexport function readMemoryLogs(options: ReadMemoryLogsOptions = {}): WideEvent[] {\n const storeName = options.store ?? DEFAULT_STORE\n const events = [...(stores.get(storeName) ?? [])]\n\n const sinceMs = normalizeTimestamp(options.since)\n const untilMs = normalizeTimestamp(options.until)\n const levels = options.level\n ? new Set<LogLevel>(Array.isArray(options.level) ? options.level : [options.level])\n : undefined\n const custom = options.filter\n\n const filtered = events.filter((event) => {\n if (levels && !levels.has(event.level)) return false\n if (sinceMs !== undefined || untilMs !== undefined) {\n const ts = typeof event.timestamp === 'string' ? Date.parse(event.timestamp) : Number.NaN\n if (Number.isNaN(ts)) return false\n if (sinceMs !== undefined && ts < sinceMs) return false\n if (untilMs !== undefined && ts > untilMs) return false\n }\n if (custom && !custom(event)) return false\n return true\n })\n\n if (options.limit !== undefined) {\n if (options.limit <= 0) return []\n if (filtered.length > options.limit) return filtered.slice(-options.limit)\n }\n return filtered\n}\n\n/**\n * Clear all events from a named store (or `'default'`).\n *\n * @example\n * ```ts\n * clearMemoryLogs() // clears the default store\n * clearMemoryLogs('my-store') // clears a named store\n * ```\n */\nexport function clearMemoryLogs(store = DEFAULT_STORE): void {\n const s = stores.get(store)\n if (s) s.length = 0\n}\n\nconst VALID_LEVELS = new Set<LogLevel>(['info', 'error', 'warn', 'debug'])\n\n/**\n * Parse a flat query-string object (e.g. from `c.req.query()` in Hono, or\n * `req.query` in Express) into {@link ReadMemoryLogsOptions} with proper type\n * coercion.\n *\n * This lets agents discover and pass filter parameters through HTTP query\n * strings directly:\n *\n * @example\n * ```ts\n * // Hono — zero glue\n * app.get('/_evlog/logs', (c) =>\n * c.json(readMemoryLogs(parseReadMemoryLogsQuery(c.req.query()))))\n *\n * // Express\n * app.get('/_evlog/logs', (req, res) =>\n * res.json(readMemoryLogs(parseReadMemoryLogsQuery(req.query as Record<string, string>))))\n * ```\n *\n * Supported query params: `store`, `since`, `until`, `level` (comma-separated),\n * `limit`. The `filter` predicate cannot be expressed as a query param.\n */\nexport function parseReadMemoryLogsQuery(\n query: Record<string, string | string[] | undefined>,\n): ReadMemoryLogsOptions {\n const opts: ReadMemoryLogsOptions = {}\n const { store, since, until, level, limit } = query\n\n if (typeof store === 'string' && store) opts.store = store\n if (typeof since === 'string' && since) opts.since = since\n if (typeof until === 'string' && until) opts.until = until\n\n if (level !== undefined) {\n const raw = Array.isArray(level) ? level : level.split(',')\n const levels = raw.map((l) => l.trim()).filter((l): l is LogLevel => VALID_LEVELS.has(l as LogLevel))\n if (levels.length === 1) [opts.level] = levels\n else if (levels.length > 1) opts.level = levels\n }\n\n if (typeof limit === 'string') {\n const n = Number.parseInt(limit, 10)\n if (!Number.isNaN(n)) opts.limit = n\n }\n\n return opts\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { I as DrainContext, ct as WideEvent } from "../audit-DVdkntSO.mjs";
1
+ import { B as DrainContext, ft as WideEvent } from "../audit-D7v6JHj0.mjs";
2
2
  //#region src/adapters/otlp.d.ts
3
3
  interface OTLPConfig {
4
4
  /** OTLP HTTP endpoint (e.g., http://localhost:4318) */
@@ -42,9 +42,9 @@ declare function toOTLPLogRecord(event: WideEvent): OTLPLogRecord;
42
42
  *
43
43
  * Configuration priority (highest to lowest):
44
44
  * 1. Overrides passed to createOTLPDrain()
45
- * 2. runtimeConfig.evlog.otlp (NUXT_EVLOG_OTLP_*)
46
- * 3. runtimeConfig.otlp (NUXT_OTLP_*)
47
- * 4. Environment variables: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME
45
+ * 2. runtimeConfig.evlog.otlp
46
+ * 3. runtimeConfig.otlp
47
+ * 4. Environment variables: OTEL_EXPORTER_OTLP_ENDPOINT (or OTLP_ENDPOINT), OTEL_SERVICE_NAME
48
48
  *
49
49
  * @example
50
50
  * ```ts
@@ -1,12 +1,16 @@
1
- import { r as httpPost } from "../http-B6YgAhyN.mjs";
2
- import { i as resolveAdapterConfig, n as defineHttpDrain } from "../drain-7n3K6kPe.mjs";
3
- import { n as toOtlpAttributeValue } from "../event-1BMl7o0k.mjs";
4
- import { n as OTEL_SEVERITY_TEXT, t as OTEL_SEVERITY_NUMBER } from "../severity-R5Egq3qz.mjs";
1
+ import { r as httpPost } from "../http-ChVS9GYc.mjs";
2
+ import { i as formatPublicEnvKeys, n as defineHttpDrain, o as resolveAdapterConfig } from "../drain-fDb-eNwz.mjs";
3
+ import { n as toOtlpAttributeValue } from "../event-qwAv-7AZ.mjs";
4
+ import { n as OTEL_SEVERITY_TEXT, t as OTEL_SEVERITY_NUMBER } from "../severity-CwXUSHt3.mjs";
5
5
  //#region src/adapters/otlp.ts
6
6
  const OTLP_FIELDS = [
7
7
  {
8
8
  key: "endpoint",
9
- env: ["NUXT_OTLP_ENDPOINT", "OTEL_EXPORTER_OTLP_ENDPOINT"]
9
+ env: [
10
+ "NUXT_OTLP_ENDPOINT",
11
+ "OTEL_EXPORTER_OTLP_ENDPOINT",
12
+ "OTLP_ENDPOINT"
13
+ ]
10
14
  },
11
15
  {
12
16
  key: "serviceName",
@@ -79,10 +83,10 @@ function buildResourceAttributes(event, config) {
79
83
  }
80
84
  /**
81
85
  * Build headers from OTEL env vars.
82
- * Kept inline as OTLP-specific (parses OTEL_EXPORTER_OTLP_HEADERS=key=val,key=val).
86
+ * Kept inline as OTLP-specific (parses OTEL_EXPORTER_OTLP_HEADERS / OTLP_HEADERS as key=val,key=val).
83
87
  */
84
88
  function getHeadersFromEnv() {
85
- const headersEnv = process.env.OTEL_EXPORTER_OTLP_HEADERS || process.env.NUXT_OTLP_HEADERS;
89
+ const headersEnv = process.env.OTEL_EXPORTER_OTLP_HEADERS || process.env.OTLP_HEADERS || process.env.NUXT_OTLP_HEADERS;
86
90
  if (headersEnv) {
87
91
  const headers = {};
88
92
  const decoded = decodeURIComponent(headersEnv);
@@ -104,9 +108,9 @@ function getHeadersFromEnv() {
104
108
  *
105
109
  * Configuration priority (highest to lowest):
106
110
  * 1. Overrides passed to createOTLPDrain()
107
- * 2. runtimeConfig.evlog.otlp (NUXT_EVLOG_OTLP_*)
108
- * 3. runtimeConfig.otlp (NUXT_OTLP_*)
109
- * 4. Environment variables: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME
111
+ * 2. runtimeConfig.evlog.otlp
112
+ * 3. runtimeConfig.otlp
113
+ * 4. Environment variables: OTEL_EXPORTER_OTLP_ENDPOINT (or OTLP_ENDPOINT), OTEL_SERVICE_NAME
110
114
  *
111
115
  * @example
112
116
  * ```ts
@@ -126,7 +130,11 @@ function createOTLPDrain(overrides) {
126
130
  const config = await resolveAdapterConfig("otlp", OTLP_FIELDS, overrides);
127
131
  if (!config.headers) config.headers = getHeadersFromEnv();
128
132
  if (!config.endpoint) {
129
- console.error("[evlog/otlp] Missing endpoint. Set NUXT_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_ENDPOINT env var, or pass to createOTLPDrain()");
133
+ console.error(`[evlog/otlp] Missing endpoint. Set ${formatPublicEnvKeys([
134
+ "NUXT_OTLP_ENDPOINT",
135
+ "OTEL_EXPORTER_OTLP_ENDPOINT",
136
+ "OTLP_ENDPOINT"
137
+ ])} env var, or pass to createOTLPDrain()`);
130
138
  return null;
131
139
  }
132
140
  return config;
@@ -1 +1 @@
1
- {"version":3,"file":"otlp.mjs","names":[],"sources":["../../src/adapters/otlp.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineHttpDrain } from '../shared/drain'\nimport { toOtlpAttributeValue } from '../shared/event'\nimport { httpPost } from '../shared/http'\nimport { OTEL_SEVERITY_NUMBER, OTEL_SEVERITY_TEXT } from '../shared/severity'\n\nexport interface OTLPConfig {\n /** OTLP HTTP endpoint (e.g., http://localhost:4318) */\n endpoint: string\n /** Override service name (defaults to event.service) */\n serviceName?: string\n /** Additional resource attributes */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Custom headers (e.g., for authentication) */\n headers?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\n/** OTLP Log Record structure */\nexport interface OTLPLogRecord {\n timeUnixNano: string\n severityNumber: number\n severityText: string\n body: { stringValue: string }\n attributes: Array<{\n key: string\n value: { stringValue?: string, intValue?: string, boolValue?: boolean }\n }>\n traceId?: string\n spanId?: string\n}\n\n/** OTLP Resource structure */\ninterface OTLPResource {\n attributes: Array<{\n key: string\n value: { stringValue?: string, intValue?: string, boolValue?: boolean }\n }>\n}\n\n/** OTLP Scope structure */\ninterface OTLPScope {\n name: string\n version?: string\n}\n\n/** OTLP ExportLogsServiceRequest structure */\ninterface ExportLogsServiceRequest {\n resourceLogs: Array<{\n resource: OTLPResource\n scopeLogs: Array<{\n scope: OTLPScope\n logRecords: OTLPLogRecord[]\n }>\n }>\n}\n\nconst OTLP_FIELDS: ConfigField<OTLPConfig>[] = [\n { key: 'endpoint', env: ['NUXT_OTLP_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT'] },\n { key: 'serviceName', env: ['NUXT_OTLP_SERVICE_NAME', 'OTEL_SERVICE_NAME'] },\n { key: 'headers' },\n { key: 'resourceAttributes' },\n { key: 'timeout' },\n { key: 'retries' },\n]\n\n// Re-exposed under a local name to keep call-sites tight while delegating to\n// the shared OTLP attribute encoder in `evlog/toolkit`.\nconst toAttributeValue = toOtlpAttributeValue\n\n/**\n * Convert an evlog WideEvent to an OTLP LogRecord.\n */\nexport function toOTLPLogRecord(event: WideEvent): OTLPLogRecord {\n const timestamp = new Date(event.timestamp).getTime() * 1_000_000 // Convert to nanoseconds\n\n // Extract known fields, rest goes to attributes\n const { level, traceId, spanId, ...rest } = event\n // Remove base fields from rest (they're handled as resource attributes)\n delete (rest as Record<string, unknown>).timestamp\n delete (rest as Record<string, unknown>).service\n delete (rest as Record<string, unknown>).environment\n delete (rest as Record<string, unknown>).version\n delete (rest as Record<string, unknown>).commitHash\n delete (rest as Record<string, unknown>).region\n\n const attributes: OTLPLogRecord['attributes'] = []\n\n // Add all remaining event fields as attributes\n for (const [key, value] of Object.entries(rest)) {\n if (value !== undefined && value !== null) {\n attributes.push({\n key,\n value: toAttributeValue(value),\n })\n }\n }\n\n const record: OTLPLogRecord = {\n timeUnixNano: String(timestamp),\n severityNumber: OTEL_SEVERITY_NUMBER[level] ?? 9,\n severityText: OTEL_SEVERITY_TEXT[level] ?? 'INFO',\n body: { stringValue: JSON.stringify(event) },\n attributes,\n }\n\n // Add trace context if present\n if (typeof traceId === 'string') {\n record.traceId = traceId\n }\n if (typeof spanId === 'string') {\n record.spanId = spanId\n }\n\n return record\n}\n\n/**\n * Build OTLP resource attributes from event and config.\n */\nfunction buildResourceAttributes(\n event: WideEvent,\n config: OTLPConfig,\n): OTLPResource['attributes'] {\n const attributes: OTLPResource['attributes'] = []\n\n // Service name\n attributes.push({\n key: 'service.name',\n value: { stringValue: config.serviceName ?? event.service },\n })\n\n // Environment\n if (event.environment) {\n attributes.push({\n key: 'deployment.environment',\n value: { stringValue: event.environment },\n })\n }\n\n // Version\n if (event.version) {\n attributes.push({\n key: 'service.version',\n value: { stringValue: event.version },\n })\n }\n\n // Region\n if (event.region) {\n attributes.push({\n key: 'cloud.region',\n value: { stringValue: event.region },\n })\n }\n\n // Commit hash\n if (event.commitHash) {\n attributes.push({\n key: 'vcs.commit.id',\n value: { stringValue: event.commitHash },\n })\n }\n\n // Custom resource attributes from config\n if (config.resourceAttributes) {\n for (const [key, value] of Object.entries(config.resourceAttributes)) {\n attributes.push({\n key,\n value: toAttributeValue(value),\n })\n }\n }\n\n return attributes\n}\n\n/**\n * Build headers from OTEL env vars.\n * Kept inline as OTLP-specific (parses OTEL_EXPORTER_OTLP_HEADERS=key=val,key=val).\n */\nfunction getHeadersFromEnv(): Record<string, string> | undefined {\n const headersEnv = process.env.OTEL_EXPORTER_OTLP_HEADERS || process.env.NUXT_OTLP_HEADERS\n if (headersEnv) {\n const headers: Record<string, string> = {}\n const decoded = decodeURIComponent(headersEnv)\n for (const pair of decoded.split(',')) {\n const eqIndex = pair.indexOf('=')\n if (eqIndex > 0) {\n const key = pair.slice(0, eqIndex).trim()\n const value = pair.slice(eqIndex + 1).trim()\n if (key && value) {\n headers[key] = value\n }\n }\n }\n if (Object.keys(headers).length > 0) return headers\n }\n\n const auth = process.env.NUXT_OTLP_AUTH\n if (auth) {\n return { Authorization: auth }\n }\n\n return undefined\n}\n\n/**\n * Create a drain function for sending logs to an OTLP endpoint.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createOTLPDrain()\n * 2. runtimeConfig.evlog.otlp (NUXT_EVLOG_OTLP_*)\n * 3. runtimeConfig.otlp (NUXT_OTLP_*)\n * 4. Environment variables: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME\n *\n * @example\n * ```ts\n * // Zero config - reads from runtimeConfig or env vars\n * nitroApp.hooks.hook('evlog:drain', createOTLPDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('evlog:drain', createOTLPDrain({\n * endpoint: 'http://localhost:4318',\n * }))\n * ```\n */\nexport function createOTLPDrain(overrides?: Partial<OTLPConfig>) {\n return defineHttpDrain<OTLPConfig>({\n name: 'otlp',\n resolve: async () => {\n const config = await resolveAdapterConfig<OTLPConfig>('otlp', OTLP_FIELDS, overrides)\n\n // OTLP-specific: resolve headers from env if not provided via config\n if (!config.headers) {\n config.headers = getHeadersFromEnv()\n }\n\n if (!config.endpoint) {\n console.error('[evlog/otlp] Missing endpoint. Set NUXT_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_ENDPOINT env var, or pass to createOTLPDrain()')\n return null\n }\n return config as OTLPConfig\n },\n encode: (events, config) => {\n if (events.length === 0) return null\n return {\n url: `${config.endpoint.replace(/\\/$/, '')}/v1/logs`,\n headers: {\n 'Content-Type': 'application/json',\n ...config.headers,\n },\n body: JSON.stringify(buildOTLPPayload(events, config)),\n }\n },\n })\n}\n\nfunction buildOTLPPayload(events: WideEvent[], config: OTLPConfig): ExportLogsServiceRequest {\n const grouped = new Map<string, WideEvent[]>()\n for (const event of events) {\n const key = `${event.service}::${event.environment}`\n const group = grouped.get(key)\n if (group) group.push(event)\n else grouped.set(key, [event])\n }\n return {\n resourceLogs: Array.from(grouped.values()).map(groupEvents => ({\n resource: { attributes: buildResourceAttributes(groupEvents[0]!, config) },\n scopeLogs: [\n {\n scope: { name: 'evlog', version: '1.0.0' },\n logRecords: groupEvents.map(toOTLPLogRecord),\n },\n ],\n })),\n }\n}\n\n/**\n * Send a single event to an OTLP endpoint.\n *\n * @example\n * ```ts\n * await sendToOTLP(event, {\n * endpoint: 'http://localhost:4318',\n * })\n * ```\n */\nexport async function sendToOTLP(event: WideEvent, config: OTLPConfig): Promise<void> {\n await sendBatchToOTLP([event], config)\n}\n\n/**\n * Send a batch of events to an OTLP endpoint.\n *\n * @example\n * ```ts\n * await sendBatchToOTLP(events, {\n * endpoint: 'http://localhost:4318',\n * })\n * ```\n */\nexport async function sendBatchToOTLP(events: WideEvent[], config: OTLPConfig): Promise<void> {\n if (events.length === 0) return\n\n const url = `${config.endpoint.replace(/\\/$/, '')}/v1/logs`\n const payload = buildOTLPPayload(events, config)\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...config.headers,\n }\n\n await httpPost({\n url,\n headers,\n body: JSON.stringify(payload),\n timeout: config.timeout ?? 5000,\n retries: config.retries,\n label: 'OTLP',\n source: 'otlp',\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"otlp.mjs","names":[],"sources":["../../src/adapters/otlp.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { formatPublicEnvKeys, resolveAdapterConfig } from '../shared/config'\nimport { defineHttpDrain } from '../shared/drain'\nimport { toOtlpAttributeValue } from '../shared/event'\nimport { httpPost } from '../shared/http'\nimport { OTEL_SEVERITY_NUMBER, OTEL_SEVERITY_TEXT } from '../shared/severity'\n\nexport interface OTLPConfig {\n /** OTLP HTTP endpoint (e.g., http://localhost:4318) */\n endpoint: string\n /** Override service name (defaults to event.service) */\n serviceName?: string\n /** Additional resource attributes */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Custom headers (e.g., for authentication) */\n headers?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\n/** OTLP Log Record structure */\nexport interface OTLPLogRecord {\n timeUnixNano: string\n severityNumber: number\n severityText: string\n body: { stringValue: string }\n attributes: Array<{\n key: string\n value: { stringValue?: string, intValue?: string, boolValue?: boolean }\n }>\n traceId?: string\n spanId?: string\n}\n\n/** OTLP Resource structure */\ninterface OTLPResource {\n attributes: Array<{\n key: string\n value: { stringValue?: string, intValue?: string, boolValue?: boolean }\n }>\n}\n\n/** OTLP Scope structure */\ninterface OTLPScope {\n name: string\n version?: string\n}\n\n/** OTLP ExportLogsServiceRequest structure */\ninterface ExportLogsServiceRequest {\n resourceLogs: Array<{\n resource: OTLPResource\n scopeLogs: Array<{\n scope: OTLPScope\n logRecords: OTLPLogRecord[]\n }>\n }>\n}\n\nconst OTLP_FIELDS: ConfigField<OTLPConfig>[] = [\n { key: 'endpoint', env: ['NUXT_OTLP_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', 'OTLP_ENDPOINT'] },\n { key: 'serviceName', env: ['NUXT_OTLP_SERVICE_NAME', 'OTEL_SERVICE_NAME'] },\n { key: 'headers' },\n { key: 'resourceAttributes' },\n { key: 'timeout' },\n { key: 'retries' },\n]\n\n// Re-exposed under a local name to keep call-sites tight while delegating to\n// the shared OTLP attribute encoder in `evlog/toolkit`.\nconst toAttributeValue = toOtlpAttributeValue\n\n/**\n * Convert an evlog WideEvent to an OTLP LogRecord.\n */\nexport function toOTLPLogRecord(event: WideEvent): OTLPLogRecord {\n const timestamp = new Date(event.timestamp).getTime() * 1_000_000 // Convert to nanoseconds\n\n // Extract known fields, rest goes to attributes\n const { level, traceId, spanId, ...rest } = event\n // Remove base fields from rest (they're handled as resource attributes)\n delete (rest as Record<string, unknown>).timestamp\n delete (rest as Record<string, unknown>).service\n delete (rest as Record<string, unknown>).environment\n delete (rest as Record<string, unknown>).version\n delete (rest as Record<string, unknown>).commitHash\n delete (rest as Record<string, unknown>).region\n\n const attributes: OTLPLogRecord['attributes'] = []\n\n // Add all remaining event fields as attributes\n for (const [key, value] of Object.entries(rest)) {\n if (value !== undefined && value !== null) {\n attributes.push({\n key,\n value: toAttributeValue(value),\n })\n }\n }\n\n const record: OTLPLogRecord = {\n timeUnixNano: String(timestamp),\n severityNumber: OTEL_SEVERITY_NUMBER[level] ?? 9,\n severityText: OTEL_SEVERITY_TEXT[level] ?? 'INFO',\n body: { stringValue: JSON.stringify(event) },\n attributes,\n }\n\n // Add trace context if present\n if (typeof traceId === 'string') {\n record.traceId = traceId\n }\n if (typeof spanId === 'string') {\n record.spanId = spanId\n }\n\n return record\n}\n\n/**\n * Build OTLP resource attributes from event and config.\n */\nfunction buildResourceAttributes(\n event: WideEvent,\n config: OTLPConfig,\n): OTLPResource['attributes'] {\n const attributes: OTLPResource['attributes'] = []\n\n // Service name\n attributes.push({\n key: 'service.name',\n value: { stringValue: config.serviceName ?? event.service },\n })\n\n // Environment\n if (event.environment) {\n attributes.push({\n key: 'deployment.environment',\n value: { stringValue: event.environment },\n })\n }\n\n // Version\n if (event.version) {\n attributes.push({\n key: 'service.version',\n value: { stringValue: event.version },\n })\n }\n\n // Region\n if (event.region) {\n attributes.push({\n key: 'cloud.region',\n value: { stringValue: event.region },\n })\n }\n\n // Commit hash\n if (event.commitHash) {\n attributes.push({\n key: 'vcs.commit.id',\n value: { stringValue: event.commitHash },\n })\n }\n\n // Custom resource attributes from config\n if (config.resourceAttributes) {\n for (const [key, value] of Object.entries(config.resourceAttributes)) {\n attributes.push({\n key,\n value: toAttributeValue(value),\n })\n }\n }\n\n return attributes\n}\n\n/**\n * Build headers from OTEL env vars.\n * Kept inline as OTLP-specific (parses OTEL_EXPORTER_OTLP_HEADERS / OTLP_HEADERS as key=val,key=val).\n */\nfunction getHeadersFromEnv(): Record<string, string> | undefined {\n const headersEnv = process.env.OTEL_EXPORTER_OTLP_HEADERS || process.env.OTLP_HEADERS || process.env.NUXT_OTLP_HEADERS\n if (headersEnv) {\n const headers: Record<string, string> = {}\n const decoded = decodeURIComponent(headersEnv)\n for (const pair of decoded.split(',')) {\n const eqIndex = pair.indexOf('=')\n if (eqIndex > 0) {\n const key = pair.slice(0, eqIndex).trim()\n const value = pair.slice(eqIndex + 1).trim()\n if (key && value) {\n headers[key] = value\n }\n }\n }\n if (Object.keys(headers).length > 0) return headers\n }\n\n const auth = process.env.NUXT_OTLP_AUTH\n if (auth) {\n return { Authorization: auth }\n }\n\n return undefined\n}\n\n/**\n * Create a drain function for sending logs to an OTLP endpoint.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createOTLPDrain()\n * 2. runtimeConfig.evlog.otlp\n * 3. runtimeConfig.otlp\n * 4. Environment variables: OTEL_EXPORTER_OTLP_ENDPOINT (or OTLP_ENDPOINT), OTEL_SERVICE_NAME\n *\n * @example\n * ```ts\n * // Zero config - reads from runtimeConfig or env vars\n * nitroApp.hooks.hook('evlog:drain', createOTLPDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('evlog:drain', createOTLPDrain({\n * endpoint: 'http://localhost:4318',\n * }))\n * ```\n */\nexport function createOTLPDrain(overrides?: Partial<OTLPConfig>) {\n return defineHttpDrain<OTLPConfig>({\n name: 'otlp',\n resolve: async () => {\n const config = await resolveAdapterConfig<OTLPConfig>('otlp', OTLP_FIELDS, overrides)\n\n // OTLP-specific: resolve headers from env if not provided via config\n if (!config.headers) {\n config.headers = getHeadersFromEnv()\n }\n\n if (!config.endpoint) {\n console.error(`[evlog/otlp] Missing endpoint. Set ${formatPublicEnvKeys(['NUXT_OTLP_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', 'OTLP_ENDPOINT'])} env var, or pass to createOTLPDrain()`)\n return null\n }\n return config as OTLPConfig\n },\n encode: (events, config) => {\n if (events.length === 0) return null\n return {\n url: `${config.endpoint.replace(/\\/$/, '')}/v1/logs`,\n headers: {\n 'Content-Type': 'application/json',\n ...config.headers,\n },\n body: JSON.stringify(buildOTLPPayload(events, config)),\n }\n },\n })\n}\n\nfunction buildOTLPPayload(events: WideEvent[], config: OTLPConfig): ExportLogsServiceRequest {\n const grouped = new Map<string, WideEvent[]>()\n for (const event of events) {\n const key = `${event.service}::${event.environment}`\n const group = grouped.get(key)\n if (group) group.push(event)\n else grouped.set(key, [event])\n }\n return {\n resourceLogs: Array.from(grouped.values()).map(groupEvents => ({\n resource: { attributes: buildResourceAttributes(groupEvents[0]!, config) },\n scopeLogs: [\n {\n scope: { name: 'evlog', version: '1.0.0' },\n logRecords: groupEvents.map(toOTLPLogRecord),\n },\n ],\n })),\n }\n}\n\n/**\n * Send a single event to an OTLP endpoint.\n *\n * @example\n * ```ts\n * await sendToOTLP(event, {\n * endpoint: 'http://localhost:4318',\n * })\n * ```\n */\nexport async function sendToOTLP(event: WideEvent, config: OTLPConfig): Promise<void> {\n await sendBatchToOTLP([event], config)\n}\n\n/**\n * Send a batch of events to an OTLP endpoint.\n *\n * @example\n * ```ts\n * await sendBatchToOTLP(events, {\n * endpoint: 'http://localhost:4318',\n * })\n * ```\n */\nexport async function sendBatchToOTLP(events: WideEvent[], config: OTLPConfig): Promise<void> {\n if (events.length === 0) return\n\n const url = `${config.endpoint.replace(/\\/$/, '')}/v1/logs`\n const payload = buildOTLPPayload(events, config)\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...config.headers,\n }\n\n await httpPost({\n url,\n headers,\n body: JSON.stringify(payload),\n timeout: config.timeout ?? 5000,\n retries: config.retries,\n label: 'OTLP',\n source: 'otlp',\n })\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { I as DrainContext, ct as WideEvent } from "../audit-DVdkntSO.mjs";
1
+ import { B as DrainContext, ft as WideEvent } from "../audit-D7v6JHj0.mjs";
2
2
  //#region src/adapters/posthog.d.ts
3
3
  /**
4
4
  * Mode for {@link createPostHogDrain}.
@@ -61,7 +61,7 @@ declare function toPostHogEvent(event: WideEvent, config: PostHogConfig): PostHo
61
61
  * 1. Overrides passed to createPostHogDrain()
62
62
  * 2. runtimeConfig.evlog.posthog
63
63
  * 3. runtimeConfig.posthog
64
- * 4. Environment variables: NUXT_POSTHOG_*, POSTHOG_*
64
+ * 4. Environment variables: POSTHOG_*
65
65
  *
66
66
  * @example
67
67
  * ```ts
@@ -1,5 +1,5 @@
1
- import { r as httpPost } from "../http-B6YgAhyN.mjs";
2
- import { i as resolveAdapterConfig, n as defineHttpDrain, t as defineDrain } from "../drain-7n3K6kPe.mjs";
1
+ import { r as httpPost } from "../http-ChVS9GYc.mjs";
2
+ import { i as formatPublicEnvKeys, n as defineHttpDrain, o as resolveAdapterConfig, t as defineDrain } from "../drain-fDb-eNwz.mjs";
3
3
  import { sendBatchToOTLP } from "./otlp.mjs";
4
4
  //#region src/adapters/posthog.ts
5
5
  const POSTHOG_FIELDS = [
@@ -54,7 +54,7 @@ function toPostHogEvent(event, config) {
54
54
  * 1. Overrides passed to createPostHogDrain()
55
55
  * 2. runtimeConfig.evlog.posthog
56
56
  * 3. runtimeConfig.posthog
57
- * 4. Environment variables: NUXT_POSTHOG_*, POSTHOG_*
57
+ * 4. Environment variables: POSTHOG_*
58
58
  *
59
59
  * @example
60
60
  * ```ts
@@ -71,7 +71,7 @@ function createPostHogDrain(overrides) {
71
71
  resolve: async () => {
72
72
  const config = await resolveAdapterConfig("posthog", POSTHOG_FIELDS, overrides);
73
73
  if (!config.apiKey) {
74
- console.error("[evlog/posthog-events] Missing apiKey. Set NUXT_POSTHOG_API_KEY env var or pass to createPostHogDrain({ mode: 'events' })");
74
+ console.error(`[evlog/posthog-events] Missing apiKey. Set ${formatPublicEnvKeys(["NUXT_POSTHOG_API_KEY", "POSTHOG_API_KEY"])} env var or pass to createPostHogDrain({ mode: 'events' })`);
75
75
  return null;
76
76
  }
77
77
  return config;
@@ -90,7 +90,7 @@ function createPostHogDrain(overrides) {
90
90
  resolve: async () => {
91
91
  const config = await resolveAdapterConfig("posthog", POSTHOG_FIELDS, overrides);
92
92
  if (!config.apiKey) {
93
- console.error("[evlog/posthog] Missing apiKey. Set NUXT_POSTHOG_API_KEY env var or pass to createPostHogDrain()");
93
+ console.error(`[evlog/posthog] Missing apiKey. Set ${formatPublicEnvKeys(["NUXT_POSTHOG_API_KEY", "POSTHOG_API_KEY"])} env var or pass to createPostHogDrain()`);
94
94
  return null;
95
95
  }
96
96
  return config;
@@ -1 +1 @@
1
- {"version":3,"file":"posthog.mjs","names":[],"sources":["../../src/adapters/posthog.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineDrain, defineHttpDrain } from '../shared/drain'\nimport { httpPost } from '../shared/http'\nimport { sendBatchToOTLP } from './otlp'\nimport type { OTLPConfig } from './otlp'\n\n/**\n * Mode for {@link createPostHogDrain}.\n *\n * - `'logs'` (default) — sends events to PostHog Logs via OTLP. Cheapest path\n * and recommended for most teams.\n * - `'events'` — sends events to the `/batch/` API as custom PostHog events.\n * Useful when you want events to appear in PostHog product analytics\n * funnels/dashboards.\n */\nexport type PostHogMode = 'logs' | 'events'\n\nexport interface PostHogConfig {\n /** PostHog project API key */\n apiKey: string\n /** PostHog host URL. Default: https://us.i.posthog.com */\n host?: string\n /**\n * Send mode. `'logs'` (default) uses PostHog Logs (OTLP, cheapest);\n * `'events'` uses the `/batch/` API for custom PostHog events.\n * @default 'logs'\n */\n mode?: PostHogMode\n /**\n * PostHog event name when `mode === 'events'`. Ignored otherwise.\n * @default 'evlog_wide_event'\n */\n eventName?: string\n /**\n * Override `distinct_id` when `mode === 'events'`. Ignored otherwise.\n * Defaults to `event.userId` (when set) or `event.service`.\n */\n distinctId?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\n/**\n * @deprecated Use {@link PostHogConfig} with `mode: 'events'` instead.\n */\nexport type PostHogEventsConfig = PostHogConfig\n\n/** PostHog event structure for the batch API */\nexport interface PostHogEvent {\n event: string\n distinct_id: string\n timestamp: string\n properties: Record<string, unknown>\n}\n\nconst POSTHOG_FIELDS: ConfigField<PostHogConfig>[] = [\n { key: 'apiKey', env: ['NUXT_POSTHOG_API_KEY', 'POSTHOG_API_KEY'] },\n { key: 'host', env: ['NUXT_POSTHOG_HOST', 'POSTHOG_HOST'] },\n { key: 'mode' },\n { key: 'eventName' },\n { key: 'distinctId' },\n { key: 'timeout' },\n { key: 'retries' },\n]\n\nfunction resolveHost(config: PostHogConfig): string {\n return (config.host ?? 'https://us.i.posthog.com').replace(/\\/$/, '')\n}\n\nfunction toOTLPConfig(config: PostHogConfig): OTLPConfig {\n return {\n endpoint: `${resolveHost(config)}/i`,\n headers: { Authorization: `Bearer ${config.apiKey}` },\n timeout: config.timeout,\n retries: config.retries,\n }\n}\n\n/**\n * Convert a WideEvent to a PostHog custom event.\n */\nexport function toPostHogEvent(event: WideEvent, config: PostHogConfig): PostHogEvent {\n const { timestamp, level, service, ...rest } = event\n return {\n event: config.eventName ?? 'evlog_wide_event',\n distinct_id: config.distinctId\n ?? (typeof event.userId === 'string' ? event.userId : undefined)\n ?? service,\n timestamp,\n properties: {\n level,\n service,\n ...rest,\n },\n }\n}\n\n/**\n * Create a drain function for sending logs to PostHog.\n *\n * - Default `mode: 'logs'` — sends events to PostHog Logs via OTLP. Recommended.\n * - `mode: 'events'` — sends events to the `/batch/` API as custom events.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createPostHogDrain()\n * 2. runtimeConfig.evlog.posthog\n * 3. runtimeConfig.posthog\n * 4. Environment variables: NUXT_POSTHOG_*, POSTHOG_*\n *\n * @example\n * ```ts\n * // Default: PostHog Logs (OTLP)\n * initLogger({ drain: createPostHogDrain() })\n *\n * // Custom events\n * initLogger({ drain: createPostHogDrain({ mode: 'events', eventName: 'server_request' }) })\n * ```\n */\nexport function createPostHogDrain(overrides?: Partial<PostHogConfig>) {\n const mode: PostHogMode = overrides?.mode ?? 'logs'\n\n if (mode === 'events') {\n return defineHttpDrain<PostHogConfig>({\n name: 'posthog-events',\n resolve: async () => {\n const config = await resolveAdapterConfig<PostHogConfig>('posthog', POSTHOG_FIELDS, overrides)\n if (!config.apiKey) {\n console.error('[evlog/posthog-events] Missing apiKey. Set NUXT_POSTHOG_API_KEY env var or pass to createPostHogDrain({ mode: \\'events\\' })')\n return null\n }\n return config as PostHogConfig\n },\n encode: (events, config) => ({\n url: `${resolveHost(config)}/batch/`,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n api_key: config.apiKey,\n batch: events.map(event => toPostHogEvent(event, config)),\n }),\n }),\n })\n }\n\n return defineDrain<PostHogConfig>({\n name: 'posthog',\n resolve: async () => {\n const config = await resolveAdapterConfig<PostHogConfig>('posthog', POSTHOG_FIELDS, overrides)\n if (!config.apiKey) {\n console.error('[evlog/posthog] Missing apiKey. Set NUXT_POSTHOG_API_KEY env var or pass to createPostHogDrain()')\n return null\n }\n return config as PostHogConfig\n },\n send: async (events, config) => {\n if (events.length === 0) return\n await sendBatchToOTLP(events, toOTLPConfig(config))\n },\n })\n}\n\n/**\n * @deprecated Use {@link createPostHogDrain} with `mode: 'events'`.\n */\nexport function createPostHogEventsDrain(overrides?: Partial<PostHogConfig>) {\n return createPostHogDrain({ ...overrides, mode: 'events' })\n}\n\n/**\n * Send a single event to PostHog Logs via OTLP.\n */\nexport async function sendToPostHog(event: WideEvent, config: PostHogConfig): Promise<void> {\n await sendBatchToPostHog([event], config)\n}\n\n/**\n * Send a batch of events to PostHog Logs via OTLP.\n */\nexport async function sendBatchToPostHog(events: WideEvent[], config: PostHogConfig): Promise<void> {\n if (events.length === 0) return\n await sendBatchToOTLP(events, toOTLPConfig(config))\n}\n\n/**\n * Send a single event to PostHog via the custom-events `/batch/` API.\n */\nexport async function sendToPostHogEvents(event: WideEvent, config: PostHogConfig): Promise<void> {\n await sendBatchToPostHogEvents([event], config)\n}\n\n/**\n * Send a batch of events to PostHog via the custom-events `/batch/` API.\n */\nexport async function sendBatchToPostHogEvents(events: WideEvent[], config: PostHogConfig): Promise<void> {\n if (events.length === 0) return\n await httpPost({\n url: `${resolveHost(config)}/batch/`,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n api_key: config.apiKey,\n batch: events.map(event => toPostHogEvent(event, config)),\n }),\n timeout: config.timeout ?? 5000,\n retries: config.retries,\n label: 'PostHog',\n source: 'posthog',\n })\n}\n"],"mappings":";;;;AA2DA,MAAM,iBAA+C;CACnD;EAAE,KAAK;EAAU,KAAK,CAAC,wBAAwB,kBAAkB;EAAE;CACnE;EAAE,KAAK;EAAQ,KAAK,CAAC,qBAAqB,eAAe;EAAE;CAC3D,EAAE,KAAK,QAAQ;CACf,EAAE,KAAK,aAAa;CACpB,EAAE,KAAK,cAAc;CACrB,EAAE,KAAK,WAAW;CAClB,EAAE,KAAK,WAAW;CACnB;AAED,SAAS,YAAY,QAA+B;AAClD,SAAQ,OAAO,QAAQ,4BAA4B,QAAQ,OAAO,GAAG;;AAGvE,SAAS,aAAa,QAAmC;AACvD,QAAO;EACL,UAAU,GAAG,YAAY,OAAO,CAAC;EACjC,SAAS,EAAE,eAAe,UAAU,OAAO,UAAU;EACrD,SAAS,OAAO;EAChB,SAAS,OAAO;EACjB;;;;;AAMH,SAAgB,eAAe,OAAkB,QAAqC;CACpF,MAAM,EAAE,WAAW,OAAO,SAAS,GAAG,SAAS;AAC/C,QAAO;EACL,OAAO,OAAO,aAAa;EAC3B,aAAa,OAAO,eACd,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS,KAAA,MACnD;EACL;EACA,YAAY;GACV;GACA;GACA,GAAG;GACJ;EACF;;;;;;;;;;;;;;;;;;;;;;;AAwBH,SAAgB,mBAAmB,WAAoC;AAGrE,MAF0B,WAAW,QAAQ,YAEhC,SACX,QAAO,gBAA+B;EACpC,MAAM;EACN,SAAS,YAAY;GACnB,MAAM,SAAS,MAAM,qBAAoC,WAAW,gBAAgB,UAAU;AAC9F,OAAI,CAAC,OAAO,QAAQ;AAClB,YAAQ,MAAM,4HAA8H;AAC5I,WAAO;;AAET,UAAO;;EAET,SAAS,QAAQ,YAAY;GAC3B,KAAK,GAAG,YAAY,OAAO,CAAC;GAC5B,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU;IACnB,SAAS,OAAO;IAChB,OAAO,OAAO,KAAI,UAAS,eAAe,OAAO,OAAO,CAAC;IAC1D,CAAC;GACH;EACF,CAAC;AAGJ,QAAO,YAA2B;EAChC,MAAM;EACN,SAAS,YAAY;GACnB,MAAM,SAAS,MAAM,qBAAoC,WAAW,gBAAgB,UAAU;AAC9F,OAAI,CAAC,OAAO,QAAQ;AAClB,YAAQ,MAAM,mGAAmG;AACjH,WAAO;;AAET,UAAO;;EAET,MAAM,OAAO,QAAQ,WAAW;AAC9B,OAAI,OAAO,WAAW,EAAG;AACzB,SAAM,gBAAgB,QAAQ,aAAa,OAAO,CAAC;;EAEtD,CAAC;;;;;AAMJ,SAAgB,yBAAyB,WAAoC;AAC3E,QAAO,mBAAmB;EAAE,GAAG;EAAW,MAAM;EAAU,CAAC;;;;;AAM7D,eAAsB,cAAc,OAAkB,QAAsC;AAC1F,OAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO;;;;;AAM3C,eAAsB,mBAAmB,QAAqB,QAAsC;AAClG,KAAI,OAAO,WAAW,EAAG;AACzB,OAAM,gBAAgB,QAAQ,aAAa,OAAO,CAAC;;;;;AAMrD,eAAsB,oBAAoB,OAAkB,QAAsC;AAChG,OAAM,yBAAyB,CAAC,MAAM,EAAE,OAAO;;;;;AAMjD,eAAsB,yBAAyB,QAAqB,QAAsC;AACxG,KAAI,OAAO,WAAW,EAAG;AACzB,OAAM,SAAS;EACb,KAAK,GAAG,YAAY,OAAO,CAAC;EAC5B,SAAS,EAAE,gBAAgB,oBAAoB;EAC/C,MAAM,KAAK,UAAU;GACnB,SAAS,OAAO;GAChB,OAAO,OAAO,KAAI,UAAS,eAAe,OAAO,OAAO,CAAC;GAC1D,CAAC;EACF,SAAS,OAAO,WAAW;EAC3B,SAAS,OAAO;EAChB,OAAO;EACP,QAAQ;EACT,CAAC"}
1
+ {"version":3,"file":"posthog.mjs","names":[],"sources":["../../src/adapters/posthog.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { formatPublicEnvKeys, resolveAdapterConfig } from '../shared/config'\nimport { defineDrain, defineHttpDrain } from '../shared/drain'\nimport { httpPost } from '../shared/http'\nimport { sendBatchToOTLP } from './otlp'\nimport type { OTLPConfig } from './otlp'\n\n/**\n * Mode for {@link createPostHogDrain}.\n *\n * - `'logs'` (default) — sends events to PostHog Logs via OTLP. Cheapest path\n * and recommended for most teams.\n * - `'events'` — sends events to the `/batch/` API as custom PostHog events.\n * Useful when you want events to appear in PostHog product analytics\n * funnels/dashboards.\n */\nexport type PostHogMode = 'logs' | 'events'\n\nexport interface PostHogConfig {\n /** PostHog project API key */\n apiKey: string\n /** PostHog host URL. Default: https://us.i.posthog.com */\n host?: string\n /**\n * Send mode. `'logs'` (default) uses PostHog Logs (OTLP, cheapest);\n * `'events'` uses the `/batch/` API for custom PostHog events.\n * @default 'logs'\n */\n mode?: PostHogMode\n /**\n * PostHog event name when `mode === 'events'`. Ignored otherwise.\n * @default 'evlog_wide_event'\n */\n eventName?: string\n /**\n * Override `distinct_id` when `mode === 'events'`. Ignored otherwise.\n * Defaults to `event.userId` (when set) or `event.service`.\n */\n distinctId?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\n/**\n * @deprecated Use {@link PostHogConfig} with `mode: 'events'` instead.\n */\nexport type PostHogEventsConfig = PostHogConfig\n\n/** PostHog event structure for the batch API */\nexport interface PostHogEvent {\n event: string\n distinct_id: string\n timestamp: string\n properties: Record<string, unknown>\n}\n\nconst POSTHOG_FIELDS: ConfigField<PostHogConfig>[] = [\n { key: 'apiKey', env: ['NUXT_POSTHOG_API_KEY', 'POSTHOG_API_KEY'] },\n { key: 'host', env: ['NUXT_POSTHOG_HOST', 'POSTHOG_HOST'] },\n { key: 'mode' },\n { key: 'eventName' },\n { key: 'distinctId' },\n { key: 'timeout' },\n { key: 'retries' },\n]\n\nfunction resolveHost(config: PostHogConfig): string {\n return (config.host ?? 'https://us.i.posthog.com').replace(/\\/$/, '')\n}\n\nfunction toOTLPConfig(config: PostHogConfig): OTLPConfig {\n return {\n endpoint: `${resolveHost(config)}/i`,\n headers: { Authorization: `Bearer ${config.apiKey}` },\n timeout: config.timeout,\n retries: config.retries,\n }\n}\n\n/**\n * Convert a WideEvent to a PostHog custom event.\n */\nexport function toPostHogEvent(event: WideEvent, config: PostHogConfig): PostHogEvent {\n const { timestamp, level, service, ...rest } = event\n return {\n event: config.eventName ?? 'evlog_wide_event',\n distinct_id: config.distinctId\n ?? (typeof event.userId === 'string' ? event.userId : undefined)\n ?? service,\n timestamp,\n properties: {\n level,\n service,\n ...rest,\n },\n }\n}\n\n/**\n * Create a drain function for sending logs to PostHog.\n *\n * - Default `mode: 'logs'` — sends events to PostHog Logs via OTLP. Recommended.\n * - `mode: 'events'` — sends events to the `/batch/` API as custom events.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createPostHogDrain()\n * 2. runtimeConfig.evlog.posthog\n * 3. runtimeConfig.posthog\n * 4. Environment variables: POSTHOG_*\n *\n * @example\n * ```ts\n * // Default: PostHog Logs (OTLP)\n * initLogger({ drain: createPostHogDrain() })\n *\n * // Custom events\n * initLogger({ drain: createPostHogDrain({ mode: 'events', eventName: 'server_request' }) })\n * ```\n */\nexport function createPostHogDrain(overrides?: Partial<PostHogConfig>) {\n const mode: PostHogMode = overrides?.mode ?? 'logs'\n\n if (mode === 'events') {\n return defineHttpDrain<PostHogConfig>({\n name: 'posthog-events',\n resolve: async () => {\n const config = await resolveAdapterConfig<PostHogConfig>('posthog', POSTHOG_FIELDS, overrides)\n if (!config.apiKey) {\n console.error(`[evlog/posthog-events] Missing apiKey. Set ${formatPublicEnvKeys(['NUXT_POSTHOG_API_KEY', 'POSTHOG_API_KEY'])} env var or pass to createPostHogDrain({ mode: 'events' })`)\n return null\n }\n return config as PostHogConfig\n },\n encode: (events, config) => ({\n url: `${resolveHost(config)}/batch/`,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n api_key: config.apiKey,\n batch: events.map(event => toPostHogEvent(event, config)),\n }),\n }),\n })\n }\n\n return defineDrain<PostHogConfig>({\n name: 'posthog',\n resolve: async () => {\n const config = await resolveAdapterConfig<PostHogConfig>('posthog', POSTHOG_FIELDS, overrides)\n if (!config.apiKey) {\n console.error(`[evlog/posthog] Missing apiKey. Set ${formatPublicEnvKeys(['NUXT_POSTHOG_API_KEY', 'POSTHOG_API_KEY'])} env var or pass to createPostHogDrain()`)\n return null\n }\n return config as PostHogConfig\n },\n send: async (events, config) => {\n if (events.length === 0) return\n await sendBatchToOTLP(events, toOTLPConfig(config))\n },\n })\n}\n\n/**\n * @deprecated Use {@link createPostHogDrain} with `mode: 'events'`.\n */\nexport function createPostHogEventsDrain(overrides?: Partial<PostHogConfig>) {\n return createPostHogDrain({ ...overrides, mode: 'events' })\n}\n\n/**\n * Send a single event to PostHog Logs via OTLP.\n */\nexport async function sendToPostHog(event: WideEvent, config: PostHogConfig): Promise<void> {\n await sendBatchToPostHog([event], config)\n}\n\n/**\n * Send a batch of events to PostHog Logs via OTLP.\n */\nexport async function sendBatchToPostHog(events: WideEvent[], config: PostHogConfig): Promise<void> {\n if (events.length === 0) return\n await sendBatchToOTLP(events, toOTLPConfig(config))\n}\n\n/**\n * Send a single event to PostHog via the custom-events `/batch/` API.\n */\nexport async function sendToPostHogEvents(event: WideEvent, config: PostHogConfig): Promise<void> {\n await sendBatchToPostHogEvents([event], config)\n}\n\n/**\n * Send a batch of events to PostHog via the custom-events `/batch/` API.\n */\nexport async function sendBatchToPostHogEvents(events: WideEvent[], config: PostHogConfig): Promise<void> {\n if (events.length === 0) return\n await httpPost({\n url: `${resolveHost(config)}/batch/`,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n api_key: config.apiKey,\n batch: events.map(event => toPostHogEvent(event, config)),\n }),\n timeout: config.timeout ?? 5000,\n retries: config.retries,\n label: 'PostHog',\n source: 'posthog',\n })\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { I as DrainContext, ct as WideEvent } from "../audit-DVdkntSO.mjs";
1
+ import { B as DrainContext, ft as WideEvent } from "../audit-D7v6JHj0.mjs";
2
2
  //#region src/adapters/sentry.d.ts
3
3
  interface SentryConfig {
4
4
  /** Sentry DSN */
@@ -39,11 +39,11 @@ declare function toSentryLog(event: WideEvent, config: SentryConfig): SentryLog;
39
39
  * 1. Overrides passed to createSentryDrain()
40
40
  * 2. runtimeConfig.evlog.sentry
41
41
  * 3. runtimeConfig.sentry
42
- * 4. Environment variables: NUXT_SENTRY_*, SENTRY_*
42
+ * 4. Environment variables: SENTRY_*
43
43
  *
44
44
  * @example
45
45
  * ```ts
46
- * // Zero config - just set NUXT_SENTRY_DSN env var
46
+ * // Zero config - just set SENTRY_DSN env var
47
47
  * nitroApp.hooks.hook('evlog:drain', createSentryDrain())
48
48
  *
49
49
  * // With overrides
@@ -1,6 +1,6 @@
1
- import { r as httpPost } from "../http-B6YgAhyN.mjs";
2
- import { i as resolveAdapterConfig, n as defineHttpDrain } from "../drain-7n3K6kPe.mjs";
3
- import { t as OTEL_SEVERITY_NUMBER } from "../severity-R5Egq3qz.mjs";
1
+ import { r as httpPost } from "../http-ChVS9GYc.mjs";
2
+ import { i as formatPublicEnvKeys, n as defineHttpDrain, o as resolveAdapterConfig } from "../drain-fDb-eNwz.mjs";
3
+ import { t as OTEL_SEVERITY_NUMBER } from "../severity-CwXUSHt3.mjs";
4
4
  //#region src/adapters/sentry.ts
5
5
  const SENTRY_FIELDS = [
6
6
  {
@@ -151,11 +151,11 @@ function buildEnvelopeBody(logs, dsn) {
151
151
  * 1. Overrides passed to createSentryDrain()
152
152
  * 2. runtimeConfig.evlog.sentry
153
153
  * 3. runtimeConfig.sentry
154
- * 4. Environment variables: NUXT_SENTRY_*, SENTRY_*
154
+ * 4. Environment variables: SENTRY_*
155
155
  *
156
156
  * @example
157
157
  * ```ts
158
- * // Zero config - just set NUXT_SENTRY_DSN env var
158
+ * // Zero config - just set SENTRY_DSN env var
159
159
  * nitroApp.hooks.hook('evlog:drain', createSentryDrain())
160
160
  *
161
161
  * // With overrides
@@ -170,7 +170,7 @@ function createSentryDrain(overrides) {
170
170
  resolve: async () => {
171
171
  const config = await resolveAdapterConfig("sentry", SENTRY_FIELDS, overrides);
172
172
  if (!config.dsn) {
173
- console.error("[evlog/sentry] Missing DSN. Set NUXT_SENTRY_DSN/SENTRY_DSN env var or pass to createSentryDrain()");
173
+ console.error(`[evlog/sentry] Missing DSN. Set ${formatPublicEnvKeys(["NUXT_SENTRY_DSN", "SENTRY_DSN"])} env var or pass to createSentryDrain()`);
174
174
  return null;
175
175
  }
176
176
  return config;
@@ -1 +1 @@
1
- {"version":3,"file":"sentry.mjs","names":[],"sources":["../../src/adapters/sentry.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineHttpDrain } from '../shared/drain'\nimport { httpPost } from '../shared/http'\nimport { OTEL_SEVERITY_NUMBER } from '../shared/severity'\n\nexport interface SentryConfig {\n /** Sentry DSN */\n dsn: string\n /** Environment override (defaults to event.environment) */\n environment?: string\n /** Release version override (defaults to event.version) */\n release?: string\n /** Additional tags to attach as attributes */\n tags?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\n/** Sentry Log attribute value with type annotation */\nexport interface SentryAttributeValue {\n value: string | number | boolean\n type: 'string' | 'integer' | 'double' | 'boolean'\n}\n\n/** Sentry Structured Log payload */\nexport interface SentryLog {\n timestamp: number\n trace_id: string\n level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'\n body: string\n severity_number: number\n attributes?: Record<string, SentryAttributeValue>\n}\n\ninterface SentryDsnParts {\n publicKey: string\n secretKey?: string\n projectId: string\n origin: string\n basePath: string\n}\n\nconst SENTRY_FIELDS: ConfigField<SentryConfig>[] = [\n { key: 'dsn', env: ['NUXT_SENTRY_DSN', 'SENTRY_DSN'] },\n { key: 'environment', env: ['NUXT_SENTRY_ENVIRONMENT', 'SENTRY_ENVIRONMENT'] },\n { key: 'release', env: ['NUXT_SENTRY_RELEASE', 'SENTRY_RELEASE'] },\n { key: 'tags' },\n { key: 'timeout' },\n { key: 'retries' },\n]\n\nfunction parseSentryDsn(dsn: string): SentryDsnParts {\n const url = new URL(dsn)\n const publicKey = url.username\n if (!publicKey) {\n throw new Error('Invalid Sentry DSN: missing public key')\n }\n\n const secretKey = url.password || undefined\n\n const pathParts = url.pathname.split('/').filter(Boolean)\n const projectId = pathParts.pop()\n if (!projectId) {\n throw new Error('Invalid Sentry DSN: missing project ID')\n }\n\n const basePath = pathParts.length > 0 ? `/${pathParts.join('/')}` : ''\n\n return {\n publicKey,\n secretKey,\n projectId,\n origin: `${url.protocol}//${url.host}`,\n basePath,\n }\n}\n\nfunction getSentryEnvelopeUrl(dsn: string): { url: string, authHeader: string } {\n const { publicKey, secretKey, projectId, origin, basePath } = parseSentryDsn(dsn)\n const url = `${origin}${basePath}/api/${projectId}/envelope/`\n let authHeader = `Sentry sentry_version=7, sentry_key=${publicKey}, sentry_client=evlog`\n if (secretKey) {\n authHeader += `, sentry_secret=${secretKey}`\n }\n return { url, authHeader }\n}\n\nfunction createTraceId(): string {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID().replace(/-/g, '')\n }\n\n return Array.from({ length: 32 }, () => Math.floor(Math.random() * 16).toString(16)).join('')\n}\n\nfunction getFirstStringValue(event: WideEvent, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = event[key]\n if (typeof value === 'string' && value.length > 0) return value\n }\n return undefined\n}\n\nfunction toAttributeValue(value: unknown): SentryAttributeValue | undefined {\n if (value === null || value === undefined) {\n return undefined\n }\n if (typeof value === 'string') {\n return { value, type: 'string' }\n }\n if (typeof value === 'boolean') {\n return { value, type: 'boolean' }\n }\n if (typeof value === 'number') {\n if (Number.isInteger(value)) {\n return { value, type: 'integer' }\n }\n return { value, type: 'double' }\n }\n return { value: JSON.stringify(value), type: 'string' }\n}\n\nexport function toSentryLog(event: WideEvent, config: SentryConfig): SentryLog {\n const { timestamp, level, service, environment, version, ...rest } = event\n\n const body = getFirstStringValue(event, ['message', 'action', 'path'])\n ?? 'evlog wide event'\n\n const traceId = (typeof event.traceId === 'string' && event.traceId.length > 0)\n ? event.traceId\n : createTraceId()\n\n const attributes: Record<string, SentryAttributeValue> = {}\n\n const env = config.environment ?? environment\n if (env) {\n attributes['sentry.environment'] = { value: env, type: 'string' }\n }\n\n const rel = config.release ?? version\n if (typeof rel === 'string' && rel.length > 0) {\n attributes['sentry.release'] = { value: rel, type: 'string' }\n }\n\n attributes['service'] = { value: service, type: 'string' }\n\n if (config.tags) {\n for (const [key, value] of Object.entries(config.tags)) {\n attributes[key] = { value, type: 'string' }\n }\n }\n\n for (const [key, value] of Object.entries(rest)) {\n if (key === 'traceId' || key === 'spanId') continue\n if (value === undefined || value === null) continue\n const attr = toAttributeValue(value)\n if (attr) {\n attributes[key] = attr\n }\n }\n\n return {\n timestamp: new Date(timestamp).getTime() / 1000,\n trace_id: traceId,\n level: level as SentryLog['level'],\n body,\n severity_number: OTEL_SEVERITY_NUMBER[level] ?? 9,\n attributes,\n }\n}\n\n/**\n * Build the Sentry Envelope body for a list of logs.\n *\n * Envelope format (line-delimited):\n * - Line 1: Envelope headers (dsn, sent_at)\n * - Line 2: Item header (type: log, item_count, content_type)\n * - Line 3: Item payload ({\"items\": [...]})\n */\nfunction buildEnvelopeBody(logs: SentryLog[], dsn: string): string {\n const envelopeHeader = JSON.stringify({\n dsn,\n sent_at: new Date().toISOString(),\n })\n\n const itemHeader = JSON.stringify({\n type: 'log',\n item_count: logs.length,\n content_type: 'application/vnd.sentry.items.log+json',\n })\n\n const itemPayload = JSON.stringify({ items: logs })\n\n return `${envelopeHeader}\\n${itemHeader}\\n${itemPayload}\\n`\n}\n\n/**\n * Create a drain function for sending logs to Sentry.\n *\n * Sends wide events as Sentry Structured Logs, visible in Explore > Logs\n * in the Sentry dashboard.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createSentryDrain()\n * 2. runtimeConfig.evlog.sentry\n * 3. runtimeConfig.sentry\n * 4. Environment variables: NUXT_SENTRY_*, SENTRY_*\n *\n * @example\n * ```ts\n * // Zero config - just set NUXT_SENTRY_DSN env var\n * nitroApp.hooks.hook('evlog:drain', createSentryDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('evlog:drain', createSentryDrain({\n * dsn: 'https://public@o0.ingest.sentry.io/123',\n * }))\n * ```\n */\nexport function createSentryDrain(overrides?: Partial<SentryConfig>) {\n return defineHttpDrain<SentryConfig>({\n name: 'sentry',\n resolve: async () => {\n const config = await resolveAdapterConfig<SentryConfig>('sentry', SENTRY_FIELDS, overrides)\n if (!config.dsn) {\n console.error('[evlog/sentry] Missing DSN. Set NUXT_SENTRY_DSN/SENTRY_DSN env var or pass to createSentryDrain()')\n return null\n }\n return config as SentryConfig\n },\n encode: (events, config) => {\n const { url, authHeader } = getSentryEnvelopeUrl(config.dsn)\n const logs = events.map(event => toSentryLog(event, config))\n return {\n url,\n headers: {\n 'Content-Type': 'application/x-sentry-envelope',\n 'X-Sentry-Auth': authHeader,\n },\n body: buildEnvelopeBody(logs, config.dsn),\n }\n },\n })\n}\n\n/**\n * Send a single event to Sentry as a structured log.\n *\n * @example\n * ```ts\n * await sendToSentry(event, {\n * dsn: process.env.SENTRY_DSN!,\n * })\n * ```\n */\nexport async function sendToSentry(event: WideEvent, config: SentryConfig): Promise<void> {\n await sendBatchToSentry([event], config)\n}\n\n/**\n * Send a batch of events to Sentry as structured logs via the Envelope endpoint.\n *\n * @example\n * ```ts\n * await sendBatchToSentry(events, {\n * dsn: process.env.SENTRY_DSN!,\n * })\n * ```\n */\nexport async function sendBatchToSentry(events: WideEvent[], config: SentryConfig): Promise<void> {\n if (events.length === 0) return\n\n const { url, authHeader } = getSentryEnvelopeUrl(config.dsn)\n\n const logs = events.map(event => toSentryLog(event, config))\n const body = buildEnvelopeBody(logs, config.dsn)\n\n await httpPost({\n url,\n headers: {\n 'Content-Type': 'application/x-sentry-envelope',\n 'X-Sentry-Auth': authHeader,\n },\n body,\n timeout: config.timeout ?? 5000,\n retries: config.retries,\n label: 'Sentry',\n source: 'sentry',\n })\n}\n"],"mappings":";;;;AA8CA,MAAM,gBAA6C;CACjD;EAAE,KAAK;EAAO,KAAK,CAAC,mBAAmB,aAAa;EAAE;CACtD;EAAE,KAAK;EAAe,KAAK,CAAC,2BAA2B,qBAAqB;EAAE;CAC9E;EAAE,KAAK;EAAW,KAAK,CAAC,uBAAuB,iBAAiB;EAAE;CAClE,EAAE,KAAK,QAAQ;CACf,EAAE,KAAK,WAAW;CAClB,EAAE,KAAK,WAAW;CACnB;AAED,SAAS,eAAe,KAA6B;CACnD,MAAM,MAAM,IAAI,IAAI,IAAI;CACxB,MAAM,YAAY,IAAI;AACtB,KAAI,CAAC,UACH,OAAM,IAAI,MAAM,yCAAyC;CAG3D,MAAM,YAAY,IAAI,YAAY,KAAA;CAElC,MAAM,YAAY,IAAI,SAAS,MAAM,IAAI,CAAC,OAAO,QAAQ;CACzD,MAAM,YAAY,UAAU,KAAK;AACjC,KAAI,CAAC,UACH,OAAM,IAAI,MAAM,yCAAyC;CAG3D,MAAM,WAAW,UAAU,SAAS,IAAI,IAAI,UAAU,KAAK,IAAI,KAAK;AAEpE,QAAO;EACL;EACA;EACA;EACA,QAAQ,GAAG,IAAI,SAAS,IAAI,IAAI;EAChC;EACD;;AAGH,SAAS,qBAAqB,KAAkD;CAC9E,MAAM,EAAE,WAAW,WAAW,WAAW,QAAQ,aAAa,eAAe,IAAI;CACjF,MAAM,MAAM,GAAG,SAAS,SAAS,OAAO,UAAU;CAClD,IAAI,aAAa,uCAAuC,UAAU;AAClE,KAAI,UACF,eAAc,mBAAmB;AAEnC,QAAO;EAAE;EAAK;EAAY;;AAG5B,SAAS,gBAAwB;AAC/B,KAAI,OAAO,WAAW,QAAQ,eAAe,WAC3C,QAAO,WAAW,OAAO,YAAY,CAAC,QAAQ,MAAM,GAAG;AAGzD,QAAO,MAAM,KAAK,EAAE,QAAQ,IAAI,QAAQ,KAAK,MAAM,KAAK,QAAQ,GAAG,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,GAAG;;AAG/F,SAAS,oBAAoB,OAAkB,MAAoC;AACjF,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,MAAM;AACpB,MAAI,OAAO,UAAU,YAAY,MAAM,SAAS,EAAG,QAAO;;;AAK9D,SAAS,iBAAiB,OAAkD;AAC1E,KAAI,UAAU,QAAQ,UAAU,KAAA,EAC9B;AAEF,KAAI,OAAO,UAAU,SACnB,QAAO;EAAE;EAAO,MAAM;EAAU;AAElC,KAAI,OAAO,UAAU,UACnB,QAAO;EAAE;EAAO,MAAM;EAAW;AAEnC,KAAI,OAAO,UAAU,UAAU;AAC7B,MAAI,OAAO,UAAU,MAAM,CACzB,QAAO;GAAE;GAAO,MAAM;GAAW;AAEnC,SAAO;GAAE;GAAO,MAAM;GAAU;;AAElC,QAAO;EAAE,OAAO,KAAK,UAAU,MAAM;EAAE,MAAM;EAAU;;AAGzD,SAAgB,YAAY,OAAkB,QAAiC;CAC7E,MAAM,EAAE,WAAW,OAAO,SAAS,aAAa,SAAS,GAAG,SAAS;CAErE,MAAM,OAAO,oBAAoB,OAAO;EAAC;EAAW;EAAU;EAAO,CAAC,IACjE;CAEL,MAAM,UAAW,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,SAAS,IACzE,MAAM,UACN,eAAe;CAEnB,MAAM,aAAmD,EAAE;CAE3D,MAAM,MAAM,OAAO,eAAe;AAClC,KAAI,IACF,YAAW,wBAAwB;EAAE,OAAO;EAAK,MAAM;EAAU;CAGnE,MAAM,MAAM,OAAO,WAAW;AAC9B,KAAI,OAAO,QAAQ,YAAY,IAAI,SAAS,EAC1C,YAAW,oBAAoB;EAAE,OAAO;EAAK,MAAM;EAAU;AAG/D,YAAW,aAAa;EAAE,OAAO;EAAS,MAAM;EAAU;AAE1D,KAAI,OAAO,KACT,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,KAAK,CACpD,YAAW,OAAO;EAAE;EAAO,MAAM;EAAU;AAI/C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,EAAE;AAC/C,MAAI,QAAQ,aAAa,QAAQ,SAAU;AAC3C,MAAI,UAAU,KAAA,KAAa,UAAU,KAAM;EAC3C,MAAM,OAAO,iBAAiB,MAAM;AACpC,MAAI,KACF,YAAW,OAAO;;AAItB,QAAO;EACL,WAAW,IAAI,KAAK,UAAU,CAAC,SAAS,GAAG;EAC3C,UAAU;EACH;EACP;EACA,iBAAiB,qBAAqB,UAAU;EAChD;EACD;;;;;;;;;;AAWH,SAAS,kBAAkB,MAAmB,KAAqB;AAcjE,QAAO,GAbgB,KAAK,UAAU;EACpC;EACA,0BAAS,IAAI,MAAM,EAAC,aAAa;EAClC,CAUuB,CAAC,IARN,KAAK,UAAU;EAChC,MAAM;EACN,YAAY,KAAK;EACjB,cAAc;EACf,CAIsC,CAAC,IAFpB,KAAK,UAAU,EAAE,OAAO,MAAM,CAEK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA0B1D,SAAgB,kBAAkB,WAAmC;AACnE,QAAO,gBAA8B;EACnC,MAAM;EACN,SAAS,YAAY;GACnB,MAAM,SAAS,MAAM,qBAAmC,UAAU,eAAe,UAAU;AAC3F,OAAI,CAAC,OAAO,KAAK;AACf,YAAQ,MAAM,oGAAoG;AAClH,WAAO;;AAET,UAAO;;EAET,SAAS,QAAQ,WAAW;GAC1B,MAAM,EAAE,KAAK,eAAe,qBAAqB,OAAO,IAAI;GAC5D,MAAM,OAAO,OAAO,KAAI,UAAS,YAAY,OAAO,OAAO,CAAC;AAC5D,UAAO;IACL;IACA,SAAS;KACP,gBAAgB;KAChB,iBAAiB;KAClB;IACD,MAAM,kBAAkB,MAAM,OAAO,IAAI;IAC1C;;EAEJ,CAAC;;;;;;;;;;;;AAaJ,eAAsB,aAAa,OAAkB,QAAqC;AACxF,OAAM,kBAAkB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;AAa1C,eAAsB,kBAAkB,QAAqB,QAAqC;AAChG,KAAI,OAAO,WAAW,EAAG;CAEzB,MAAM,EAAE,KAAK,eAAe,qBAAqB,OAAO,IAAI;CAG5D,MAAM,OAAO,kBADA,OAAO,KAAI,UAAS,YAAY,OAAO,OAAO,CACxB,EAAE,OAAO,IAAI;AAEhD,OAAM,SAAS;EACb;EACA,SAAS;GACP,gBAAgB;GAChB,iBAAiB;GAClB;EACD;EACA,SAAS,OAAO,WAAW;EAC3B,SAAS,OAAO;EAChB,OAAO;EACP,QAAQ;EACT,CAAC"}
1
+ {"version":3,"file":"sentry.mjs","names":[],"sources":["../../src/adapters/sentry.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { formatPublicEnvKeys, resolveAdapterConfig } from '../shared/config'\nimport { defineHttpDrain } from '../shared/drain'\nimport { httpPost } from '../shared/http'\nimport { OTEL_SEVERITY_NUMBER } from '../shared/severity'\n\nexport interface SentryConfig {\n /** Sentry DSN */\n dsn: string\n /** Environment override (defaults to event.environment) */\n environment?: string\n /** Release version override (defaults to event.version) */\n release?: string\n /** Additional tags to attach as attributes */\n tags?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\n/** Sentry Log attribute value with type annotation */\nexport interface SentryAttributeValue {\n value: string | number | boolean\n type: 'string' | 'integer' | 'double' | 'boolean'\n}\n\n/** Sentry Structured Log payload */\nexport interface SentryLog {\n timestamp: number\n trace_id: string\n level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'\n body: string\n severity_number: number\n attributes?: Record<string, SentryAttributeValue>\n}\n\ninterface SentryDsnParts {\n publicKey: string\n secretKey?: string\n projectId: string\n origin: string\n basePath: string\n}\n\nconst SENTRY_FIELDS: ConfigField<SentryConfig>[] = [\n { key: 'dsn', env: ['NUXT_SENTRY_DSN', 'SENTRY_DSN'] },\n { key: 'environment', env: ['NUXT_SENTRY_ENVIRONMENT', 'SENTRY_ENVIRONMENT'] },\n { key: 'release', env: ['NUXT_SENTRY_RELEASE', 'SENTRY_RELEASE'] },\n { key: 'tags' },\n { key: 'timeout' },\n { key: 'retries' },\n]\n\nfunction parseSentryDsn(dsn: string): SentryDsnParts {\n const url = new URL(dsn)\n const publicKey = url.username\n if (!publicKey) {\n throw new Error('Invalid Sentry DSN: missing public key')\n }\n\n const secretKey = url.password || undefined\n\n const pathParts = url.pathname.split('/').filter(Boolean)\n const projectId = pathParts.pop()\n if (!projectId) {\n throw new Error('Invalid Sentry DSN: missing project ID')\n }\n\n const basePath = pathParts.length > 0 ? `/${pathParts.join('/')}` : ''\n\n return {\n publicKey,\n secretKey,\n projectId,\n origin: `${url.protocol}//${url.host}`,\n basePath,\n }\n}\n\nfunction getSentryEnvelopeUrl(dsn: string): { url: string, authHeader: string } {\n const { publicKey, secretKey, projectId, origin, basePath } = parseSentryDsn(dsn)\n const url = `${origin}${basePath}/api/${projectId}/envelope/`\n let authHeader = `Sentry sentry_version=7, sentry_key=${publicKey}, sentry_client=evlog`\n if (secretKey) {\n authHeader += `, sentry_secret=${secretKey}`\n }\n return { url, authHeader }\n}\n\nfunction createTraceId(): string {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID().replace(/-/g, '')\n }\n\n return Array.from({ length: 32 }, () => Math.floor(Math.random() * 16).toString(16)).join('')\n}\n\nfunction getFirstStringValue(event: WideEvent, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = event[key]\n if (typeof value === 'string' && value.length > 0) return value\n }\n return undefined\n}\n\nfunction toAttributeValue(value: unknown): SentryAttributeValue | undefined {\n if (value === null || value === undefined) {\n return undefined\n }\n if (typeof value === 'string') {\n return { value, type: 'string' }\n }\n if (typeof value === 'boolean') {\n return { value, type: 'boolean' }\n }\n if (typeof value === 'number') {\n if (Number.isInteger(value)) {\n return { value, type: 'integer' }\n }\n return { value, type: 'double' }\n }\n return { value: JSON.stringify(value), type: 'string' }\n}\n\nexport function toSentryLog(event: WideEvent, config: SentryConfig): SentryLog {\n const { timestamp, level, service, environment, version, ...rest } = event\n\n const body = getFirstStringValue(event, ['message', 'action', 'path'])\n ?? 'evlog wide event'\n\n const traceId = (typeof event.traceId === 'string' && event.traceId.length > 0)\n ? event.traceId\n : createTraceId()\n\n const attributes: Record<string, SentryAttributeValue> = {}\n\n const env = config.environment ?? environment\n if (env) {\n attributes['sentry.environment'] = { value: env, type: 'string' }\n }\n\n const rel = config.release ?? version\n if (typeof rel === 'string' && rel.length > 0) {\n attributes['sentry.release'] = { value: rel, type: 'string' }\n }\n\n attributes['service'] = { value: service, type: 'string' }\n\n if (config.tags) {\n for (const [key, value] of Object.entries(config.tags)) {\n attributes[key] = { value, type: 'string' }\n }\n }\n\n for (const [key, value] of Object.entries(rest)) {\n if (key === 'traceId' || key === 'spanId') continue\n if (value === undefined || value === null) continue\n const attr = toAttributeValue(value)\n if (attr) {\n attributes[key] = attr\n }\n }\n\n return {\n timestamp: new Date(timestamp).getTime() / 1000,\n trace_id: traceId,\n level: level as SentryLog['level'],\n body,\n severity_number: OTEL_SEVERITY_NUMBER[level] ?? 9,\n attributes,\n }\n}\n\n/**\n * Build the Sentry Envelope body for a list of logs.\n *\n * Envelope format (line-delimited):\n * - Line 1: Envelope headers (dsn, sent_at)\n * - Line 2: Item header (type: log, item_count, content_type)\n * - Line 3: Item payload ({\"items\": [...]})\n */\nfunction buildEnvelopeBody(logs: SentryLog[], dsn: string): string {\n const envelopeHeader = JSON.stringify({\n dsn,\n sent_at: new Date().toISOString(),\n })\n\n const itemHeader = JSON.stringify({\n type: 'log',\n item_count: logs.length,\n content_type: 'application/vnd.sentry.items.log+json',\n })\n\n const itemPayload = JSON.stringify({ items: logs })\n\n return `${envelopeHeader}\\n${itemHeader}\\n${itemPayload}\\n`\n}\n\n/**\n * Create a drain function for sending logs to Sentry.\n *\n * Sends wide events as Sentry Structured Logs, visible in Explore > Logs\n * in the Sentry dashboard.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createSentryDrain()\n * 2. runtimeConfig.evlog.sentry\n * 3. runtimeConfig.sentry\n * 4. Environment variables: SENTRY_*\n *\n * @example\n * ```ts\n * // Zero config - just set SENTRY_DSN env var\n * nitroApp.hooks.hook('evlog:drain', createSentryDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('evlog:drain', createSentryDrain({\n * dsn: 'https://public@o0.ingest.sentry.io/123',\n * }))\n * ```\n */\nexport function createSentryDrain(overrides?: Partial<SentryConfig>) {\n return defineHttpDrain<SentryConfig>({\n name: 'sentry',\n resolve: async () => {\n const config = await resolveAdapterConfig<SentryConfig>('sentry', SENTRY_FIELDS, overrides)\n if (!config.dsn) {\n console.error(`[evlog/sentry] Missing DSN. Set ${formatPublicEnvKeys(['NUXT_SENTRY_DSN', 'SENTRY_DSN'])} env var or pass to createSentryDrain()`)\n return null\n }\n return config as SentryConfig\n },\n encode: (events, config) => {\n const { url, authHeader } = getSentryEnvelopeUrl(config.dsn)\n const logs = events.map(event => toSentryLog(event, config))\n return {\n url,\n headers: {\n 'Content-Type': 'application/x-sentry-envelope',\n 'X-Sentry-Auth': authHeader,\n },\n body: buildEnvelopeBody(logs, config.dsn),\n }\n },\n })\n}\n\n/**\n * Send a single event to Sentry as a structured log.\n *\n * @example\n * ```ts\n * await sendToSentry(event, {\n * dsn: process.env.SENTRY_DSN!,\n * })\n * ```\n */\nexport async function sendToSentry(event: WideEvent, config: SentryConfig): Promise<void> {\n await sendBatchToSentry([event], config)\n}\n\n/**\n * Send a batch of events to Sentry as structured logs via the Envelope endpoint.\n *\n * @example\n * ```ts\n * await sendBatchToSentry(events, {\n * dsn: process.env.SENTRY_DSN!,\n * })\n * ```\n */\nexport async function sendBatchToSentry(events: WideEvent[], config: SentryConfig): Promise<void> {\n if (events.length === 0) return\n\n const { url, authHeader } = getSentryEnvelopeUrl(config.dsn)\n\n const logs = events.map(event => toSentryLog(event, config))\n const body = buildEnvelopeBody(logs, config.dsn)\n\n await httpPost({\n url,\n headers: {\n 'Content-Type': 'application/x-sentry-envelope',\n 'X-Sentry-Auth': authHeader,\n },\n body,\n timeout: config.timeout ?? 5000,\n retries: config.retries,\n label: 'Sentry',\n source: 'sentry',\n })\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { $ as RequestLogger } from "../audit-DVdkntSO.mjs";
1
+ import { rt as RequestLogger } from "../audit-D7v6JHj0.mjs";
2
2
  import { GatewayModelId, TelemetryIntegration } from "ai";
3
3
  import { LanguageModelV3, LanguageModelV3Middleware } from "@ai-sdk/provider";
4
4