evlog 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +27 -0
  2. package/dist/_drain-C9Nr-6Wc.mjs +18 -0
  3. package/dist/_drain-C9Nr-6Wc.mjs.map +1 -0
  4. package/dist/_http-C2UoHWgm.mjs +82 -0
  5. package/dist/_http-C2UoHWgm.mjs.map +1 -0
  6. package/dist/{_severity-Q1BuITU_.mjs → _severity-BLiOKoxh.mjs} +1 -1
  7. package/dist/{_severity-Q1BuITU_.mjs.map → _severity-BLiOKoxh.mjs.map} +1 -1
  8. package/dist/adapters/axiom.d.mts +3 -1
  9. package/dist/adapters/axiom.d.mts.map +1 -1
  10. package/dist/adapters/axiom.mjs +5 -2
  11. package/dist/adapters/axiom.mjs.map +1 -1
  12. package/dist/adapters/better-stack.d.mts +3 -1
  13. package/dist/adapters/better-stack.d.mts.map +1 -1
  14. package/dist/adapters/better-stack.mjs +5 -2
  15. package/dist/adapters/better-stack.mjs.map +1 -1
  16. package/dist/adapters/fs.d.mts +37 -0
  17. package/dist/adapters/fs.d.mts.map +1 -0
  18. package/dist/adapters/fs.mjs +106 -0
  19. package/dist/adapters/fs.mjs.map +1 -0
  20. package/dist/adapters/otlp.d.mts +3 -1
  21. package/dist/adapters/otlp.d.mts.map +1 -1
  22. package/dist/adapters/otlp.mjs +6 -3
  23. package/dist/adapters/otlp.mjs.map +1 -1
  24. package/dist/adapters/posthog.d.mts +3 -1
  25. package/dist/adapters/posthog.d.mts.map +1 -1
  26. package/dist/adapters/posthog.mjs +7 -3
  27. package/dist/adapters/posthog.mjs.map +1 -1
  28. package/dist/adapters/sentry.d.mts +3 -1
  29. package/dist/adapters/sentry.d.mts.map +1 -1
  30. package/dist/adapters/sentry.mjs +6 -3
  31. package/dist/adapters/sentry.mjs.map +1 -1
  32. package/dist/ai/index.d.mts +88 -0
  33. package/dist/ai/index.d.mts.map +1 -0
  34. package/dist/ai/index.mjs +199 -0
  35. package/dist/ai/index.mjs.map +1 -0
  36. package/dist/browser.d.mts +1 -1
  37. package/dist/client.d.mts +2 -0
  38. package/dist/client.mjs +2 -0
  39. package/dist/{dist-BsWcv7B8.mjs → dist-BFn8qsRC.mjs} +1 -1
  40. package/dist/{dist-BsWcv7B8.mjs.map → dist-BFn8qsRC.mjs.map} +1 -1
  41. package/dist/elysia/index.d.mts +2 -2
  42. package/dist/elysia/index.mjs +1 -1
  43. package/dist/enrichers.d.mts +1 -1
  44. package/dist/{error-iV3zJCY3.d.mts → error-BheHTFFB.d.mts} +2 -2
  45. package/dist/{error-iV3zJCY3.d.mts.map → error-BheHTFFB.d.mts.map} +1 -1
  46. package/dist/error.d.mts +1 -1
  47. package/dist/{errors-BJRXUfMg.mjs → errors-BQgyQ9xe.mjs} +1 -1
  48. package/dist/{errors-BJRXUfMg.mjs.map → errors-BQgyQ9xe.mjs.map} +1 -1
  49. package/dist/{errors-CKSfdvLa.d.mts → errors-D8WVZclz.d.mts} +2 -2
  50. package/dist/{errors-CKSfdvLa.d.mts.map → errors-D8WVZclz.d.mts.map} +1 -1
  51. package/dist/express/index.d.mts +2 -2
  52. package/dist/express/index.mjs +3 -3
  53. package/dist/express/index.mjs.map +1 -1
  54. package/dist/fastify/index.d.mts +2 -2
  55. package/dist/fastify/index.mjs +2 -2
  56. package/dist/{headers-Ba1eKT3i.mjs → headers-DJ_YZbxT.mjs} +9 -8
  57. package/dist/headers-DJ_YZbxT.mjs.map +1 -0
  58. package/dist/hono/index.d.mts +2 -2
  59. package/dist/hono/index.mjs +1 -1
  60. package/dist/index.d.mts +5 -5
  61. package/dist/{logger-CvDYZUze.d.mts → logger-BkXYNnHP.d.mts} +21 -5
  62. package/dist/logger-BkXYNnHP.d.mts.map +1 -0
  63. package/dist/logger.d.mts +2 -2
  64. package/dist/logger.mjs +111 -109
  65. package/dist/logger.mjs.map +1 -1
  66. package/dist/{middleware-hZqyXoSk.d.mts → middleware-B-4hPOVG.d.mts} +2 -2
  67. package/dist/{middleware-hZqyXoSk.d.mts.map → middleware-B-4hPOVG.d.mts.map} +1 -1
  68. package/dist/nestjs/index.d.mts +2 -2
  69. package/dist/nestjs/index.d.mts.map +1 -1
  70. package/dist/nestjs/index.mjs +3 -3
  71. package/dist/nestjs/index.mjs.map +1 -1
  72. package/dist/next/client.d.mts +1 -1
  73. package/dist/next/index.d.mts +10 -4
  74. package/dist/next/index.d.mts.map +1 -1
  75. package/dist/next/index.mjs +8 -5
  76. package/dist/next/index.mjs.map +1 -1
  77. package/dist/nitro/errorHandler.mjs +2 -2
  78. package/dist/nitro/module.d.mts +2 -2
  79. package/dist/nitro/plugin.mjs +6 -4
  80. package/dist/nitro/plugin.mjs.map +1 -1
  81. package/dist/nitro/v3/errorHandler.mjs +3 -3
  82. package/dist/nitro/v3/module.d.mts +1 -1
  83. package/dist/nitro/v3/plugin.mjs +7 -5
  84. package/dist/nitro/v3/plugin.mjs.map +1 -1
  85. package/dist/nitro/v3/useLogger.d.mts +1 -1
  86. package/dist/{nitro-D1pPm37T.mjs → nitro-CzyGROOC.mjs} +2 -2
  87. package/dist/nitro-CzyGROOC.mjs.map +1 -0
  88. package/dist/{nitro-CGGTUned.d.mts → nitro-DCNNxY_7.d.mts} +10 -2
  89. package/dist/nitro-DCNNxY_7.d.mts.map +1 -0
  90. package/dist/nuxt/module.d.mts +21 -1
  91. package/dist/nuxt/module.d.mts.map +1 -1
  92. package/dist/nuxt/module.mjs +7 -2
  93. package/dist/nuxt/module.mjs.map +1 -1
  94. package/dist/{parseError-BztqcPwZ.d.mts → parseError-B08FS7EQ.d.mts} +2 -2
  95. package/dist/parseError-B08FS7EQ.d.mts.map +1 -0
  96. package/dist/{routes-CE3_c-iZ.mjs → routes-CGPmbzCZ.mjs} +1 -1
  97. package/dist/{routes-CE3_c-iZ.mjs.map → routes-CGPmbzCZ.mjs.map} +1 -1
  98. package/dist/runtime/client/log.d.mts +1 -1
  99. package/dist/runtime/server/useLogger.d.mts +1 -1
  100. package/dist/runtime/utils/parseError.d.mts +2 -2
  101. package/dist/source-location-B1VVgXkh.mjs +1165 -0
  102. package/dist/source-location-B1VVgXkh.mjs.map +1 -0
  103. package/dist/{storage-CJBW5Vos.mjs → storage-DsueXspk.mjs} +1 -1
  104. package/dist/{storage-CJBW5Vos.mjs.map → storage-DsueXspk.mjs.map} +1 -1
  105. package/dist/sveltekit/index.d.mts +2 -2
  106. package/dist/sveltekit/index.mjs +4 -4
  107. package/dist/toolkit.d.mts +3 -3
  108. package/dist/toolkit.mjs +4 -4
  109. package/dist/{types-B8-kC2ME.d.mts → types-CBpJBj_7.d.mts} +11 -1
  110. package/dist/types-CBpJBj_7.d.mts.map +1 -0
  111. package/dist/types.d.mts +1 -1
  112. package/dist/{useLogger-_Ec6mXoR.d.mts → useLogger-DBPGEDf_.d.mts} +2 -2
  113. package/dist/{useLogger-_Ec6mXoR.d.mts.map → useLogger-DBPGEDf_.d.mts.map} +1 -1
  114. package/dist/utils.d.mts +1 -1
  115. package/dist/utils.d.mts.map +1 -1
  116. package/dist/utils.mjs +22 -16
  117. package/dist/utils.mjs.map +1 -1
  118. package/dist/vite/index.d.mts +80 -0
  119. package/dist/vite/index.d.mts.map +1 -0
  120. package/dist/vite/index.mjs +213 -0
  121. package/dist/vite/index.mjs.map +1 -0
  122. package/dist/workers.d.mts +1 -1
  123. package/package.json +53 -5
  124. package/dist/_http-DHpGetLZ.mjs +0 -72
  125. package/dist/_http-DHpGetLZ.mjs.map +0 -1
  126. package/dist/headers-Ba1eKT3i.mjs.map +0 -1
  127. package/dist/logger-CvDYZUze.d.mts.map +0 -1
  128. package/dist/nitro-CGGTUned.d.mts.map +0 -1
  129. package/dist/nitro-D1pPm37T.mjs.map +0 -1
  130. package/dist/parseError-BztqcPwZ.d.mts.map +0 -1
  131. package/dist/types-B8-kC2ME.d.mts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"posthog.d.mts","names":[],"sources":["../../src/adapters/posthog.ts"],"mappings":";;UAQiB,aAAA;;EAEf,MAAA;;EAEA,IAAA;;EAEA,OAAA;AAAA;AAAA,UAGe,mBAAA,SAA4B,aAAA;;EAE3C,SAAA;EATA;EAWA,UAAA;AAAA;;UAIe,YAAA;EACf,KAAA;EACA,WAAA;EACA,SAAA;EACA,UAAA,EAAY,MAAA;AAAA;;;;iBA+BE,cAAA,CAAe,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,mBAAA,GAAsB,YAAA;AAnC/E;;;;;;;;;;;AAmCA;;;;;;;;;;AAnCA,iBA2EgB,kBAAA,CAAmB,SAAA,GAAY,OAAA,CAAQ,aAAA,KAAc,GAAA,EAAf,YAAA,GAAe,YAAA,OAAA,OAAA;;;;;AAArE;;;;;;iBAyBsB,aAAA,CAAc,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,aAAA,GAAgB,OAAA;;;;;;;;;;;iBAcxD,kBAAA,CAAmB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,aAAA,GAAgB,OAAA;;AAdtF;;;;;;;;;;;;;;;AAcA;;;iBA4BgB,wBAAA,CAAyB,SAAA,GAAY,OAAA,CAAQ,mBAAA,KAAoB,GAAA,EAArB,YAAA,GAAqB,YAAA,OAAA,OAAA;;;;;;;;;;;iBAyB3D,mBAAA,CAAoB,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,mBAAA,GAAsB,OAAA;AAzB1F;;;;;;;;;;AAAA,iBAuCsB,wBAAA,CAAyB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,mBAAA,GAAsB,OAAA"}
