evlog 2.19.1 → 2.20.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.
- package/README.md +30 -1
- package/dist/adapters/axiom.d.mts +1 -1
- package/dist/adapters/axiom.mjs +2 -2
- package/dist/adapters/better-stack.d.mts +1 -1
- package/dist/adapters/better-stack.mjs +2 -2
- package/dist/adapters/datadog.d.mts +1 -1
- package/dist/adapters/datadog.mjs +2 -2
- package/dist/adapters/fs.d.mts +1 -1
- package/dist/adapters/fs.mjs +1 -1
- package/dist/adapters/hyperdx.d.mts +1 -1
- package/dist/adapters/hyperdx.mjs +1 -1
- package/dist/adapters/memory.d.mts +1 -1
- package/dist/adapters/memory.mjs +1 -1
- package/dist/adapters/otlp.d.mts +1 -1
- package/dist/adapters/otlp.mjs +2 -2
- package/dist/adapters/posthog.d.mts +1 -1
- package/dist/adapters/posthog.mjs +2 -2
- package/dist/adapters/sentry.d.mts +1 -1
- package/dist/adapters/sentry.mjs +2 -2
- package/dist/ai/index.d.mts +27 -10
- package/dist/ai/index.d.mts.map +1 -1
- package/dist/ai/index.mjs +80 -15
- package/dist/ai/index.mjs.map +1 -1
- package/dist/asyncStorageScope-DnF7Xk8l.mjs +81 -0
- package/dist/asyncStorageScope-DnF7Xk8l.mjs.map +1 -0
- package/dist/{audit-BQt8yAHo.mjs → audit-BXCYMjcC.mjs} +31 -93
- package/dist/audit-BXCYMjcC.mjs.map +1 -0
- package/dist/{audit-D7v6JHj0.d.mts → audit-BZrUvjfW.d.mts} +71 -53
- package/dist/audit-BZrUvjfW.d.mts.map +1 -0
- package/dist/audit-action.d.mts +2 -0
- package/dist/audit-action.mjs +74 -0
- package/dist/audit-action.mjs.map +1 -0
- package/dist/audit.d.mts +2 -0
- package/dist/audit.mjs +3 -0
- package/dist/better-auth/index.d.mts +1 -1
- package/dist/browser.d.mts +1 -1
- package/dist/{index-EvnrXvQM.d.mts → catalog-1cQnNxR2.d.mts} +4 -3
- package/dist/catalog-1cQnNxR2.d.mts.map +1 -0
- package/dist/catalog.d.mts +2 -0
- package/dist/catalog.mjs +205 -0
- package/dist/catalog.mjs.map +1 -0
- package/dist/{define-DTQpu4f6.d.mts → define-Ct2QyrE9.d.mts} +3 -3
- package/dist/{define-DTQpu4f6.d.mts.map → define-Ct2QyrE9.d.mts.map} +1 -1
- package/dist/{drain-fDb-eNwz.mjs → drain-Dl2ZJKRA.mjs} +3 -3
- package/dist/{drain-fDb-eNwz.mjs.map → drain-Dl2ZJKRA.mjs.map} +1 -1
- package/dist/elysia/index.d.mts +8 -7
- package/dist/elysia/index.d.mts.map +1 -1
- package/dist/elysia/index.mjs +11 -8
- package/dist/elysia/index.mjs.map +1 -1
- package/dist/{enrich-error-stack-next.node-Dgm_rCf5.mjs → enrich-error-stack-next.node-KB0Oap7R.mjs} +1 -1
- package/dist/{enrich-error-stack-next.node-Dgm_rCf5.mjs.map → enrich-error-stack-next.node-KB0Oap7R.mjs.map} +1 -1
- package/dist/{enricher-CBRmQw6e.d.mts → enricher-BOzt2FCi.d.mts} +2 -2
- package/dist/{enricher-CBRmQw6e.d.mts.map → enricher-BOzt2FCi.d.mts.map} +1 -1
- package/dist/enrichers.d.mts +2 -2
- package/dist/{error-CpghjrkY.d.mts → error-BRymuv8U.d.mts} +2 -2
- package/dist/{error-CpghjrkY.d.mts.map → error-BRymuv8U.d.mts.map} +1 -1
- package/dist/error.d.mts +1 -1
- package/dist/{errors-BLU4Tfpe.d.mts → errors-C7qA6CAi.d.mts} +2 -2
- package/dist/{errors-BLU4Tfpe.d.mts.map → errors-C7qA6CAi.d.mts.map} +1 -1
- package/dist/eve/index.d.mts +72 -0
- package/dist/eve/index.d.mts.map +1 -0
- package/dist/eve/index.mjs +593 -0
- package/dist/eve/index.mjs.map +1 -0
- package/dist/express/index.d.mts +4 -4
- package/dist/express/index.d.mts.map +1 -1
- package/dist/express/index.mjs +3 -3
- package/dist/express/index.mjs.map +1 -1
- package/dist/fastify/index.d.mts +4 -4
- package/dist/fastify/index.d.mts.map +1 -1
- package/dist/fastify/index.mjs +4 -2
- package/dist/fastify/index.mjs.map +1 -1
- package/dist/fork-S9gpZmF8.mjs +72 -0
- package/dist/fork-S9gpZmF8.mjs.map +1 -0
- package/dist/hono/index.d.mts +3 -3
- package/dist/hono/index.d.mts.map +1 -1
- package/dist/hono/index.mjs +3 -6
- package/dist/hono/index.mjs.map +1 -1
- package/dist/{http-ChVS9GYc.mjs → http-pKfd8UDu.mjs} +2 -2
- package/dist/{http-ChVS9GYc.mjs.map → http-pKfd8UDu.mjs.map} +1 -1
- package/dist/http.d.mts +1 -1
- package/dist/index.d.mts +9 -9
- package/dist/index.mjs +3 -203
- package/dist/{instrumentation-create-BrjQtSKD.d.mts → instrumentation-create-gSDk0leX.d.mts} +2 -2
- package/dist/{instrumentation-create-BrjQtSKD.d.mts.map → instrumentation-create-gSDk0leX.d.mts.map} +1 -1
- package/dist/{integration-DYp2uw8O.mjs → integration-CeL90DtN.mjs} +3 -2
- package/dist/{integration-DYp2uw8O.mjs.map → integration-CeL90DtN.mjs.map} +1 -1
- package/dist/{logger-mHIWxBhJ.d.mts → logger-CxWz7QJ3.d.mts} +7 -3
- package/dist/logger-CxWz7QJ3.d.mts.map +1 -0
- package/dist/logger.d.mts +2 -2
- package/dist/logger.mjs +2 -2
- package/dist/{fork-CgGlAaHa.mjs → middleware-Cdebyfdt.mjs} +3 -69
- package/dist/middleware-Cdebyfdt.mjs.map +1 -0
- package/dist/{middleware-B_k4Mrzg.d.mts → middleware-fbtEs6bq.d.mts} +3 -3
- package/dist/middleware-fbtEs6bq.d.mts.map +1 -0
- package/dist/nestjs/index.d.mts +5 -5
- package/dist/nestjs/index.d.mts.map +1 -1
- package/dist/nestjs/index.mjs +4 -3
- package/dist/nestjs/index.mjs.map +1 -1
- package/dist/next/client.d.mts +1 -1
- package/dist/next/index.d.mts +5 -5
- package/dist/next/index.d.mts.map +1 -1
- package/dist/next/index.mjs +3 -3
- package/dist/next/index.mjs.map +1 -1
- package/dist/next/instrumentation/create.d.mts +1 -1
- package/dist/next/instrumentation/create.mjs +3 -1
- package/dist/next/instrumentation/create.mjs.map +1 -1
- package/dist/next/instrumentation.d.mts +1 -1
- package/dist/next/stream.d.mts +1 -1
- package/dist/nitro/errorHandler.mjs +9 -4
- package/dist/nitro/errorHandler.mjs.map +1 -1
- package/dist/nitro/module.d.mts +2 -2
- package/dist/nitro/module.mjs +1 -1
- package/dist/nitro/plugin.mjs +2 -2
- package/dist/nitro/v3/errorHandler.d.mts +0 -10
- package/dist/nitro/v3/errorHandler.mjs +13 -3
- package/dist/nitro/v3/errorHandler.mjs.map +1 -1
- package/dist/nitro/v3/index.d.mts +2 -2
- package/dist/nitro/v3/module.d.mts +1 -1
- package/dist/nitro/v3/module.mjs +1 -1
- package/dist/nitro/v3/plugin.mjs +2 -2
- package/dist/nitro/v3/useLogger.d.mts +2 -2
- package/dist/nitro/v3/useLogger.d.mts.map +1 -1
- package/dist/nitro/v3/useLogger.mjs.map +1 -1
- package/dist/{nitro-_Hda8Deo.d.mts → nitro-CcN7HDnr.d.mts} +2 -2
- package/dist/{nitro-_Hda8Deo.d.mts.map → nitro-CcN7HDnr.d.mts.map} +1 -1
- package/dist/{nitro-ClRZLD1g.mjs → nitro-DYFCSlho.mjs} +30 -3
- package/dist/nitro-DYFCSlho.mjs.map +1 -0
- package/dist/{nitroConfigBridge-BkVWnSV3.mjs → nitroConfigBridge-lHPsE5zG.mjs} +8 -6
- package/dist/nitroConfigBridge-lHPsE5zG.mjs.map +1 -0
- package/dist/{nodeResponse-CIEEbrNE.mjs → nodeResponse-Dsl7gZUf.mjs} +1 -1
- package/dist/{nodeResponse-CIEEbrNE.mjs.map → nodeResponse-Dsl7gZUf.mjs.map} +1 -1
- package/dist/nuxt/module.d.mts +1 -1
- package/dist/nuxt/module.mjs +2 -2
- package/dist/orpc/index.d.mts +4 -4
- package/dist/orpc/index.d.mts.map +1 -1
- package/dist/orpc/index.mjs +2 -2
- package/dist/orpc/index.mjs.map +1 -1
- package/dist/{package-CNV_CXs8.mjs → package-Drb3wqqt.mjs} +2 -2
- package/dist/package-Drb3wqqt.mjs.map +1 -0
- package/dist/{parseError-BeBXEd2V.d.mts → parseError-BmoJ7XeF.d.mts} +2 -2
- package/dist/parseError-BmoJ7XeF.d.mts.map +1 -0
- package/dist/react-router/index.d.mts +4 -4
- package/dist/react-router/index.d.mts.map +1 -1
- package/dist/react-router/index.mjs +3 -2
- package/dist/react-router/index.mjs.map +1 -1
- package/dist/register-disk-snippet-B5svlT8-.mjs +21 -0
- package/dist/register-disk-snippet-B5svlT8-.mjs.map +1 -0
- package/dist/runtime/client/log.d.mts +1 -1
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs +1 -1
- package/dist/runtime/server/useLogger.d.mts +1 -1
- package/dist/runtime/server/useLogger.mjs.map +1 -1
- package/dist/runtime/utils/parseError.d.mts +2 -2
- package/dist/{storage-7X37OToT.mjs → storage-BeFdoGTI.mjs} +1 -1
- package/dist/storage-BeFdoGTI.mjs.map +1 -0
- package/dist/stream.d.mts +1 -1
- package/dist/stream.d.mts.map +1 -1
- package/dist/stream.mjs +7 -1
- package/dist/stream.mjs.map +1 -1
- package/dist/sveltekit/index.d.mts +3 -4
- package/dist/sveltekit/index.d.mts.map +1 -1
- package/dist/sveltekit/index.mjs +6 -3
- package/dist/sveltekit/index.mjs.map +1 -1
- package/dist/toolkit.d.mts +7 -7
- package/dist/toolkit.d.mts.map +1 -1
- package/dist/toolkit.mjs +7 -6
- package/dist/types.d.mts +1 -1
- package/dist/{useLogger-Cfv8Ck8b.d.mts → useLogger-BupVLO9_.d.mts} +3 -3
- package/dist/useLogger-BupVLO9_.d.mts.map +1 -0
- package/dist/{utils-CJJG0ZYW.d.mts → utils-D_LY-J1k.d.mts} +2 -2
- package/dist/{utils-CJJG0ZYW.d.mts.map → utils-D_LY-J1k.d.mts.map} +1 -1
- package/dist/utils.d.mts +1 -1
- package/dist/vite/index.d.mts +1 -1
- package/dist/workers.d.mts +3 -3
- package/dist/workers.d.mts.map +1 -1
- package/dist/workers.mjs +1 -1
- package/dist/workers.mjs.map +1 -1
- package/package.json +25 -2
- package/dist/audit-BQt8yAHo.mjs.map +0 -1
- package/dist/audit-D7v6JHj0.d.mts.map +0 -1
- package/dist/fork-CgGlAaHa.mjs.map +0 -1
- package/dist/index-EvnrXvQM.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/logger-mHIWxBhJ.d.mts.map +0 -1
- package/dist/middleware-B_k4Mrzg.d.mts.map +0 -1
- package/dist/nitro-ClRZLD1g.mjs.map +0 -1
- package/dist/nitroConfigBridge-BkVWnSV3.mjs.map +0 -1
- package/dist/package-CNV_CXs8.mjs.map +0 -1
- package/dist/parseError-BeBXEd2V.d.mts.map +0 -1
- package/dist/storage-7X37OToT.mjs.map +0 -1
- package/dist/useLogger-Cfv8Ck8b.d.mts.map +0 -1
package/dist/ai/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/ai/index.ts"],"sourcesContent":["import { gateway, wrapLanguageModel, bindTelemetryIntegration } from 'ai'\nimport type { GatewayModelId, TelemetryIntegration, OnStartEvent, OnToolCallFinishEvent, OnFinishEvent } from 'ai'\nimport type { LanguageModelV3, LanguageModelV3Middleware, LanguageModelV3StreamPart } from '@ai-sdk/provider'\nimport type { RequestLogger } from '../types'\n\n/**\n * Fine-grained control over tool call input capture.\n */\nexport interface ToolInputsOptions {\n /**\n * Max character length for the stringified input JSON.\n * Inputs exceeding this limit are truncated with a `…` suffix.\n */\n maxLength?: number\n /**\n * Custom transform applied to each captured input before storing.\n * Receives the parsed input and tool name; return value is stored.\n * Runs before `maxLength` truncation.\n */\n transform?: (input: unknown, toolName: string) => unknown\n}\n\n/**\n * Pricing entry for a single model: cost per 1 million tokens in dollars.\n */\nexport interface ModelCost {\n input: number\n output: number\n}\n\n/**\n * Options for `createAILogger` and `createAIMiddleware`.\n */\nexport interface AILoggerOptions {\n /**\n * When enabled, `toolCalls` contains `{ name, input }` objects instead of plain tool name strings.\n * Opt-in because inputs can be large and may contain sensitive data.\n *\n * - `true` — capture all inputs as-is\n * - `{ maxLength, transform }` — capture with truncation or custom transform\n * @default false\n */\n toolInputs?: boolean | ToolInputsOptions\n /**\n * Pricing map for estimating request cost.\n * Keys are model IDs (e.g. `'claude-sonnet-4.6'`, `'gpt-4o'`), values are\n * `{ input, output }` in dollars per 1M tokens.\n *\n * When provided, the wide event includes `ai.estimatedCost` (in dollars).\n *\n * @example\n * ```ts\n * const ai = createAILogger(log, {\n * cost: {\n * 'claude-sonnet-4.6': { input: 3, output: 15 },\n * 'gpt-4o': { input: 2.5, output: 10 },\n * },\n * })\n * ```\n */\n cost?: Record<string, ModelCost>\n}\n\n/**\n * Per-step token usage breakdown for multi-step agent runs.\n */\nexport interface AIStepUsage {\n model: string\n inputTokens: number\n outputTokens: number\n toolCalls?: string[]\n}\n\n/**\n * Tool execution detail captured via `TelemetryIntegration`.\n */\nexport interface AIToolExecution {\n name: string\n durationMs: number\n success: boolean\n error?: string\n}\n\n/**\n * Embedding metadata captured via `captureEmbed`.\n */\nexport interface AIEmbeddingData {\n model?: string\n tokens: number\n dimensions?: number\n count?: number\n}\n\n/**\n * Shape of the `ai` field written to the wide event, and the public\n * snapshot returned by `AILogger.getMetadata()`.\n *\n * `model` and `provider` are populated after the first model call.\n * They may be undefined when only `captureEmbed` has been called or\n * before any AI activity has happened.\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[] | Array<{ name: string, input: unknown }>\n responseId?: string\n steps?: number\n stepsUsage?: AIStepUsage[]\n msToFirstChunk?: number\n msToFinish?: number\n tokensPerSecond?: number\n error?: string\n tools?: AIToolExecution[]\n totalDurationMs?: number\n embedding?: AIEmbeddingData\n estimatedCost?: number\n}\n\n/**\n * Public alias for the metadata snapshot returned by `AILogger.getMetadata()`.\n *\n * Mirrors the shape of the `ai` field on the wide event, so the same object\n * can be persisted, surfaced to end-users, or compared across runs.\n */\nexport type AIMetadata = AIEventData\n\n/**\n * Callback fired on every metadata update (per step, per embed, on error,\n * and on integration completion). Receives a structured snapshot.\n */\nexport type AIMetadataListener = (metadata: AIMetadata) => void\n\nexport interface AILogger {\n /**\n * Wrap a language model with evlog middleware.\n * All `generateText` and `streamText` calls using the wrapped model\n * 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 * Also works with pre-wrapped models (e.g. from supermemory, guardrails):\n * `ai.wrap(withSupermemory(base, orgId))` composes correctly.\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 * // With model info (v2)\n * ai.captureEmbed({ usage, model: 'text-embedding-3-small', dimensions: 1536 })\n *\n * // After embedMany\n * ai.captureEmbed({ usage, count: texts.length })\n * ```\n */\n captureEmbed: (result: {\n usage: { tokens: number }\n model?: string\n dimensions?: number\n count?: number\n }) => void\n\n /**\n * Get a snapshot of the current AI execution metadata.\n *\n * Returns the same structured object that is written to the `ai` field\n * of the wide event. Safe to call at any time — including inside the\n * AI SDK's `onFinish` callback, after `await generateText()`, or while a\n * stream is in progress.\n *\n * The returned snapshot is a fresh copy: mutating it does not affect\n * subsequent calls or the underlying state.\n *\n * @example Persist execution history after a run\n * ```ts\n * const ai = createAILogger(log, { cost: { ... } })\n *\n * await generateText({ model: ai.wrap('anthropic/claude-sonnet-4.6'), prompt })\n *\n * const metadata = ai.getMetadata()\n * await db.insert('ai_runs', metadata)\n * ```\n *\n * @example Surface usage to end-users in a streaming response\n * ```ts\n * const result = streamText({\n * model: ai.wrap('anthropic/claude-sonnet-4.6'),\n * messages,\n * onFinish: () => {\n * const { totalTokens, estimatedCost } = ai.getMetadata()\n * trackUsage(userId, { totalTokens, estimatedCost })\n * },\n * })\n * ```\n */\n getMetadata: () => AIMetadata\n\n /**\n * Get the current estimated cost in dollars.\n *\n * Returns `undefined` if no `cost` map was provided to `createAILogger`,\n * or if the model is not in the pricing map.\n *\n * Convenience for `getMetadata().estimatedCost`.\n *\n * @example\n * ```ts\n * const ai = createAILogger(log, {\n * cost: { 'claude-sonnet-4.6': { input: 3, output: 15 } },\n * })\n *\n * await generateText({ model: ai.wrap('anthropic/claude-sonnet-4.6'), prompt })\n *\n * console.log(`Cost: $${ai.getEstimatedCost()?.toFixed(4)}`)\n * ```\n */\n getEstimatedCost: () => number | undefined\n\n /**\n * Subscribe to metadata updates.\n *\n * The callback fires every time the underlying state flushes — once per\n * step (in multi-step agent runs), once per `captureEmbed` call, on\n * model errors, and once on `createEvlogIntegration`'s `onFinish`.\n *\n * Each invocation receives a fresh snapshot (same shape as `getMetadata`).\n * Returns an unsubscribe function.\n *\n * @example Stream incremental usage updates to the client\n * ```ts\n * const ai = createAILogger(log)\n *\n * ai.onUpdate((metadata) => {\n * pushToClient({ type: 'ai-progress', metadata })\n * })\n *\n * const result = streamText({ model: ai.wrap('...'), messages })\n * ```\n *\n * @example Cleanup\n * ```ts\n * const off = ai.onUpdate((metadata) => { ... })\n * // later\n * off()\n * ```\n */\n onUpdate: (callback: AIMetadataListener) => () => void\n\n /**\n * Internal accumulator state exposed for `createEvlogIntegration` to share.\n * @internal\n */\n _state: AccumulatorState\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 the evlog AI middleware that captures AI SDK data into a wide event.\n *\n * Use this when you need explicit middleware composition with other wrappers\n * (e.g. supermemory, guardrails). For most cases, use `createAILogger` instead.\n *\n * Note: `captureEmbed` is not available with the raw middleware — use\n * `createAILogger` if you need embedding capture.\n *\n * @example Nuxt API route with supermemory\n * ```ts\n * import { createAIMiddleware } from 'evlog/ai'\n * import { wrapLanguageModel } from 'ai'\n *\n * export default defineEventHandler(async (event) => {\n * const log = useLogger(event)\n *\n * const model = wrapLanguageModel({\n * model: withSupermemory(base, orgId),\n * middleware: [createAIMiddleware(log, { toolInputs: true })],\n * })\n * })\n * ```\n */\nexport function createAIMiddleware(log: RequestLogger, options?: AILoggerOptions): LanguageModelV3Middleware {\n return buildMiddleware(log, options)\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 *\n * @example Capture tool call inputs\n * ```ts\n * const ai = createAILogger(log, { toolInputs: true })\n * ```\n */\nexport function createAILogger(log: RequestLogger, options?: AILoggerOptions): AILogger {\n const state = createAccumulatorState(options)\n state._log = log\n const middleware = buildMiddlewareFromState(log, state)\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: {\n usage: { tokens: number }\n model?: string\n dimensions?: number\n count?: number\n }) => {\n state.calls++\n state.usage.inputTokens += result.usage.tokens\n state.embedding = {\n tokens: (state.embedding?.tokens ?? 0) + result.usage.tokens,\n ...(result.model ? { model: result.model } : state.embedding?.model ? { model: state.embedding.model } : {}),\n ...(result.dimensions ? { dimensions: result.dimensions } : state.embedding?.dimensions ? { dimensions: state.embedding.dimensions } : {}),\n ...(result.count ? { count: (state.embedding?.count ?? 0) + result.count } : state.embedding?.count ? { count: state.embedding.count } : {}),\n }\n flushState(log, state)\n },\n\n getMetadata: () => buildMetadata(state),\n\n getEstimatedCost: () => computeEstimatedCost(state),\n\n onUpdate: (callback: AIMetadataListener) => {\n state.subscribers.add(callback)\n return () => {\n state.subscribers.delete(callback)\n }\n },\n\n _state: state,\n }\n}\n\n/**\n * Snapshot of how much of each cumulative array we've already sent to the\n * wide event. `flushState` reads it to compute the delta and updates it in\n * place; passing zero-watermarks to `buildMetadata` yields a full snapshot.\n */\ninterface Watermarks {\n toolCalls: number\n toolCallInputs: number\n stepsUsage: number\n toolExecutions: number\n models: Set<string>\n}\n\nfunction freshWatermarks(): Watermarks {\n return { toolCalls: 0, toolCallInputs: 0, stepsUsage: 0, toolExecutions: 0, models: new Set() }\n}\n\ninterface AccumulatorState {\n calls: number\n steps: number\n usage: UsageAccumulator\n models: string[]\n lastProvider: string | undefined\n allToolCalls: string[]\n allToolCallInputs: Array<{ name: string, input: unknown }>\n stepsUsage: AIStepUsage[]\n lastFinishReason: string | undefined\n lastMsToFirstChunk: number | undefined\n lastMsToFinish: number | undefined\n lastError: string | undefined\n lastResponseId: string | undefined\n toolInputs: boolean\n toolInputsOptions: ToolInputsOptions | undefined\n toolExecutions: AIToolExecution[]\n generationStartTime: number | undefined\n totalDurationMs: number | undefined\n embedding: AIEmbeddingData | undefined\n costMap: Record<string, ModelCost> | undefined\n subscribers: Set<AIMetadataListener>\n /** @internal What's already been written to the wide event. */\n _flushed: Watermarks\n /** @internal Logger reference for integration flush */\n _log?: RequestLogger\n}\n\nfunction resolveToolInputs(raw?: boolean | ToolInputsOptions): { enabled: boolean, options: ToolInputsOptions | undefined } {\n if (!raw) return { enabled: false, options: undefined }\n if (raw === true) return { enabled: true, options: undefined }\n return { enabled: true, options: raw }\n}\n\nfunction processToolInput(input: unknown, toolName: string, options: ToolInputsOptions | undefined): unknown {\n let value = input\n if (options?.transform) {\n value = options.transform(value, toolName)\n }\n if (options?.maxLength) {\n const str = typeof value === 'string' ? value : JSON.stringify(value)\n if (str.length > options.maxLength) {\n return `${str.slice(0, options.maxLength)}…`\n }\n }\n return value\n}\n\nfunction createAccumulatorState(options?: AILoggerOptions): AccumulatorState {\n const { enabled, options: captureOpts } = resolveToolInputs(options?.toolInputs)\n return {\n calls: 0,\n steps: 0,\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n reasoningTokens: 0,\n },\n models: [],\n lastProvider: undefined,\n allToolCalls: [],\n allToolCallInputs: [],\n stepsUsage: [],\n lastFinishReason: undefined,\n lastMsToFirstChunk: undefined,\n lastMsToFinish: undefined,\n lastError: undefined,\n lastResponseId: undefined,\n toolInputs: enabled,\n toolInputsOptions: captureOpts,\n toolExecutions: [],\n generationStartTime: undefined,\n totalDurationMs: undefined,\n embedding: undefined,\n costMap: options?.cost,\n subscribers: new Set(),\n _flushed: freshWatermarks(),\n }\n}\n\nfunction computeEstimatedCost(state: AccumulatorState): number | undefined {\n if (!state.costMap) return undefined\n const lastModel = state.models[state.models.length - 1]\n if (!lastModel) return undefined\n const pricing = state.costMap[lastModel]\n if (!pricing) return undefined\n const inputCost = (state.usage.inputTokens / 1_000_000) * pricing.input\n const outputCost = (state.usage.outputTokens / 1_000_000) * pricing.output\n const total = inputCost + outputCost\n return total > 0 ? Math.round(total * 1_000_000) / 1_000_000 : undefined\n}\n\n/**\n * Build the `ai.*` payload from the accumulator. Pass `since` to emit\n * only the array entries appended after that watermark (used by\n * `flushState` to avoid quadratic growth on the wide event, since evlog's\n * `mergeInto` concatenates arrays). The default — fresh watermarks —\n * yields the full cumulative snapshot used by `getMetadata()` and\n * delivered to `onUpdate` subscribers.\n */\nfunction buildMetadata(state: AccumulatorState, since: Watermarks = freshWatermarks()): AIMetadata {\n const lastModel = state.models[state.models.length - 1]\n\n const data: AIMetadata = {\n calls: state.calls,\n inputTokens: state.usage.inputTokens,\n outputTokens: state.usage.outputTokens,\n totalTokens: state.usage.inputTokens + state.usage.outputTokens,\n }\n\n if (lastModel) data.model = lastModel\n if (state.lastProvider) data.provider = state.lastProvider\n if (state.usage.cacheReadTokens > 0) data.cacheReadTokens = state.usage.cacheReadTokens\n if (state.usage.cacheWriteTokens > 0) data.cacheWriteTokens = state.usage.cacheWriteTokens\n if (state.usage.reasoningTokens > 0) data.reasoningTokens = state.usage.reasoningTokens\n if (state.lastFinishReason) data.finishReason = state.lastFinishReason\n if (state.lastResponseId) data.responseId = state.lastResponseId\n if (state.lastMsToFirstChunk !== undefined) data.msToFirstChunk = state.lastMsToFirstChunk\n if (state.lastMsToFinish !== undefined) {\n data.msToFinish = state.lastMsToFinish\n if (state.usage.outputTokens > 0 && state.lastMsToFinish > 0) {\n data.tokensPerSecond = Math.round((state.usage.outputTokens / state.lastMsToFinish) * 1000)\n }\n }\n if (state.lastError) data.error = state.lastError\n if (state.totalDurationMs !== undefined) data.totalDurationMs = state.totalDurationMs\n if (state.embedding) data.embedding = { ...state.embedding }\n const cost = computeEstimatedCost(state)\n if (cost !== undefined) data.estimatedCost = cost\n\n if (state.toolInputs) {\n if (state.allToolCallInputs.length > since.toolCallInputs) {\n data.toolCalls = state.allToolCallInputs.slice(since.toolCallInputs).map(t => ({ ...t }))\n }\n } else if (state.allToolCalls.length > since.toolCalls) {\n data.toolCalls = state.allToolCalls.slice(since.toolCalls)\n }\n\n if (state.steps > 1 && state.stepsUsage.length > since.stepsUsage) {\n data.steps = state.steps\n data.stepsUsage = state.stepsUsage\n .slice(since.stepsUsage)\n .map(s => ({ ...s, ...(s.toolCalls ? { toolCalls: [...s.toolCalls] } : {}) }))\n }\n\n if (state.toolExecutions.length > since.toolExecutions) {\n data.tools = state.toolExecutions.slice(since.toolExecutions).map(t => ({ ...t }))\n }\n\n // `models` is only emitted once a second distinct model appears, then\n // deduplicated across flushes so the merged wide event stays unique.\n const uniqueModels = new Set(state.models)\n if (uniqueModels.size > 1) {\n const newModels = [...uniqueModels].filter(m => !since.models.has(m))\n if (newModels.length > 0) data.models = newModels\n }\n\n return data\n}\n\nfunction notifySubscribers(state: AccumulatorState, metadata: AIMetadata): void {\n if (state.subscribers.size === 0) return\n for (const subscriber of state.subscribers) {\n try {\n subscriber(metadata)\n } catch {\n // Subscribers must not break the AI flow.\n }\n }\n}\n\n/**\n * Push the accumulator's latest changes onto the wide event using delta\n * semantics for arrays, then notify subscribers with the full snapshot.\n */\nfunction flushState(log: RequestLogger, state: AccumulatorState): void {\n const flushed = state._flushed\n const data = buildMetadata(state, flushed)\n\n flushed.toolCalls = state.allToolCalls.length\n flushed.toolCallInputs = state.allToolCallInputs.length\n flushed.toolExecutions = state.toolExecutions.length\n if (data.stepsUsage) flushed.stepsUsage = state.stepsUsage.length\n if (data.models) for (const m of data.models) flushed.models.add(m)\n\n log.set({ ai: data } as Record<string, unknown>)\n\n if (state.subscribers.size > 0) {\n notifySubscribers(state, buildMetadata(state))\n }\n}\n\nfunction recordModel(state: AccumulatorState, provider: string, modelId: string, responseModelId?: string): void {\n const resolved = resolveProviderAndModel(provider, responseModelId ?? modelId)\n state.models.push(resolved.model)\n state.lastProvider = resolved.provider\n}\n\nfunction safeParseJSON(input: string): unknown {\n try {\n return JSON.parse(input)\n } catch {\n return input\n }\n}\n\nfunction recordError(log: RequestLogger, state: AccumulatorState, model: { provider: string, modelId: string }, error: unknown): void {\n state.calls++\n state.steps++\n recordModel(state, model.provider, model.modelId)\n state.lastFinishReason = 'error'\n state.lastError = error instanceof Error ? error.message : String(error)\n\n const resolved = resolveProviderAndModel(model.provider, model.modelId)\n state.stepsUsage.push({\n model: resolved.model,\n inputTokens: 0,\n outputTokens: 0,\n })\n\n flushState(log, state)\n}\n\nfunction buildMiddleware(log: RequestLogger, options?: AILoggerOptions): LanguageModelV3Middleware {\n const state = createAccumulatorState(options)\n state._log = log\n return buildMiddlewareFromState(log, state)\n}\n\nfunction buildMiddlewareFromState(log: RequestLogger, state: AccumulatorState): LanguageModelV3Middleware {\n return {\n specificationVersion: 'v3',\n wrapGenerate: async ({ doGenerate, model }) => {\n try {\n const result = await doGenerate()\n\n state.calls++\n state.steps++\n addUsage(state.usage, result.usage)\n recordModel(state, model.provider, model.modelId, result.response?.modelId)\n state.lastFinishReason = result.finishReason.unified\n\n if (result.response?.id) {\n state.lastResponseId = result.response.id\n }\n\n const stepToolCalls: string[] = []\n for (const item of result.content) {\n if (item.type === 'tool-call') {\n state.allToolCalls.push(item.toolName)\n stepToolCalls.push(item.toolName)\n if (state.toolInputs) {\n const raw = typeof item.input === 'string' ? safeParseJSON(item.input) : item.input\n state.allToolCallInputs.push({\n name: item.toolName,\n input: processToolInput(raw, item.toolName, state.toolInputsOptions),\n })\n }\n }\n }\n\n const resolvedModel = resolveProviderAndModel(model.provider, result.response?.modelId ?? model.modelId)\n state.stepsUsage.push({\n model: resolvedModel.model,\n inputTokens: result.usage.inputTokens.total ?? 0,\n outputTokens: result.usage.outputTokens.total ?? 0,\n ...(stepToolCalls.length > 0 ? { toolCalls: stepToolCalls } : {}),\n })\n\n flushState(log, state)\n return result\n } catch (error) {\n recordError(log, state, model, error)\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 let streamResponseId: string | undefined\n const streamToolCalls: string[] = []\n const streamToolInputBuffers = new Map<string, { name: string, chunks: string[] }>()\n let streamError: string | undefined\n\n let doStreamResult: Awaited<ReturnType<typeof doStream>>\n try {\n doStreamResult = await doStream()\n } catch (error) {\n recordError(log, state, model, error)\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 if (state.toolInputs) {\n streamToolInputBuffers.set(chunk.id, { name: chunk.toolName, chunks: [] })\n }\n }\n\n if (chunk.type === 'tool-input-delta' && state.toolInputs) {\n const buffer = streamToolInputBuffers.get(chunk.id)\n if (buffer) {\n buffer.chunks.push(chunk.delta)\n }\n }\n\n if (chunk.type === 'tool-input-end' && state.toolInputs) {\n const buffer = streamToolInputBuffers.get(chunk.id)\n if (buffer) {\n const raw = safeParseJSON(buffer.chunks.join(''))\n state.allToolCallInputs.push({\n name: buffer.name,\n input: processToolInput(raw, buffer.name, state.toolInputsOptions),\n })\n streamToolInputBuffers.delete(chunk.id)\n }\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') {\n if (chunk.modelId) streamModelId = chunk.modelId\n if (chunk.id) streamResponseId = chunk.id\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 state.calls++\n state.steps++\n\n if (streamUsage) {\n state.usage.inputTokens += streamUsage.inputTokens\n state.usage.outputTokens += streamUsage.outputTokens\n state.usage.cacheReadTokens += streamUsage.cacheReadTokens\n state.usage.cacheWriteTokens += streamUsage.cacheWriteTokens\n state.usage.reasoningTokens += streamUsage.reasoningTokens\n }\n\n recordModel(state, model.provider, model.modelId, streamModelId)\n state.lastFinishReason = streamFinishReason\n\n state.allToolCalls.push(...streamToolCalls)\n\n if (streamResponseId) {\n state.lastResponseId = streamResponseId\n }\n\n if (firstChunkTime) {\n state.lastMsToFirstChunk = firstChunkTime - streamStart\n }\n state.lastMsToFinish = Date.now() - streamStart\n\n if (streamError) state.lastError = streamError\n\n const resolvedModel = resolveProviderAndModel(model.provider, streamModelId ?? model.modelId)\n state.stepsUsage.push({\n model: resolvedModel.model,\n inputTokens: streamUsage?.inputTokens ?? 0,\n outputTokens: streamUsage?.outputTokens ?? 0,\n ...(streamToolCalls.length > 0 ? { toolCalls: [...streamToolCalls] } : {}),\n })\n\n flushState(log, state)\n },\n })\n\n return {\n stream: stream.pipeThrough(transformStream),\n ...rest,\n }\n },\n }\n}\n\n/**\n * Create an AI SDK `TelemetryIntegration` that captures tool execution\n * timing, errors, and total generation wall time into the wide event.\n *\n * Complements the middleware-based `createAILogger`: the middleware captures\n * token usage and streaming metrics at the model level, while the integration\n * captures application-level lifecycle events (tool execution, total duration).\n *\n * When passed an `AILogger`, shares its accumulator so both paths write to\n * the same `ai.*` field. Can also be used standalone with a `RequestLogger`.\n *\n * @example Combined with middleware (recommended)\n * ```ts\n * import { createAILogger, createEvlogIntegration } from 'evlog/ai'\n *\n * const log = useLogger(event)\n * const ai = createAILogger(log)\n *\n * const result = await generateText({\n * model: ai.wrap('anthropic/claude-sonnet-4.6'),\n * tools: { getWeather },\n * experimental_telemetry: {\n * isEnabled: true,\n * integrations: [createEvlogIntegration(ai)],\n * },\n * })\n * ```\n *\n * @example Standalone (no middleware wrapping)\n * ```ts\n * import { createEvlogIntegration } from 'evlog/ai'\n *\n * const integration = createEvlogIntegration(log)\n *\n * const result = await generateText({\n * model: openai('gpt-4o'),\n * experimental_telemetry: {\n * isEnabled: true,\n * integrations: [integration],\n * },\n * })\n * ```\n */\nexport function createEvlogIntegration(\n logOrAi: RequestLogger | AILogger,\n options?: AILoggerOptions,\n): TelemetryIntegration {\n let log: RequestLogger\n let state: AccumulatorState\n\n if ('_state' in logOrAi && logOrAi._state) {\n state = logOrAi._state\n log = state._log!\n } else {\n log = logOrAi as RequestLogger\n state = createAccumulatorState(options)\n state._log = log\n }\n\n class EvlogIntegration implements TelemetryIntegration {\n\n onStart(_event: OnStartEvent) {\n state.generationStartTime = Date.now()\n }\n\n onToolCallFinish(event: OnToolCallFinishEvent) {\n const execution: AIToolExecution = {\n name: (event.toolCall as { toolName: string }).toolName,\n durationMs: event.durationMs,\n success: event.success,\n }\n if (!event.success && event.error) {\n execution.error = event.error instanceof Error ? event.error.message : String(event.error)\n }\n state.toolExecutions.push(execution)\n }\n\n onFinish(_event: OnFinishEvent) {\n if (state.generationStartTime) {\n state.totalDurationMs = Date.now() - state.generationStartTime\n }\n flushState(log, state)\n }\n \n }\n\n return bindTelemetryIntegration(new EvlogIntegration())\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/ai/index.ts"],"sourcesContent":["import * as aiModule from 'ai'\nimport { gateway, wrapLanguageModel } from 'ai'\nimport type { GatewayModelId } from 'ai'\nimport type { LanguageModelV3, LanguageModelV3Middleware, LanguageModelV3StreamPart } from '@ai-sdk/provider'\nimport type { RequestLogger } from '../types'\n\nconst { bindTelemetryIntegration } = aiModule as {\n bindTelemetryIntegration?: (integration: EvlogTelemetryIntegration) => EvlogTelemetry\n}\n\n/** @internal v6 tool execution event shape. */\ninterface V6ToolCallFinishEvent {\n toolCall: { toolName: string }\n durationMs: number\n success: boolean\n error?: unknown\n}\n\n/** @internal v7 tool execution event shape. */\ninterface V7ToolExecutionEndEvent {\n toolCall: { toolName: string }\n toolExecutionMs: number\n toolOutput: { type: 'tool-result', output?: unknown } | { type: 'tool-error', error: unknown }\n}\n\n/** @internal v7 embedding telemetry event shape. */\ninterface V7EmbedEndEvent {\n modelId: string\n usage: { tokens: number }\n embeddings: Array<{ length?: number }>\n values: string[]\n}\n\n/**\n * Telemetry integration returned by {@link createEvlogIntegration}.\n * Implements hooks for AI SDK v6 (`onToolCallFinish`, `onFinish`) and v7\n * (`onToolExecutionEnd`, `onEnd`, `onEmbedEnd`, `onAbort`, `onError`).\n */\nexport type EvlogTelemetry = {\n onStart?: (event: unknown) => void | PromiseLike<void>\n /** AI SDK v6 — superseded by `onToolExecutionEnd` in v7. */\n onToolCallFinish?: (event: unknown) => void | PromiseLike<void>\n onToolExecutionEnd?: (event: unknown) => void | PromiseLike<void>\n /** AI SDK v6 — superseded by `onEnd` in v7. */\n onFinish?: (event: unknown) => void | PromiseLike<void>\n onEnd?: (event: unknown) => void | PromiseLike<void>\n onEmbedEnd?: (event: unknown) => void | PromiseLike<void>\n onAbort?: (event: unknown) => void | PromiseLike<void>\n onError?: (event: unknown) => void | PromiseLike<void>\n}\n\n/** @internal Concrete integration class — both v6 and v7 hook names. */\ninterface EvlogTelemetryIntegration extends EvlogTelemetry {}\n\n/**\n * Fine-grained control over tool call input capture.\n */\nexport interface ToolInputsOptions {\n /**\n * Max character length for the stringified input JSON.\n * Inputs exceeding this limit are truncated with a `…` suffix.\n */\n maxLength?: number\n /**\n * Custom transform applied to each captured input before storing.\n * Receives the parsed input and tool name; return value is stored.\n * Runs before `maxLength` truncation.\n */\n transform?: (input: unknown, toolName: string) => unknown\n}\n\n/**\n * Pricing entry for a single model: cost per 1 million tokens in dollars.\n */\nexport interface ModelCost {\n input: number\n output: number\n}\n\n/**\n * Options for `createAILogger` and `createAIMiddleware`.\n */\nexport interface AILoggerOptions {\n /**\n * When enabled, `toolCalls` contains `{ name, input }` objects instead of plain tool name strings.\n * Opt-in because inputs can be large and may contain sensitive data.\n *\n * - `true` — capture all inputs as-is\n * - `{ maxLength, transform }` — capture with truncation or custom transform\n * @default false\n */\n toolInputs?: boolean | ToolInputsOptions\n /**\n * Pricing map for estimating request cost.\n * Keys are model IDs (e.g. `'claude-sonnet-4.6'`, `'gpt-4o'`), values are\n * `{ input, output }` in dollars per 1M tokens.\n *\n * When provided, the wide event includes `ai.estimatedCost` (in dollars).\n *\n * @example\n * ```ts\n * const ai = createAILogger(log, {\n * cost: {\n * 'claude-sonnet-4.6': { input: 3, output: 15 },\n * 'gpt-4o': { input: 2.5, output: 10 },\n * },\n * })\n * ```\n */\n cost?: Record<string, ModelCost>\n}\n\n/**\n * Per-step token usage breakdown for multi-step agent runs.\n */\nexport interface AIStepUsage {\n model: string\n inputTokens: number\n outputTokens: number\n toolCalls?: string[]\n}\n\n/**\n * Tool execution detail captured via telemetry integration hooks.\n */\nexport interface AIToolExecution {\n name: string\n durationMs: number\n success: boolean\n error?: string\n}\n\n/**\n * Embedding metadata captured via `captureEmbed`.\n */\nexport interface AIEmbeddingData {\n model?: string\n tokens: number\n dimensions?: number\n count?: number\n}\n\n/**\n * Shape of the `ai` field written to the wide event, and the public\n * snapshot returned by `AILogger.getMetadata()`.\n *\n * `model` and `provider` are populated after the first model call.\n * They may be undefined when only `captureEmbed` has been called or\n * before any AI activity has happened.\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[] | Array<{ name: string, input: unknown }>\n responseId?: string\n steps?: number\n stepsUsage?: AIStepUsage[]\n msToFirstChunk?: number\n msToFinish?: number\n tokensPerSecond?: number\n error?: string\n tools?: AIToolExecution[]\n totalDurationMs?: number\n embedding?: AIEmbeddingData\n estimatedCost?: number\n}\n\n/**\n * Public alias for the metadata snapshot returned by `AILogger.getMetadata()`.\n *\n * Mirrors the shape of the `ai` field on the wide event, so the same object\n * can be persisted, surfaced to end-users, or compared across runs.\n */\nexport type AIMetadata = AIEventData\n\n/**\n * Callback fired on every metadata update (per step, per embed, on error,\n * and on integration completion). Receives a structured snapshot.\n */\nexport type AIMetadataListener = (metadata: AIMetadata) => void\n\nexport interface AILogger {\n /**\n * Wrap a language model with evlog middleware.\n * All `generateText` and `streamText` calls using the wrapped model\n * 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 * Also works with pre-wrapped models (e.g. from supermemory, guardrails):\n * `ai.wrap(withSupermemory(base, orgId))` composes correctly.\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 * // With model info (v2)\n * ai.captureEmbed({ usage, model: 'text-embedding-3-small', dimensions: 1536 })\n *\n * // After embedMany\n * ai.captureEmbed({ usage, count: texts.length })\n * ```\n */\n captureEmbed: (result: {\n usage: { tokens: number }\n model?: string\n dimensions?: number\n count?: number\n }) => void\n\n /**\n * Get a snapshot of the current AI execution metadata.\n *\n * Returns the same structured object that is written to the `ai` field\n * of the wide event. Safe to call at any time — including inside the\n * AI SDK's `onFinish` callback, after `await generateText()`, or while a\n * stream is in progress.\n *\n * The returned snapshot is a fresh copy: mutating it does not affect\n * subsequent calls or the underlying state.\n *\n * @example Persist execution history after a run\n * ```ts\n * const ai = createAILogger(log, { cost: { ... } })\n *\n * await generateText({ model: ai.wrap('anthropic/claude-sonnet-4.6'), prompt })\n *\n * const metadata = ai.getMetadata()\n * await db.insert('ai_runs', metadata)\n * ```\n *\n * @example Surface usage to end-users in a streaming response\n * ```ts\n * const result = streamText({\n * model: ai.wrap('anthropic/claude-sonnet-4.6'),\n * messages,\n * onFinish: () => {\n * const { totalTokens, estimatedCost } = ai.getMetadata()\n * trackUsage(userId, { totalTokens, estimatedCost })\n * },\n * })\n * ```\n */\n getMetadata: () => AIMetadata\n\n /**\n * Get the current estimated cost in dollars.\n *\n * Returns `undefined` if no `cost` map was provided to `createAILogger`,\n * or if the model is not in the pricing map.\n *\n * Convenience for `getMetadata().estimatedCost`.\n *\n * @example\n * ```ts\n * const ai = createAILogger(log, {\n * cost: { 'claude-sonnet-4.6': { input: 3, output: 15 } },\n * })\n *\n * await generateText({ model: ai.wrap('anthropic/claude-sonnet-4.6'), prompt })\n *\n * console.log(`Cost: $${ai.getEstimatedCost()?.toFixed(4)}`)\n * ```\n */\n getEstimatedCost: () => number | undefined\n\n /**\n * Subscribe to metadata updates.\n *\n * The callback fires every time the underlying state flushes — once per\n * step (in multi-step agent runs), once per `captureEmbed` call, on\n * model errors, and once on `createEvlogIntegration`'s `onFinish`.\n *\n * Each invocation receives a fresh snapshot (same shape as `getMetadata`).\n * Returns an unsubscribe function.\n *\n * @example Stream incremental usage updates to the client\n * ```ts\n * const ai = createAILogger(log)\n *\n * ai.onUpdate((metadata) => {\n * pushToClient({ type: 'ai-progress', metadata })\n * })\n *\n * const result = streamText({ model: ai.wrap('...'), messages })\n * ```\n *\n * @example Cleanup\n * ```ts\n * const off = ai.onUpdate((metadata) => { ... })\n * // later\n * off()\n * ```\n */\n onUpdate: (callback: AIMetadataListener) => () => void\n\n /**\n * Internal accumulator state exposed for `createEvlogIntegration` to share.\n * @internal\n */\n _state: AccumulatorState\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 the evlog AI middleware that captures AI SDK data into a wide event.\n *\n * Use this when you need explicit middleware composition with other wrappers\n * (e.g. supermemory, guardrails). For most cases, use `createAILogger` instead.\n *\n * Note: `captureEmbed` is not available with the raw middleware — use\n * `createAILogger` if you need embedding capture.\n *\n * @example Nuxt API route with supermemory\n * ```ts\n * import { createAIMiddleware } from 'evlog/ai'\n * import { wrapLanguageModel } from 'ai'\n *\n * export default defineEventHandler(async (event) => {\n * const log = useLogger(event)\n *\n * const model = wrapLanguageModel({\n * model: withSupermemory(base, orgId),\n * middleware: [createAIMiddleware(log, { toolInputs: true })],\n * })\n * })\n * ```\n */\nexport function createAIMiddleware(log: RequestLogger, options?: AILoggerOptions): LanguageModelV3Middleware {\n return buildMiddleware(log, options)\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 *\n * @example Capture tool call inputs\n * ```ts\n * const ai = createAILogger(log, { toolInputs: true })\n * ```\n */\nexport function createAILogger(log: RequestLogger, options?: AILoggerOptions): AILogger {\n const state = createAccumulatorState(options)\n state._log = log\n const middleware = buildMiddlewareFromState(log, state)\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: {\n usage: { tokens: number }\n model?: string\n dimensions?: number\n count?: number\n }) => {\n state.calls++\n state.usage.inputTokens += result.usage.tokens\n state.embedding = {\n tokens: (state.embedding?.tokens ?? 0) + result.usage.tokens,\n ...(result.model ? { model: result.model } : state.embedding?.model ? { model: state.embedding.model } : {}),\n ...(result.dimensions ? { dimensions: result.dimensions } : state.embedding?.dimensions ? { dimensions: state.embedding.dimensions } : {}),\n ...(result.count ? { count: (state.embedding?.count ?? 0) + result.count } : state.embedding?.count ? { count: state.embedding.count } : {}),\n }\n flushState(log, state)\n },\n\n getMetadata: () => buildMetadata(state),\n\n getEstimatedCost: () => computeEstimatedCost(state),\n\n onUpdate: (callback: AIMetadataListener) => {\n state.subscribers.add(callback)\n return () => {\n state.subscribers.delete(callback)\n }\n },\n\n _state: state,\n }\n}\n\n/**\n * Snapshot of how much of each cumulative array we've already sent to the\n * wide event. `flushState` reads it to compute the delta and updates it in\n * place; passing zero-watermarks to `buildMetadata` yields a full snapshot.\n */\ninterface Watermarks {\n toolCalls: number\n toolCallInputs: number\n stepsUsage: number\n toolExecutions: number\n models: Set<string>\n}\n\nfunction freshWatermarks(): Watermarks {\n return { toolCalls: 0, toolCallInputs: 0, stepsUsage: 0, toolExecutions: 0, models: new Set() }\n}\n\ninterface AccumulatorState {\n calls: number\n steps: number\n usage: UsageAccumulator\n models: string[]\n lastProvider: string | undefined\n allToolCalls: string[]\n allToolCallInputs: Array<{ name: string, input: unknown }>\n stepsUsage: AIStepUsage[]\n lastFinishReason: string | undefined\n lastMsToFirstChunk: number | undefined\n lastMsToFinish: number | undefined\n lastError: string | undefined\n lastResponseId: string | undefined\n toolInputs: boolean\n toolInputsOptions: ToolInputsOptions | undefined\n toolExecutions: AIToolExecution[]\n generationStartTime: number | undefined\n totalDurationMs: number | undefined\n embedding: AIEmbeddingData | undefined\n costMap: Record<string, ModelCost> | undefined\n subscribers: Set<AIMetadataListener>\n /** @internal What's already been written to the wide event. */\n _flushed: Watermarks\n /** @internal Logger reference for integration flush */\n _log?: RequestLogger\n}\n\nfunction resolveToolInputs(raw?: boolean | ToolInputsOptions): { enabled: boolean, options: ToolInputsOptions | undefined } {\n if (!raw) return { enabled: false, options: undefined }\n if (raw === true) return { enabled: true, options: undefined }\n return { enabled: true, options: raw }\n}\n\nfunction processToolInput(input: unknown, toolName: string, options: ToolInputsOptions | undefined): unknown {\n let value = input\n if (options?.transform) {\n value = options.transform(value, toolName)\n }\n if (options?.maxLength) {\n const str = typeof value === 'string' ? value : JSON.stringify(value)\n if (str.length > options.maxLength) {\n return `${str.slice(0, options.maxLength)}…`\n }\n }\n return value\n}\n\nfunction createAccumulatorState(options?: AILoggerOptions): AccumulatorState {\n const { enabled, options: captureOpts } = resolveToolInputs(options?.toolInputs)\n return {\n calls: 0,\n steps: 0,\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n reasoningTokens: 0,\n },\n models: [],\n lastProvider: undefined,\n allToolCalls: [],\n allToolCallInputs: [],\n stepsUsage: [],\n lastFinishReason: undefined,\n lastMsToFirstChunk: undefined,\n lastMsToFinish: undefined,\n lastError: undefined,\n lastResponseId: undefined,\n toolInputs: enabled,\n toolInputsOptions: captureOpts,\n toolExecutions: [],\n generationStartTime: undefined,\n totalDurationMs: undefined,\n embedding: undefined,\n costMap: options?.cost,\n subscribers: new Set(),\n _flushed: freshWatermarks(),\n }\n}\n\nfunction computeEstimatedCost(state: AccumulatorState): number | undefined {\n if (!state.costMap) return undefined\n const lastModel = state.models[state.models.length - 1]\n if (!lastModel) return undefined\n const pricing = state.costMap[lastModel]\n if (!pricing) return undefined\n const inputCost = (state.usage.inputTokens / 1_000_000) * pricing.input\n const outputCost = (state.usage.outputTokens / 1_000_000) * pricing.output\n const total = inputCost + outputCost\n return total > 0 ? Math.round(total * 1_000_000) / 1_000_000 : undefined\n}\n\n/**\n * Build the `ai.*` payload from the accumulator. Pass `since` to emit\n * only the array entries appended after that watermark (used by\n * `flushState` to avoid quadratic growth on the wide event, since evlog's\n * `mergeInto` concatenates arrays). The default — fresh watermarks —\n * yields the full cumulative snapshot used by `getMetadata()` and\n * delivered to `onUpdate` subscribers.\n */\nfunction buildMetadata(state: AccumulatorState, since: Watermarks = freshWatermarks()): AIMetadata {\n const lastModel = state.models[state.models.length - 1]\n\n const data: AIMetadata = {\n calls: state.calls,\n inputTokens: state.usage.inputTokens,\n outputTokens: state.usage.outputTokens,\n totalTokens: state.usage.inputTokens + state.usage.outputTokens,\n }\n\n if (lastModel) data.model = lastModel\n if (state.lastProvider) data.provider = state.lastProvider\n if (state.usage.cacheReadTokens > 0) data.cacheReadTokens = state.usage.cacheReadTokens\n if (state.usage.cacheWriteTokens > 0) data.cacheWriteTokens = state.usage.cacheWriteTokens\n if (state.usage.reasoningTokens > 0) data.reasoningTokens = state.usage.reasoningTokens\n if (state.lastFinishReason) data.finishReason = state.lastFinishReason\n if (state.lastResponseId) data.responseId = state.lastResponseId\n if (state.lastMsToFirstChunk !== undefined) data.msToFirstChunk = state.lastMsToFirstChunk\n if (state.lastMsToFinish !== undefined) {\n data.msToFinish = state.lastMsToFinish\n if (state.usage.outputTokens > 0 && state.lastMsToFinish > 0) {\n data.tokensPerSecond = Math.round((state.usage.outputTokens / state.lastMsToFinish) * 1000)\n }\n }\n if (state.lastError) data.error = state.lastError\n if (state.totalDurationMs !== undefined) data.totalDurationMs = state.totalDurationMs\n if (state.embedding) data.embedding = { ...state.embedding }\n const cost = computeEstimatedCost(state)\n if (cost !== undefined) data.estimatedCost = cost\n\n if (state.toolInputs) {\n if (state.allToolCallInputs.length > since.toolCallInputs) {\n data.toolCalls = state.allToolCallInputs.slice(since.toolCallInputs).map(t => ({ ...t }))\n }\n } else if (state.allToolCalls.length > since.toolCalls) {\n data.toolCalls = state.allToolCalls.slice(since.toolCalls)\n }\n\n if (state.steps > 1 && state.stepsUsage.length > since.stepsUsage) {\n data.steps = state.steps\n data.stepsUsage = state.stepsUsage\n .slice(since.stepsUsage)\n .map(s => ({ ...s, ...(s.toolCalls ? { toolCalls: [...s.toolCalls] } : {}) }))\n }\n\n if (state.toolExecutions.length > since.toolExecutions) {\n data.tools = state.toolExecutions.slice(since.toolExecutions).map(t => ({ ...t }))\n }\n\n // `models` is only emitted once a second distinct model appears, then\n // deduplicated across flushes so the merged wide event stays unique.\n const uniqueModels = new Set(state.models)\n if (uniqueModels.size > 1) {\n const newModels = [...uniqueModels].filter(m => !since.models.has(m))\n if (newModels.length > 0) data.models = newModels\n }\n\n return data\n}\n\nfunction notifySubscribers(state: AccumulatorState, metadata: AIMetadata): void {\n if (state.subscribers.size === 0) return\n for (const subscriber of state.subscribers) {\n try {\n subscriber(metadata)\n } catch {\n // Subscribers must not break the AI flow.\n }\n }\n}\n\n/**\n * Push the accumulator's latest changes onto the wide event using delta\n * semantics for arrays, then notify subscribers with the full snapshot.\n */\nfunction flushState(log: RequestLogger, state: AccumulatorState): void {\n const flushed = state._flushed\n const data = buildMetadata(state, flushed)\n\n flushed.toolCalls = state.allToolCalls.length\n flushed.toolCallInputs = state.allToolCallInputs.length\n flushed.toolExecutions = state.toolExecutions.length\n if (data.stepsUsage) flushed.stepsUsage = state.stepsUsage.length\n if (data.models) for (const m of data.models) flushed.models.add(m)\n\n log.set({ ai: data } as Record<string, unknown>)\n\n if (state.subscribers.size > 0) {\n notifySubscribers(state, buildMetadata(state))\n }\n}\n\nfunction recordModel(state: AccumulatorState, provider: string, modelId: string, responseModelId?: string): void {\n const resolved = resolveProviderAndModel(provider, responseModelId ?? modelId)\n state.models.push(resolved.model)\n state.lastProvider = resolved.provider\n}\n\nfunction safeParseJSON(input: string): unknown {\n try {\n return JSON.parse(input)\n } catch {\n return input\n }\n}\n\nfunction recordError(log: RequestLogger, state: AccumulatorState, model: { provider: string, modelId: string }, error: unknown): void {\n state.calls++\n state.steps++\n recordModel(state, model.provider, model.modelId)\n state.lastFinishReason = 'error'\n state.lastError = error instanceof Error ? error.message : String(error)\n\n const resolved = resolveProviderAndModel(model.provider, model.modelId)\n state.stepsUsage.push({\n model: resolved.model,\n inputTokens: 0,\n outputTokens: 0,\n })\n\n flushState(log, state)\n}\n\nfunction buildMiddleware(log: RequestLogger, options?: AILoggerOptions): LanguageModelV3Middleware {\n const state = createAccumulatorState(options)\n state._log = log\n return buildMiddlewareFromState(log, state)\n}\n\nfunction buildMiddlewareFromState(log: RequestLogger, state: AccumulatorState): LanguageModelV3Middleware {\n return {\n specificationVersion: 'v3',\n wrapGenerate: async ({ doGenerate, model }) => {\n try {\n const result = await doGenerate()\n\n state.calls++\n state.steps++\n addUsage(state.usage, result.usage)\n recordModel(state, model.provider, model.modelId, result.response?.modelId)\n state.lastFinishReason = result.finishReason.unified\n\n if (result.response?.id) {\n state.lastResponseId = result.response.id\n }\n\n const stepToolCalls: string[] = []\n for (const item of result.content) {\n if (item.type === 'tool-call') {\n state.allToolCalls.push(item.toolName)\n stepToolCalls.push(item.toolName)\n if (state.toolInputs) {\n const raw = typeof item.input === 'string' ? safeParseJSON(item.input) : item.input\n state.allToolCallInputs.push({\n name: item.toolName,\n input: processToolInput(raw, item.toolName, state.toolInputsOptions),\n })\n }\n }\n }\n\n const resolvedModel = resolveProviderAndModel(model.provider, result.response?.modelId ?? model.modelId)\n state.stepsUsage.push({\n model: resolvedModel.model,\n inputTokens: result.usage.inputTokens.total ?? 0,\n outputTokens: result.usage.outputTokens.total ?? 0,\n ...(stepToolCalls.length > 0 ? { toolCalls: stepToolCalls } : {}),\n })\n\n flushState(log, state)\n return result\n } catch (error) {\n recordError(log, state, model, error)\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 let streamResponseId: string | undefined\n const streamToolCalls: string[] = []\n const streamToolInputBuffers = new Map<string, { name: string, chunks: string[] }>()\n let streamError: string | undefined\n\n let doStreamResult: Awaited<ReturnType<typeof doStream>>\n try {\n doStreamResult = await doStream()\n } catch (error) {\n recordError(log, state, model, error)\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 if (state.toolInputs) {\n streamToolInputBuffers.set(chunk.id, { name: chunk.toolName, chunks: [] })\n }\n }\n\n if (chunk.type === 'tool-input-delta' && state.toolInputs) {\n const buffer = streamToolInputBuffers.get(chunk.id)\n if (buffer) {\n buffer.chunks.push(chunk.delta)\n }\n }\n\n if (chunk.type === 'tool-input-end' && state.toolInputs) {\n const buffer = streamToolInputBuffers.get(chunk.id)\n if (buffer) {\n const raw = safeParseJSON(buffer.chunks.join(''))\n state.allToolCallInputs.push({\n name: buffer.name,\n input: processToolInput(raw, buffer.name, state.toolInputsOptions),\n })\n streamToolInputBuffers.delete(chunk.id)\n }\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') {\n if (chunk.modelId) streamModelId = chunk.modelId\n if (chunk.id) streamResponseId = chunk.id\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 state.calls++\n state.steps++\n\n if (streamUsage) {\n state.usage.inputTokens += streamUsage.inputTokens\n state.usage.outputTokens += streamUsage.outputTokens\n state.usage.cacheReadTokens += streamUsage.cacheReadTokens\n state.usage.cacheWriteTokens += streamUsage.cacheWriteTokens\n state.usage.reasoningTokens += streamUsage.reasoningTokens\n }\n\n recordModel(state, model.provider, model.modelId, streamModelId)\n state.lastFinishReason = streamFinishReason\n\n state.allToolCalls.push(...streamToolCalls)\n\n if (streamResponseId) {\n state.lastResponseId = streamResponseId\n }\n\n if (firstChunkTime) {\n state.lastMsToFirstChunk = firstChunkTime - streamStart\n }\n state.lastMsToFinish = Date.now() - streamStart\n\n if (streamError) state.lastError = streamError\n\n const resolvedModel = resolveProviderAndModel(model.provider, streamModelId ?? model.modelId)\n state.stepsUsage.push({\n model: resolvedModel.model,\n inputTokens: streamUsage?.inputTokens ?? 0,\n outputTokens: streamUsage?.outputTokens ?? 0,\n ...(streamToolCalls.length > 0 ? { toolCalls: [...streamToolCalls] } : {}),\n })\n\n flushState(log, state)\n },\n })\n\n return {\n stream: stream.pipeThrough(transformStream),\n ...rest,\n }\n },\n }\n}\n\nfunction formatTelemetryError(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction recordToolExecution(\n state: AccumulatorState,\n input: { name: string, durationMs: number, success: boolean, error?: string },\n): void {\n const execution: AIToolExecution = {\n name: input.name,\n durationMs: input.durationMs,\n success: input.success,\n }\n if (input.error) execution.error = input.error\n state.toolExecutions.push(execution)\n}\n\nfunction adaptV6ToolEvent(event: V6ToolCallFinishEvent) {\n return {\n name: event.toolCall.toolName,\n durationMs: event.durationMs,\n success: event.success,\n error: !event.success && event.error !== undefined\n ? formatTelemetryError(event.error)\n : undefined,\n }\n}\n\nfunction adaptV7ToolEvent(event: V7ToolExecutionEndEvent) {\n const success = event.toolOutput.type === 'tool-result'\n return {\n name: event.toolCall.toolName,\n durationMs: event.toolExecutionMs,\n success,\n error: !success && event.toolOutput.type === 'tool-error'\n ? formatTelemetryError(event.toolOutput.error)\n : undefined,\n }\n}\n\nfunction recordGenerationEnd(state: AccumulatorState, log: RequestLogger): void {\n if (state.generationStartTime !== undefined) {\n state.totalDurationMs = Date.now() - state.generationStartTime\n }\n flushState(log, state)\n}\n\nfunction recordEmbedEnd(state: AccumulatorState, log: RequestLogger, event: V7EmbedEndEvent): void {\n state.calls++\n state.usage.inputTokens += event.usage.tokens\n const dimensions = event.embeddings[0]?.length\n state.embedding = {\n tokens: (state.embedding?.tokens ?? 0) + event.usage.tokens,\n model: event.modelId,\n ...(dimensions !== undefined\n ? { dimensions }\n : state.embedding?.dimensions\n ? { dimensions: state.embedding.dimensions }\n : {}),\n count: (state.embedding?.count ?? 0) + event.values.length,\n }\n flushState(log, state)\n}\n\nfunction finalizeIntegration(integration: EvlogTelemetryIntegration): EvlogTelemetry {\n if (typeof bindTelemetryIntegration === 'function') {\n return bindTelemetryIntegration(integration)\n }\n return integration\n}\n\n/**\n * Create an AI SDK telemetry integration that captures tool execution\n * timing, errors, and total generation wall time into the wide event.\n *\n * Compatible with AI SDK v6 (`TelemetryIntegration`) and v7 (`Telemetry`).\n * On v7, also captures embeddings via `onEmbedEnd`, aborts via `onAbort`,\n * and unrecoverable errors via `onError`.\n *\n * Complements the middleware-based `createAILogger`: the middleware captures\n * token usage and streaming metrics at the model level, while the integration\n * captures application-level lifecycle events (tool execution, total duration).\n *\n * When passed an `AILogger`, shares its accumulator so both paths write to\n * the same `ai.*` field. Can also be used standalone with a `RequestLogger`.\n *\n * @example Combined with middleware (recommended)\n * ```ts\n * import { createAILogger, createEvlogIntegration } from 'evlog/ai'\n *\n * const log = useLogger(event)\n * const ai = createAILogger(log)\n *\n * const result = await generateText({\n * model: ai.wrap('anthropic/claude-sonnet-4.6'),\n * tools: { getWeather },\n * telemetry: {\n * integrations: [createEvlogIntegration(ai)],\n * },\n * })\n * ```\n *\n * @example Standalone (no middleware wrapping)\n * ```ts\n * import { createEvlogIntegration } from 'evlog/ai'\n *\n * const integration = createEvlogIntegration(log)\n *\n * const result = await generateText({\n * model: openai('gpt-4o'),\n * telemetry: {\n * integrations: [integration],\n * },\n * })\n * ```\n */\nexport function createEvlogIntegration(\n logOrAi: RequestLogger | AILogger,\n options?: AILoggerOptions,\n): EvlogTelemetry {\n let log: RequestLogger\n let state: AccumulatorState\n\n if ('_state' in logOrAi && logOrAi._state) {\n state = logOrAi._state\n log = state._log!\n } else {\n log = logOrAi as RequestLogger\n state = createAccumulatorState(options)\n state._log = log\n }\n\n class EvlogIntegration implements EvlogTelemetryIntegration {\n\n onStart(_event: unknown) {\n state.generationStartTime = Date.now()\n }\n\n onToolCallFinish(event: unknown) {\n recordToolExecution(state, adaptV6ToolEvent(event as V6ToolCallFinishEvent))\n }\n\n onToolExecutionEnd(event: unknown) {\n recordToolExecution(state, adaptV7ToolEvent(event as V7ToolExecutionEndEvent))\n }\n\n onFinish(_event: unknown) {\n recordGenerationEnd(state, log)\n }\n\n onEnd(_event: unknown) {\n recordGenerationEnd(state, log)\n }\n\n onEmbedEnd(event: unknown) {\n recordEmbedEnd(state, log, event as V7EmbedEndEvent)\n }\n\n onAbort(event: unknown) {\n state.lastFinishReason = 'abort'\n const { reason } = event as { reason?: unknown }\n if (reason !== undefined) {\n state.lastError = formatTelemetryError(reason)\n }\n recordGenerationEnd(state, log)\n }\n\n onError(error: unknown) {\n state.lastError = formatTelemetryError(error)\n flushState(log, state)\n }\n\n }\n\n return finalizeIntegration(new EvlogIntegration())\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import "node:async_hooks";
|
|
2
|
+
//#region src/shared/asyncStorageScope.ts
|
|
3
|
+
/**
|
|
4
|
+
* Whether this runtime provides a working native `AsyncLocalStorage.enterWith()`.
|
|
5
|
+
*
|
|
6
|
+
* Cloudflare Workers expose `enterWith` on the prototype but throw when it is
|
|
7
|
+
* called, so a `typeof` check alone is not enough — we probe with a call.
|
|
8
|
+
*/
|
|
9
|
+
function supportsAsyncLocalStorageEnterWith(storage) {
|
|
10
|
+
if (typeof storage.enterWith !== "function") return false;
|
|
11
|
+
try {
|
|
12
|
+
storage.enterWith(void 0);
|
|
13
|
+
return true;
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Bind `value` to `storage` for the current async execution context.
|
|
20
|
+
* Uses native `enterWith()` when available; otherwise relies on
|
|
21
|
+
* {@link patchAsyncLocalStorageEnterWith}.
|
|
22
|
+
*/
|
|
23
|
+
function bindAsyncLocalStorage(storage, value) {
|
|
24
|
+
storage.enterWith(value);
|
|
25
|
+
}
|
|
26
|
+
/** Clear a value previously bound with {@link bindAsyncLocalStorage}. */
|
|
27
|
+
function clearAsyncLocalStorage(storage) {
|
|
28
|
+
storage.enterWith(void 0);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Polyfill `enterWith()` on a single `AsyncLocalStorage` instance.
|
|
32
|
+
*
|
|
33
|
+
* Elysia's lifecycle is split across hooks (`onRequest` → handler → `onAfterResponse`).
|
|
34
|
+
* Unlike Express or Fastify, there is no single `next()` boundary to wrap in
|
|
35
|
+
* `storage.run()`, so the integration binds the logger with `enterWith()`.
|
|
36
|
+
*
|
|
37
|
+
* The polyfill stores the value on the ALS instance when no native `run()` frame
|
|
38
|
+
* is active. That matches single-request `wrangler dev` flows and async work
|
|
39
|
+
* spawned from a handler, but it does **not** replicate native per-async-context
|
|
40
|
+
* isolation when multiple requests interleave in the same isolate. Prefer `{ log }`
|
|
41
|
+
* from derive for concurrent Workers handlers.
|
|
42
|
+
*/
|
|
43
|
+
function patchAsyncLocalStorageEnterWith(storage) {
|
|
44
|
+
if (supportsAsyncLocalStorageEnterWith(storage)) return;
|
|
45
|
+
let fallbackStore;
|
|
46
|
+
let runDepth = 0;
|
|
47
|
+
const originalGetStore = storage.getStore.bind(storage);
|
|
48
|
+
const originalRun = storage.run.bind(storage);
|
|
49
|
+
Object.defineProperty(storage, "enterWith", {
|
|
50
|
+
configurable: true,
|
|
51
|
+
writable: true,
|
|
52
|
+
value(store) {
|
|
53
|
+
fallbackStore = store;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
Object.defineProperty(storage, "run", {
|
|
57
|
+
configurable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value(store, callback, ...args) {
|
|
60
|
+
runDepth++;
|
|
61
|
+
try {
|
|
62
|
+
return originalRun(store, callback, ...args);
|
|
63
|
+
} finally {
|
|
64
|
+
runDepth--;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
Object.defineProperty(storage, "getStore", {
|
|
69
|
+
configurable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
value() {
|
|
72
|
+
if (runDepth > 0) return originalGetStore();
|
|
73
|
+
const active = originalGetStore();
|
|
74
|
+
return active !== void 0 ? active : fallbackStore;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { clearAsyncLocalStorage as n, patchAsyncLocalStorageEnterWith as r, bindAsyncLocalStorage as t };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=asyncStorageScope-DnF7Xk8l.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncStorageScope-DnF7Xk8l.mjs","names":[],"sources":["../src/shared/asyncStorageScope.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\n\n/**\n * Whether this runtime provides a working native `AsyncLocalStorage.enterWith()`.\n *\n * Cloudflare Workers expose `enterWith` on the prototype but throw when it is\n * called, so a `typeof` check alone is not enough — we probe with a call.\n */\nexport function supportsAsyncLocalStorageEnterWith(\n storage: { enterWith?: unknown },\n): boolean {\n if (typeof storage.enterWith !== 'function') return false\n try {\n storage.enterWith(undefined)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Bind `value` to `storage` for the current async execution context.\n * Uses native `enterWith()` when available; otherwise relies on\n * {@link patchAsyncLocalStorageEnterWith}.\n */\nexport function bindAsyncLocalStorage<T>(\n storage: AsyncLocalStorage<T>,\n value: T,\n): void {\n storage.enterWith(value)\n}\n\n/** Clear a value previously bound with {@link bindAsyncLocalStorage}. */\nexport function clearAsyncLocalStorage<T>(storage: AsyncLocalStorage<T>): void {\n storage.enterWith(undefined as unknown as T)\n}\n\n/**\n * Polyfill `enterWith()` on a single `AsyncLocalStorage` instance.\n *\n * Elysia's lifecycle is split across hooks (`onRequest` → handler → `onAfterResponse`).\n * Unlike Express or Fastify, there is no single `next()` boundary to wrap in\n * `storage.run()`, so the integration binds the logger with `enterWith()`.\n *\n * The polyfill stores the value on the ALS instance when no native `run()` frame\n * is active. That matches single-request `wrangler dev` flows and async work\n * spawned from a handler, but it does **not** replicate native per-async-context\n * isolation when multiple requests interleave in the same isolate. Prefer `{ log }`\n * from derive for concurrent Workers handlers.\n */\nexport function patchAsyncLocalStorageEnterWith<T>(\n storage: AsyncLocalStorage<T>,\n): void {\n if (supportsAsyncLocalStorageEnterWith(storage)) return\n\n let fallbackStore: T | undefined\n let runDepth = 0\n const originalGetStore = storage.getStore.bind(storage)\n const originalRun = storage.run.bind(storage)\n\n Object.defineProperty(storage, 'enterWith', {\n configurable: true,\n writable: true,\n value(store: T): void {\n fallbackStore = store\n },\n })\n\n Object.defineProperty(storage, 'run', {\n configurable: true,\n writable: true,\n value<TReturn>(\n store: T,\n callback: (...args: unknown[]) => TReturn,\n ...args: unknown[]\n ): TReturn {\n runDepth++\n try {\n return originalRun(store, callback, ...args)\n } finally {\n runDepth--\n }\n },\n })\n\n Object.defineProperty(storage, 'getStore', {\n configurable: true,\n writable: true,\n value(): T | undefined {\n if (runDepth > 0) return originalGetStore()\n const active = originalGetStore()\n return active !== undefined ? active : fallbackStore\n },\n })\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,mCACd,SACS;AACT,KAAI,OAAO,QAAQ,cAAc,WAAY,QAAO;AACpD,KAAI;AACF,UAAQ,UAAU,KAAA,EAAU;AAC5B,SAAO;SACD;AACN,SAAO;;;;;;;;AASX,SAAgB,sBACd,SACA,OACM;AACN,SAAQ,UAAU,MAAM;;;AAI1B,SAAgB,uBAA0B,SAAqC;AAC7E,SAAQ,UAAU,KAAA,EAA0B;;;;;;;;;;;;;;;AAgB9C,SAAgB,gCACd,SACM;AACN,KAAI,mCAAmC,QAAQ,CAAE;CAEjD,IAAI;CACJ,IAAI,WAAW;CACf,MAAM,mBAAmB,QAAQ,SAAS,KAAK,QAAQ;CACvD,MAAM,cAAc,QAAQ,IAAI,KAAK,QAAQ;AAE7C,QAAO,eAAe,SAAS,aAAa;EAC1C,cAAc;EACd,UAAU;EACV,MAAM,OAAgB;AACpB,mBAAgB;;EAEnB,CAAC;AAEF,QAAO,eAAe,SAAS,OAAO;EACpC,cAAc;EACd,UAAU;EACV,MACE,OACA,UACA,GAAG,MACM;AACT;AACA,OAAI;AACF,WAAO,YAAY,OAAO,UAAU,GAAG,KAAK;aACpC;AACR;;;EAGL,CAAC;AAEF,QAAO,eAAe,SAAS,YAAY;EACzC,cAAc;EACd,UAAU;EACV,QAAuB;AACrB,OAAI,WAAW,EAAG,QAAO,kBAAkB;GAC3C,MAAM,SAAS,kBAAkB;AACjC,UAAO,WAAW,KAAA,IAAY,SAAS;;EAE1C,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { colors, cssColors, detectEnvironment, escapeFormatString, formatDuration, getConsoleMethod, getCssLevelColor, getLevelColor, globToRegExp, isBrowser, isDev, isLevelEnabled, matchesPattern } from "./utils.mjs";
|
|
2
|
-
import { n as buildErrorEntries,
|
|
2
|
+
import { n as buildErrorEntries, r as compactStackForStorage } from "./pretty-error-THg0U0w9.mjs";
|
|
3
3
|
import { t as resolveDevTerminal } from "./dev-terminal-D4UaEm17.mjs";
|
|
4
4
|
import { EvlogError } from "./error.mjs";
|
|
5
5
|
import { r as getHeader$1 } from "./headers-VtmnWcfn.mjs";
|
|
@@ -525,6 +525,7 @@ let globalSilent = false;
|
|
|
525
525
|
/** Minimum level for the global `log` API only (`ownsEvent === false`). Default: all levels. */
|
|
526
526
|
let globalMinLevel = "debug";
|
|
527
527
|
let _locked = false;
|
|
528
|
+
let _loggerInitialized = false;
|
|
528
529
|
let globalPluginRunner = getEmptyPluginRunner();
|
|
529
530
|
/**
|
|
530
531
|
* Initialize the logger with configuration.
|
|
@@ -550,13 +551,9 @@ function initLogger(config = {}) {
|
|
|
550
551
|
globalMinLevel = config.minLevel ?? "debug";
|
|
551
552
|
globalPluginRunner = config.plugins?.length ? createPluginRunner(config.plugins) : getEmptyPluginRunner();
|
|
552
553
|
if (globalPluginRunner.plugins.length > 0) globalPluginRunner.runSetup({ env: { ...globalEnv } });
|
|
553
|
-
if (!isBrowser() && typeof process !== "undefined" && process.versions?.node) import("./pretty-error-snippet.node-itfCajBM.mjs").then((n) => n.t).then((mod) => {
|
|
554
|
-
registerPrettyErrorSnippetReader(mod.readCodeSnippetFromDisk);
|
|
555
|
-
}).catch(() => {
|
|
556
|
-
registerPrettyErrorSnippetReader(null);
|
|
557
|
-
});
|
|
558
554
|
const hasAnyDrain = !!globalDrain || globalPluginRunner.hasDrain;
|
|
559
555
|
if (globalSilent && !hasAnyDrain && !config._suppressDrainWarning) console.warn("[evlog] silent mode is enabled but no drain is configured. Events will be built and sampled but not output anywhere. Set a drain via initLogger({ drain }) or a framework hook (evlog:drain).");
|
|
556
|
+
_loggerInitialized = true;
|
|
560
557
|
}
|
|
561
558
|
/**
|
|
562
559
|
* @internal Get the globally registered plugin runner.
|
|
@@ -587,6 +584,12 @@ function isLoggerLocked() {
|
|
|
587
584
|
return _locked;
|
|
588
585
|
}
|
|
589
586
|
/**
|
|
587
|
+
* @internal Whether {@link initLogger} has completed at least once.
|
|
588
|
+
*/
|
|
589
|
+
function isLoggerInitialized() {
|
|
590
|
+
return _loggerInitialized;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
590
593
|
* @internal Get the globally configured drain callback.
|
|
591
594
|
* Used by framework middleware to fall back to the global drain
|
|
592
595
|
* when no middleware-level drain is provided.
|
|
@@ -912,8 +915,7 @@ function prettyPrintWideEvent(event) {
|
|
|
912
915
|
styles.push(cssColors.dim, cssColors.reset, lc, cssColors.reset, cssColors.cyan, cssColors.reset);
|
|
913
916
|
} else {
|
|
914
917
|
const lc = getLevelColor(levelLabel);
|
|
915
|
-
|
|
916
|
-
else parts.push(`${colors.dim}${ts}${colors.reset} ${lc}${levelLabel.toUpperCase()}${colors.reset} ${colors.cyan}[${service}]${colors.reset}`);
|
|
918
|
+
parts.push(`${colors.dim}${ts}${colors.reset} ${lc}${levelLabel.toUpperCase()}${colors.reset} ${colors.cyan}[${service}]${colors.reset}`);
|
|
917
919
|
}
|
|
918
920
|
if (rest.method && rest.path) {
|
|
919
921
|
parts.push(browser ? ` ${escapeFormatString(String(rest.method))} ${escapeFormatString(String(rest.path))}` : ` ${rest.method} ${rest.path}`);
|
|
@@ -1159,8 +1161,9 @@ function createLogger(initialContext = {}, internalOptions) {
|
|
|
1159
1161
|
const durationMs = Date.now() - startTime;
|
|
1160
1162
|
const level = manualLevel ?? (hasError ? "error" : hasWarn ? "warn" : "info");
|
|
1161
1163
|
let forceKeep = false;
|
|
1164
|
+
const auditForceKeep = consumeAuditForceKeep(context);
|
|
1162
1165
|
if (overrides?._forceKeep) forceKeep = true;
|
|
1163
|
-
else if (
|
|
1166
|
+
else if (auditForceKeep) forceKeep = true;
|
|
1164
1167
|
else if (globalSampling.keep?.length) forceKeep = shouldKeep({
|
|
1165
1168
|
status: overrides?.status ?? context.status,
|
|
1166
1169
|
duration: durationMs,
|
|
@@ -1542,75 +1545,6 @@ function auditDiff(before, after, options = {}) {
|
|
|
1542
1545
|
return result;
|
|
1543
1546
|
}
|
|
1544
1547
|
/**
|
|
1545
|
-
* Define a typed audit action with optional fixed target type and catalog metadata.
|
|
1546
|
-
*
|
|
1547
|
-
* Returns a curried helper that fills in the action name (and target shape
|
|
1548
|
-
* if provided) so call sites stay terse and the action set is discoverable
|
|
1549
|
-
* in one place. Metadata (`description`, `severity`, `requiresChanges`, …)
|
|
1550
|
-
* is exposed on the factory for introspection, docs, and review tooling.
|
|
1551
|
-
*
|
|
1552
|
-
* @example
|
|
1553
|
-
* ```ts
|
|
1554
|
-
* const refund = defineAuditAction('invoice.refund', {
|
|
1555
|
-
* target: 'invoice',
|
|
1556
|
-
* severity: 'high',
|
|
1557
|
-
* requiresChanges: true,
|
|
1558
|
-
* redactPaths: ['cardNumber'],
|
|
1559
|
-
* })
|
|
1560
|
-
*
|
|
1561
|
-
* log.audit(refund({
|
|
1562
|
-
* actor: { type: 'user', id: user.id },
|
|
1563
|
-
* target: { id: 'inv_889' }, // type inferred as 'invoice'
|
|
1564
|
-
* outcome: 'success',
|
|
1565
|
-
* }))
|
|
1566
|
-
* ```
|
|
1567
|
-
*/
|
|
1568
|
-
function defineAuditAction(action, options) {
|
|
1569
|
-
const targetType = options?.target;
|
|
1570
|
-
const factory = ((input) => {
|
|
1571
|
-
const merged = {
|
|
1572
|
-
...input,
|
|
1573
|
-
action
|
|
1574
|
-
};
|
|
1575
|
-
if (targetType && input.target && !input.target.type) merged.target = {
|
|
1576
|
-
...input.target,
|
|
1577
|
-
type: targetType
|
|
1578
|
-
};
|
|
1579
|
-
return merged;
|
|
1580
|
-
});
|
|
1581
|
-
Object.defineProperties(factory, {
|
|
1582
|
-
action: {
|
|
1583
|
-
value: action,
|
|
1584
|
-
enumerable: true
|
|
1585
|
-
},
|
|
1586
|
-
target: {
|
|
1587
|
-
value: options?.target,
|
|
1588
|
-
enumerable: true
|
|
1589
|
-
},
|
|
1590
|
-
description: {
|
|
1591
|
-
value: options?.description,
|
|
1592
|
-
enumerable: true
|
|
1593
|
-
},
|
|
1594
|
-
severity: {
|
|
1595
|
-
value: options?.severity,
|
|
1596
|
-
enumerable: true
|
|
1597
|
-
},
|
|
1598
|
-
requiresChanges: {
|
|
1599
|
-
value: options?.requiresChanges,
|
|
1600
|
-
enumerable: true
|
|
1601
|
-
},
|
|
1602
|
-
requiresReason: {
|
|
1603
|
-
value: options?.requiresReason,
|
|
1604
|
-
enumerable: true
|
|
1605
|
-
},
|
|
1606
|
-
redactPaths: {
|
|
1607
|
-
value: options?.redactPaths,
|
|
1608
|
-
enumerable: true
|
|
1609
|
-
}
|
|
1610
|
-
});
|
|
1611
|
-
return factory;
|
|
1612
|
-
}
|
|
1613
|
-
/**
|
|
1614
1548
|
* Test helper that captures every audit event emitted while it is active.
|
|
1615
1549
|
*
|
|
1616
1550
|
* Returns `{ events, restore, toIncludeAuditOf, assertAudit }`:
|
|
@@ -1688,14 +1622,21 @@ function consumeAuditForceKeep(context) {
|
|
|
1688
1622
|
if (context.audit) return true;
|
|
1689
1623
|
return false;
|
|
1690
1624
|
}
|
|
1625
|
+
/** @internal True when `audit` has the minimum fields required before emit decoration. */
|
|
1626
|
+
function isCompleteAuditFields(a) {
|
|
1627
|
+
if (!a || typeof a !== "object") return false;
|
|
1628
|
+
const audit = a;
|
|
1629
|
+
return typeof audit.action === "string" && typeof audit.actor?.type === "string" && typeof audit.actor?.id === "string";
|
|
1630
|
+
}
|
|
1691
1631
|
/**
|
|
1692
1632
|
* @internal Decorate the audit field on an event right before drain — fills
|
|
1693
1633
|
* in the deterministic idempotency key. Called by the logger pipeline so
|
|
1694
1634
|
* it works for both `log.audit()` and direct `log.set({ audit })` paths.
|
|
1635
|
+
* Skips partial/legacy shapes that omit required actor fields.
|
|
1695
1636
|
*/
|
|
1696
1637
|
function finalizeAudit(event) {
|
|
1697
1638
|
const a = event.audit;
|
|
1698
|
-
if (!a) return;
|
|
1639
|
+
if (!isCompleteAuditFields(a)) return;
|
|
1699
1640
|
const decorated = decorateAudit(a, String(event.timestamp));
|
|
1700
1641
|
event.audit = decorated;
|
|
1701
1642
|
_testCollector?.(decorated, event);
|
|
@@ -1862,17 +1803,14 @@ function signed(drain, options) {
|
|
|
1862
1803
|
}
|
|
1863
1804
|
/**
|
|
1864
1805
|
* @internal Resolve the Web Crypto SubtleCrypto interface. Available natively
|
|
1865
|
-
* in browsers, Node 19+, Bun, Deno,
|
|
1866
|
-
*
|
|
1867
|
-
*
|
|
1806
|
+
* in browsers, Node 19+, Bun, Deno, Cloudflare Workers, and Convex. Requires
|
|
1807
|
+
* `globalThis.crypto.subtle` — no `node:crypto` fallback so non-Node bundlers
|
|
1808
|
+
* can import the main entrypoint without resolving Node built-ins (#387).
|
|
1868
1809
|
*/
|
|
1869
|
-
|
|
1870
|
-
const
|
|
1871
|
-
if (
|
|
1872
|
-
|
|
1873
|
-
/* @vite-ignore */
|
|
1874
|
-
"node:crypto"
|
|
1875
|
-
)).webcrypto.subtle;
|
|
1810
|
+
function getSubtle() {
|
|
1811
|
+
const subtle = globalThis.crypto?.subtle;
|
|
1812
|
+
if (subtle) return subtle;
|
|
1813
|
+
throw new Error("[evlog/audit] Web Crypto is not available. signed() requires globalThis.crypto.subtle (Node 19+, modern browsers, Cloudflare Workers, Convex, Bun, Deno).");
|
|
1876
1814
|
}
|
|
1877
1815
|
function normalizeAlgo(algorithm) {
|
|
1878
1816
|
switch (algorithm.toLowerCase()) {
|
|
@@ -1893,10 +1831,10 @@ function bufToHex(buf) {
|
|
|
1893
1831
|
return out;
|
|
1894
1832
|
}
|
|
1895
1833
|
async function digestHex(algorithm, data) {
|
|
1896
|
-
return bufToHex(await
|
|
1834
|
+
return bufToHex(await getSubtle().digest(normalizeAlgo(algorithm), new TextEncoder().encode(data)));
|
|
1897
1835
|
}
|
|
1898
1836
|
async function hmacHex(algorithm, secret, data) {
|
|
1899
|
-
const subtle =
|
|
1837
|
+
const subtle = getSubtle();
|
|
1900
1838
|
const hash = normalizeAlgo(algorithm);
|
|
1901
1839
|
const key = await subtle.importKey("raw", new TextEncoder().encode(secret), {
|
|
1902
1840
|
name: "HMAC",
|
|
@@ -1946,6 +1884,6 @@ const auditRedactPreset = { paths: [
|
|
|
1946
1884
|
"set-cookie"
|
|
1947
1885
|
] };
|
|
1948
1886
|
//#endregion
|
|
1949
|
-
export {
|
|
1887
|
+
export { definePlugin as A, isLoggerInitialized as C, mergeInto as D, markWideEventDrainStarted as E, normalizeRedactConfig as F, redactEvent as I, resolveRedactConfig as L, enricherPlugin as M, getEmptyPluginRunner as N, shouldKeep as O, isGloballyRedacted as P, isEnabled as S, lockLogger as T, createRequestLogger as _, auditEnricher as a, getGlobalPluginRunner as b, buildAuditFields as c, mockAudit as d, signed as f, createLogger as g, _log as h, auditDiff as i, drainPlugin as j, createPluginRunner as k, consumeAuditForceKeep as l, withAuditMethods as m, AuditDeniedError as n, auditOnly as o, withAudit as p, audit as r, auditRedactPreset as s, AUDIT_SCHEMA_VERSION as t, finalizeAudit as u, getEnvironment as v, isLoggerLocked as w, initLogger as x, getGlobalDrain as y };
|
|
1950
1888
|
|
|
1951
|
-
//# sourceMappingURL=audit-
|
|
1889
|
+
//# sourceMappingURL=audit-BXCYMjcC.mjs.map
|