1
+ {"version":3,"file":"posthog.d.mts","names":[],"sources":["../../src/adapters/posthog.ts"],"mappings":";;UAQiB,aAAA;;EAEf,MAAA;;EAEA,IAAA;;EAEA,OAAA;EANe;EAQf,OAAA;AAAA;AAAA,UAGe,mBAAA,SAA4B,aAAA;EAT3C;EAWA,SAAA;EAPA;EASA,UAAA;AAAA;;UAIe,YAAA;EACf,KAAA;EACA,WAAA;EACA,SAAA;EACA,UAAA,EAAY,MAAA;AAAA;;;;iBAiCE,cAAA,CAAe,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,mBAAA,GAAsB,YAAA;;;;;;;;;;;AAA/E;;;;;;;;;;;iBAwCgB,kBAAA,CAAmB,SAAA,GAAY,OAAA,CAAQ,aAAA,KAAc,GAAA,EAAf,YAAA,GAAe,YAAA,OAAA,OAAA;;;;AAArE;;;;;;;iBAyBsB,aAAA,CAAc,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,aAAA,GAAgB,OAAA;;;;;;;;;;;iBAcxD,kBAAA,CAAmB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,aAAA,GAAgB,OAAA;AAdtF;;;;;;;;;;;;;;;AAcA;;;;AAdA,iBA0CgB,wBAAA,CAAyB,SAAA,GAAY,OAAA,CAAQ,mBAAA,KAAoB,GAAA,EAArB,YAAA,GAAqB,YAAA,OAAA,OAAA;;;;;;;;;;;iBAyB3D,mBAAA,CAAoB,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,mBAAA,GAAsB,OAAA;;;;;;;;;;;iBAcpE,wBAAA,CAAyB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,mBAAA,GAAsB,OAAA"}
@@ -1,4 +1,5 @@
1
- import { n as defineDrain, r as resolveAdapterConfig, t as httpPost } from "../_http-DHpGetLZ.mjs";
1
+ import { n as resolveAdapterConfig, t as httpPost } from "../_http-C2UoHWgm.mjs";
2
+ import { t as defineDrain } from "../_drain-C9Nr-6Wc.mjs";
2
3
  import { sendBatchToOTLP } from "./otlp.mjs";
3
4
  //#region src/adapters/posthog.ts
4
5
  const POSTHOG_FIELDS = [
@@ -10,7 +11,8 @@ const POSTHOG_FIELDS = [
10
11
  key: "host",
11
12
  env: ["NUXT_POSTHOG_HOST", "POSTHOG_HOST"]
12
13
  },
13
- { key: "timeout" }
14
+ { key: "timeout" },
15
+ { key: "retries" }
14
16
  ];
15
17
  const POSTHOG_EVENTS_FIELDS = [
16
18
  ...POSTHOG_FIELDS,
@@ -24,7 +26,8 @@ function toOTLPConfig(config) {
24
26
  return {
25
27
  endpoint: `${resolveHost(config)}/i`,
26
28
  headers: { Authorization: `Bearer ${config.apiKey}` },
27
- timeout: config.timeout
29
+ timeout: config.timeout,
30
+ retries: config.retries
28
31
  };
29
32
  }
30
33
  /**
@@ -173,6 +176,7 @@ async function sendBatchToPostHogEvents(events, config) {
173
176
  batch
174
177
  }),
175
178
  timeout: config.timeout ?? 5e3,
179
+ retries: config.retries,
176
180
  label: "PostHog"
177
181
  });
178
182
  }
@@ -1 +1 @@
1
- {"version":3,"file":"posthog.mjs","names":[],"sources":["../../src/adapters/posthog.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from './_config'\nimport { resolveAdapterConfig } from './_config'\nimport { defineDrain } from './_drain'\nimport { httpPost } from './_http'\nimport { sendBatchToOTLP } from './otlp'\nimport type { OTLPConfig } from './otlp'\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 /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\nexport interface PostHogEventsConfig extends PostHogConfig {\n /** PostHog event name. Default: evlog_wide_event */\n eventName?: string\n /** Override distinct_id (defaults to event.service) */\n distinctId?: string\n}\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: 'timeout' },\n]\n\nconst POSTHOG_EVENTS_FIELDS: ConfigField<PostHogEventsConfig>[] = [\n ...POSTHOG_FIELDS,\n { key: 'eventName' },\n { key: 'distinctId' },\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 const host = resolveHost(config)\n return {\n endpoint: `${host}/i`,\n headers: { Authorization: `Bearer ${config.apiKey}` },\n timeout: config.timeout,\n }\n}\n\n/**\n * Convert a WideEvent to a PostHog custom event format.\n */\nexport function toPostHogEvent(event: WideEvent, config: PostHogEventsConfig): PostHogEvent {\n const { timestamp, level, service, ...rest } = event\n\n return {\n event: config.eventName ?? 'evlog_wide_event',\n distinct_id: config.distinctId ?? (typeof event.userId === 'string' ? event.userId : undefined) ?? service,\n timestamp,\n properties: {\n level,\n service,\n ...rest,\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// PostHog Logs (OTLP) — default\n// ---------------------------------------------------------------------------\n\n/**\n * Create a drain function for sending logs to PostHog Logs via OTLP.\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 * // Zero config - just set NUXT_POSTHOG_API_KEY env var\n * nitroApp.hooks.hook('evlog:drain', createPostHogDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('evlog:drain', createPostHogDrain({\n * apiKey: 'phc_...',\n * host: 'https://eu.i.posthog.com',\n * }))\n * ```\n */\nexport function createPostHogDrain(overrides?: Partial<PostHogConfig>) {\n return defineDrain<PostHogConfig>({\n name: 'posthog',\n resolve: () => {\n const config = resolveAdapterConfig<PostHogConfig>('posthog', POSTHOG_FIELDS, overrides)\n if (!config.apiKey) {\n console.error('[evlog/posthog] Missing apiKey. Set 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: sendBatchToPostHog,\n })\n}\n\n/**\n * Send a single event to PostHog Logs via OTLP.\n *\n * @example\n * ```ts\n * await sendToPostHog(event, {\n * apiKey: process.env.POSTHOG_API_KEY!,\n * })\n * ```\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 *\n * @example\n * ```ts\n * await sendBatchToPostHog(events, {\n * apiKey: process.env.POSTHOG_API_KEY!,\n * })\n * ```\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// PostHog Events (custom events via /batch/)\n// ---------------------------------------------------------------------------\n\n/**\n * Create a drain function for sending logs to PostHog as custom events.\n *\n * Uses PostHog's `/batch/` API. Consider using `createPostHogDrain()` instead\n * which uses PostHog Logs (OTLP) and is significantly cheaper.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createPostHogEventsDrain()\n * 2. runtimeConfig.evlog.posthog\n * 3. runtimeConfig.posthog\n * 4. Environment variables: NUXT_POSTHOG_API_KEY/POSTHOG_API_KEY, NUXT_POSTHOG_HOST/POSTHOG_HOST\n *\n * @example\n * ```ts\n * nitroApp.hooks.hook('evlog:drain', createPostHogEventsDrain({\n * eventName: 'server_request',\n * }))\n * ```\n */\nexport function createPostHogEventsDrain(overrides?: Partial<PostHogEventsConfig>) {\n return defineDrain<PostHogEventsConfig>({\n name: 'posthog-events',\n resolve: () => {\n const config = resolveAdapterConfig<PostHogEventsConfig>('posthog', POSTHOG_EVENTS_FIELDS, overrides)\n if (!config.apiKey) {\n console.error('[evlog/posthog-events] Missing apiKey. Set NUXT_POSTHOG_API_KEY/POSTHOG_API_KEY env var or pass to createPostHogEventsDrain()')\n return null\n }\n return config as PostHogEventsConfig\n },\n send: sendBatchToPostHogEvents,\n })\n}\n\n/**\n * Send a single event to PostHog as a custom event.\n *\n * @example\n * ```ts\n * await sendToPostHogEvents(event, {\n * apiKey: process.env.POSTHOG_API_KEY!,\n * })\n * ```\n */\nexport async function sendToPostHogEvents(event: WideEvent, config: PostHogEventsConfig): Promise<void> {\n await sendBatchToPostHogEvents([event], config)\n}\n\n/**\n * Send a batch of events to PostHog as custom events via the `/batch/` API.\n *\n * @example\n * ```ts\n * await sendBatchToPostHogEvents(events, {\n * apiKey: process.env.POSTHOG_API_KEY!,\n * })\n * ```\n */\nexport async function sendBatchToPostHogEvents(events: WideEvent[], config: PostHogEventsConfig): Promise<void> {\n if (events.length === 0) return\n\n const url = `${resolveHost(config)}/batch/`\n const batch = events.map(event => toPostHogEvent(event, config))\n\n await httpPost({\n url,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ api_key: config.apiKey, batch }),\n timeout: config.timeout ?? 5000,\n label: 'PostHog',\n })\n}\n"],"mappings":";;;AAgCA,MAAM,iBAA+C;CACnD;EAAE,KAAK;EAAU,KAAK,CAAC,wBAAwB,kBAAkB;EAAE;CACnE;EAAE,KAAK;EAAQ,KAAK,CAAC,qBAAqB,eAAe;EAAE;CAC3D,EAAE,KAAK,WAAW;CACnB;AAED,MAAM,wBAA4D;CAChE,GAAG;CACH,EAAE,KAAK,aAAa;CACpB,EAAE,KAAK,cAAc;CACtB;AAED,SAAS,YAAY,QAA+B;AAClD,SAAQ,OAAO,QAAQ,4BAA4B,QAAQ,OAAO,GAAG;;AAGvE,SAAS,aAAa,QAAmC;AAEvD,QAAO;EACL,UAAU,GAFC,YAAY,OAAO,CAEZ;EAClB,SAAS,EAAE,eAAe,UAAU,OAAO,UAAU;EACrD,SAAS,OAAO;EACjB;;;;;AAMH,SAAgB,eAAe,OAAkB,QAA2C;CAC1F,MAAM,EAAE,WAAW,OAAO,SAAS,GAAG,SAAS;AAE/C,QAAO;EACL,OAAO,OAAO,aAAa;EAC3B,aAAa,OAAO,eAAe,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS,KAAA,MAAc;EACnG;EACA,YAAY;GACV;GACA;GACA,GAAG;GACJ;EACF;;;;;;;;;;;;;;;;;;;;;;;AA4BH,SAAgB,mBAAmB,WAAoC;AACrE,QAAO,YAA2B;EAChC,MAAM;EACN,eAAe;GACb,MAAM,SAAS,qBAAoC,WAAW,gBAAgB,UAAU;AACxF,OAAI,CAAC,OAAO,QAAQ;AAClB,YAAQ,MAAM,mHAAmH;AACjI,WAAO;;AAET,UAAO;;EAET,MAAM;EACP,CAAC;;;;;;;;;;;;AAaJ,eAAsB,cAAc,OAAkB,QAAsC;AAC1F,OAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;AAa3C,eAAsB,mBAAmB,QAAqB,QAAsC;AAClG,KAAI,OAAO,WAAW,EAAG;AACzB,OAAM,gBAAgB,QAAQ,aAAa,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;AA0BrD,SAAgB,yBAAyB,WAA0C;AACjF,QAAO,YAAiC;EACtC,MAAM;EACN,eAAe;GACb,MAAM,SAAS,qBAA0C,WAAW,uBAAuB,UAAU;AACrG,OAAI,CAAC,OAAO,QAAQ;AAClB,YAAQ,MAAM,gIAAgI;AAC9I,WAAO;;AAET,UAAO;;EAET,MAAM;EACP,CAAC;;;;;;;;;;;;AAaJ,eAAsB,oBAAoB,OAAkB,QAA4C;AACtG,OAAM,yBAAyB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;AAajD,eAAsB,yBAAyB,QAAqB,QAA4C;AAC9G,KAAI,OAAO,WAAW,EAAG;CAEzB,MAAM,MAAM,GAAG,YAAY,OAAO,CAAC;CACnC,MAAM,QAAQ,OAAO,KAAI,UAAS,eAAe,OAAO,OAAO,CAAC;AAEhE,OAAM,SAAS;EACb;EACA,SAAS,EAAE,gBAAgB,oBAAoB;EAC/C,MAAM,KAAK,UAAU;GAAE,SAAS,OAAO;GAAQ;GAAO,CAAC;EACvD,SAAS,OAAO,WAAW;EAC3B,OAAO;EACR,CAAC"}
1
+ {"version":3,"file":"posthog.mjs","names":[],"sources":["../../src/adapters/posthog.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from './_config'\nimport { resolveAdapterConfig } from './_config'\nimport { defineDrain } from './_drain'\nimport { httpPost } from './_http'\nimport { sendBatchToOTLP } from './otlp'\nimport type { OTLPConfig } from './otlp'\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 /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n /** Number of retry attempts on transient failures. Default: 2 */\n retries?: number\n}\n\nexport interface PostHogEventsConfig extends PostHogConfig {\n /** PostHog event name. Default: evlog_wide_event */\n eventName?: string\n /** Override distinct_id (defaults to event.service) */\n distinctId?: string\n}\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: 'timeout' },\n { key: 'retries' },\n]\n\nconst POSTHOG_EVENTS_FIELDS: ConfigField<PostHogEventsConfig>[] = [\n ...POSTHOG_FIELDS,\n { key: 'eventName' },\n { key: 'distinctId' },\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 const host = resolveHost(config)\n return {\n endpoint: `${host}/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 format.\n */\nexport function toPostHogEvent(event: WideEvent, config: PostHogEventsConfig): PostHogEvent {\n const { timestamp, level, service, ...rest } = event\n\n return {\n event: config.eventName ?? 'evlog_wide_event',\n distinct_id: config.distinctId ?? (typeof event.userId === 'string' ? event.userId : undefined) ?? service,\n timestamp,\n properties: {\n level,\n service,\n ...rest,\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// PostHog Logs (OTLP) — default\n// ---------------------------------------------------------------------------\n\n/**\n * Create a drain function for sending logs to PostHog Logs via OTLP.\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 * // Zero config - just set NUXT_POSTHOG_API_KEY env var\n * nitroApp.hooks.hook('evlog:drain', createPostHogDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('evlog:drain', createPostHogDrain({\n * apiKey: 'phc_...',\n * host: 'https://eu.i.posthog.com',\n * }))\n * ```\n */\nexport function createPostHogDrain(overrides?: Partial<PostHogConfig>) {\n return defineDrain<PostHogConfig>({\n name: 'posthog',\n resolve: () => {\n const config = resolveAdapterConfig<PostHogConfig>('posthog', POSTHOG_FIELDS, overrides)\n if (!config.apiKey) {\n console.error('[evlog/posthog] Missing apiKey. Set 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: sendBatchToPostHog,\n })\n}\n\n/**\n * Send a single event to PostHog Logs via OTLP.\n *\n * @example\n * ```ts\n * await sendToPostHog(event, {\n * apiKey: process.env.POSTHOG_API_KEY!,\n * })\n * ```\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 *\n * @example\n * ```ts\n * await sendBatchToPostHog(events, {\n * apiKey: process.env.POSTHOG_API_KEY!,\n * })\n * ```\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// PostHog Events (custom events via /batch/)\n// ---------------------------------------------------------------------------\n\n/**\n * Create a drain function for sending logs to PostHog as custom events.\n *\n * Uses PostHog's `/batch/` API. Consider using `createPostHogDrain()` instead\n * which uses PostHog Logs (OTLP) and is significantly cheaper.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createPostHogEventsDrain()\n * 2. runtimeConfig.evlog.posthog\n * 3. runtimeConfig.posthog\n * 4. Environment variables: NUXT_POSTHOG_API_KEY/POSTHOG_API_KEY, NUXT_POSTHOG_HOST/POSTHOG_HOST\n *\n * @example\n * ```ts\n * nitroApp.hooks.hook('evlog:drain', createPostHogEventsDrain({\n * eventName: 'server_request',\n * }))\n * ```\n */\nexport function createPostHogEventsDrain(overrides?: Partial<PostHogEventsConfig>) {\n return defineDrain<PostHogEventsConfig>({\n name: 'posthog-events',\n resolve: () => {\n const config = resolveAdapterConfig<PostHogEventsConfig>('posthog', POSTHOG_EVENTS_FIELDS, overrides)\n if (!config.apiKey) {\n console.error('[evlog/posthog-events] Missing apiKey. Set NUXT_POSTHOG_API_KEY/POSTHOG_API_KEY env var or pass to createPostHogEventsDrain()')\n return null\n }\n return config as PostHogEventsConfig\n },\n send: sendBatchToPostHogEvents,\n })\n}\n\n/**\n * Send a single event to PostHog as a custom event.\n *\n * @example\n * ```ts\n * await sendToPostHogEvents(event, {\n * apiKey: process.env.POSTHOG_API_KEY!,\n * })\n * ```\n */\nexport async function sendToPostHogEvents(event: WideEvent, config: PostHogEventsConfig): Promise<void> {\n await sendBatchToPostHogEvents([event], config)\n}\n\n/**\n * Send a batch of events to PostHog as custom events via the `/batch/` API.\n *\n * @example\n * ```ts\n * await sendBatchToPostHogEvents(events, {\n * apiKey: process.env.POSTHOG_API_KEY!,\n * })\n * ```\n */\nexport async function sendBatchToPostHogEvents(events: WideEvent[], config: PostHogEventsConfig): Promise<void> {\n if (events.length === 0) return\n\n const url = `${resolveHost(config)}/batch/`\n const batch = events.map(event => toPostHogEvent(event, config))\n\n await httpPost({\n url,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ api_key: config.apiKey, batch }),\n timeout: config.timeout ?? 5000,\n retries: config.retries,\n label: 'PostHog',\n })\n}\n"],"mappings":";;;;AAkCA,MAAM,iBAA+C;CACnD;EAAE,KAAK;EAAU,KAAK,CAAC,wBAAwB,kBAAkB;EAAE;CACnE;EAAE,KAAK;EAAQ,KAAK,CAAC,qBAAqB,eAAe;EAAE;CAC3D,EAAE,KAAK,WAAW;CAClB,EAAE,KAAK,WAAW;CACnB;AAED,MAAM,wBAA4D;CAChE,GAAG;CACH,EAAE,KAAK,aAAa;CACpB,EAAE,KAAK,cAAc;CACtB;AAED,SAAS,YAAY,QAA+B;AAClD,SAAQ,OAAO,QAAQ,4BAA4B,QAAQ,OAAO,GAAG;;AAGvE,SAAS,aAAa,QAAmC;AAEvD,QAAO;EACL,UAAU,GAFC,YAAY,OAAO,CAEZ;EAClB,SAAS,EAAE,eAAe,UAAU,OAAO,UAAU;EACrD,SAAS,OAAO;EAChB,SAAS,OAAO;EACjB;;;;;AAMH,SAAgB,eAAe,OAAkB,QAA2C;CAC1F,MAAM,EAAE,WAAW,OAAO,SAAS,GAAG,SAAS;AAE/C,QAAO;EACL,OAAO,OAAO,aAAa;EAC3B,aAAa,OAAO,eAAe,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS,KAAA,MAAc;EACnG;EACA,YAAY;GACV;GACA;GACA,GAAG;GACJ;EACF;;;;;;;;;;;;;;;;;;;;;;;AA4BH,SAAgB,mBAAmB,WAAoC;AACrE,QAAO,YAA2B;EAChC,MAAM;EACN,eAAe;GACb,MAAM,SAAS,qBAAoC,WAAW,gBAAgB,UAAU;AACxF,OAAI,CAAC,OAAO,QAAQ;AAClB,YAAQ,MAAM,mHAAmH;AACjI,WAAO;;AAET,UAAO;;EAET,MAAM;EACP,CAAC;;;;;;;;;;;;AAaJ,eAAsB,cAAc,OAAkB,QAAsC;AAC1F,OAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;AAa3C,eAAsB,mBAAmB,QAAqB,QAAsC;AAClG,KAAI,OAAO,WAAW,EAAG;AACzB,OAAM,gBAAgB,QAAQ,aAAa,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;AA0BrD,SAAgB,yBAAyB,WAA0C;AACjF,QAAO,YAAiC;EACtC,MAAM;EACN,eAAe;GACb,MAAM,SAAS,qBAA0C,WAAW,uBAAuB,UAAU;AACrG,OAAI,CAAC,OAAO,QAAQ;AAClB,YAAQ,MAAM,gIAAgI;AAC9I,WAAO;;AAET,UAAO;;EAET,MAAM;EACP,CAAC;;;;;;;;;;;;AAaJ,eAAsB,oBAAoB,OAAkB,QAA4C;AACtG,OAAM,yBAAyB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;AAajD,eAAsB,yBAAyB,QAAqB,QAA4C;AAC9G,KAAI,OAAO,WAAW,EAAG;CAEzB,MAAM,MAAM,GAAG,YAAY,OAAO,CAAC;CACnC,MAAM,QAAQ,OAAO,KAAI,UAAS,eAAe,OAAO,OAAO,CAAC;AAEhE,OAAM,SAAS;EACb;EACA,SAAS,EAAE,gBAAgB,oBAAoB;EAC/C,MAAM,KAAK,UAAU;GAAE,SAAS,OAAO;GAAQ;GAAO,CAAC;EACvD,SAAS,OAAO,WAAW;EAC3B,SAAS,OAAO;EAChB,OAAO;EACR,CAAC"}
@@ -1,4 +1,4 @@
1
- import { T as WideEvent, r as DrainContext } from "../types-B8-kC2ME.mjs";
1
+ import { T as WideEvent, r as DrainContext } from "../types-CBpJBj_7.mjs";
2
2
  //#region src/adapters/sentry.d.ts
3
3
  interface SentryConfig {
4
4
  /** Sentry DSN */
@@ -11,6 +11,8 @@ interface SentryConfig {
11
11
  tags?: Record<string, string>;
12
12
  /** Request timeout in milliseconds. Default: 5000 */
13
13
  timeout?: number;
14
+ /** Number of retry attempts on transient failures. Default: 2 */
15
+ retries?: number;
14
16
  }
15
17
  /** Sentry Log attribute value with type annotation */
16
18
  interface SentryAttributeValue {
@@ -1 +1 @@
1
- {"version":3,"file":"sentry.d.mts","names":[],"sources":["../../src/adapters/sentry.ts"],"mappings":";;UAOiB,YAAA;;EAEf,GAAA;;EAEA,WAAA;;EAEA,OAAA;EANe;EAQf,IAAA,GAAO,MAAA;;EAEP,OAAA;AAAA;;UAIe,oBAAA;EACf,KAAA;EACA,IAAA;AAAA;;UAIe,SAAA;EACf,SAAA;EACA,QAAA;EACA,KAAA;EACA,IAAA;EACA,eAAA;EACA,UAAA,GAAa,MAAA,SAAe,oBAAA;AAAA;AAAA,iBA0Fd,WAAA,CAAY,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,YAAA,GAAe,SAAA;;;;;;;;;;;;AAArE;;;;;;;;;;;;iBAiGgB,iBAAA,CAAkB,SAAA,GAAY,OAAA,CAAQ,YAAA,KAAa,GAAA,EAAd,YAAA,GAAc,YAAA,OAAA,OAAA;;;AAAnE;;;;;;;;iBAyBsB,YAAA,CAAa,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,YAAA,GAAe,OAAA;;;;;;;;;;;iBActD,iBAAA,CAAkB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,YAAA,GAAe,OAAA"}
1
+ {"version":3,"file":"sentry.d.mts","names":[],"sources":["../../src/adapters/sentry.ts"],"mappings":";;UAOiB,YAAA;;EAEf,GAAA;;EAEA,WAAA;;EAEA,OAAA;EANe;EAQf,IAAA,GAAO,MAAA;;EAEP,OAAA;EARA;EAUA,OAAA;AAAA;;UAIe,oBAAA;EACf,KAAA;EACA,IAAA;AAAA;;UAIe,SAAA;EACf,SAAA;EACA,QAAA;EACA,KAAA;EACA,IAAA;EACA,eAAA;EACA,UAAA,GAAa,MAAA,SAAe,oBAAA;AAAA;AAAA,iBA2Fd,WAAA,CAAY,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,YAAA,GAAe,SAAA;;;;;;;;;;;AAArE;;;;;;;;;;;;;iBAiGgB,iBAAA,CAAkB,SAAA,GAAY,OAAA,CAAQ,YAAA,KAAa,GAAA,EAAd,YAAA,GAAc,YAAA,OAAA,OAAA;;AAAnE;;;;;;;;;iBAyBsB,YAAA,CAAa,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,YAAA,GAAe,OAAA;;;;;;;;;;AAA5E;iBAcsB,iBAAA,CAAkB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,YAAA,GAAe,OAAA"}
@@ -1,5 +1,6 @@
1
- import { n as defineDrain, r as resolveAdapterConfig, t as httpPost } from "../_http-DHpGetLZ.mjs";
2
- import { t as OTEL_SEVERITY_NUMBER } from "../_severity-Q1BuITU_.mjs";
1
+ import { n as resolveAdapterConfig, t as httpPost } from "../_http-C2UoHWgm.mjs";
2
+ import { t as defineDrain } from "../_drain-C9Nr-6Wc.mjs";
3
+ import { t as OTEL_SEVERITY_NUMBER } from "../_severity-BLiOKoxh.mjs";
3
4
  //#region src/adapters/sentry.ts
4
5
  const SENTRY_FIELDS = [
5
6
  {
@@ -15,7 +16,8 @@ const SENTRY_FIELDS = [
15
16
  env: ["NUXT_SENTRY_RELEASE", "SENTRY_RELEASE"]
16
17
  },
17
18
  { key: "tags" },
18
- { key: "timeout" }
19
+ { key: "timeout" },
20
+ { key: "retries" }
19
21
  ];
20
22
  function parseSentryDsn(dsn) {
21
23
  const url = new URL(dsn);
@@ -211,6 +213,7 @@ async function sendBatchToSentry(events, config) {
211
213
  },
212
214
  body,
213
215
  timeout: config.timeout ?? 5e3,
216
+ retries: config.retries,
214
217
  label: "Sentry"
215
218
  });
216
219
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sentry.mjs","names":[],"sources":["../../src/adapters/sentry.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from './_config'\nimport { resolveAdapterConfig } from './_config'\nimport { defineDrain } from './_drain'\nimport { httpPost } from './_http'\nimport { OTEL_SEVERITY_NUMBER } from './_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}\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]\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 defineDrain<SentryConfig>({\n name: 'sentry',\n resolve: () => {\n const config = 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 send: sendBatchToSentry,\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 label: 'Sentry',\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sentry.mjs","names":[],"sources":["../../src/adapters/sentry.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from './_config'\nimport { resolveAdapterConfig } from './_config'\nimport { defineDrain } from './_drain'\nimport { httpPost } from './_http'\nimport { OTEL_SEVERITY_NUMBER } from './_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 defineDrain<SentryConfig>({\n name: 'sentry',\n resolve: () => {\n const config = 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 send: sendBatchToSentry,\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 })\n}\n"],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ import { g as RequestLogger } from "../types-CBpJBj_7.mjs";
2
+ import { GatewayModelId } from "ai";
3
+ import { LanguageModelV3 } from "@ai-sdk/provider";
4
+
5
+ //#region src/ai/index.d.ts
6
+ /**
7
+ * Shape of the `ai` field written to the wide event.
8
+ */
9
+ interface AIEventData {
10
+ calls: number;
11
+ model: string;
12
+ models?: string[];
13
+ provider: string;
14
+ inputTokens: number;
15
+ outputTokens: number;
16
+ totalTokens: number;
17
+ cacheReadTokens?: number;
18
+ cacheWriteTokens?: number;
19
+ reasoningTokens?: number;
20
+ finishReason?: string;
21
+ toolCalls?: string[];
22
+ steps?: number;
23
+ msToFirstChunk?: number;
24
+ msToFinish?: number;
25
+ tokensPerSecond?: number;
26
+ error?: string;
27
+ }
28
+ interface AILogger {
29
+ /**
30
+ * Wrap a language model with evlog middleware.
31
+ * All `generateText`, `streamText`, `generateObject`, and `streamObject` calls
32
+ * using the wrapped model are captured automatically into the wide event.
33
+ *
34
+ * Accepts a `LanguageModelV3` object or a model string (e.g. `'anthropic/claude-sonnet-4.6'`).
35
+ * Strings are resolved via the AI SDK gateway.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const ai = createAILogger(log)
40
+ * const model = ai.wrap('anthropic/claude-sonnet-4.6')
41
+ *
42
+ * // Also accepts a model object
43
+ * const model = ai.wrap(anthropic('claude-sonnet-4.6'))
44
+ * ```
45
+ */
46
+ wrap: (model: LanguageModelV3 | GatewayModelId) => LanguageModelV3;
47
+ /**
48
+ * Manually capture token usage from an `embed()` or `embedMany()` result.
49
+ * Embedding models use a different type than language models, so they
50
+ * cannot be wrapped with middleware.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * const { embedding, usage } = await embed({ model: embeddingModel, value: query })
55
+ * ai.captureEmbed({ usage })
56
+ * ```
57
+ */
58
+ captureEmbed: (result: {
59
+ usage: {
60
+ tokens: number;
61
+ };
62
+ }) => void;
63
+ }
64
+ /**
65
+ * Create an AI logger that captures AI SDK data into the wide event.
66
+ *
67
+ * Uses model middleware (`wrapLanguageModel`) to transparently intercept
68
+ * all LLM calls. `onFinish` and `onStepFinish` remain free for user code.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { createAILogger } from 'evlog/ai'
73
+ *
74
+ * const log = useLogger(event)
75
+ * const ai = createAILogger(log)
76
+ * const model = ai.wrap('anthropic/claude-sonnet-4.6')
77
+ *
78
+ * const result = streamText({
79
+ * model,
80
+ * messages,
81
+ * onFinish: ({ text }) => saveConversation(text),
82
+ * })
83
+ * ```
84
+ */
85
+ declare function createAILogger(log: RequestLogger): AILogger;
86
+ //#endregion
87
+ export { AIEventData, AILogger, createAILogger };
88
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/ai/index.ts"],"mappings":";;;;;;;AAQA;UAAiB,WAAA;EACf,KAAA;EACA,KAAA;EACA,MAAA;EACA,QAAA;EACA,WAAA;EACA,YAAA;EACA,WAAA;EACA,eAAA;EACA,gBAAA;EACA,eAAA;EACA,YAAA;EACA,SAAA;EACA,KAAA;EACA,cAAA;EACA,UAAA;EACA,eAAA;EACA,KAAA;AAAA;AAAA,UAGe,QAAA;EAHV;;AAGP;;;;;;;;;;;;;;;EAkBE,IAAA,GAAO,KAAA,EAAO,eAAA,GAAkB,cAAA,KAAmB,eAAA;EAapC;;;AA8DjB;;;;;;;;EA9DE,YAAA,GAAe,MAAA;IAAU,KAAA;MAAS,MAAA;IAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;iBA8DpB,cAAA,CAAe,GAAA,EAAK,aAAA,GAAgB,QAAA"}
@@ -0,0 +1,199 @@
1
+ import { gateway, wrapLanguageModel } from "ai";
2
+ //#region src/ai/index.ts
3
+ function addUsage(acc, usage) {
4
+ acc.inputTokens += usage.inputTokens.total ?? 0;
5
+ acc.outputTokens += usage.outputTokens.total ?? 0;
6
+ acc.cacheReadTokens += usage.inputTokens.cacheRead ?? 0;
7
+ acc.cacheWriteTokens += usage.inputTokens.cacheWrite ?? 0;
8
+ acc.reasoningTokens += usage.outputTokens.reasoning ?? 0;
9
+ }
10
+ /**
11
+ * When using `gateway('google/gemini-3-flash')`, the model object has
12
+ * `provider: 'gateway'` and `modelId: 'google/gemini-3-flash'`.
13
+ * This extracts the real provider and model name from the modelId.
14
+ */
15
+ function resolveProviderAndModel(provider, modelId) {
16
+ if (provider !== "gateway" || !modelId.includes("/")) return {
17
+ provider,
18
+ model: modelId
19
+ };
20
+ const slashIndex = modelId.indexOf("/");
21
+ return {
22
+ provider: modelId.slice(0, slashIndex),
23
+ model: modelId.slice(slashIndex + 1)
24
+ };
25
+ }
26
+ /**
27
+ * Create an AI logger that captures AI SDK data into the wide event.
28
+ *
29
+ * Uses model middleware (`wrapLanguageModel`) to transparently intercept
30
+ * all LLM calls. `onFinish` and `onStepFinish` remain free for user code.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import { createAILogger } from 'evlog/ai'
35
+ *
36
+ * const log = useLogger(event)
37
+ * const ai = createAILogger(log)
38
+ * const model = ai.wrap('anthropic/claude-sonnet-4.6')
39
+ *
40
+ * const result = streamText({
41
+ * model,
42
+ * messages,
43
+ * onFinish: ({ text }) => saveConversation(text),
44
+ * })
45
+ * ```
46
+ */
47
+ function createAILogger(log) {
48
+ let calls = 0;
49
+ let steps = 0;
50
+ const usage = {
51
+ inputTokens: 0,
52
+ outputTokens: 0,
53
+ cacheReadTokens: 0,
54
+ cacheWriteTokens: 0,
55
+ reasoningTokens: 0
56
+ };
57
+ const models = [];
58
+ const providers = [];
59
+ const allToolCalls = [];
60
+ let lastFinishReason;
61
+ let lastMsToFirstChunk;
62
+ let lastMsToFinish;
63
+ let lastError;
64
+ function flush() {
65
+ const uniqueModels = [...new Set(models)];
66
+ const lastModel = models[models.length - 1];
67
+ const lastProvider = providers[providers.length - 1];
68
+ const data = {
69
+ calls,
70
+ inputTokens: usage.inputTokens,
71
+ outputTokens: usage.outputTokens,
72
+ totalTokens: usage.inputTokens + usage.outputTokens
73
+ };
74
+ if (lastModel) data.model = lastModel;
75
+ if (lastProvider) data.provider = lastProvider;
76
+ if (uniqueModels.length > 1) data.models = uniqueModels;
77
+ if (usage.cacheReadTokens > 0) data.cacheReadTokens = usage.cacheReadTokens;
78
+ if (usage.cacheWriteTokens > 0) data.cacheWriteTokens = usage.cacheWriteTokens;
79
+ if (usage.reasoningTokens > 0) data.reasoningTokens = usage.reasoningTokens;
80
+ if (lastFinishReason) data.finishReason = lastFinishReason;
81
+ if (allToolCalls.length > 0) data.toolCalls = [...allToolCalls];
82
+ if (steps > 1) data.steps = steps;
83
+ if (lastMsToFirstChunk !== void 0) data.msToFirstChunk = lastMsToFirstChunk;
84
+ if (lastMsToFinish !== void 0) {
85
+ data.msToFinish = lastMsToFinish;
86
+ if (usage.outputTokens > 0 && lastMsToFinish > 0) data.tokensPerSecond = Math.round(usage.outputTokens / lastMsToFinish * 1e3);
87
+ }
88
+ if (lastError) data.error = lastError;
89
+ log.set({ ai: data });
90
+ }
91
+ function recordModel(provider, modelId, responseModelId) {
92
+ const resolved = resolveProviderAndModel(provider, responseModelId ?? modelId);
93
+ models.push(resolved.model);
94
+ providers.push(resolved.provider);
95
+ }
96
+ const middleware = {
97
+ wrapGenerate: async ({ doGenerate, model }) => {
98
+ try {
99
+ const result = await doGenerate();
100
+ calls++;
101
+ steps++;
102
+ addUsage(usage, result.usage);
103
+ recordModel(model.provider, model.modelId, result.response?.modelId);
104
+ lastFinishReason = result.finishReason.unified;
105
+ for (const item of result.content) if (item.type === "tool-call") allToolCalls.push(item.toolName);
106
+ flush();
107
+ return result;
108
+ } catch (error) {
109
+ calls++;
110
+ steps++;
111
+ recordModel(model.provider, model.modelId);
112
+ lastFinishReason = "error";
113
+ lastError = error instanceof Error ? error.message : String(error);
114
+ flush();
115
+ throw error;
116
+ }
117
+ },
118
+ wrapStream: async ({ doStream, model }) => {
119
+ const streamStart = Date.now();
120
+ let firstChunkTime;
121
+ let streamUsage;
122
+ let streamFinishReason;
123
+ let streamModelId;
124
+ const streamToolCalls = [];
125
+ let streamError;
126
+ let doStreamResult;
127
+ try {
128
+ doStreamResult = await doStream();
129
+ } catch (error) {
130
+ calls++;
131
+ steps++;
132
+ recordModel(model.provider, model.modelId);
133
+ lastFinishReason = "error";
134
+ lastError = error instanceof Error ? error.message : String(error);
135
+ flush();
136
+ throw error;
137
+ }
138
+ const { stream, ...rest } = doStreamResult;
139
+ const transformStream = new TransformStream({
140
+ transform(chunk, controller) {
141
+ if (!firstChunkTime && chunk.type === "text-delta") firstChunkTime = Date.now();
142
+ if (chunk.type === "tool-input-start") streamToolCalls.push(chunk.toolName);
143
+ if (chunk.type === "finish") {
144
+ streamUsage = {
145
+ inputTokens: chunk.usage.inputTokens.total ?? 0,
146
+ outputTokens: chunk.usage.outputTokens.total ?? 0,
147
+ cacheReadTokens: chunk.usage.inputTokens.cacheRead ?? 0,
148
+ cacheWriteTokens: chunk.usage.inputTokens.cacheWrite ?? 0,
149
+ reasoningTokens: chunk.usage.outputTokens.reasoning ?? 0
150
+ };
151
+ streamFinishReason = chunk.finishReason.unified;
152
+ }
153
+ if (chunk.type === "response-metadata" && "modelId" in chunk && chunk.modelId) streamModelId = chunk.modelId;
154
+ if (chunk.type === "error") streamError = chunk.error instanceof Error ? chunk.error.message : String(chunk.error);
155
+ controller.enqueue(chunk);
156
+ },
157
+ flush() {
158
+ calls++;
159
+ steps++;
160
+ if (streamUsage) {
161
+ usage.inputTokens += streamUsage.inputTokens;
162
+ usage.outputTokens += streamUsage.outputTokens;
163
+ usage.cacheReadTokens += streamUsage.cacheReadTokens;
164
+ usage.cacheWriteTokens += streamUsage.cacheWriteTokens;
165
+ usage.reasoningTokens += streamUsage.reasoningTokens;
166
+ }
167
+ recordModel(model.provider, model.modelId, streamModelId);
168
+ lastFinishReason = streamFinishReason;
169
+ for (const name of streamToolCalls) allToolCalls.push(name);
170
+ if (firstChunkTime) lastMsToFirstChunk = firstChunkTime - streamStart;
171
+ lastMsToFinish = Date.now() - streamStart;
172
+ if (streamError) lastError = streamError;
173
+ flush();
174
+ }
175
+ });
176
+ return {
177
+ stream: stream.pipeThrough(transformStream),
178
+ ...rest
179
+ };
180
+ }
181
+ };
182
+ return {
183
+ wrap: (model) => {
184
+ return wrapLanguageModel({
185
+ model: typeof model === "string" ? gateway(model) : model,
186
+ middleware
187
+ });
188
+ },
189
+ captureEmbed: (result) => {
190
+ calls++;
191
+ usage.inputTokens += result.usage.tokens;
192
+ flush();
193
+ }
194
+ };
195
+ }
196
+ //#endregion
197
+ export { createAILogger };
198
+
199
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/ai/index.ts"],"sourcesContent":["import { gateway, wrapLanguageModel } from 'ai'\nimport type { GatewayModelId } from 'ai'\nimport type { LanguageModelV3, LanguageModelV3Middleware, LanguageModelV3StreamPart } from '@ai-sdk/provider'\nimport type { RequestLogger } from '../types'\n\n/**\n * Shape of the `ai` field written to the wide event.\n */\nexport interface AIEventData {\n calls: number\n model: string\n models?: string[]\n provider: string\n inputTokens: number\n outputTokens: number\n totalTokens: number\n cacheReadTokens?: number\n cacheWriteTokens?: number\n reasoningTokens?: number\n finishReason?: string\n toolCalls?: string[]\n steps?: number\n msToFirstChunk?: number\n msToFinish?: number\n tokensPerSecond?: number\n error?: string\n}\n\nexport interface AILogger {\n /**\n * Wrap a language model with evlog middleware.\n * All `generateText`, `streamText`, `generateObject`, and `streamObject` calls\n * using the wrapped model are captured automatically into the wide event.\n *\n * Accepts a `LanguageModelV3` object or a model string (e.g. `'anthropic/claude-sonnet-4.6'`).\n * Strings are resolved via the AI SDK gateway.\n *\n * @example\n * ```ts\n * const ai = createAILogger(log)\n * const model = ai.wrap('anthropic/claude-sonnet-4.6')\n *\n * // Also accepts a model object\n * const model = ai.wrap(anthropic('claude-sonnet-4.6'))\n * ```\n */\n wrap: (model: LanguageModelV3 | GatewayModelId) => LanguageModelV3\n\n /**\n * Manually capture token usage from an `embed()` or `embedMany()` result.\n * Embedding models use a different type than language models, so they\n * cannot be wrapped with middleware.\n *\n * @example\n * ```ts\n * const { embedding, usage } = await embed({ model: embeddingModel, value: query })\n * ai.captureEmbed({ usage })\n * ```\n */\n captureEmbed: (result: { usage: { tokens: number } }) => void\n}\n\ninterface UsageAccumulator {\n inputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheWriteTokens: number\n reasoningTokens: number\n}\n\nfunction addUsage(\n acc: UsageAccumulator,\n usage: {\n inputTokens: { total: number | undefined, cacheRead?: number | undefined, cacheWrite?: number | undefined }\n outputTokens: { total: number | undefined, reasoning?: number | undefined }\n },\n): void {\n acc.inputTokens += usage.inputTokens.total ?? 0\n acc.outputTokens += usage.outputTokens.total ?? 0\n acc.cacheReadTokens += usage.inputTokens.cacheRead ?? 0\n acc.cacheWriteTokens += usage.inputTokens.cacheWrite ?? 0\n acc.reasoningTokens += usage.outputTokens.reasoning ?? 0\n}\n\n/**\n * When using `gateway('google/gemini-3-flash')`, the model object has\n * `provider: 'gateway'` and `modelId: 'google/gemini-3-flash'`.\n * This extracts the real provider and model name from the modelId.\n */\nfunction resolveProviderAndModel(provider: string, modelId: string): { provider: string, model: string } {\n if (provider !== 'gateway' || !modelId.includes('/')) {\n return { provider, model: modelId }\n }\n const slashIndex = modelId.indexOf('/')\n return {\n provider: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n}\n\n/**\n * Create an AI logger that captures AI SDK data into the wide event.\n *\n * Uses model middleware (`wrapLanguageModel`) to transparently intercept\n * all LLM calls. `onFinish` and `onStepFinish` remain free for user code.\n *\n * @example\n * ```ts\n * import { createAILogger } from 'evlog/ai'\n *\n * const log = useLogger(event)\n * const ai = createAILogger(log)\n * const model = ai.wrap('anthropic/claude-sonnet-4.6')\n *\n * const result = streamText({\n * model,\n * messages,\n * onFinish: ({ text }) => saveConversation(text),\n * })\n * ```\n */\nexport function createAILogger(log: RequestLogger): AILogger {\n let calls = 0\n let steps = 0\n const usage: UsageAccumulator = {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n reasoningTokens: 0,\n }\n const models: string[] = []\n const providers: string[] = []\n const allToolCalls: string[] = []\n let lastFinishReason: string | undefined\n let lastMsToFirstChunk: number | undefined\n let lastMsToFinish: number | undefined\n let lastError: string | undefined\n\n function flush(): void {\n const uniqueModels = [...new Set(models)]\n const lastModel = models[models.length - 1]\n const lastProvider = providers[providers.length - 1]\n\n const data: Partial<AIEventData> & { calls: number, inputTokens: number, outputTokens: number, totalTokens: number } = {\n calls,\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n totalTokens: usage.inputTokens + usage.outputTokens,\n }\n\n if (lastModel) data.model = lastModel\n if (lastProvider) data.provider = lastProvider\n if (uniqueModels.length > 1) data.models = uniqueModels\n if (usage.cacheReadTokens > 0) data.cacheReadTokens = usage.cacheReadTokens\n if (usage.cacheWriteTokens > 0) data.cacheWriteTokens = usage.cacheWriteTokens\n if (usage.reasoningTokens > 0) data.reasoningTokens = usage.reasoningTokens\n if (lastFinishReason) data.finishReason = lastFinishReason\n if (allToolCalls.length > 0) data.toolCalls = [...allToolCalls]\n if (steps > 1) data.steps = steps\n if (lastMsToFirstChunk !== undefined) data.msToFirstChunk = lastMsToFirstChunk\n if (lastMsToFinish !== undefined) {\n data.msToFinish = lastMsToFinish\n if (usage.outputTokens > 0 && lastMsToFinish > 0) {\n data.tokensPerSecond = Math.round((usage.outputTokens / lastMsToFinish) * 1000)\n }\n }\n if (lastError) data.error = lastError\n\n log.set({ ai: data } as Record<string, unknown>)\n }\n\n function recordModel(provider: string, modelId: string, responseModelId?: string): void {\n const resolved = resolveProviderAndModel(provider, responseModelId ?? modelId)\n models.push(resolved.model)\n providers.push(resolved.provider)\n }\n\n const middleware: LanguageModelV3Middleware = {\n wrapGenerate: async ({ doGenerate, model }) => {\n try {\n const result = await doGenerate()\n\n calls++\n steps++\n addUsage(usage, result.usage)\n recordModel(model.provider, model.modelId, result.response?.modelId)\n lastFinishReason = result.finishReason.unified\n\n for (const item of result.content) {\n if (item.type === 'tool-call') {\n allToolCalls.push(item.toolName)\n }\n }\n\n flush()\n return result\n } catch (error) {\n calls++\n steps++\n recordModel(model.provider, model.modelId)\n lastFinishReason = 'error'\n lastError = error instanceof Error ? error.message : String(error)\n flush()\n throw error\n }\n },\n\n wrapStream: async ({ doStream, model }) => {\n const streamStart = Date.now()\n let firstChunkTime: number | undefined\n\n let streamUsage: UsageAccumulator | undefined\n let streamFinishReason: string | undefined\n let streamModelId: string | undefined\n const streamToolCalls: string[] = []\n let streamError: string | undefined\n\n let doStreamResult: Awaited<ReturnType<typeof doStream>>\n try {\n doStreamResult = await doStream()\n } catch (error) {\n calls++\n steps++\n recordModel(model.provider, model.modelId)\n lastFinishReason = 'error'\n lastError = error instanceof Error ? error.message : String(error)\n flush()\n throw error\n }\n\n const { stream, ...rest } = doStreamResult\n\n const transformStream = new TransformStream<\n LanguageModelV3StreamPart,\n LanguageModelV3StreamPart\n >({\n transform(chunk, controller) {\n if (!firstChunkTime && chunk.type === 'text-delta') {\n firstChunkTime = Date.now()\n }\n\n if (chunk.type === 'tool-input-start') {\n streamToolCalls.push(chunk.toolName)\n }\n\n if (chunk.type === 'finish') {\n streamUsage = {\n inputTokens: chunk.usage.inputTokens.total ?? 0,\n outputTokens: chunk.usage.outputTokens.total ?? 0,\n cacheReadTokens: chunk.usage.inputTokens.cacheRead ?? 0,\n cacheWriteTokens: chunk.usage.inputTokens.cacheWrite ?? 0,\n reasoningTokens: chunk.usage.outputTokens.reasoning ?? 0,\n }\n streamFinishReason = chunk.finishReason.unified\n }\n\n if (chunk.type === 'response-metadata' && 'modelId' in chunk && chunk.modelId) {\n streamModelId = chunk.modelId as string\n }\n\n if (chunk.type === 'error') {\n streamError = chunk.error instanceof Error ? chunk.error.message : String(chunk.error)\n }\n\n controller.enqueue(chunk)\n },\n\n flush() {\n calls++\n steps++\n\n if (streamUsage) {\n usage.inputTokens += streamUsage.inputTokens\n usage.outputTokens += streamUsage.outputTokens\n usage.cacheReadTokens += streamUsage.cacheReadTokens\n usage.cacheWriteTokens += streamUsage.cacheWriteTokens\n usage.reasoningTokens += streamUsage.reasoningTokens\n }\n\n recordModel(model.provider, model.modelId, streamModelId)\n lastFinishReason = streamFinishReason\n\n for (const name of streamToolCalls) {\n allToolCalls.push(name)\n }\n\n if (firstChunkTime) {\n lastMsToFirstChunk = firstChunkTime - streamStart\n }\n lastMsToFinish = Date.now() - streamStart\n\n if (streamError) lastError = streamError\n\n flush()\n },\n })\n\n return {\n stream: stream.pipeThrough(transformStream),\n ...rest,\n }\n },\n }\n\n return {\n wrap: (model: LanguageModelV3 | GatewayModelId) => {\n const resolved = typeof model === 'string' ? gateway(model) : model\n return wrapLanguageModel({ model: resolved, middleware })\n },\n\n captureEmbed: (result: { usage: { tokens: number } }) => {\n calls++\n usage.inputTokens += result.usage.tokens\n flush()\n },\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { r as DrainContext } from "./types-B8-kC2ME.mjs";
1
+ import { r as DrainContext } from "./types-CBpJBj_7.mjs";
2
2
  import { DrainPipelineOptions, PipelineDrainFn } from "./pipeline.mjs";
3
3
 
4
4
  //#region src/browser.d.ts
@@ -0,0 +1,2 @@
1
+ import { clearIdentity, initLog, log as _clientLog, setIdentity } from "./runtime/client/log.mjs";
2
+ export { clearIdentity, initLog, _clientLog as log, setIdentity };
@@ -0,0 +1,2 @@
1
+ import { clearIdentity, initLog, log as _clientLog, setIdentity } from "./runtime/client/log.mjs";
2
+ export { clearIdentity, initLog, _clientLog as log, setIdentity };
@@ -48,4 +48,4 @@ function parsePath(input = "") {
48
48
  //#endregion
49
49
  export { parseURL as t };
50
50
 
51
- //# sourceMappingURL=dist-BsWcv7B8.mjs.map
51
+ //# sourceMappingURL=dist-BFn8qsRC.mjs.map